Fixes fail two ways, both producing a green-looking diff that ships the bug. Patching the
symptom: suppressing the visible failure while the cause survives, so the defect recurs through a
different path. A regression test that does not exercise the bug: one green before the patch
proves nothing, because it stays green if the fix is deleted. This guide adds the fix discipline on
top of the base implement-task rules. These are conventions the review packet inspects — nothing
enforces them at edit time.
Writing the bug report is a different job with its own guide in the starter kit's advanced tier
(write-bug-report) — this guide consumes a report and produces the fix. A test that fails
sometimes is a different oracle entirely: load fix-flaky-test, not this.
Rules
- Reproduce the bug in your worktree before you patch. Re-run the report's reproduction and paste the failing output. If you cannot reproduce, do not patch — the discrepancy between your environment and the report's is itself a finding (versions, seeds, fixtures, clock, OS), not a dismissal. The reproduction is the falsification target for the whole task; without it, "fixed" is a claim with no possible counter-evidence.
- Patch the root cause, not the symptom. Before patching, restate in your own words why this location is the cause and not merely where the failure became visible; if you cannot, you have not root-caused it (see Hunting the cause below). Swallowing the error, clamping the value, or special-casing the one triggering input leaves the cause live under a different trigger.
- The regression test fails before the fix and passes after. Patch your fix out (revert it, or comment out the path it touches); run the test — it must fail. Restore the fix; run it — it must pass. Paste both transitions. A regression test that stays green when the fix is removed is a tautology. Assert on the behavior the bug broke — the output, the returned value, the emitted event — not on internal state.
- Run the full suite, not just the regression test, and paste the output. A patch that passes its own test but breaks a neighbor trades a known bug for an unknown one.
- Keep the fix minimal; no bundling. Bugs have neighbors, and a fix task is the most tempting place to "just also fix" the related defect or rename the confusing variable. Don't. Every related discovery is a finding candidate in your summary, not a second fix in the diff — a one-cause fix is reviewable; a bundle is not.
- Record why the patch addresses the cause in your summary, in one or two sentences. The reviewer checks exactly this. "The patch worked" is a verification output, not a reason.
- Paste everything; resolve commands from
AGENTS.md; ask when a command is undefined. A guessed test command produces a false signal about whether the bug is gone. And never write a review result on your own work.
Hunting the cause
Root-causing demands hostility to the first plausible explanation:
- The first suspicious line is rarely the origin. Trace from the observable failure back to the state-plus-input that produces it; a correlated symptom upstream of the cause is the classic false catch.
- Anchor the cause at file:line, with the state and input that trigger it. "Somewhere in the cache layer" is a symptom location. A cause you cannot anchor, you cannot prove patched.
- State Expected vs Actual, and Expected by whose authority. Expected comes from the spec's requirement, not your opinion of good behavior. If no requirement covers the broken behavior, say so — that coverage gap is itself a finding.
- "Can't reproduce" is a lead, not an exit. Vary what the report could not: load, parallel siblings, seed, clock, data state. Surface a blocked question if it still will not fire.
Refuses
| Temptation | Do instead |
|---|---|
| Patching where the failure is visible instead of where it starts | Trace to the cause; restate why that location is the origin |
| A regression test that was never seen red | Patch the fix out; paste the failing run, then the passing one |
| "I can't reproduce it, must be environment-specific" | The discrepancy is the finding; investigate or surface a blocker |
| "While I'm here, this related bug…" | Finding candidate in the summary; one cause per fix |
| A test asserting internal state | Assert the behavior the bug broke |
| "Tests passed" with no command, exit, or output | Paste the real, re-runnable output |
| Re-running a sometimes-failing test until green | Wrong guide — load fix-flaky-test |
Self-review gate
Before declaring the task done:
- The pre-patch reproduction output is pasted — the bug fired in your worktree.
- The regression test's red-then-green transition is pasted (fix patched out, then restored).
- The full suite ran after your final edit, output pasted.
- The summary states why the patch addresses the cause, not the symptom.
- The diff is the minimal fix; related defects are finding candidates, not edits.
- You issued no review result on your own work.
Bundled resources
references/task-template.md— a working-notes scaffold for the run: reproduction block, hypothesis trail (each rejected attempt teaches the next), progress checklist, pasted evidence, self-review. The task packet itself uses the kit's task template.