Systematic Debugging
Use this skill to investigate a current defect without guessing, overfitting
fixes, masking symptoms, or making broad speculative changes. Start from
observable evidence, isolate the cause, fix the smallest correct thing, and
verify the behavior that failed.
When to Use
Use this skill for any task involving:
- Failing tests, test regressions, skipped/ignored tests that need investigation,
or unexpected assertions.
- Bug reports, incorrect application behavior, runtime exceptions, crashes,
panics, stack traces, or user-visible failures.
- Unexpected state transitions, data corruption symptoms, stale state, or invalid
domain state.
- Flaky or nondeterministic failures, timing-sensitive behavior, async issues,
concurrency issues, races, deadlocks, or ordering problems.
- Performance regressions, timeouts, resource leaks, excessive memory/CPU/I/O,
or degraded latency/throughput.
- Build, lint, formatting, type-check, compilation, dependency, or toolchain
failures.
- Integration failures across APIs, services, databases, queues, caches, UI,
filesystem, network, auth, configuration, or environment boundaries.
- A current incident symptom when the immediate need is reproduce/diagnose/fix.
For postmortem, prevention, repeated failures, or organizational/system causes,
use
root-cause-analysis after the active failure is understood.
Do not use this skill for purely mechanical formatting, documentation-only
changes, or greenfield implementation with no failure or symptom to explain.
Core Principles
- Start from the observable symptom, not an assumed cause.
- Preserve and inspect exact evidence: error text, stack trace, logs, failing
assertion, diff, request/response, screenshot, trace, profile, or user-visible
behavior.
- When that or production evidence may expose secrets, credentials, PII, tenant
data, payloads, or private paths, load
security-review and
security-review-evidence. Keep raw
artifacts local and ignored; report sanitized summaries only. Do not add this
routing for evidence without a sensitive-data risk.
- Reproduce the issue before fixing whenever feasible. If reproduction is not
feasible, explain why and use the strongest available evidence.
- Find the smallest reliable reproduction: narrow command, test filter, route,
input, fixture, component, dataset, seed, profile, or environment.
- Compare expected behavior against actual behavior before changing code.
- Form multiple plausible hypotheses; do not stop at the first plausible bug.
- Test hypotheses one at a time and record evidence for or against each one.
- Prefer direct evidence over speculation, intuition, or broad pattern matching.
- Distinguish symptom, proximate trigger, direct cause, and contributing factors.
- Keep fixes minimal, targeted, and aligned with the domain model and public
contracts.
- Add or update regression coverage for confirmed defects.
- Do not weaken tests, delete assertions, reduce coverage, bypass validation, or
mark tests ignored/skipped unless the direct cause proves the original behavior
contract was wrong and the change is explicitly justified.
Investigation Workflow
Follow this sequence unless the repository has a stricter local runbook:
- Clarify the symptom
- State what failed and where it was observed.
- Identify impact: user-visible behavior, failing test, broken command,
incident symptom, performance metric, or integration boundary.
- Locate the failing surface
- Identify the failing command, test, route, component, module, workflow,
query, job, or tool invocation.
- Prefer repository-provided commands and docs over ad hoc commands.
- Reproduce the failure
- Run the narrowest relevant command first.
- If flaky, run enough repetitions or vary concurrency/seed/time/environment
to characterize nondeterminism without hiding it.
- Capture exact failure evidence
- Save or quote the important error message, assertion, stack frame, log line,
response body/status, profile metric, or visible behavior.
- Avoid summarizing away details that distinguish one failure mode from
another.
- Inspect recent changes and call paths
- Read the relevant code, tests, fixtures, config, schema, generated code
boundaries, and recent diffs/history if available.
- Trace data/control flow across boundaries before editing.
- Use local code navigation for symbols, references, implementations, call
relationships, and diagnostics when call paths matter. Use direct
reads/search for exact error text, docs, config, logs, fixtures, and
generated assets, and repository commands for tests, builds, or other
validation.
- Build a hypothesis list
- Include at least two plausible causes when the failure is not obvious.
- Separate code defects from data, environment, dependency, timing, and test
expectation hypotheses.
- Rank hypotheses
- Prefer high-likelihood, high-testability hypotheses first.
- Define what observation would confirm or falsify each hypothesis.
- Instrument or inspect only as needed
- Add temporary logging, tracing, assertions, probes, or debuggers only when
reading and focused tests do not provide enough evidence.
- Remove temporary instrumentation before finishing unless it is intentionally
production-quality observability.
- Isolate the direct cause
- Prove why the failure occurs and why competing hypotheses are less likely or
false.
- Identify whether the direct cause is code logic, contract mismatch, missing
validation, incorrect test expectation, data setup, configuration,
dependency/toolchain change, race/timing, caching, or environment drift.
- Implement the smallest correct fix
- Change one causal area at a time.
- Avoid broad refactors, unrelated cleanup, or public contract changes unless
the evidence requires them.
- Add or update regression tests
- Add the narrowest behavior-oriented coverage that would have caught the
defect.
- Prefer public behavior and domain outcomes over private implementation
details when practical.
- Run focused verification first
- Re-run the reproducer, failing test, affected lints/type checks, or focused
benchmark/profile.
- Run broader verification when justified
- Broaden to package/module/full-suite checks only when the change crosses
boundaries, affects shared behavior, or focused checks cannot provide
enough confidence.
- Summarize evidence, direct cause, fix, and verification
- State what was observed, what changed, why it fixes the direct cause, and
what remains unverified.
Debugging Output
Produce a concise debugging summary when the task involved a confirmed defect,
regression, flaky behavior, or non-obvious failure. Use this format, trimming
fields that truly do not apply:
## Debugging Summary
- Symptom:
- Impacted behavior:
- Expected behavior:
- Actual behavior:
- Direct cause:
- Proximate trigger:
- Contributing factors:
- Why the fix is correct:
- Tests added or updated:
- Verification run:
- Not run / remaining risks:
- Follow-up work:
Avoid shallow explanations such as "the test was wrong", "state was invalid",
"race condition", or "environment issue" unless you explain why, show the
evidence, and distinguish the direct cause from the symptom.
If the work reveals repeated failures, broad contributing factors, or prevention
items beyond the direct fix, hand off to root-cause-analysis for a postmortem-
style RCA rather than expanding this debugging pass.
Testing and Verification Expectations
- Use focused tests and commands while investigating. Start narrow; broaden only
for meaningful confidence.
- Add regression coverage for confirmed defects unless impossible or already
covered by an existing test that was failing for the right reason.
- Keep tests behavior-oriented and domain-facing where practical. Avoid brittle
tests coupled to private implementation details unless the defect is itself an
implementation contract.
- Resolve failing tests, clippy/lint errors, type errors, compilation errors,
formatting issues, and introduced warnings before considering the task done.
- Do not run long full-suite or expensive commands by default. Use them when the
fix touches shared infrastructure, public contracts, cross-cutting behavior,
generated artifacts, schemas, concurrency, performance, or release-critical
surfaces.
- Clearly state every verification command/check run and whether it passed.
- Clearly state important checks not run and why.
- Do not claim performance improvements without before/after measurements from
the same tool and comparable conditions.
Guardrails
Do not:
- Guess and patch without reproduction when reproduction is feasible.
- Treat the first plausible issue as the direct cause without testing alternatives.
- Make multiple unrelated changes in one debugging pass.
- Paper over errors with retries, sleeps, broad exception handlers, broad null
checks, silent defaults, swallowed errors, cache clears, or relaxed validation
unless evidence proves that behavior is correct for the domain.
- Change public contracts, API behavior, schemas, migrations, data formats,
permissions, error semantics, or compatibility guarantees without evidence,
tests, and explicit justification.
- Assume an environment issue before checking code-level causes, configuration,
inputs, data setup, dependencies, and command differences.
- Ignore flakiness or nondeterminism. Characterize it and either fix it or report
the remaining risk explicitly.
- Leave temporary logs, debug prints, tracing, sleeps, feature flags, or probes in
production code.
- Mark tests ignored/skipped, delete assertions, or reduce coverage as a
substitute for fixing the defect.
Debugging Heuristics by Failure Class
When the core workflow is not enough, use the progressive reference
references/failure-heuristics.md for
failure-class prompts covering unit, integration, flaky, async, state,
serialization, boundary, environment, dependency, performance, UI, database, and
build failures.
Communication Style
Communicate in short, evidence-based updates:
- State what failed and the exact evidence observed.
- State the hypothesis currently being tested and why it is plausible.
- State what changed and why it addresses the direct cause.
- State what verification was performed and the result.
- State uncertainty explicitly when evidence is incomplete; do not overstate
confidence.
Examples
Good debugging behavior
The creates_order_without_discount test fails with expected total 100, actual total 90. I reproduced it with the single test filter. The failing
path applies the promotional discount even when the request has no coupon. My
hypotheses are: stale fixture data, default coupon value, or unconditional
discount application. Inspecting the request fixture shows no coupon; tracing
the calculation shows the discount branch checks customer.is_eligible but not
coupon.is_some(). I will add a regression assertion for eligible customers
without coupons, update the branch condition, then rerun the focused test and
the order calculation tests.
Why this is good: it preserves exact evidence, reproduces narrowly, compares
expected and actual behavior, names multiple hypotheses, tests the relevant path,
implements a targeted fix, and verifies with focused tests.
Bad debugging behavior to avoid
The order test is probably flaky because discounts are complicated. I changed
the expected total to 90, added a retry, and refactored the pricing module so
the suite passes locally.
Why this is bad: it guesses without evidence, weakens the test, hides possible
nondeterminism with a retry, makes broad unrelated changes, and never explains
the direct cause or why the new behavior is correct.
Zod Boundary Debugging
For a Zod failure, record installed version/import, parser method, sanitized input class, issue code/path, and transform/refinement/async involvement. Load zod-engineering; distinguish expected rejection from parser/application failure and do not weaken schemas to match locale wording.
1---2name: systematic-debugging3description: Evidence-driven debugging for active bugs, failing tests, runtime exceptions, flaky behavior, performance regressions, build/lint/type/compile failures, integration failures, crashes, and unexpected behavior. Use before proposing fixes for a current symptom. Use root-cause-analysis for recurring incidents, systemic failures, and postmortem-style prevention work.4---56# Systematic Debugging78Use this skill to investigate a current defect without guessing, overfitting9fixes, masking symptoms, or making broad speculative changes. Start from10observable evidence, isolate the cause, fix the smallest correct thing, and11verify the behavior that failed.1213## When to Use1415Use this skill for any task involving:1617- Failing tests, test regressions, skipped/ignored tests that need investigation,18 or unexpected assertions.19- Bug reports, incorrect application behavior, runtime exceptions, crashes,20 panics, stack traces, or user-visible failures.21- Unexpected state transitions, data corruption symptoms, stale state, or invalid22 domain state.23- Flaky or nondeterministic failures, timing-sensitive behavior, async issues,24 concurrency issues, races, deadlocks, or ordering problems.25- Performance regressions, timeouts, resource leaks, excessive memory/CPU/I/O,26 or degraded latency/throughput.27- Build, lint, formatting, type-check, compilation, dependency, or toolchain28 failures.29- Integration failures across APIs, services, databases, queues, caches, UI,30 filesystem, network, auth, configuration, or environment boundaries.31- A current incident symptom when the immediate need is reproduce/diagnose/fix.32 For postmortem, prevention, repeated failures, or organizational/system causes,33 use `root-cause-analysis` after the active failure is understood.3435Do not use this skill for purely mechanical formatting, documentation-only36changes, or greenfield implementation with no failure or symptom to explain.3738## Core Principles3940- Start from the observable symptom, not an assumed cause.41- Preserve and inspect exact evidence: error text, stack trace, logs, failing42 assertion, diff, request/response, screenshot, trace, profile, or user-visible43 behavior.44- When that or production evidence may expose secrets, credentials, PII, tenant45 data, payloads, or private paths, load46 [`security-review`](../security-review/SKILL.md) and47 [`security-review-evidence`](../security-review-evidence/SKILL.md). Keep raw48 artifacts local and ignored; report sanitized summaries only. Do not add this49 routing for evidence without a sensitive-data risk.50- Reproduce the issue before fixing whenever feasible. If reproduction is not51 feasible, explain why and use the strongest available evidence.52- Find the smallest reliable reproduction: narrow command, test filter, route,53 input, fixture, component, dataset, seed, profile, or environment.54- Compare expected behavior against actual behavior before changing code.55- Form multiple plausible hypotheses; do not stop at the first plausible bug.56- Test hypotheses one at a time and record evidence for or against each one.57- Prefer direct evidence over speculation, intuition, or broad pattern matching.58- Distinguish symptom, proximate trigger, direct cause, and contributing factors.59- Keep fixes minimal, targeted, and aligned with the domain model and public60 contracts.61- Add or update regression coverage for confirmed defects.62- Do not weaken tests, delete assertions, reduce coverage, bypass validation, or63 mark tests ignored/skipped unless the direct cause proves the original behavior64 contract was wrong and the change is explicitly justified.6566## Investigation Workflow6768Follow this sequence unless the repository has a stricter local runbook:69701. **Clarify the symptom**71 - State what failed and where it was observed.72 - Identify impact: user-visible behavior, failing test, broken command,73 incident symptom, performance metric, or integration boundary.742. **Locate the failing surface**75 - Identify the failing command, test, route, component, module, workflow,76 query, job, or tool invocation.77 - Prefer repository-provided commands and docs over ad hoc commands.783. **Reproduce the failure**79 - Run the narrowest relevant command first.80 - If flaky, run enough repetitions or vary concurrency/seed/time/environment81 to characterize nondeterminism without hiding it.824. **Capture exact failure evidence**83 - Save or quote the important error message, assertion, stack frame, log line,84 response body/status, profile metric, or visible behavior.85 - Avoid summarizing away details that distinguish one failure mode from86 another.875. **Inspect recent changes and call paths**88 - Read the relevant code, tests, fixtures, config, schema, generated code89 boundaries, and recent diffs/history if available.90 - Trace data/control flow across boundaries before editing.91 - Use local code navigation for symbols, references, implementations, call92 relationships, and diagnostics when call paths matter. Use direct93 reads/search for exact error text, docs, config, logs, fixtures, and94 generated assets, and repository commands for tests, builds, or other95 validation.966. **Build a hypothesis list**97 - Include at least two plausible causes when the failure is not obvious.98 - Separate code defects from data, environment, dependency, timing, and test99 expectation hypotheses.1007. **Rank hypotheses**101 - Prefer high-likelihood, high-testability hypotheses first.102 - Define what observation would confirm or falsify each hypothesis.1038. **Instrument or inspect only as needed**104 - Add temporary logging, tracing, assertions, probes, or debuggers only when105 reading and focused tests do not provide enough evidence.106 - Remove temporary instrumentation before finishing unless it is intentionally107 production-quality observability.1089. **Isolate the direct cause**109 - Prove why the failure occurs and why competing hypotheses are less likely or110 false.111 - Identify whether the direct cause is code logic, contract mismatch, missing112 validation, incorrect test expectation, data setup, configuration,113 dependency/toolchain change, race/timing, caching, or environment drift.11410. **Implement the smallest correct fix**115 - Change one causal area at a time.116 - Avoid broad refactors, unrelated cleanup, or public contract changes unless117 the evidence requires them.11811. **Add or update regression tests**119 - Add the narrowest behavior-oriented coverage that would have caught the120 defect.121 - Prefer public behavior and domain outcomes over private implementation122 details when practical.12312. **Run focused verification first**124 - Re-run the reproducer, failing test, affected lints/type checks, or focused125 benchmark/profile.12613. **Run broader verification when justified**127 - Broaden to package/module/full-suite checks only when the change crosses128 boundaries, affects shared behavior, or focused checks cannot provide129 enough confidence.13014. **Summarize evidence, direct cause, fix, and verification**131 - State what was observed, what changed, why it fixes the direct cause, and132 what remains unverified.133134## Debugging Output135136Produce a concise debugging summary when the task involved a confirmed defect,137regression, flaky behavior, or non-obvious failure. Use this format, trimming138fields that truly do not apply:139140```markdown141## Debugging Summary142143- Symptom:144- Impacted behavior:145- Expected behavior:146- Actual behavior:147- Direct cause:148- Proximate trigger:149- Contributing factors:150- Why the fix is correct:151- Tests added or updated:152- Verification run:153- Not run / remaining risks:154- Follow-up work:155```156157Avoid shallow explanations such as "the test was wrong", "state was invalid",158"race condition", or "environment issue" unless you explain why, show the159evidence, and distinguish the direct cause from the symptom.160161If the work reveals repeated failures, broad contributing factors, or prevention162items beyond the direct fix, hand off to `root-cause-analysis` for a postmortem-163style RCA rather than expanding this debugging pass.164165## Testing and Verification Expectations166167- Use focused tests and commands while investigating. Start narrow; broaden only168 for meaningful confidence.169- Add regression coverage for confirmed defects unless impossible or already170 covered by an existing test that was failing for the right reason.171- Keep tests behavior-oriented and domain-facing where practical. Avoid brittle172 tests coupled to private implementation details unless the defect is itself an173 implementation contract.174- Resolve failing tests, clippy/lint errors, type errors, compilation errors,175 formatting issues, and introduced warnings before considering the task done.176- Do not run long full-suite or expensive commands by default. Use them when the177 fix touches shared infrastructure, public contracts, cross-cutting behavior,178 generated artifacts, schemas, concurrency, performance, or release-critical179 surfaces.180- Clearly state every verification command/check run and whether it passed.181- Clearly state important checks not run and why.182- Do not claim performance improvements without before/after measurements from183 the same tool and comparable conditions.184185## Guardrails186187Do **not**:188189- Guess and patch without reproduction when reproduction is feasible.190- Treat the first plausible issue as the direct cause without testing alternatives.191- Make multiple unrelated changes in one debugging pass.192- Paper over errors with retries, sleeps, broad exception handlers, broad null193 checks, silent defaults, swallowed errors, cache clears, or relaxed validation194 unless evidence proves that behavior is correct for the domain.195- Change public contracts, API behavior, schemas, migrations, data formats,196 permissions, error semantics, or compatibility guarantees without evidence,197 tests, and explicit justification.198- Assume an environment issue before checking code-level causes, configuration,199 inputs, data setup, dependencies, and command differences.200- Ignore flakiness or nondeterminism. Characterize it and either fix it or report201 the remaining risk explicitly.202- Leave temporary logs, debug prints, tracing, sleeps, feature flags, or probes in203 production code.204- Mark tests ignored/skipped, delete assertions, or reduce coverage as a205 substitute for fixing the defect.206207## Debugging Heuristics by Failure Class208209When the core workflow is not enough, use the progressive reference210[`references/failure-heuristics.md`](references/failure-heuristics.md) for211failure-class prompts covering unit, integration, flaky, async, state,212serialization, boundary, environment, dependency, performance, UI, database, and213build failures.214215## Communication Style216217Communicate in short, evidence-based updates:218219- State what failed and the exact evidence observed.220- State the hypothesis currently being tested and why it is plausible.221- State what changed and why it addresses the direct cause.222- State what verification was performed and the result.223- State uncertainty explicitly when evidence is incomplete; do not overstate224 confidence.225226## Examples227228### Good debugging behavior229230> The `creates_order_without_discount` test fails with `expected total 100,231> actual total 90`. I reproduced it with the single test filter. The failing232> path applies the promotional discount even when the request has no coupon. My233> hypotheses are: stale fixture data, default coupon value, or unconditional234> discount application. Inspecting the request fixture shows no coupon; tracing235> the calculation shows the discount branch checks `customer.is_eligible` but not236> `coupon.is_some()`. I will add a regression assertion for eligible customers237> without coupons, update the branch condition, then rerun the focused test and238> the order calculation tests.239240Why this is good: it preserves exact evidence, reproduces narrowly, compares241expected and actual behavior, names multiple hypotheses, tests the relevant path,242implements a targeted fix, and verifies with focused tests.243244### Bad debugging behavior to avoid245246> The order test is probably flaky because discounts are complicated. I changed247> the expected total to `90`, added a retry, and refactored the pricing module so248> the suite passes locally.249250Why this is bad: it guesses without evidence, weakens the test, hides possible251nondeterminism with a retry, makes broad unrelated changes, and never explains252the direct cause or why the new behavior is correct.253254## Zod Boundary Debugging255256For a Zod failure, record installed version/import, parser method, sanitized input class, issue code/path, and transform/refinement/async involvement. Load [`zod-engineering`](../zod-engineering/SKILL.md); distinguish expected rejection from parser/application failure and do not weaken schemas to match locale wording.