Systematic Debugging
SkillDev toolsUse when a bug is non-obvious or has resisted quick fixes — applies a 4-phase root cause analysis to find and permanently resolve the issue rather than patching symptoms
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Systematic Debugging skill
What this skill tells your AI
The instructions your AI receives, as published by drvoss/everything-copilot-cli in skills/development/systematic-debugging/SKILL.md and read by ahel’s review.
A structured 4-phase methodology for diagnosing and fixing non-obvious bugs. Prevents the common failure modes of "shotgun debugging" (random changes hoping something sticks) and "symptom patching" (fixing the visible error without understanding the cause).
When to Use
- A bug has resisted one or more quick-fix attempts
- The bug only appears in certain environments (prod but not dev, intermittent)
- The cause is unclear after an initial look
- A "fixed" bug keeps coming back
- Multiple engineers have looked at it without resolution
When NOT to Use
| Instead of systematic-debugging | Use |
|---|---|
| Obvious typo or off-by-one | Fix directly |
| Build/compilation failure | fix-build-errors skill |
| Performance problem (not a bug) | profiling tools |
| Security vulnerability | security-scan skill |
The 4-Phase Process
Phase 1 — Reproduce
A bug you cannot reproduce reliably cannot be debugged reliably.
Goal: Get a 100% reproducible test case that triggers the bug on demand.
# 1. Note the exact symptoms: error message, stack trace, request/response
# 2. Identify the minimum inputs that trigger it
# 3. Write a failing test that captures the reproduction
# Find the code path involved
Select-String -Path "src\\**\\*.ts" -Pattern "<error keyword>"
# Check recent changes
git --no-pager log --oneline -20
git --no-pager diff HEAD~5 -- <suspect file>
Reproduction criteria:
- Bug triggers on demand with a specific input or sequence
- Bug does NOT trigger with a slightly different (correct) input
- Reproduction is encoded as a failing test
When it is safe, run the minimal reproduction at least twice and record both commands and outputs;
one observation is not proof of reproducibility. If outcomes vary, label the reproduction status
intermittent rather than hiding the variation.
Before handing the issue to diagnosis or another session, produce a reproduction brief with:
- target and commit
- runtime, OS, lockfile, and feature flags
- expected behavior as an observation, without a cause hypothesis
- actual behavior as an observation, without a cause hypothesis
- minimal steps and fixtures
- status:
yes,no, orintermittent - commands, logs, traces, or other evidence
- unknowns and the next hypothesis to test
The brief is the handoff artifact at the reproduce-before-repair boundary already enforced here
and in fix-github-issue. Never alter production data to obtain it,
and redact secrets from evidence.
If you cannot reproduce it in < 15 minutes, move to Phase 2 anyway — understanding the system often reveals the trigger.
Phase 2 — Understand the System
Bugs live in the gap between what you think the code does and what it actually does. Close that gap before guessing at solutions.
# Read the code path end-to-end, not just the error location
# Follow data from entry point to crash point
# Trace the call stack
Select-String -Path "src\\**\\*.ts" -Pattern "<function name>"
# Check state at each step — add temporary logs if needed
# Never modify production behavior during debugging
Questions to answer:
- What is the expected behavior? (From spec, tests, or docs)
- What is the actual behavior? (From error, logs, or reproduction)
- Where exactly does the actual diverge from expected? (Specific line or state)
- What assumptions does this code make? Which one is violated?
Tools:
# Read the function signature and its callers
Select-String -Path "src\\**\\*.ts" -Pattern "functionName"
# Check what data looks like going in
# Add a temporary debug log (remember to remove before committing)
# console.log('[DEBUG]', JSON.stringify(input, null, 2));
# Check recent git changes to the file
git --no-pager log --follow -p -- src/path/to/file.ts | Select-Object -First 80
Phase 3 — Hypothesize and Verify
Generate one specific hypothesis about the root cause, then verify or falsify it. Do not try multiple fixes simultaneously — you will not know which one worked.
Hypothesis template:
Hypothesis: The bug is caused by [specific condition].
Prediction: If I [specific change], then [specific observable outcome].
Test: [How I will verify the prediction]
Example:
Hypothesis: The JWT expiry check compares Unix timestamp (seconds) to Date.now() (ms).
Prediction: If I divide Date.now() by 1000, the check will pass for valid tokens.
Test: The reproduction test case will pass with this change.
Verify with a targeted change:
# Make only the minimal change needed to test the hypothesis
# Run the reproduction test
npm test -- --testPathPattern="reproduction-test"
# If the test passes: hypothesis confirmed → write a proper fix
# If the test fails: hypothesis falsified → form a new hypothesis
Repeat until a hypothesis is confirmed. Do not patch symptoms.
Phase 4 — Fix and Prevent Recurrence
The root cause is confirmed. Now fix it properly and prevent it from returning.
# 1. Write the real fix (not the hypothesis test hack)
# 2. Ensure the reproduction test passes with the fix
# 3. Write additional regression tests for edge cases
# 4. Run the full test suite — no regressions
npm test
# 5. Remove any temporary debug logs
Select-String -Path "src\\**\\*.ts" -Pattern "\\[DEBUG\\]"
# 6. Write a clear commit message explaining root cause
git commit -m "fix: <what was wrong and why>
Root cause: <explanation of the actual bug>
Fix: <what was changed and why it resolves the root cause>
Regression test: <name of the test that now covers this>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>"
Prevention checklist:
- Root cause is documented in the commit message
- At least one regression test covers the specific scenario
- Related code paths are checked for the same pattern
- If the bug was a class of error (e.g., "timestamp unit mismatch"), check for other instances
Common Rationalizations
| Rationalization | Reality |
|---|---|
| "I'll just try a few things and see what sticks" | Shotgun debugging wastes hours and leaves you without understanding. A methodical approach finds the bug faster. |
| "It's probably a framework/library bug" | It's almost never a framework bug. Blame your code first; verify framework behavior before blaming it. |
| "I can't reproduce it, so I'll just add more logging" | Logging without a hypothesis produces noise. Reproduce first, then verify a specific hypothesis. |
| "I understand the code well enough" | Write down what you think the code does before reading it. The gap between your mental model and reality is where the bug lives. |
| "The fix is obvious, I don't need a regression test" | Obvious fixes regress. The regression test is how the next engineer (or future you) learns the lesson without re-debugging. |
Red Flags
- You've made more than 3 changes without a confirmed hypothesis
- The bug "disappeared" without a clear explanation
- Your fix makes the test pass but you don't understand why
- The same bug has been "fixed" before
- No regression test was added after the fix
Escalation — The Rule of Three
If you have made 3 or more hypothesis-driven fix attempts without resolution:
- Stop making further fixes
- Collect the evidence — record each hypothesis, the test you ran, and why it was falsified
- Escalate to architectural review using the
councilskill:- Architect — is the design itself creating the failure?
- Skeptic — what assumption is everyone making without checking?
- Pragmatist — what is the fastest path back to a working system?
- Critic — would a redesign be cheaper than more incremental fixes?
The Rule of Three usually means the problem is architectural, not an implementation detail. A fourth fix attempt without escalation is often just another symptom patch.
Verification
- Bug is reproducible with a specific test case
- Root cause is identified (not just the symptom)
- Fix addresses the root cause, not the symptom
- Regression test exists and passes
- Full test suite passes with no new failures
- Commit message explains the root cause
Tips
-
Binary search the bug: use
git bisectto find the commit that introduced itgit bisect start git bisect bad HEAD git bisect good <last-known-good-commit> # git bisect will check out commits for you to test -
Rubber duck debugging: explain the bug out loud (or to an agent). The act of articulating often reveals the assumption you didn't know you were making.
-
Check the obvious last: timestamp units, off-by-one errors, null vs undefined, async/await missing, wrong environment variable — these are common root causes.
-
Use the
exploreagent to trace a call path across many files simultaneously.
See Also
fix-build-errors— compilation and build failurestdd-workflow— write regression tests as part of the fixsecurity-scan— if the bug is security-relatedcouncil— escalate persistent failures to a structured architectural review
Signals
- GitHub stars
- 46
- Forks
- 11
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
systematic-debugging-drvoss- Source
- github.com/drvoss/everything-copilot-cli