Diagnose
Read the Codex desktop binding when this workflow needs harness mechanics, model routing, or recovery.
A fix may not ship without a named cause: one plain sentence stating what was wrong, backed by evidence, readable by a non-engineer decider. This skill is the discipline a working lane follows inline when fixing bugs. It is not a lane type of its own, and it deliberately has no binding slots: everything repo-specific already arrived in the lane's brief.
The named-cause test is the trigger, and it binds on every fix. If you can already state the cause in one sentence and point at the evidence, the loop is satisfied: ship. If you cannot, the loop runs, however small the bug looks. "Hard bugs only" is the wrong gate, because the first fix attempt is where the vibes-fix ships: a change that makes the symptom go away for reasons nobody can state.
The loop
Six steps, in order. A failed fix re-enters at the step whose output it disproved, usually the hypothesis list, sometimes the repro itself.
- Reproduce red. Write a failing automated test that catches the user's exact symptom, before any fix attempt; it is the loop you iterate against now and the regression test you keep after. Where test infra genuinely cannot reach the bug (timing, a third-party boundary), the recorded fallback is a documented manual repro with exact steps, flagged as a fallback at close-out, never silently substituted.
- Minimize proportionately. Shrink the repro until it is tight, fast and deterministic enough to iterate against, cutting one element at a time and re-running after each cut. Tight is the purpose and the stopping point: a two-second deterministic loop is the tool; shrinking past it is polishing the repro instead of finding the cause. Non-deterministic bugs minimize toward a reproduction rate high enough to debug against.
- Hypothesize falsifiably. Generate several ranked hypotheses before testing any: a single hypothesis anchors on the first plausible idea. Each is stated so evidence could kill it, skeptic-style: "if X is the cause, then changing Y makes the bug disappear." A hypothesis with no prediction is a vibe; sharpen it or discard it.
- Instrument. Evidence gathering precedes any fix attempt. Each probe maps to one hypothesis's prediction, changing one variable at a time: a breakpoint beats ten logs, targeted logs beat logging everything and grepping. Tag every debug probe with one unique prefix so cleanup is a single grep. When a check fails, suspect the observation method before the system: indirect evidence (mtimes, cached screenshots, self-reports) feels cheaper than direct observation and lies more often.
- Fix. Only against the hypothesis the instrumentation confirmed. Watch the red test go green.
- Regression-test. Re-run the original, un-minimized repro; keep the failing test from step 1 in the suite as the regression test; grep the probe tag out. Then write the closing artifact.
The closing artifact
Two things, and close-out audits check for both:
- The named cause: one plain sentence a non-engineer decider reads without translation ("the cache key omitted the locale, so two languages shared one entry"), with the evidence that confirmed it.
- The regression test: the step-1 test, now green in the suite; or the recorded manual-repro fallback with its exact steps, flagged as a fallback.
An unnamed cause is not done, whatever the symptom is doing.
Structural causes feed the friction gate
Sometimes the named cause says the bug is a symptom: a missing seam, a rule duplicated in N places and updated in N−1. The lane still fixes the instance under this skill's own bar, then reports the structural cause as friction, codebase-review's third entry gate, in its close-out summary. The diagnosing lane never expands its own scope to fix the structure: that is a review-and-disposition matter, decided with more information than the lane has.
Where it sits in the pack
- Lane briefs: orchestrate points bug-shaped items here, so the discipline arrives with the work.
- Mid-build bugs: implement routes a bug surfacing mid-build here; the named-cause test binds before the lane resumes building.
- Close-out audit: the orchestrator's audit checks the two closing artifacts on every bug fix; the named cause is what it reads first.
- Domain memory: where the repo binds domain-memory, a root cause that reveals a standing fact (an assumption the repo held that the bug just proved wrong) is offered to it as a fact record: the same correction class as a decider correcting a session, with reality as the corrector.
- Deliberately not hooked: handoff GOTCHAS. The durable copy of a diagnosis's lesson is the domain-memory record; writing it into handoff GOTCHAS too would be the same meaning in two places.
Done when (checkable: verify each line before reporting complete)
- The cause is stated in one plain sentence with its confirming evidence, readable by a non-engineer decider, or no fix shipped.
- A failing automated test existed before the fix, caught the user's exact symptom, passes after, and stays in the suite as the regression test; where one genuinely could not reach the bug, the recorded manual repro carries exact steps and is flagged as the fallback at close-out.
- The repro was minimized until tight, fast and deterministic enough to iterate against, and no further.
- Every hypothesis tested carried a falsifiable prediction, and the fix answers the hypothesis the instrumentation confirmed, not a hunch that survived by making the symptom vanish.
- The original un-minimized repro no longer reproduces, and a grep of the probe tag comes back empty.
- A structural cause, where the diagnosis revealed one, is reported as friction toward codebase-review's entry gate, with the instance fixed and the lane's scope unexpanded.
- Where the repo binds domain-memory: a standing fact revealed by the root cause was offered as a record, or there was none.
Attribution
Adapted from Matt Pocock's diagnosing-bugs (MIT). The six-step spine is his: build a tight feedback loop and watch it go red, minimize by cutting one element at a time, generate ranked falsifiable hypotheses each stating its prediction (his format and several of these phrasings, near-verbatim), instrument one variable at a time with tagged probes rather than logging everything, write the regression test before the fix and re-run the original repro after, and state the confirmed cause so the next debugger learns. So are tight as the loop's quality bar, the reproduction-rate framing for flaky bugs, and the post-mortem handoff of architectural causes to his improve-codebase-architecture, the seed of the friction-gate escalation here.
What this pack changes: the named-cause test as the binding trigger (any fix shipping without a nameable cause, not hard bugs only), the failing-automated-test-first bar with the documented manual repro as a recorded, flagged fallback, proportionate minimize (tight enough to iterate against is the stopping point, not load-bearing minimality for its own sake), the plain-sentence closing artifact audited at lane close-out, the domain-memory feed for standing facts, and the friction-gate rewiring into codebase-review's entry gate with the diagnosing lane's scope pinned.
One line in step 4 (suspect the observation method before the system) is adapted from Lauren Tan's principle-prove-it-works (MIT).
1---2name: diagnose-23description: For a bug-fix brief, a bug resisting its first fix, or a fix about to ship without a proven cause, reproduce the failure, state its cause with evidence, and keep a regression check before shipping.4---56# Diagnose78Read the [Codex desktop binding](../../../CODEX.md) when this workflow needs harness mechanics, model routing, or recovery.910A fix may not ship without a **named cause**: one plain sentence stating what was wrong, backed by evidence, readable by a non-engineer decider. This skill is the discipline a working lane follows inline when fixing bugs. It is not a lane type of its own, and it deliberately has no binding slots: everything repo-specific already arrived in the lane's brief.1112**The named-cause test is the trigger, and it binds on every fix.** If you can already state the cause in one sentence and point at the evidence, the loop is satisfied: ship. If you cannot, the loop runs, however small the bug looks. "Hard bugs only" is the wrong gate, because the first fix attempt is where the vibes-fix ships: a change that makes the symptom go away for reasons nobody can state.1314## The loop1516Six steps, in order. A failed fix re-enters at the step whose output it disproved, usually the hypothesis list, sometimes the repro itself.17181. **Reproduce red.** Write a failing automated test that catches the user's exact symptom, **before any fix attempt**; it is the loop you iterate against now and the regression test you keep after. Where test infra genuinely cannot reach the bug (timing, a third-party boundary), the recorded fallback is a documented manual repro with exact steps, flagged as a fallback at close-out, never silently substituted.192. **Minimize proportionately.** Shrink the repro until it is **tight**, fast and deterministic enough to iterate against, cutting one element at a time and re-running after each cut. Tight is the purpose and the stopping point: a two-second deterministic loop is the tool; shrinking past it is polishing the repro instead of finding the cause. Non-deterministic bugs minimize toward a reproduction *rate* high enough to debug against.203. **Hypothesize falsifiably.** Generate several ranked hypotheses before testing any: a single hypothesis anchors on the first plausible idea. Each is stated so evidence could kill it, skeptic-style: "if X is the cause, then changing Y makes the bug disappear." A hypothesis with no prediction is a vibe; sharpen it or discard it.214. **Instrument.** Evidence gathering precedes any fix attempt. Each probe maps to one hypothesis's prediction, changing one variable at a time: a breakpoint beats ten logs, targeted logs beat logging everything and grepping. Tag every debug probe with one unique prefix so cleanup is a single grep. When a check fails, suspect the observation method before the system: indirect evidence (mtimes, cached screenshots, self-reports) feels cheaper than direct observation and lies more often.225. **Fix.** Only against the hypothesis the instrumentation confirmed. Watch the red test go green.236. **Regression-test.** Re-run the original, un-minimized repro; keep the failing test from step 1 in the suite as the regression test; grep the probe tag out. Then write the closing artifact.2425## The closing artifact2627Two things, and close-out audits check for both:2829- **The named cause**: one plain sentence a non-engineer decider reads without translation ("the cache key omitted the locale, so two languages shared one entry"), with the evidence that confirmed it.30- **The regression test**: the step-1 test, now green in the suite; or the recorded manual-repro fallback with its exact steps, flagged as a fallback.3132An unnamed cause is not done, whatever the symptom is doing.3334## Structural causes feed the friction gate3536Sometimes the named cause says the bug is a **symptom**: a missing seam, a rule duplicated in N places and updated in N−1. The lane still fixes the instance under this skill's own bar, then reports the structural cause as **friction**, [codebase-review](../../investigate/codebase-review/SKILL.md)'s third entry gate, in its close-out summary. The diagnosing lane never expands its own scope to fix the structure: that is a review-and-disposition matter, decided with more information than the lane has.3738## Where it sits in the pack3940- **Lane briefs**: [orchestrate](../orchestrate/SKILL.md) points bug-shaped items here, so the discipline arrives with the work.41- **Mid-build bugs**: [implement](../implement/SKILL.md) routes a bug surfacing mid-build here; the named-cause test binds before the lane resumes building.42- **Close-out audit**: the orchestrator's audit checks the two closing artifacts on every bug fix; the named cause is what it reads first.43- **Domain memory**: where the repo binds [domain-memory](../../orient/domain-memory/SKILL.md), a root cause that reveals a **standing fact** (an assumption the repo held that the bug just proved wrong) is offered to it as a fact record: the same correction class as a decider correcting a session, with reality as the corrector.44- **Deliberately not hooked: handoff GOTCHAS.** The durable copy of a diagnosis's lesson is the domain-memory record; writing it into [handoff](../handoff/SKILL.md) GOTCHAS too would be the same meaning in two places.4546## Done when (checkable: verify each line before reporting complete)4748- The cause is stated in one plain sentence with its confirming evidence, readable by a non-engineer decider, or no fix shipped.49- A failing automated test existed before the fix, caught the user's exact symptom, passes after, and stays in the suite as the regression test; where one genuinely could not reach the bug, the recorded manual repro carries exact steps and is flagged as the fallback at close-out.50- The repro was minimized until tight, fast and deterministic enough to iterate against, and no further.51- Every hypothesis tested carried a falsifiable prediction, and the fix answers the hypothesis the instrumentation confirmed, not a hunch that survived by making the symptom vanish.52- The original un-minimized repro no longer reproduces, and a grep of the probe tag comes back empty.53- A structural cause, where the diagnosis revealed one, is reported as friction toward codebase-review's entry gate, with the instance fixed and the lane's scope unexpanded.54- Where the repo binds domain-memory: a standing fact revealed by the root cause was offered as a record, or there was none.5556## Attribution5758Adapted from Matt Pocock's [`diagnosing-bugs`](https://github.com/mattpocock/skills/tree/main/skills/engineering/diagnosing-bugs) (MIT). The six-step spine is his: build a tight feedback loop and watch it go red, minimize by cutting one element at a time, generate ranked falsifiable hypotheses each stating its prediction (his format and several of these phrasings, near-verbatim), instrument one variable at a time with tagged probes rather than logging everything, write the regression test before the fix and re-run the original repro after, and state the confirmed cause so the next debugger learns. So are *tight* as the loop's quality bar, the reproduction-rate framing for flaky bugs, and the post-mortem handoff of architectural causes to his `improve-codebase-architecture`, the seed of the friction-gate escalation here.5960What this pack changes: the named-cause test as the binding trigger (any fix shipping without a nameable cause, not hard bugs only), the failing-automated-test-first bar with the documented manual repro as a recorded, flagged fallback, proportionate minimize (tight enough to iterate against is the stopping point, not load-bearing minimality for its own sake), the plain-sentence closing artifact audited at lane close-out, the domain-memory feed for standing facts, and the friction-gate rewiring into codebase-review's entry gate with the diagnosing lane's scope pinned.6162One line in step 4 (suspect the observation method before the system) is adapted from Lauren Tan's [`principle-prove-it-works`](https://github.com/cursor/plugins/tree/main/pstack/skills/principle-prove-it-works) (MIT).