A bug report arrives with a confident story: "The Orders page is slow because the new caching layer is broken." The reporter might be a customer, a teammate, or an AI agent that mined the logs overnight. Either way, the story mixes what they saw with what they think caused it.
If you plan the fix from the story, you fix the theory, not the bug. AI-written issues make this worse. They read like finished diagnoses, complete with a suspected file and line number, and it is tempting to skip straight to the code.
Every bug report contains two kinds of statement:
Rewrite the report as a list and tag each line. If nothing observable survives, stop and ask the reporter for one concrete thing they saw before you write any code.
Orders page is broken after the cache change
The Orders page has been really slow since yesterday. It is because the new Redis cache is not being hit, so every request goes to the database. The OrderCacheService probably has the wrong key format. Please fix the key format.
❌ Figure: Bad example - One observable (slow since yesterday) buried under three guesses and a proposed fix
| Claim | Type |
| Orders page slow since yesterday | Observable, needs a time and a measurement |
| Redis cache is not being hit | Inference |
| Every request goes to the database | Inference |
OrderCacheService has the wrong key format | Inference |
| Fix the key format | Proposed fix, based on an inference |
✅ Figure: Good example - The same report as a claim table. Only one line is evidence, and it still needs numbers
Before you look at code, write one sentence that states the fault in measurable terms:
Between 09:10 and 09:40 on 2 September, GET /orders for customer ALFKI took 12 seconds instead of the usual 200 ms.Everything you do next exists to explain that sentence. If you cannot write it, you do not have a bug yet. You have a feeling.
Check the claims against logs, metrics, the database, and a reproduction. Do not check them against the issue text or against the last person who touched the file.
Mark each claim from the report as one of:
Plan the fix from the confirmed claims only. Put the table in the pull request so the reviewer can see what was checked.
| Claim | Result | Evidence |
| Orders page slow since yesterday | Confirmed | p95 for GET /orders rose from 210 ms to 11.8 s at 08:52 on 2 Sep |
| Redis cache is not being hit | Refuted | Cache hit ratio steady at 94% before and after the onset |
| Every request goes to the database | Refuted | Database calls per request are 3 before and after the onset, and database time per request is unchanged |
OrderCacheService has the wrong key format | Could not verify | Keys match the integration tests, but nobody has inspected a live key. Irrelevant now that the cache is ruled out |
| Actual cause | Confirmed | Traces show 96% of request time inside calls to the carrier API, one call per order line. The calls were added in the 08:50 deployment. Reproduced on staging with a 120-line order |
✅ Figure: Good example - The proposed fix would have changed the cache key and left the real cause in place
Agents write plausible bug reports fast, and they write them with the same confident tone whether the diagnosis is right or wrong. When an agent triages or investigates a bug, give it the same steps:
Put these steps in the prompt or skill the agent uses for bug triage, so it verifies before it explores the code. Once the anchor sentence and the confirmed claims exist, Do you use AI to explore unfamiliar code? has prompts for the code-reading part.
Tip: Once the cause is confirmed, write a test that fails on the unfixed code before you fix it. The test proves the fix changes the behaviour you observed. It does not replace the evidence for the cause, so keep both.