Describing a bug so it can be found
By the end you can
- Report what you observed instead of what you concluded, and know why the difference is expensive
- Supply the three parts of a findable bug report — symptom, likely location, and what fixed looks like
- Ask for a failing test first, so the fix has something to prove itself against
- Distinguish reporting the symptom from fixing the symptom, which are opposite instructions
the session cache is broken, fix itSomewhere between noticing the problem and typing that sentence, you did the hardest part of debugging — and then you threw away the evidence and kept only the conclusion.
If your conclusion is right, this costs you nothing. If it is wrong, you have just aimed an agent with a lot of momentum at the wrong file, and everything it finds there will be read as confirmation. You will get a plausible fix to a cache that was never broken, and the actual bug will still be there when you close the session.
What a findable report contains
The documented rewrite of fix the login bug supplies three things, and it is
worth seeing them separated (Best
practices):
users report that login fails after session timeout. check the auth flow in
src/auth/, especially token refresh. write a failing test that reproduces the
issue, then fix it.| Part | The clause | Why it earns its place |
|---|---|---|
| Symptom | login fails after session timeout | Observable, falsifiable, and not yet a theory |
| Likely location | check the auth flow in src/auth/ | Scopes the search without closing it |
| What "fixed" means | write a failing test that reproduces the issue | Gives the loop a condition it can check itself |
Notice that the middle clause is a hint, not an instruction. "Check the auth flow, especially token refresh" leaves room for the answer to be somewhere else. "The token refresh is broken" does not. One sentence invites a search; the other ends it.
Why the failing test goes first
write a failing test that reproduces the issue, then fix it is doing more work
than it looks like.
A test written before the fix has to reproduce the bug from your description alone. If it cannot, you have learned something enormous for the price of one turn: the bug is not where either of you thought, or your description of it is wrong. Both are much cheaper to find now than after a diff exists.
And once it exists, the loop has a pass condition it can run without you. That is the difference between a session you have to watch and one you can leave (Best practices). The documented failure it prevents has a name — the trust-then-verify gap, where a plausible-looking implementation quietly does not handle the edge case. The documented fix is blunt: if you cannot verify it, do not ship it.
Paste the error. All of it.
The other documented rewrite in this family:
the build is failingthe build fails with this error: [paste the actual error]. fix it and verify the
build succeeds. address the root cause, don't suppress the error.Your summary of a stack trace is a paraphrase, and Lesson 2.2 already made that case. The error text is free, exact, and contains the line number you were about to leave out.
The word "symptom" means two opposite things
This trips up nearly everyone, because both instructions appear on the same documentation page:
- When reporting: give the symptom, not your diagnosis. You do not yet know the cause; asserting one narrows the search prematurely.
- When fixing: address the root cause, not the symptom. A
try/catchthat swallows the error makes the symptom disappear and leaves the bug in place.
They are not in conflict once you see who each one is addressed to. The first governs what you put in; the second governs what you will accept back. Ask for observations, insist on causes.
Checkpoint
You should be able to take a bug you have already diagnosed in your head and write the report without the diagnosis in it — symptom, a location hint that still allows other answers, and a failing test as the definition of done.