debugging-patterns · diff
git:20260506.b1f0fef to git:20260909.6778255
28 added, 101 removed. Audit A to A.
---
name: debugging-patterns
description: "Isolate root causes through structured evidence gathering, pattern analysis, hypothesis testing (max 3 at a time, highest confidence first), and fix validation with a reproducing test before implementation. Use when any verification step fails, tests break, or debugging a reported bug. This skill MUST be consulted because symptom-fixing creates new bugs, and unbounded hypothesis testing causes tunnel vision; root cause must be proven before any fix attempt."
allowed-tools: Bash, Read, Grep, Glob, TaskCreate, TaskList, TaskUpdate
context: fork
agent: general-purpose
---
# Debugging Patterns
- Domain skill for structured investigation of bugs and unexpected behavior.
-
- ## Iron Law
-
- **ALWAYS FIND ROOT CAUSE BEFORE ATTEMPTING FIXES. Symptom fixes are failure.**
-
- A fix that doesn't address root cause creates a new bug later. Every. Single. Time.
-
- ## Four-Phase Investigation
-
- ### 1. Gather Evidence
-
- Collect before theorizing:
-
- ```bash
- # Error logs, stack traces, recent changes
- git log --oneline -10
- git diff HEAD~3..HEAD --stat
- ```
-
- - Read error messages and stack traces FULLY — don't skim
- - Check logs in chronological order around the failure
- - Note what changed recently (`git log`, `git diff`)
- - Reproduce the error — if you can't reproduce it, you can't verify the fix
+ ## Contract
- ### 2. Pattern Analysis
+ Iron law: **find and prove the root cause before attempting any fix; a symptom fix is a failure.** Invoked by `/flow:debug` Phases 1–3 (evidence → hypotheses → fix), by `/flow:start` and `/flow:resolve` on demand whenever a build, test, server-start, smoke, E2E, or visual step fails (no `bug` label required), and by the `error-handler-inspector` agent. Returns the confirmed root cause with evidence, the hypothesis table with each result, a reproducing test that failed before the fix and passes after, and a full-suite run with no regressions. Permitted skips: none — a clear error message shortens the investigation (one or two hypotheses) but never removes the reproducing test.
- Look for patterns in the evidence:
+ ## Evidence Before Theory
- - When does it fail vs succeed? (inputs, timing, environment)
- - What's different between working and broken states?
- - Is the error consistent or intermittent?
- - Use `Grep` to find similar patterns: error messages, function calls, data flows
+ Read the full error message and stack trace first — never skim, never start with "let me understand the code." Then `git log --oneline -10` and `git diff HEAD~3..HEAD --stat` for recent changes. Reproduce the failure; if you cannot reproduce it you cannot verify a fix. Trace backward from the error, checking inputs, API responses, and config values at each boundary, and only then read code.
- ### 3. Hypothesis Testing
+ ## Hypothesis Discipline
- Form and test hypotheses systematically. Use TaskCreate for each hypothesis:
+ Form at most `debugging.maxHypotheses` (default 3) hypotheses at a time. More means insufficient evidence — return to evidence gathering. Create one task per hypothesis:
```
TaskCreate("Hypothesis 1: {theory}", "Confidence: High\nTest: {specific test}\nEvidence: {what points here}")
- TaskCreate("Hypothesis 2: {theory}", "Confidence: Medium\nTest: {specific test}\nEvidence: {what points here}")
- TaskCreate("Hypothesis 3: {theory}", "Confidence: Low\nTest: {specific test}\nEvidence: {what points here}")
```
- | # | Hypothesis | Confidence | Test | Result |
- |---|-----------|------------|------|--------|
- | 1 | {theory} | High/Med/Low | {specific test} | {outcome} |
- | 2 | {theory} | High/Med/Low | {specific test} | {outcome} |
- | 3 | {theory} | High/Med/Low | {specific test} | {outcome} |
-
- For each hypothesis: TaskUpdate(status: "in_progress") before testing, TaskUpdate(status: "completed") after — whether confirmed or disproven. Record the result.
+ Rules:
+ - Test highest confidence first, ONE at a time — never change two things simultaneously.
+ - `TaskUpdate(status: "in_progress")` before testing; `TaskUpdate(status: "completed")` after, recording confirmed or disproven. A disproven hypothesis is progress.
+ - Write all hypotheses down before testing any, and actively seek disconfirming evidence for the leading one.
+ - Before blaming the last change, check whether the bug predates it (`git stash && test`). Check simple causes (typo, wrong variable, off-by-one) before elaborate ones.
- **Rules:**
- - Maximum 3 hypotheses at a time (more means insufficient evidence — go back to phase 1)
- - Test highest confidence first
- - Test ONE at a time — never change two things simultaneously
- - A disproven hypothesis is progress, not failure
+ Display the table:
- ### 4. Fix Validation
+ | # | Hypothesis | Confidence | Test | Result |
+ |---|-----------|------------|------|--------|
- **Write a test that reproduces the bug BEFORE fixing.** If the test doesn't fail, you haven't found the bug.
+ ## Fix Validation
- ```
- TaskCreate("Fix validation", "Write reproducing test, implement fix, verify no regressions")
- TaskUpdate("Fix validation", status: "in_progress")
- ```
+ Write a test that reproduces the bug BEFORE fixing. If it does not fail, you have not found the bug.
- 1. Write failing test that captures the bug behavior
- 2. Verify the test fails for the right reason
- 3. Implement the fix
- 4. Verify the test passes
- 5. Run full test suite — no regressions
+ 1. Write the failing test; confirm it fails for the right reason.
+ 2. Implement the minimal fix.
+ 3. Confirm the test passes.
+ 4. Run the full suite — no regressions.
- TaskUpdate("Fix validation", status: "completed") after all tests pass.
- Use TaskList to confirm all hypotheses resolved and fix validated.
+ Track as `TaskCreate("Fix validation", ...)`; `TaskList` must show every hypothesis and the fix task completed before returning.
## Verification Failure Mode
- This skill activates automatically when ANY verification step fails — not just for `bug`-labeled issues:
-
- - **Build failure**: Read error output, fix, rebuild
- - **Test failure**: Read test output, trace to root cause, fix
- - **Server start failure**: Read logs, fix configuration or code, retry
- - **Smoke test failure**: Read response, trace to handler, fix
- - **E2E failure**: Read failure screenshot/logs, trace to root cause, fix
- - **Visual verification failure**: Read screenshot, identify rendering issue, fix
-
- Streamlined investigation: read error fully, form 1-2 hypotheses, fix and re-verify. No elaborate investigation needed for clear error messages — just fix and move on.
-
- ## Log-First Methodology
-
- Read logs and errors BEFORE reading code:
-
- 1. **Start at the error** — read the full error message and stack trace
- 2. **Trace backward** — follow the data flow from error to origin
- 3. **Check boundaries** — inputs, API responses, config values at each step
- 4. **Only then read code** — now you know WHERE to look
-
- Never start with "let me read the code and understand how it works." Start with "what went wrong and where."
+ When invoked because a verification step failed (build, test, server start, smoke, E2E, visual): read the output fully, form one or two hypotheses, fix, re-verify. Iteration ceilings belong to the caller (`closedLoop.maxBuildIterations`, `closedLoop.maxServerRetries`, `closedLoop.maxDebugIterations`). The user never has to supply logs or say what went wrong — you have the same output.
## Stop Conditions
| Trigger | Action |
|---------|--------|
- | 3+ failed fix attempts | Stop fixing forward. The problem is architectural. Return to EXPLORE. |
- | Can't explain current behavior | Don't guess. Investigate more. Add logging, add assertions. |
- | Tunnel vision (>30 min on one theory) | Step back. List what you KNOW vs what you ASSUME. |
- | Fix works but you can't explain WHY | Revert. An unexplained fix is a time bomb. |
-
- ## Cognitive Bias Awareness
-
- | Bias | Symptom | Antidote |
- |------|---------|----------|
- | **Confirmation bias** | Only looking for evidence that confirms your theory | Actively seek DISCONFIRMING evidence |
- | **Anchoring** | First theory dominates even after disproof | Write down ALL hypotheses before testing any |
- | **Recency bias** | Blaming the last change | Check if the bug existed before the last change: `git stash && test` |
- | **Complexity bias** | Assuming an elaborate cause | Check the simple things first: typos, wrong variable, off-by-one |
+ | 3+ failed fix attempts | Stop fixing forward; the problem is architectural. Return to EXPLORE. |
+ | Cannot explain current behavior | Do not guess. Add logging and assertions; investigate more. |
+ | Tunnel vision (>30 min on one theory) | Step back; list what you KNOW vs what you ASSUME. |
+ | Fix works but you cannot explain why | Revert. An unexplained fix is a time bomb. |
- ## Rationalization Prevention
+ ## Not Fixes
- | Excuse | Response |
- |--------|----------|
- | "I know what's wrong" | Then prove it with evidence. If you're right, it takes 30 seconds. |
- | "Quick fix, then proper fix later" | Later never comes. Fix root cause now. |
- | "It works on my machine" | Then the bug is in environment differences. Investigate THAT. |
- | "Let me just add a try-catch" | That's hiding the bug, not fixing it. Find the root cause. |
- | "It's probably a race condition" | Probably? Prove it. Add timing logs, reproduce it reliably. |
+ A try-catch that hides the error, "quick fix now, proper fix later", or "probably a race condition" without timing evidence are symptom fixes. "I know what's wrong" still requires proof — if you are right it takes thirty seconds. "It works on my machine" means the bug is in the environment difference; investigate that.