01 Overview
A bug report is often treated as a container for a complaint. In practice it is a small piece of technical writing with a reader who has never seen the failure, does not share the reporter's context, and will decide within a minute whether the report is worth acting on. That reader might be a triage lead scanning a queue, an engineer picking up work, a product manager weighing tradeoffs, or a future version of the reporter trying to remember what happened six months ago. The report has to serve all of them without a live narrator.
What a bug report actually promises the reader is narrower and more useful than most people assume. It does not promise a fix. It does not promise that the defect is important. It promises that a specific, describable thing happens under specific, describable conditions, that someone observed it, and that the observation can be repeated or at least reasoned about. Everything else in the report exists to support that promise.
When a report keeps that promise, downstream decisions get easier. Severity becomes a judgment about damage rather than a guess about urgency. Priority becomes a scheduling choice rather than a negotiation about whether the problem is real. Triage becomes routing rather than archaeology. The craft of bug writing is mostly the craft of making a small, honest, checkable claim and then getting out of the reader's way.
02 What the report is actually claiming
Strip away the template fields and a bug report makes a claim of the form: on this build, in this environment, following these steps, this observable result occurs, and this other result was expected. Each clause carries weight. The build matters because behavior changes between versions, and a defect that cannot be tied to a version cannot be confirmed or closed. The environment matters because configuration, data state, permissions, and platform differences routinely explain why one person sees a failure and another does not.
The steps matter because they are the only part of the claim a reader can independently test. The observed result matters because it is the evidence. The expected result matters because it is the part most often left implicit, and implicit expectations are where disagreements breed. If the reporter never states what should have happened, the reader is free to assume the current behavior is intended, and the report quietly dies.
A strong report also distinguishes what was observed from what was inferred. Saying the save button did nothing is an observation. Saying the save handler is broken is a diagnosis. Both can appear in a report, but they belong in different places, and the diagnosis should be labeled as a hypothesis rather than smuggled in as fact. Readers trust reports that separate the two, because it tells them which parts are safe to build on and which parts are the reporter thinking out loud.
03 Severity versus priority
Severity describes how much damage the defect does when it occurs. A crash that loses a user's work is severe. A cosmetic misalignment on a rarely visited settings page is not. Severity is a property of the defect itself, and in principle it can be assessed by anyone who understands the product and the failure mode, without knowing anything about the release schedule. It should be stable across teams and across weeks.
Priority describes when the team intends to fix the defect. It is a scheduling decision, and it depends on context that severity cannot capture: what else is in flight, what the release timeline looks like, how many users hit the path, whether a workaround exists, and whether the affected area is about to be rewritten anyway. A low-severity defect can carry high priority if it blocks a launch or embarrasses a demo. A high-severity defect can carry lower priority if it only occurs in a configuration nobody ships.
The two fields are frequently conflated, and the conflation causes real friction. When severity is used as a proxy for priority, every severe-sounding report becomes an implicit demand for immediate work, and triage turns into an argument about adjectives. Keeping them separate gives the team two honest conversations instead of one confused one: first, how bad is this, and second, when will we deal with it. Both answers can change independently, and saying so out loud is not indecision.
04 Writing steps someone else can follow
Reproduction steps are instructions, and instructions have a reader. The test of a good step list is whether a competent person who has never seen the feature can follow it on the stated build and arrive at the same failure. That means starting from a known state, naming the exact entry point, and describing each action in terms of what the user does rather than what the code does. Clicking a labeled control is a step. Invoking a handler is not.
Keep the list as short as it can be while remaining reliable. Extra steps dilute the signal and make it harder to tell which action actually triggers the failure. If the defect only appears after a particular sequence, say so and explain why that sequence matters. If it appears intermittently, say that too, and describe how often and under what conditions, because an honest intermittent report is far more useful than a fabricated deterministic one.
Include the observed result and the expected result as the final beats of the list, clearly separated. Note anything you had to set up beforehand, such as account state, feature flags, or sample data, because those preconditions are often the difference between a reproduction and a shrug. Where you can, attach evidence that shortens the reader's work: a screenshot, a log excerpt, a short recording. Evidence does not replace steps, but it lets a reader confirm the claim before committing to the reproduction.
05 Running the triage queue
Triage is a routing meeting, not a debate about whether the reporter is right. The goal is to move each incoming report to a state where someone owns the next action. That usually means one of a small set of outcomes: accept it into the backlog with a severity and priority, mark it as a duplicate of an existing report, send it back for more information, decline it as intended behavior, or record it as not reproducible on the current build. Each outcome is legitimate, and each needs a reason attached.
Good triage depends on reports that are cheap to evaluate. A report with a clear affected area, a stated build, and short steps can be routed in seconds. A report that requires the triage lead to reconstruct the environment or guess at the expected behavior consumes the meeting's attention and delays everyone else. This is why report quality is not a stylistic preference; it is throughput. The queue moves at the speed of its least legible entry.
When a report is deferred or declined, record why. The reason is the only thing that prevents the same report from being re-filed next month and re-litigated from scratch. When a report is accepted, set severity and priority as separate fields and let them disagree if the situation warrants it. Triage is also the right moment to check whether the defect is a symptom of something broader, because a cluster of small reports pointing at one root cause is a finding in itself.
06 When a defect comes back
A defect that returns after being marked fixed is not a failure of the process; it is information. The first question is whether it is genuinely the same defect or a new one that resembles it. Same steps, same build lineage, same observable result suggests a regression or an incomplete fix. Different steps or a different surface suggests a new report that should reference the old one rather than reopen it blindly.
If it is a regression, the report should say so explicitly and link the earlier work. That link is what lets an engineer see what changed and when, and it is often more valuable than any amount of new description. Include the build where the defect was last known to be absent if you can determine it, because that narrows the search enormously. If you cannot determine it, say that too rather than guessing.
A returning defect is also a prompt to examine the verification step. If the fix was closed without a reproduction that exercised the original failure, the closure was optimistic. Verification means running the steps that once failed and confirming they now pass, on the build that claims the fix. When a defect comes back, the honest response is to strengthen the verification habit, not to assign blame. The report's job is to make the recurrence visible and traceable; the team's job is to learn from it.
07 Frequently asked questions
How much detail is too much? There is no fixed limit, but there is a useful test: every sentence should help the reader reproduce, understand, or route the defect. Background that does none of those things can be trimmed or moved to a comment. Long reports are not automatically thorough, and short reports are not automatically lazy. The measure is whether the reader can act.
What if I cannot reproduce it reliably? File it anyway, and be explicit about the uncertainty. Describe what you saw, how often, and under what conditions, and note what you tried. An intermittent report with honest boundaries is more useful than silence, and it gives the team something to instrument. Marking it as not reproducible is a valid triage outcome, but it should be a conclusion reached after investigation, not a reflex.
Who decides severity and priority? Anyone can propose them, but the team owns them. Reporters should state the impact they observed and let triage set the fields, because priority depends on context the reporter may not have. If you disagree with the assessment, say so with reasons rather than restating the original claim. The report's promise is that the defect is real and describable; the scheduling conversation is a separate, legitimate discussion that happens after that promise is kept.