Systematic Debugging
Find root cause before attempting fixes. Symptom fixes mask underlying issues and waste time.
The Four Phases
Complete each phase before proceeding to the next.
Phase 1: Root Cause Investigation
Before attempting any fix:
Read error messages carefully
- Read stack traces completely — they often contain the exact solution
- Note line numbers, file paths, error codes
Reproduce consistently
- Identify exact steps to trigger reliably
- If not reproducible, gather more data before forming hypotheses
Check recent changes
- Git diff, recent commits, new dependencies, config changes
- Environmental differences
Gather evidence in multi-component systems
When a system has multiple components (CI → build → signing, API → service → database), add diagnostic instrumentation before proposing fixes:
For each component boundary:
- Log what data enters and exits the component
- Verify environment/config propagation
- Check state at each layer
Run once to gather evidence showing WHERE it breaks
Then investigate that specific component
Example (multi-layer system):
# Layer 1: Workflow
echo "=== Secrets available: ==="
echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}"
# Layer 2: Build script
env | grep IDENTITY || echo "IDENTITY not in environment"
# Layer 3: Signing
security find-identity -v
# Layer 4: Actual signing
codesign --sign "$IDENTITY" --verbose=4 "$APP"
Trace data flow
See root-cause-tracing.md for the complete backward tracing technique.
Quick version:
- Where does the bad value originate?
- What called this with the bad value?
- Keep tracing up until you find the source
- Fix at source, not at symptom
Phase 2: Pattern Analysis
- Find working examples — locate similar working code in the same codebase
- Compare against references — read reference implementations completely before applying
- Identify differences — list every difference between working and broken, however small
- Understand dependencies — what components, settings, config, or assumptions are involved?
Phase 3: Hypothesis and Testing
- Form a single hypothesis — state clearly: "I think X is the root cause because Y"
- Test minimally — make the smallest possible change to test the hypothesis; one variable at a time
- Verify before continuing — if it worked, proceed to Phase 4; if not, form a new hypothesis (avoid stacking fixes)
Phase 4: Implementation
Create a failing test case — simplest possible reproduction, automated if feasible
Implement a single fix — address root cause only; no "while I'm here" improvements
Verify the fix — test passes, no other tests broken, issue actually resolved
If the fix fails — count attempts:
- < 3 attempts: return to Phase 1, re-analyze with new information
- ≥ 3 attempts: stop and question the architecture (see below)
If 3+ fixes failed: question architecture
Pattern indicating architectural problems:
- Each fix reveals new shared state / coupling / problem in a different place
- Fixes require massive refactoring to implement
- Each fix creates new symptoms elsewhere
Stop and question fundamentals:
- Is this pattern fundamentally sound?
- Should we refactor architecture vs. continue fixing symptoms?
Discuss with the human before attempting more fixes.
Signs You Should Return to Phase 1
If any of these apply, pause and re-investigate before continuing:
- Attempting a fix without understanding the root cause
- Skipping reproduction or test verification
- Stacking multiple speculative changes
- On the 3rd+ fix attempt without new evidence
- Proposing solutions before tracing data flow
Supporting Techniques
Available in this directory:
root-cause-tracing.md — trace bugs backward through call stack to find original trigger
defense-in-depth.md — add validation at multiple layers after finding root cause
condition-based-waiting.md — replace arbitrary timeouts with condition polling
Related skills:
- tdd — for creating failing test cases (Phase 4)
- dev-testing — verify fix worked before claiming success
Quick Reference
| Phase |
Key Activities |
Success Criteria |
| 1. Root Cause |
Read errors, reproduce, check changes, gather evidence |
Understand what and why |
| 2. Pattern |
Find working examples, compare |
Identify differences |
| 3. Hypothesis |
Form theory, test minimally |
Confirmed or new hypothesis |
| 4. Implementation |
Create test, fix, verify |
Bug resolved, tests pass |
1---2name: debugging-helpers3description: Use when encountering any bug, test failure, or unexpected behavior, before proposing fixes4---56# Systematic Debugging78Find root cause before attempting fixes. Symptom fixes mask underlying issues and waste time.910## The Four Phases1112Complete each phase before proceeding to the next.1314### Phase 1: Root Cause Investigation1516Before attempting any fix:17181. **Read error messages carefully**19 - Read stack traces completely — they often contain the exact solution20 - Note line numbers, file paths, error codes21222. **Reproduce consistently**23 - Identify exact steps to trigger reliably24 - If not reproducible, gather more data before forming hypotheses25263. **Check recent changes**27 - Git diff, recent commits, new dependencies, config changes28 - Environmental differences29304. **Gather evidence in multi-component systems**3132 When a system has multiple components (CI → build → signing, API → service → database), add diagnostic instrumentation before proposing fixes:3334 ```35 For each component boundary:36 - Log what data enters and exits the component37 - Verify environment/config propagation38 - Check state at each layer3940 Run once to gather evidence showing WHERE it breaks41 Then investigate that specific component42 ```4344 Example (multi-layer system):45 ```bash46 # Layer 1: Workflow47 echo "=== Secrets available: ==="48 echo "IDENTITY: ${IDENTITY:+SET}${IDENTITY:-UNSET}"4950 # Layer 2: Build script51 env | grep IDENTITY || echo "IDENTITY not in environment"5253 # Layer 3: Signing54 security find-identity -v5556 # Layer 4: Actual signing57 codesign --sign "$IDENTITY" --verbose=4 "$APP"58 ```59605. **Trace data flow**6162 See `root-cause-tracing.md` for the complete backward tracing technique.6364 Quick version:65 - Where does the bad value originate?66 - What called this with the bad value?67 - Keep tracing up until you find the source68 - Fix at source, not at symptom6970### Phase 2: Pattern Analysis71721. **Find working examples** — locate similar working code in the same codebase732. **Compare against references** — read reference implementations completely before applying743. **Identify differences** — list every difference between working and broken, however small754. **Understand dependencies** — what components, settings, config, or assumptions are involved?7677### Phase 3: Hypothesis and Testing78791. **Form a single hypothesis** — state clearly: "I think X is the root cause because Y"802. **Test minimally** — make the smallest possible change to test the hypothesis; one variable at a time813. **Verify before continuing** — if it worked, proceed to Phase 4; if not, form a new hypothesis (avoid stacking fixes)8283### Phase 4: Implementation84851. **Create a failing test case** — simplest possible reproduction, automated if feasible862. **Implement a single fix** — address root cause only; no "while I'm here" improvements873. **Verify the fix** — test passes, no other tests broken, issue actually resolved88894. **If the fix fails** — count attempts:90 - < 3 attempts: return to Phase 1, re-analyze with new information91 - ≥ 3 attempts: stop and question the architecture (see below)92935. **If 3+ fixes failed: question architecture**9495 Pattern indicating architectural problems:96 - Each fix reveals new shared state / coupling / problem in a different place97 - Fixes require massive refactoring to implement98 - Each fix creates new symptoms elsewhere99100 Stop and question fundamentals:101 - Is this pattern fundamentally sound?102 - Should we refactor architecture vs. continue fixing symptoms?103104 Discuss with the human before attempting more fixes.105106## Signs You Should Return to Phase 1107108If any of these apply, pause and re-investigate before continuing:109110- Attempting a fix without understanding the root cause111- Skipping reproduction or test verification112- Stacking multiple speculative changes113- On the 3rd+ fix attempt without new evidence114- Proposing solutions before tracing data flow115116## Supporting Techniques117118Available in this directory:119120- **`root-cause-tracing.md`** — trace bugs backward through call stack to find original trigger121- **`defense-in-depth.md`** — add validation at multiple layers after finding root cause122- **`condition-based-waiting.md`** — replace arbitrary timeouts with condition polling123124Related skills:125- **tdd** — for creating failing test cases (Phase 4)126- **dev-testing** — verify fix worked before claiming success127128## Quick Reference129130| Phase | Key Activities | Success Criteria |131|-------|---------------|------------------|132| 1. Root Cause | Read errors, reproduce, check changes, gather evidence | Understand what and why |133| 2. Pattern | Find working examples, compare | Identify differences |134| 3. Hypothesis | Form theory, test minimally | Confirmed or new hypothesis |135| 4. Implementation | Create test, fix, verify | Bug resolved, tests pass |