Bug
A bug is a gap between what the software did and what somebody expected it to do. A bug report has two jobs. Prove the gap is real, and hand the engineer everything they need to reproduce it and close it.
Most reports do the first job and skip the second. "The pay link is broken," filed as the whole ticket, means the engineer's first hour goes to reconstructing what you saw instead of fixing what's broken. And if they reconstruct it wrong, they can land on a different bug in the same space and never fix the one you reported. The report needs to be simple enough that a busy person fills it out in a few minutes without dreading it. It can't be a chore, or people go back to filing one-liners.
The spine of a good report is three lines. What you did, what you got, what should have happened. Everything else on the card is evidence and logistics, plus one field that fills in after the fix.
The card, blank
Title
[The observed behavior, not your diagnosis]
What happened
[What you saw, specifically]
What should have happened
[The documentation, acceptance criterion, or spec you expected. Cite it.]
Steps to reproduce
- [Start from a state anyone can reach]
- [The exact actions, in order]
- [The point where it breaks]
Environment
[Where it happened: build or version, browser or device, account type]
Evidence
[Logs, screenshots, the request and the response]
Severity
[Critical / Major / Minor / Cosmetic]
Root cause / countermeasure
[Empty at filing. The engineer who fixed it fills it in after.]
The format here is relatively standard. This is my favorite version of it. Copy the shape into your tracker and make it the description format for every bug you file.
Field by field, bad versus good
Title. Report what you saw, not what you think caused it.
- Bad. "Caching bug in the link service"
- Good. "Pay link opens the payment form for an invoice that's already paid"
The bad title is a diagnosis, and if that diagnosis is wrong, you've sent the engineer down your bad guess before they've read line two of the card. The good title points straight at the gap and makes no claim about why. Report the symptom you can actually see. Leave the why to the person doing the fix.
What happened. The specific event, not the summary.
- Bad. "The pay link is broken"
- Good. "A customer paid invoice 1042 through its reminder link, clicked the same link the next morning, and got a live payment form for the full amount"
"Broken" describes your mood. The good version names the invoice, the sequence, and what appeared on screen. The engineer should be able to picture the exact moment it went wrong from your paragraph alone.
What should have happened. Cite the source, don't describe it from memory.
- Bad. "It should work"
- Good. "An already-paid invoice resolves to a paid confirmation, not a payment form. That expectation is written on the pay-link task card."
This is the half people skip, and it's half the argument. Point at the acceptance criterion, the spec, or the doc page, whichever one you actually checked. When the card cites its source, the engineer reads it, reproduces it, and gets to work. When it doesn't, they stop and come find you first, and now two people are on one bug.
Steps to reproduce. From a state anyone can reach.
- Bad. "Just click the link"
- Good. "1. Pay an overdue invoice through its reminder link. 2. Wait for the payment to settle. 3. Open the same link again. The payment form loads instead of the confirmation."
The steps start where any engineer can start, not where you happen to be standing. Exact actions, in order, ending at the point where it breaks. If you can't write the steps, you don't have a reproducible bug yet, and saying so on the card is more useful than filing a mystery.
Environment and evidence. Where did it happen, and what did the system actually say.
"Chrome" isn't an environment. "Production, desktop browser, customer account with one settled invoice" is. And attach what the system actually said. The screenshot, the request-and-response pair, the log line. Your description says what happened. The evidence proves it.
Severity is how bad it is. Priority is when it gets fixed. Two different questions.
The standard ladder, printed plainly because the point of a scale is that everyone means the same thing by the same word:
- Critical. Users are blocked, and there's no way around it.
- Major. It's broken, but a workaround exists.
- Minor. It's wrong, but livable.
- Cosmetic. It looks bad and works fine.
The reporter makes the severity call so the priority conversation starts from one word instead of a paragraph. If your team runs its own ladder, use theirs; consistency beats precision here.
Root cause. Empty at filing, filled after the fix.
The engineer who fixed the thing writes this one, and your job is to make sure it doesn't sit empty a week later. Ask why, then ask why again, about five times over, until you're past the cause that turns out to be just another symptom. The exercise comes off Toyota's factory floors, and it's aimed at the process, not at a person. What you're hunting is a countermeasure, the change that keeps this entire class of bug from coming back, not just the patch that closes this one card.
Once it's filed, a bug card rides the same board as everything else your team builds, column by column from To do over to Done. The board's whole lifecycle is on the Agile page; I'm not re-walking it here.
The card, filled
One specimen from the invoicing case. The pay-link feature you followed down from the opportunity. Every detail below is made up to show the shape of a filled card, and none of it comes from a real incident. Notice what it breaks. The already-paid behavior you watched get written onto the task card.
Title
Pay link opens the payment form for an invoice that's already paid
What happened
A customer paid invoice 1042 through its reminder link, clicked the same link again the next morning, and got a live payment form for the full amount.
What should have happened
An already-paid invoice resolves to a paid confirmation, not a payment form. That expectation is written on the pay-link task card.
Steps to reproduce
- Pay an overdue invoice through its reminder link
- Wait for the payment to settle
- Open the same link again. The payment form loads instead of the confirmation
Environment
Production, desktop browser, customer account with one settled invoice
Evidence
Screenshot of the live form; the lookup request and response showing the invoice still marked open (unpaid) after settlement
Severity
Major. The payment went through and the paid status is visible in the customer's account, so there's a way around it. But a double charge is one click away, which is why it sits at the top of Major.
Root cause / countermeasure
[Empty at filing]
Everything above that last field is what the engineer got at the moment of filing. It's enough to start work without a single follow-up question, and that's the bar. The last field fills in after the fix, and here's what it held. The system only updated its payment records once a night, so the link was checking yesterday's data and treating a paid invoice as still open. The countermeasure came in two halves. Check the link against live payment status, and add the already-paid case to the test suite, the case the original tests never covered, so the whole class of bug stays closed. The patch fixed one card. The countermeasure retired the category.
Write it the day you see it
The next time something breaks on you, write the three lines before you touch anything else. What you did, what you got, what should have happened. Attach the evidence, make the severity call, and file it. Same day. A bug report written while the screen is still in front of you takes five minutes. The same report reconstructed tomorrow from memory takes an hour and lands wrong.
And read the card you just filed against the card the work was built from. The bug above broke a rule that was written down before anyone coded a line. When your bug reports keep citing acceptance criteria, your cards are doing their job. When they can't cite anything, the gap isn't in the bug. It's one level up, in the work that never got written down.