engineering
Ticket Writing
Write clear, well-scoped engineering tickets with acceptance criteria, technical context, effort estimates, and dependency mapping.
ticketsjiralinearproject-management
Works well with agents
ticket-writing/
SKILL.md
Markdown| 1 | |
| 2 | # Ticket Writing |
| 3 | |
| 4 | ## Before you start |
| 5 | |
| 6 | Gather the following from the user: |
| 7 | |
| 8 | 1. **What needs to be built/changed?** (Feature, fix, refactor, or chore) |
| 9 | 2. **Why?** (Link to PRD, user report, incident, or business goal) |
| 10 | 3. **What's the tech stack?** (Languages, frameworks, database, hosting) |
| 11 | 4. **What's the team context?** (How familiar is the team with this area of the codebase?) |
| 12 | |
| 13 | If the user gives you a vague request ("write tickets for search"), push back: "What specific behavior should search have? What does the user see today vs. what should they see?" |
| 14 | |
| 15 | ## Ticket template |
| 16 | |
| 17 | Use the following template for every ticket: |
| 18 | |
| 19 | --- |
| 20 | |
| 21 | ### Title |
| 22 | |
| 23 | Use the format: `[Action verb] [specific thing] [context]` |
| 24 | |
| 25 | **Good**: "Add rate limiting to /api/search endpoint (10 req/s per user)" |
| 26 | **Bad**: "Fix search" or "Search improvements" or "Rate limiting" |
| 27 | |
| 28 | ### Context |
| 29 | |
| 30 | 2-3 sentences explaining WHY this work matters. Link to the parent epic, PRD, or incident. The engineer should understand the business motivation without reading another document. |
| 31 | |
| 32 | ``` |
| 33 | The /api/search endpoint currently has no rate limiting, which allowed a single |
| 34 | user to generate 50k requests in an hour last Tuesday (INC-234), degrading |
| 35 | search performance for all users. This ticket adds per-user rate limiting to |
| 36 | prevent abuse while maintaining normal usage patterns. |
| 37 | ``` |
| 38 | |
| 39 | ### Acceptance Criteria |
| 40 | |
| 41 | Write specific, testable conditions. Use the format: |
| 42 | |
| 43 | ``` |
| 44 | - [ ] Given [precondition], when [action], then [expected result] |
| 45 | - [ ] Given a user has made 10 requests in the last second, |
| 46 | when they make an 11th request, |
| 47 | then they receive a 429 response with a Retry-After header |
| 48 | - [ ] Given a user has been rate-limited, |
| 49 | when the rate limit window expires, |
| 50 | then their next request succeeds normally |
| 51 | - [ ] Rate limit configuration (requests per second, window size) |
| 52 | is stored in environment variables, not hardcoded |
| 53 | ``` |
| 54 | |
| 55 | Rules for acceptance criteria: |
| 56 | - Every criterion must be independently verifiable |
| 57 | - Include both the happy path AND edge cases |
| 58 | - Include error/failure states explicitly |
| 59 | - If there are performance requirements, state them with numbers |
| 60 | |
| 61 | ### Technical Notes |
| 62 | |
| 63 | Point the engineer in the right direction without dictating the implementation: |
| 64 | |
| 65 | ``` |
| 66 | Relevant files: |
| 67 | - `src/api/routes/search.ts` — endpoint handler |
| 68 | - `src/middleware/` — existing middleware patterns |
| 69 | |
| 70 | Considerations: |
| 71 | - We use Redis for session storage; consider using it for rate limit |
| 72 | counters too |
| 73 | - The existing auth middleware in `src/middleware/auth.ts` follows a |
| 74 | pattern that could be adapted |
| 75 | - Check if the API gateway already provides rate limiting before |
| 76 | implementing at the application level |
| 77 | ``` |
| 78 | |
| 79 | ### Effort Estimate |
| 80 | |
| 81 | Provide a t-shirt size with reasoning: |
| 82 | |
| 83 | ``` |
| 84 | Size: M (2-3 days) |
| 85 | Reasoning: The rate limiting logic itself is straightforward, but this |
| 86 | requires adding Redis counter logic, a new middleware, tests, and |
| 87 | updating API documentation. No schema changes needed. |
| 88 | ``` |
| 89 | |
| 90 | ### Dependencies |
| 91 | |
| 92 | ``` |
| 93 | Blocked by: None |
| 94 | Blocks: SEARCH-456 (search performance monitoring — needs rate limiting in place first) |
| 95 | Related: SEARCH-123 (search index optimization — separate work, but same area) |
| 96 | ``` |
| 97 | |
| 98 | --- |
| 99 | |
| 100 | ## Ticket sizing guide |
| 101 | |
| 102 | | Size | Duration | Characteristics | |
| 103 | |------|----------|----------------| |
| 104 | | **XS** | < 1 day | Config change, copy update, one-line fix with existing test coverage | |
| 105 | | **S** | 1-2 days | Single file/component change, clear implementation path, tests exist | |
| 106 | | **M** | 2-4 days | Multiple files, possibly new patterns, tests needed | |
| 107 | | **L** | 1-1.5 weeks | Crosses system boundaries, needs design decisions, may need migration | |
| 108 | | **XL** | > 1.5 weeks | **Should be broken down further.** If a ticket is XL, split it. | |
| 109 | |
| 110 | ## Splitting rules |
| 111 | |
| 112 | A ticket should be split when: |
| 113 | - It has more than 5 acceptance criteria |
| 114 | - It crosses more than 2 system boundaries (e.g., frontend + API + database + background job) |
| 115 | - The estimate is L or larger |
| 116 | - Different parts could be worked on by different people in parallel |
| 117 | |
| 118 | How to split: |
| 119 | 1. **By layer**: Backend ticket + Frontend ticket + Migration ticket |
| 120 | 2. **By behavior**: Happy path ticket + Error handling ticket + Edge cases ticket |
| 121 | 3. **By user flow**: Create ticket + Read ticket + Update ticket + Delete ticket |
| 122 | |
| 123 | Each sub-ticket must be independently deployable and valuable. |
| 124 | |
| 125 | ## Quality checklist |
| 126 | |
| 127 | Before delivering tickets, verify: |
| 128 | |
| 129 | - [ ] Title starts with an action verb and is specific enough to be understood without reading the body |
| 130 | - [ ] Context explains WHY, not just WHAT |
| 131 | - [ ] Every acceptance criterion is testable with a clear pass/fail condition |
| 132 | - [ ] Technical notes point to relevant files/patterns without dictating implementation |
| 133 | - [ ] Estimate includes reasoning, not just a size |
| 134 | - [ ] Dependencies are bidirectional (if A blocks B, B should note it's blocked by A) |
| 135 | - [ ] No ticket is estimated larger than L — split XL tickets |
| 136 | - [ ] Error states and edge cases are covered in acceptance criteria, not just happy paths |
| 137 | |
| 138 | ## Common mistakes to avoid |
| 139 | |
| 140 | - **Acceptance criteria that are actually tasks**. "Implement the search function" is a task. "Given a query, when the user submits it, then results appear within 200ms" is a criterion. |
| 141 | - **Missing the "not" cases**. Always include what should NOT happen. "The system must NOT return results from deleted records" is as important as what it should return. |
| 142 | - **Context-free tickets**. If an engineer needs to read the PRD, the Slack thread, AND talk to the PM to understand the ticket, the ticket is missing context. |
| 143 | - **Implicit acceptance criteria**. "It should work like the existing search" is not a criterion. Spell out the specific behaviors, even if they match existing patterns. |
| 144 | - **Coupling unrelated work**. "Add rate limiting AND update the search algorithm" is two tickets. Don't bundle work that could fail independently. |
| 145 |