Systematic Debugging
Four-phase scientific method for root-cause analysis. Integrates with slow-is-fast reasoning principles.
Iron Law: No fix without verified root cause. Never say "this should fix it."
Phase 1: Root Cause Investigation
1.1 Collect Symptoms
Gather all available evidence before forming any hypothesis:
- Read the full error message/stack trace
- Identify when it started (check
git log --oneline -20 for recent changes)
- Determine reproduction conditions (always? intermittent? environment-specific?)
- Check if there are related error reports or failing tests
1.2 Reproduce
A bug you can't reproduce is a bug you can't fix.
- Write down the exact reproduction steps
- Confirm you can trigger the failure consistently
- If intermittent: identify the variable (timing, data, concurrency, environment)
1.3 Narrow the Scope
Use binary search thinking:
- Bisect in time:
git log --oneline — when did it last work?
- Bisect in space: Which module/layer? Add strategic logging or assertions
- Bisect in data: Which inputs trigger it? Minimal reproduction case
Output after Phase 1:
Root cause hypothesis: <one sentence>
Evidence: <what supports this>
Confidence: <low/medium/high>
Phase 2: Pattern Analysis
Match against known bug patterns before investigating from scratch:
| Pattern |
Signature |
Where to Look |
| Race condition |
Intermittent, timing-dependent, "works on retry" |
Shared state, async operations, missing locks/awaits |
| Nil/null propagation |
Crash on property access, "undefined is not a function" |
Optional chaining gaps, missing null checks at boundaries |
| State corruption |
Wrong value at wrong time, stale data |
Mutable shared state, cache invalidation, stale closures |
| Integration failure |
Works in isolation, fails in composition |
API contract mismatch, version skew, env config |
| Config drift |
Works locally, fails in CI/staging/prod |
Environment variables, feature flags, dependency versions |
| Stale cache |
Old behavior persists after fix, "but I already changed that" |
Build cache, module cache, CDN, browser cache, ORM cache |
| Test pollution |
Test passes alone, fails in suite (or vice versa) |
Shared global state, missing cleanup, execution order |
For Flaky Tests
Use the polluter-finding approach:
- Run the failing test in isolation — does it pass?
- If yes: another test is polluting shared state
- Binary search the test suite to find the polluter:
# Run first half of suite + failing test
# If fails: polluter is in first half. Recurse.
# If passes: polluter is in second half. Recurse.
- Once found: fix the shared state leak, don't just reorder tests
Phase 3: Hypothesis Testing
Scientific Method
For each hypothesis:
- Predict: "If hypothesis X is correct, then Y should be true"
- Test: Design a minimal experiment that confirms or refutes
- Observe: Record actual result — no interpretation yet
- Conclude: Does evidence support or refute? Update hypothesis
Single variable: Change only one thing per test. Multiple changes = uninterpretable results.
3-Strike Rule
After 3 failed hypotheses:
- STOP. Do not try a 4th fix.
- Reassess: you likely have the wrong mental model of the system
- Ask: "What assumption am I making that could be wrong?"
- Consider: is this an architectural issue, not a bug?
- Present findings to user and ask for guidance
Red Flags (you're on the wrong track)
- Fix works but you don't understand why
- Fix requires touching 5+ files for a "simple" bug
- You're adding workarounds instead of fixing root cause
- The "fix" breaks something else
Phase 4: Implementation
Fix Root Cause, Not Symptoms
- Wrong: Adding a null check where null shouldn't be possible
- Right: Fixing the code path that produces null
Minimal Diff
- Change only what's necessary for the fix
- No drive-by refactoring during bug fixes
- No "while I'm here" improvements
Regression Test
- Write a test that fails with the bug present
- Apply the fix
- Verify the test passes
- Run the full test suite — no regressions
Verification Report
After fix is applied, output:
## Debug Report
Symptom: <what was observed>
Root cause: <what actually caused it>
Evidence: <how we confirmed>
Fix: <what was changed and why>
Regression test: <test name/location>
Hypotheses tested: <N> (<list with outcomes>)
Confidence: <high — verified | medium — likely but edge cases possible>
Anti-Patterns
- Shotgun debugging: Changing random things hoping something works
- Fix-and-pray: Applying a fix without understanding the cause
- Symptom patching: Hiding the bug instead of fixing it (e.g., try/catch swallowing errors)
- Blame the framework: Assuming the bug is in a dependency before checking your own code
- Stale hypothesis: Continuing to pursue a theory after evidence contradicts it
- Over-logging: Adding 50 log statements instead of thinking about the problem
1---2name: investigate3description: Systematic root-cause debugging. Use when: diagnosing bugs, investigating failures, debugging flaky tests, tracing unexpected behavior. Triggers on: '/investigate', 'debug this', 'why is this failing', 'find the root cause', 'flaky test'.4---56# Systematic Debugging78Four-phase scientific method for root-cause analysis. Integrates with `slow-is-fast` reasoning principles.910**Iron Law: No fix without verified root cause. Never say "this should fix it."**1112## Phase 1: Root Cause Investigation1314### 1.1 Collect Symptoms1516Gather all available evidence before forming any hypothesis:1718- Read the full error message/stack trace19- Identify when it started (check `git log --oneline -20` for recent changes)20- Determine reproduction conditions (always? intermittent? environment-specific?)21- Check if there are related error reports or failing tests2223### 1.2 Reproduce2425**A bug you can't reproduce is a bug you can't fix.**2627- Write down the exact reproduction steps28- Confirm you can trigger the failure consistently29- If intermittent: identify the variable (timing, data, concurrency, environment)3031### 1.3 Narrow the Scope3233Use binary search thinking:3435- **Bisect in time**: `git log --oneline` — when did it last work?36- **Bisect in space**: Which module/layer? Add strategic logging or assertions37- **Bisect in data**: Which inputs trigger it? Minimal reproduction case3839Output after Phase 1:40```41Root cause hypothesis: <one sentence>42Evidence: <what supports this>43Confidence: <low/medium/high>44```4546## Phase 2: Pattern Analysis4748Match against known bug patterns before investigating from scratch:4950| Pattern | Signature | Where to Look |51|---------|-----------|---------------|52| **Race condition** | Intermittent, timing-dependent, "works on retry" | Shared state, async operations, missing locks/awaits |53| **Nil/null propagation** | Crash on property access, "undefined is not a function" | Optional chaining gaps, missing null checks at boundaries |54| **State corruption** | Wrong value at wrong time, stale data | Mutable shared state, cache invalidation, stale closures |55| **Integration failure** | Works in isolation, fails in composition | API contract mismatch, version skew, env config |56| **Config drift** | Works locally, fails in CI/staging/prod | Environment variables, feature flags, dependency versions |57| **Stale cache** | Old behavior persists after fix, "but I already changed that" | Build cache, module cache, CDN, browser cache, ORM cache |58| **Test pollution** | Test passes alone, fails in suite (or vice versa) | Shared global state, missing cleanup, execution order |5960### For Flaky Tests6162Use the polluter-finding approach:63641. Run the failing test in isolation — does it pass?652. If yes: another test is polluting shared state663. Binary search the test suite to find the polluter:67 ```bash68 # Run first half of suite + failing test69 # If fails: polluter is in first half. Recurse.70 # If passes: polluter is in second half. Recurse.71 ```724. Once found: fix the shared state leak, don't just reorder tests7374## Phase 3: Hypothesis Testing7576### Scientific Method7778For each hypothesis:79801. **Predict**: "If hypothesis X is correct, then Y should be true"812. **Test**: Design a minimal experiment that confirms or refutes823. **Observe**: Record actual result — no interpretation yet834. **Conclude**: Does evidence support or refute? Update hypothesis8485**Single variable**: Change only one thing per test. Multiple changes = uninterpretable results.8687### 3-Strike Rule8889After **3 failed hypotheses**:9091- **STOP.** Do not try a 4th fix.92- Reassess: you likely have the wrong mental model of the system93- Ask: "What assumption am I making that could be wrong?"94- Consider: is this an architectural issue, not a bug?95- Present findings to user and ask for guidance9697### Red Flags (you're on the wrong track)9899- Fix works but you don't understand why100- Fix requires touching 5+ files for a "simple" bug101- You're adding workarounds instead of fixing root cause102- The "fix" breaks something else103104## Phase 4: Implementation105106### Fix Root Cause, Not Symptoms107108- **Wrong**: Adding a null check where null shouldn't be possible109- **Right**: Fixing the code path that produces null110111### Minimal Diff112113- Change only what's necessary for the fix114- No drive-by refactoring during bug fixes115- No "while I'm here" improvements116117### Regression Test1181191. Write a test that **fails** with the bug present1202. Apply the fix1213. Verify the test **passes**1224. Run the full test suite — no regressions123124### Verification Report125126After fix is applied, output:127128```129## Debug Report130131Symptom: <what was observed>132Root cause: <what actually caused it>133Evidence: <how we confirmed>134Fix: <what was changed and why>135Regression test: <test name/location>136Hypotheses tested: <N> (<list with outcomes>)137Confidence: <high — verified | medium — likely but edge cases possible>138```139140## Anti-Patterns141142- **Shotgun debugging**: Changing random things hoping something works143- **Fix-and-pray**: Applying a fix without understanding the cause144- **Symptom patching**: Hiding the bug instead of fixing it (e.g., try/catch swallowing errors)145- **Blame the framework**: Assuming the bug is in a dependency before checking your own code146- **Stale hypothesis**: Continuing to pursue a theory after evidence contradicts it147- **Over-logging**: Adding 50 log statements instead of thinking about the problem