From d8405bba17edfe0621988782c0148de06366982a Mon Sep 17 00:00:00 2001 From: Brummel Date: Sat, 9 May 2026 14:21:02 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20skill=20debug=20=E2=80=94=20RED-first?= =?UTF-8?q?=20bug=20diagnoser=20with=20Iron=20Law?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- skills/debug/SKILL.md | 155 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 skills/debug/SKILL.md diff --git a/skills/debug/SKILL.md b/skills/debug/SKILL.md new file mode 100644 index 0000000..e88f605 --- /dev/null +++ b/skills/debug/SKILL.md @@ -0,0 +1,155 @@ +--- +name: debug +description: Use when a bug surfaces — failing test, segfault, wrong stdout, panic, or any observable misbehaviour. Bug fixes are RED-first TDD; no fix is attempted before the failing test is committed. Mandatory for any bug, including ones that look trivial. +--- + +# debug — RED-first bug diagnoser + +> **Violating the letter of these rules is violating the spirit.** + +## Overview + +Bugs in AILang are diagnosed and fixed by a two-stage handoff: this +skill produces the RED test and the cause analysis; the `implement` +skill then drives the fix to GREEN. Skipping the RED stage — even for +"trivial" bugs — produces fixes that don't stick and tests that don't +exist to catch the next regression. + +## When to Use / Skipping + +Trigger this skill on: +- a failing `cargo test` (any crate) +- wrong stdout from `ail run ` +- a segfault from a built binary +- a panic in the compiler +- a structured diagnostic from `ailang-bencher` or `ailang-architect` + that names a concrete misbehaviour + +**Never skipped.** A bug without a regression test is a code change, +not a fix. Ad-hoc judgement that a bug is "too small for TDD" is the +exact failure mode this skill exists to prevent. + +## The Iron Law + +``` +NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST +NO FIX WITHOUT A FAILING TEST FIRST +``` + +Both clauses are non-negotiable. The first is from +`superpowers:systematic-debugging`. The second is the project's +own rule (formerly in CLAUDE.md "Bug fixes — TDD, always"). + +## The Process — four phases + +Each phase must complete before the next starts. + +### Phase 1 — Root Cause Investigation + +1. Read the error message in full. Stack traces, line numbers, exit + codes — none of them get skimmed. +2. Reproduce with the shortest possible command. If you can't repro + reliably, gather more data — do NOT guess. +3. Check recent changes: `git log --oneline -20`, + `git diff ..HEAD`. +4. For multi-component issues (compiler → emitter → linker; or + runtime → C glue → binary), instrument every boundary. Find the + layer where the data goes wrong before deciding which layer to + fix. +5. Trace data flow backward from symptom to source. Fix at source, + not at symptom. + +### Phase 2 — Pattern Analysis + +1. Find a similar working example in the codebase. What's different? +2. If the bug is in a pattern (e.g. ADT match lowering, RC drop + emission), read the reference implementation completely. No + skimming. +3. List every difference between working and broken — however small. + +### Phase 3 — Hypothesis and Test + +1. State the hypothesis as a single falsifiable claim: + *"X is the root cause because Y."* +2. **Write the failing test FIRST**, before any fix attempt: + - smallest possible reproducer (E2E in `crates/ail/tests/e2e.rs`, + or unit test in the affected crate) + - automated, deterministic — same input always same output + - doc comment names the property the test protects, not just + what it does +3. Run it to confirm it fails on the current code, with the symptom + the bug-report described. +4. Commit the failing test as a separate commit: + `git commit -m "test: red for "`. + +### Phase 4 — Hand off to `implement` + +The fix itself is `implement`'s job, run in mini-mode. Hand it: +- path to the RED-test file +- 1-2 sentence cause summary from Phase 1 +- hard constraint: *"minimal fix, no surrounding cleanup, + no opportunistic refactor"* + +`implement` runs the GREEN side and commits `fix: `. + +### Phase 4.5 — 3+ failures = architecture question + +If the third hypothesis fails: + +``` +STOP. Do not attempt Fix #4. +``` + +Three failed fixes in a row indicate the architecture is wrong, not +that the latest hypothesis is wrong. Each fix likely revealed new +shared state or coupling in a different place. Surface the +architecture question to the user; do not guess again. + +## Handoff Contract + +The carrier `debug` hands to `implement`: + +| Field | Content | +|-------|---------| +| `red_test_path` | absolute path to the failing test file | +| `cause_summary` | 1-2 sentences naming the file + function + why | +| `constraint` | `"minimal fix, no surrounding cleanup"` | + +Anything else (broader refactor, doc rewrite, new feature) is OUT of +scope for the bug-fix iteration and gets queued for a separate one. + +## Common Rationalisations + +| Excuse | Reality | +|--------|---------| +| "The implementer says it's obviously the new tag-extract emit" | Confident guesses paper over real causes. Repro, isolate, RED test, then fix. | +| "Trivial bug, existing tests will catch it if we break something" | The existing tests already passed while this bug shipped — by definition they don't cover it. | +| "30 seconds to repro, 30 seconds to fix, skip the test" | 30 seconds to repro is also 30 seconds to capture as a regression fixture. Don't trade durable coverage for nothing. | +| "I'll write the test after the fix works" | Test-after proves nothing about whether the test would have caught the bug pre-fix. | +| "Two fixes failed; the third hypothesis is the right one" | Two failures means the hypothesis space is wrong. STOP, dispatch the debugger agent, do not guess again. | +| "End-of-day, just push the fix and write the test tomorrow" | End-of-day pressure is exactly when shotgun fixes corrupt the tree. Clean tree + open bug > three speculative half-fixes merged. | +| "Architecture question is for next milestone, fix-and-revisit" | Phase 4.5 fires NOW or never. Carrying the wrong shape forward compounds. | + +## Red Flags — STOP and follow process + +- "Quick fix for now, investigate later" +- "Just try changing X and see if it works" +- "I see the symptom, let me fix it" +- "The test is redundant, I manually verified" +- "Pattern says X but I'll adapt it differently" +- *"One more fix attempt"* (when ≥ 2 already failed) + +All of these mean: **return to Phase 1**. + +## Cross-references + +- **Upstream pattern:** `superpowers:systematic-debugging` — + source of the four-phase Iron Law and Phase 4.5. +- **Agent dispatched:** `skills/debug/agents/ailang-debugger.md` — + carries the actual diagnostic work (read CLAUDE.md / DESIGN.md / + JOURNAL, reproduce, write RED test, propose minimal fix). +- **Hand-off target:** `skills/implement/SKILL.md` — runs the GREEN + side after the RED test is committed. +- **Project source:** former CLAUDE.md "Bug fixes — TDD, always" + section is now superseded by this file; CLAUDE.md keeps a one-line + pointer.