agentleFS
greglas75greglas75/zuvo/skills/debug/SKILL.md

debug

Skill7 starsChanged 27 days agoMITView on GitHub

Systematic bug investigation with a five-phase framework: reproduce, narrow, diagnose, fix, verify. Supports automated regression bisect via --regression flag. Produces a structured debug report with root cause analysis, regression test, and CQ/Q self-evaluations.

192 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use add-discord, add-slack and 10 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • MicrosoftSkill

    add-discord

    Add Discord bot channel integration via Chat SDK.

    Also in 11 projects that use this

  • MicrosoftSkill

    add-slack

    Add Slack channel integration via Chat SDK.

    Also in 11 projects that use this

  • +10 more from microsoft

The file

Show its rules and text

We split this skill into the rules it gives an agent

62 rules. 0 are common, 46 are distinctive, and 16 are very specific to this project.

  • 0

    Common

    Most of the 175 edited versions we read keep these.

  • 46

    Distinctive

    This author's own choices. Worth a look.

  • 16

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read ../../shared/includes/env-compat.md for agent dispatch patterns, path resolution, and progress tracking across all supported platforms.

    line 73
  2. Very specific:

    Read ../../shared/includes/codesift-setup.md for the full initialization sequence.

    line 77
  3. Distinctive:

    After CodeSift setup, read the error, stack trace, or target file.

    line 105
  4. Distinctive:

    If PHASE 0 file missing: Run self-evaluation using the embedded minimal checklist below.

    line 142
  5. Distinctive:

    All branches exercised? (Q11)

    line 146
  6. Distinctive:

    Test imports real production code?

    line 147
  7. Distinctive:

    No duplicated logic blocks?

    line 153
  8. Very specific:

    Run the knowledge prime protocol from knowledge-prime.md:

    line 174
  9. Distinctive:

    Timeline: When did it start? Was there a recent deploy, config change, or dependency update?

    line 193
  10. Distinctive:

    If reproduction is inconsistent, flag as a potential race condition, environment-dependent issue, or test-order dependency.

    line 195
  11. Distinctive:

    Run the failing test or hit the failing endpoint.

    line 201
  12. Distinctive:

    If intermittent: Run 3 times to confirm flakiness, then proceed with a flaky flag.

    line 204
  13. Distinctive:

    Before changing anything, determine whether this is a new regression or a pre-existing problem.

    line 212
  14. Distinctive:

    Run existing tests for the affected area.

    line 214
  15. Very specific:

    Check recent commits to the affected files: git log --oneline -10 -- [affected-files]

    line 215
  16. Very specific:

    If CodeSift is available: changed_symbols(repo, since="HEAD~5") to see symbol-level changes near the bug.

    line 216
  17. Distinctive:

    Check request validation -- does the schema reject the input, or does it let bad data through?

    line 260
  18. Distinctive:

    Check auth context at the point of failure

    line 261
  19. Distinctive:

    Check the database query -- does it return expected data?

    line 262
  20. Distinctive:

    Check error handling -- does the catch block swallow, transform, or propagate correctly?

    line 263
  21. Distinctive:

    Check browser console for errors, network tab for failed requests

    line 266
  22. Distinctive:

    Check event handlers -- does the user action trigger the expected dispatch or callback?

    line 269
  23. Distinctive:

    Check SSR hydration mismatch if applicable

    line 270
  24. Distinctive:

    Run EXPLAIN ANALYZE -- missing index?

    line 274
  25. Distinctive:

    Check for N+1 patterns (same query executed in a loop)

    line 275
  26. Distinctive:

    Check connection pool exhaustion or timeout settings

    line 276
  27. Distinctive:

    Check if dataset size has grown beyond what the query handles efficiently

    line 277
  28. Distinctive:

    Run the failing test 5 times.

    line 280
  29. Distinctive:

    Check for shared mutable state between tests (globals, singletons, database rows)

    line 281
  30. Distinctive:

    Check timing assumptions (setTimeout, sleep, waitFor with insufficient duration)

    line 282
  31. Distinctive:

    Check execution-order dependency (does the test rely on another test running first?)

    line 283
  32. Distinctive:

    Check resource cleanup (ports, connections, file handles released properly?)

    line 284
  33. Distinctive:

    Run only the tests covering the affected area:

    line 299
  34. Distinctive:

    If any fail, the fix is incomplete or introduced a new problem.

    line 303
  35. Very specific:

    Read ../../shared/includes/verification-protocol.md -- no completion claims without fresh evidence.

    line 316
  36. Distinctive:

    Write a test that:

    line 320
  37. Very specific:

    Run Q1-Q25 self-evaluation on the regression test.

    line 325
  38. Very specific:

    Run CQ1-CQ40 on each modified production file.

    line 335
  39. Very specific:

    Record the verdicts: after triage: every finding is fixed, rejected (a false positive) or deferred — record each by its ID: in ONE call, …

    line 367
  40. Very specific:

    If adversarial-review is not in PATH: ~/.zuvo/adversarial-review (stable.

    line 369
  41. Distinctive:

    Wait for complete output. Handle findings by severity:

    line 371
  42. Distinctive:

    Do NOT discard findings based on confidence alone.

    line 376
  43. Distinctive:

    After confirming the fix works, add validation at multiple layers to prevent the same class of bug from recurring:

    line 382
  44. Distinctive:

    Not every layer applies to every bug.

    line 391
  45. Distinctive:

    No test can reproduce it (flaky, environment-dependent, requires manual UI interaction)

    line 408
  46. Distinctive:

    Write a small, focused test that captures the regression:

    line 414
  47. Distinctive:

    Run the test once on HEAD to confirm it fails

    line 423
  48. Distinctive:

    If the user is unsure: show git log --oneline -30 and ask them to identify the last known-good point.

    line 431
  49. Distinctive:

    If the test also fails on the "good" commit, this is not a regression.

    line 440
  50. Distinctive:

    If bisect exceeds 20 steps: the range is too wide or the test is flaky.

    line 455
  51. Distinctive:

    If the test is flaky (inconsistent results on the same commit): abort and address flakiness first.

    line 456
  52. Very specific:

    If bisect encounters merge conflicts during checkout: abort and use manual git bisect good/bad stepping, skipping problematic commits with …

    line 457
  53. Very specific:

    Read the full diff: git show <first-bad-commit>

    line 463
  54. Distinctive:

    Run the same verification as Phase 4: targeted tests, full suite, original reproduction, CQ self-eval on production changes, Q self-eval on …

    line 474
  55. Distinctive:

    Always execute, even if bisect was aborted:

    line 478
  56. Very specific:

    If debugging reveals unrelated issues, do not fix them during the debug session.

    line 490
  57. Very specific:

    After the fix is verified, run the knowledge curation protocol from knowledge-curate.md:

    line 604
  58. Very specific:

    Follow the retrospective protocol from retrospective.md.

    line 617
  59. Distinctive:

    If gate check skips: print "RETRO: skipped (trivial session)" and proceed to completion.

    line 619
  60. Distinctive:

    Before printing the final output block, verify every item.

    line 625
  61. Distinctive:

    After Phase 4 or Phase R verification passes:

    line 642
  62. Very specific:

    Append via wrapper (REQUIRED): Never >> directly to ~/.zuvo/runs.log — the wrapper is the gate that verifies a retro entry exists for this …

    line 668

“Common” is measured: kept by at least 6 in 10 of the 175 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

zuvo:debug — Structured Bug Investigation

A disciplined five-phase process for turning a bug report, error message, or unexpected behavior into a confirmed root cause, verified fix, and permanent regression test.

Scope: Any bug, error, or unexpected behavior that needs investigation. Out of scope: Code quality sweeps (use zuvo:code-audit), general review (use zuvo:review), performance problems without a specific bug (use zuvo:performance-audit).

Argument Parsing

Parse $ARGUMENTS to determine the starting phase:

InputStarting point
(empty)Ask the user: "Describe the issue. Share the error message, stack trace, or explain what is happening."
Error message or stack tracePhase 1.5 (Minimal Reproduction) -- verify the error is reproducible before narrowing
Code snippet or file referencePhase 3 (Diagnose) -- read the code, trace the execution path
Description like "why does X" or "X is broken"Phase 1 (Reproduce) -- gather context before proceeding
--regression flag, or words like "bisect", "regression", "this used to work"Phase R (Regression Bisect) -- automated git bisect to find the breaking commit

Environment Compatibility

Dispatch follows ../../shared/includes/execution-policy.md through env-compat. Reuse existing authorization within that policy; session restrictions take precedence. Run each required gate and report its actual independence or an unmet requirement.

Read ../../shared/includes/env-compat.md for agent dispatch patterns, path resolution, and progress tracking across all supported platforms.

CodeSift Integration

Read ../../shared/includes/codesift-setup.md for the full initialization sequence.

Key tools for debugging:

PhaseTaskCodeSift toolFallback
2Identify recent symbol-level changeschanged_symbols(repo, since="HEAD~5")git log --oneline + git diff
2Compact change summarydiff_outline(repo, since="HEAD~5")git diff --stat
2Blast radius of recent changesimpact_analysis(repo, since="HEAD~5", depth=2)Grep for imports of changed files
3Trace callers/callees of buggy functiontrace_call_chain(repo, symbol_name, direction, depth=3)Repeated Grep for function name
3Understand buggy function with imports and siblingsget_context_bundle(repo, symbol_name)Read the entire file
3Find where an error is thrownsearch_text(repo, query="error message", regex=true)Grep
3Read multiple functions along the call pathget_symbols(repo, symbol_ids=[...])Multiple Read calls
3File structure around the bugget_file_outline(repo, file_path)Read the file
AnyBatch 3+ lookupscodebase_retrieval(repo, queries=[...])Sequential Grep/Read

Mandatory File Loading

PHASE 0 — Bootstrap (always, before reading error/file)

  1. ../../shared/includes/codesift-setup.md      -- [READ | MISSING -> STOP]

This is the ONLY file loaded before reading the error report or target file.

PHASE 0.5 — Classify (read error/file, determine bug category)

After CodeSift setup, read the error, stack trace, or target file. Classify bug category:

  • logic: wrong output, off-by-one, condition error, missing branch
  • async: race condition, unhandled rejection, deadlock, timeout
  • data: wrong query, missing join, constraint violation, data corruption
  • integration: API contract mismatch, version incompatibility, env config error
  • test-failure: existing test broke, flaky test, test infrastructure issue

Print: [CLASSIFIED] Bug category: {logic|async|data|integration|test-failure}

PHASE 1 — Conditional Load (based on bug category)

Includelogicasyncdataintegrationtest-failure
../../rules/cq-patterns.mdFullCQ15,CQ21 focusCQ6,7,9 focusCQ8,CQ19 focusSKIP
../../rules/cq-checklist.mdFullCQ15,CQ21 focusCQ6,7,9 focusCQ8,CQ19 focusSKIP
../../rules/testing.mdSKIPSKIPSKIPSKIPFull

Print loaded files:

PHASE 1 — LOADED:
  [list with READ/SKIP status per file]

Optional Files (loaded if available)

  ../../shared/includes/knowledge-prime.md   -- [READ | MISSING -> degraded]

DEFERRED — Load at completion

  ../../shared/includes/run-logger.md        -- [READ at final step]
  ../../shared/includes/retrospective.md     -- [READ at final step]
  ../../shared/includes/knowledge-curate.md  -- [READ at final step | MISSING -> degraded]

If PHASE 0 file missing: Run self-evaluation using the embedded minimal checklist below. Note "DEGRADED — codesift-setup.md unavailable" in the debug report.

Minimal checklist (fallback only):

  1. Error path tested? (Q7)
  2. All branches exercised? (Q11)
  3. Test imports real production code? (Q13)
  4. Assertions verify values, not just shape? (Q15)
  5. Expected values from spec, not copied from implementation? (Q17)
  6. Boundary validation present? (CQ3)
  7. Auth guard paired with query filter? (CQ4)
  8. Infrastructure errors handled with timeout? (CQ8)
  9. No duplicated logic blocks? (CQ14)

Framework: Five Phases

Phase 1:   REPRODUCE    -- Understand expected vs. actual behavior
Phase 1.5: MINIMAL REPRO -- Verify a stack trace is current and reproducible
Phase 2:   NARROW       -- Establish baseline, reduce the search space
Phase 3:   DIAGNOSE     -- Trace the code path, form and test hypotheses
Phase 4:   FIX + VERIFY -- Implement fix, regression test, quality gates

Phase R:   REGRESSION BISECT -- Alternative path for "this used to work" bugs
           Replaces Phases 1-3 with automated git bisect, then joins Phase 4.

Phase 0: Knowledge Prime

Run the knowledge prime protocol from knowledge-prime.md:

WORK_TYPE = "research"
WORK_KEYWORDS = <keywords from the bug description, error messages, affected files>
WORK_FILES = <files mentioned in the bug report, if any>

Known gotchas from prior sessions may directly identify the root cause.


Phase 1: Reproduce

Establish a clear, reproducible failure. Gather from the user if not provided:

  • Expected behavior: What should happen?
  • Actual behavior: What happens instead?
  • Reproduction steps: Exact sequence to trigger the bug
  • Scope: Does it happen always, intermittently, for all users, or under specific conditions?
  • Timeline: When did it start? Was there a recent deploy, config change, or dependency update?

If reproduction is inconsistent, flag as a potential race condition, environment-dependent issue, or test-order dependency.

Phase 1.5: Minimal Reproduction

A stack trace proves an error occurred at some point. It does not prove the error is reproducible right now. Before narrowing:

  1. Run the failing test or hit the failing endpoint. Can you trigger the same error?
  2. If yes: Proceed to Phase 2 with confirmed reproduction.
  3. If no: The trace may be from a different state (stale data, previous deploy, changed config). Go back to Phase 1: gather expected vs actual, steps, scope.
  4. If intermittent: Run 3 times to confirm flakiness, then proceed with a flaky flag.

Skip this phase only when the failure is self-evident (type error visible in code, compilation failure).

Phase 2: Narrow

2.0 Baseline Check

Before changing anything, determine whether this is a new regression or a pre-existing problem.

  1. Run existing tests for the affected area. Are any already failing?
  2. Check recent commits to the affected files: git log --oneline -10 -- [affected-files]
  3. If CodeSift is available: changed_symbols(repo, since="HEAD~5") to see symbol-level changes near the bug. diff_outline(repo, since="HEAD~5") for a compact summary.
  4. Record the current test state as a baseline.

Output:

BASELINE: [N] passing, [M] failing in affected area
REGRESSION: YES (commit [hash]) | NO (pre-existing) | UNKNOWN

2.1 Reduce the Search Space

Work through these in order, stopping when the failure point is identified:

  1. Error message and stack trace -- Read the full trace, not just the last line. The root cause is usually earlier in the chain.
  2. Logs around the failure time -- What happened immediately before the error?
  3. Recent changes -- Commits, deploys, dependency updates, config changes in the relevant window.
  4. Environment comparison -- If it works in one environment but not another, find the difference.
  5. Binary search -- If the code path is long, identify the midpoint and determine whether the bug is upstream or downstream.

Phase 3: Diagnose

Trace the execution path from input to failure.

  1. Entry point -- Where does the triggering action enter the system?
  2. Trace forward -- Follow data through each function and service until the point of failure. If CodeSift is available, use trace_call_chain(repo, symbol_name, direction="callees", depth=3) from the entry point. Use get_context_bundle(repo, symbol_name) to understand the buggy function with its imports and neighbors.
  3. Form hypotheses (max 3) -- List 2-3 possible root causes, ordered by likelihood.
  4. Test each hypothesis -- For each: what evidence would confirm or rule it out? Gather that evidence. If 2 hypotheses fail, pivot: re-read the code path from scratch, add logging, or widen the search scope. Do not keep guessing in the same direction.
  5. Root cause -- Identify the specific line, condition, or assumption that fails. Distinguish root cause from symptoms.

Error-Type Playbooks

Error typeMost common root causes
undefined or nullMissing null guard, wrong property key, async timing issue
Wrong valueOff-by-one, unit mismatch, stale cached data
Permission deniedAuth context not propagated, RBAC misconfigured, missing query filter
TimeoutN+1 query, missing database index, unbounded loop
Flaky / intermittentRace condition, shared global state, test-order dependency
Works in dev, fails in prodMissing env variable, production data edge case, timezone difference

Stack-Specific Diagnostic Sequences

API / Backend:

  1. Reproduce with curl or the test runner against the endpoint
  2. Check request validation -- does the schema reject the input, or does it let bad data through?
  3. Check auth context at the point of failure
  4. Check the database query -- does it return expected data? Run EXPLAIN for slow queries.
  5. Check error handling -- does the catch block swallow, transform, or propagate correctly?

Frontend / UI:

  1. Check browser console for errors, network tab for failed requests
  2. Determine if API data is correct -- if yes, the bug is in rendering or state management
  3. Trace component prop flow to the failing component
  4. Check event handlers -- does the user action trigger the expected dispatch or callback?
  5. Check SSR hydration mismatch if applicable

Database / Performance:

  1. Identify the slow or failing query from logs or ORM debug mode
  2. Run EXPLAIN ANALYZE -- missing index? full table scan? cartesian join?
  3. Check for N+1 patterns (same query executed in a loop)
  4. Check connection pool exhaustion or timeout settings
  5. Check if dataset size has grown beyond what the query handles efficiently

Async / Flaky:

  1. Run the failing test 5 times. How often does it fail?
  2. Check for shared mutable state between tests (globals, singletons, database rows)
  3. Check timing assumptions (setTimeout, sleep, waitFor with insufficient duration)
  4. Check execution-order dependency (does the test rely on another test running first?)
  5. Check resource cleanup (ports, connections, file handles released properly?)

Phase 4: Fix and Verify

4.1 Implement the Fix

  1. Apply the minimal fix -- Address the root cause only. Do not refactor adjacent code or fix unrelated issues.
  2. Explain why -- Connect the fix to the diagnosed root cause. Add a code comment if the fix is non-obvious.
  3. Check side effects -- Does the fix alter behavior for other callers? Does it change the function's contract?
  4. Consider edge cases -- Does the fix hold for null, empty, concurrent, and high-load scenarios?

4.2 Run Targeted Tests

Run only the tests covering the affected area:

[test-runner] [affected-test-files]

If any fail, the fix is incomplete or introduced a new problem. Iterate.

4.3 Run Full Suite

[test-runner]

Compare with the Phase 2.0 baseline. No new failures should appear. If new failures exist, the fix has side effects. Investigate before proceeding.

4.4 Confirm Original Reproduction is Resolved

Re-run the exact reproduction from Phase 1 or Phase 1.5. If the bug still occurs, the root cause diagnosis was wrong. Return to Phase 3.

Read ../../shared/includes/verification-protocol.md -- no completion claims without fresh evidence.

4.5 Write Regression Test

Write a test that:

  1. Recreates the exact condition that triggered the bug
  2. Asserts the correct behavior (the bug no longer occurs)
  3. Would have caught this bug if it had existed before the original code was written

Run Q1-Q25 self-evaluation on the regression test. Read ../../rules/testing.md for the full protocol.

Condensed reference: ../../shared/includes/quality-gates.md

  • Score each gate individually (1/0, N/A counts as 1 but needs justification)
  • Critical gates: Q7, Q11, Q13, Q15, Q17 -- any = 0 means fix the test
  • Threshold: >= 16 PASS, 9-15 FIX (address worst gaps), < 9 REWRITE

4.6 CQ Self-Evaluation (on production code changes)

Run CQ1-CQ40 on each modified production file. Read ../../rules/cq-checklist.md for the full protocol.

  • Static critical gates: CQ3, CQ4, CQ5, CQ6, CQ8, CQ14 -- any = 0 means FAIL
  • Conditional gates: CQ16 (money), CQ19 (API boundary), CQ20 (dual fields), CQ21 (concurrency), CQ22 (subscriptions), CQ23-CQ28 -- activated by code context
  • Threshold: >= 24 PASS, 22-23 CONDITIONAL PASS, < 22 FAIL
  • Provide file:function:line evidence for every critical gate scored as 1

4.6b Adversarial Review (MANDATORY — do NOT skip)

# Scoped review patch on stdout — the git index is NEVER touched (no staging).
# PATH args = the files this fix touched (production fix + regression test).
# Quote each SEPARATELY — never one space-joined string or a bare $FILES: zsh does
# not word-split an unquoted expansion, so the helper gets the whole list as ONE
# path, matches nothing and exits 2. Use "${FILES[@]}" for an array.
# With NO PATH args the helper reviews the WHOLE dirty tree, untracked files
# included, and that content is sent to the external providers — always scope it.
# `|| _prc=$?` (never `; _prc=$?`): under `set -e` the plain form aborts the shell
# at the assignment, so exit 3 and the BLOCKED branch would never be reached.
# The BLOCKED branch ends in `false`, so the block's own exit status is non-zero:
# printing alone lets a `set -e` / `if ! …` caller sail past a review that never
# ran. `false`, not `exit`, so an inlining caller's shell is not killed.
if [ -x "$HOME/.zuvo/build-review-patch" ]; then
  _prc=0; _patch=$("$HOME/.zuvo/build-review-patch" "<fixed-file>" "<regression-test-file>") || _prc=$?
  if [ "$_prc" -eq 3 ]; then echo "adversarial review: skipped (no changes)"
  elif [ "$_prc" -ne 0 ]; then echo "BLOCKED: build-review-patch failed (rc=$_prc). Adversarial review did NOT run; do NOT proceed to commit and do NOT report this skill complete" >&2; false
  else printf '%s\n' "$_patch" | ~/.zuvo/adversarial-review --mode code; fi
else
  ~/.zuvo/adversarial-review --mode code --files "<changed files>"
fi

Record the verdicts after triage: every finding is fixed, rejected (a false positive) or deferred — record each by its ID: in ONE call, ~/.zuvo/adversarial-review --record-disposition ID-1 fixed --record-disposition ID-2 rejected …, per ../../shared/includes/adversarial-loop.md Step 4.9 (the review lists its IDs on stderr).

If adversarial-review is not in PATH: ~/.zuvo/adversarial-review (stable; the versioned cache path breaks after any release)

Wait for complete output. Handle findings by severity:

  • CRITICAL — confirm it first: two or more lanes in its .agreement group, or your own check (a failing test, a reproduced input, the cited code read and the defect traced). Confirmed → fix immediately. A single-lane CRITICAL you cannot confirm is triaged as a WARNING and reported as [CRITICAL→WARNING single-lane] (adversarial-loop.md Step 4).
  • WARNING — fix if localized (< 10 lines). Otherwise record it with ~/.zuvo/backlog-add --repo "$R" --class <C> --conf <N> --source debug --file "$F" --line <n> [--anchor "$A"] --title "$T" (backlog-protocol.md "Filing from a skill", Adversarial review; pass --anchor "$A" only when the class requires one, BUG, SEC or DATA, or the finding carries one, never an invented one; assign "$R", "$F" and "$T" before the call, and "$A" only when you pass --anchor, as "Free text goes through a variable" in that section says; an empty value you pass is a bug, and backlog-add refuses a missing required field (REFUSED missing-field:<f>)). Report the B- or F-id it prints; a finding still not persisted is listed under NOT PERSISTED (<reason>), never appended by hand.
  • INFO — known concerns (max 3, one line each).

Do NOT discard findings based on confidence alone. Confidence measures how sure the reviewer is, not how important the issue is. A CRITICAL with low confidence means "verify this — if true, it's serious."

"Pre-existing" is NOT a reason to skip a finding. If the issue is in a file you are already editing, fix it now. If not, call backlog-add for each pre-existing finding: ~/.zuvo/backlog-add --repo "$R" --class <C> --conf <N> --source drive-by:debug --file "$F" --line <n> [--anchor "$A"] --title "$T" (drive-by-findings.md; backlog-protocol.md "Filing from a skill", Adversarial review; <C> is the drive-by tag the finding qualifies for; the anchor as for the WARNING command above; assign "$R", "$F" and "$T" before the call, and "$A" only when you pass --anchor, as "Free text goes through a variable" in that section says; an empty value you pass is a bug, and backlog-add refuses a missing required field (REFUSED missing-field:<f>)). The helper's bars may keep it in the backlog, keep it in the ledger only, or discard it, so report what it printed. Each one it kept counts, under its tag, in the Drive-by: N recorded (…) line and the ~/.zuvo/log-drive-by receipt of "Backlog Persistence" below. The adversarial review found a real problem — don't dismiss it just because it existed before your changes.

4.7 Defense-in-Depth

After confirming the fix works, add validation at multiple layers to prevent the same class of bug from recurring:

LayerWhat to addExample
Entry validationGuard at the function or endpoint boundaryNull check, schema validation, type narrowing
Business logicAssertion or invariant within the core logicGuard clause, exhaustive switch, pre/post-condition
Environment guardRuntime check for assumptions about external stateConfig validation at startup, connection health check
Debug instrumentationLogging or metric that makes this failure class visible in productionStructured log with correlation ID at the failure point

Not every layer applies to every bug. Add guards where they make sense. The goal is that if a similar bug occurs in the future, it fails loudly and early rather than silently propagating.


Phase R: Regression Bisect

An alternative flow for bugs that are confirmed regressions. Replaces Phases 1-3 with automated git bisect, then joins Phase 4 for the fix and verification.

When to Use

  • The user says "this used to work", "regression", or explicitly passes --regression
  • The bug is a behavioral change from a previously working state
  • A test can be written that reproduces the failure deterministically

When NOT to Use (fall back to standard Phases 1-4)

  • The bug is not a regression (new feature, never worked correctly)
  • No test can reproduce it (flaky, environment-dependent, requires manual UI interaction)
  • The change is very recent (last 1-2 commits) -- just read the diff with git show
  • Uncommitted changes cannot be stashed cleanly

R.1 Write a Minimal Reproducer Test

Write a small, focused test that captures the regression:

  1. The test must FAIL on current HEAD (it reproduces the bug)
  2. Save it as __bisect_test.{ts,py,sh} (temporary, deleted after bisect completes)
  3. Determine the test command based on the project's runner:
    • Vitest: npx vitest run __bisect_test.ts --reporter=verbose
    • Jest: npx jest __bisect_test.ts --verbose
    • Pytest: python -m pytest __bisect_test.py -x -q
    • Shell: bash __bisect_test.sh
  4. Run the test once on HEAD to confirm it fails

R.2 Determine Good and Bad Commit Range

  • Bad commit: Current HEAD (confirmed failing in R.1)
  • Good commit: Determined by one of:
    • User-provided commit hash or tag ("it worked in v2.3")
    • Auto-detection: test against HEAD10, HEAD20, HEAD~30. Use the first commit where the test passes.
    • If the user is unsure: show git log --oneline -30 and ask them to identify the last known-good point.
  • Verify the good commit:
    git stash
    git checkout <good-commit> --quiet
    [run test command -- must exit 0]
    git checkout - --quiet
    git stash pop 2>/dev/null
  • If the test also fails on the "good" commit, this is not a regression. Fall back to standard debug flow (Phase 1).

R.3 Run Git Bisect

Stash uncommitted changes first.

git stash
git bisect start HEAD <good-commit>
git bisect run <test-command>

The bisect will output the first bad commit when complete.

Guardrails:

  • If bisect exceeds 20 steps: the range is too wide or the test is flaky. Abort with git bisect reset and fall back to manual debugging.
  • If the test is flaky (inconsistent results on the same commit): abort and address flakiness first.
  • If bisect encounters merge conflicts during checkout: abort and use manual git bisect good/bad stepping, skipping problematic commits with git bisect skip.

R.4 Analyze the Breaking Commit

Once bisect identifies the first bad commit:

  1. Read the full diff: git show <first-bad-commit>
  2. Identify the specific change that caused the regression
  3. Reset bisect: git bisect reset
  4. Restore stashed changes: git stash pop 2>/dev/null

R.5 Fix and Verify

The exact breaking commit is now known, making the root cause typically clear from the diff.

  1. Apply a targeted fix informed by knowing which change broke things
  2. Rename the reproducer test from __bisect_test.* to a permanent name (e.g., regression-[description].test.ts)
  3. Run the same verification as Phase 4: targeted tests, full suite, original reproduction, CQ self-eval on production changes, Q self-eval on regression test

R.6 Cleanup

Always execute, even if bisect was aborted:

git bisect reset 2>/dev/null
git stash pop 2>/dev/null
rm -f __bisect_test.ts __bisect_test.py __bisect_test.sh

Backlog Persistence

If debugging reveals unrelated issues, do not fix them during the debug session. Follow ../../shared/includes/drive-by-findings.md with <skill> = debug: backlog the security, bug, size, duplication, complexity, performance, dead-code and readability problems noticed OUTSIDE the bug's fence in files the investigation read (each one backlog-add call with --source drive-by:debug, which dedupes and picks the backlog or the findings ledger: drive-by-findings.md step 1), list every SEC one in the Debug Report, then ALWAYS record the receipt ~/.zuvo/log-drive-by --skill debug --sec <a> --bug <b> … (all zeros is an honest outcome). The counts include the pre-existing adversarial findings 4.6b filed with --source drive-by:debug.

Debug does not commit, so it stages nothing: the Debug Report lists the wrote= paths every backlog-add call of the run printed, for the user's own commit (backlog-protocol.md "Filing from a skill", Committing what backlog-add wrote).


Output: Standard Debug Report

## Debug Report: [issue summary]

### Reproduction
- **Expected:** [what should happen]
- **Actual:** [what happens instead]
- **Steps:** [how to reproduce]
- **Scope:** [always / intermittent / specific conditions]
- **Baseline:** [N] passing, [M] failing before fix

### Diagnosis

| # | Hypothesis | Evidence | Verdict |
|---|-----------|----------|---------|
| 1 | [most likely cause] | [file:line, log output, test result] | CONFIRMED / RULED OUT |
| 2 | [alternative cause] | [evidence] | CONFIRMED / RULED OUT |

**Confidence:** HIGH / MEDIUM / LOW -- [reasoning]

### Root Cause
[1-3 sentences explaining WHY the bug occurs, not just where]
File: [file:line]

### Fix Applied
```[language]
// Before:
[broken code]

// After:
[fixed code]
```

### Defense-in-Depth
[Guards added at which layers, or "N/A -- fix is self-guarding"]

### Verification
- Targeted tests: PASS ([N] tests)
- Full suite: PASS (no new failures vs baseline)
- Original reproduction: RESOLVED
- CQ self-eval: [score]/[applicable]
- Regression test Q self-eval: [score]/[applicable]

### Side Effects
[Any other paths affected, or "None -- change is isolated to [scope]"]

### Regression Test
```[language]
it('should [describe the bug scenario]', () => {
  // Reproduce the bug condition
  // Assert correct behavior
});
```

Output: Regression Bisect Report

## Debug Report: [issue summary] (Regression Bisect)

### Regression Detection
- **Symptom:** [what stopped working]
- **Reproducer test:** __bisect_test.ts -> renamed to [final-test-name]
- **Good commit:** [hash] ([date] -- [message])
- **Bad commit:** HEAD ([hash])
- **Bisect steps:** [N] steps across [M] commits

### Breaking Commit
- **Commit:** [hash] -- [message]
- **Author:** [author] ([date])
- **Files changed:** [list]
- **Root cause:** [1-3 sentences -- what in this commit broke the behavior]

### Fix Applied
```[language]
// Before (from breaking commit):
[code that caused regression]

// After (fix):
[fixed code]
```

### Defense-in-Depth
[Guards added at which layers]

### Verification
- Targeted tests: PASS ([N] tests)
- Full suite: PASS (no new failures)
- Original reproduction: RESOLVED
- CQ self-eval: [score]/29
- Regression test Q self-eval: [score]/19

Knowledge Curation

After the fix is verified, run the knowledge curation protocol from knowledge-curate.md:

WORK_TYPE = "research"
CALLER = "zuvo:debug"
REFERENCE = <git SHA of the fix commit>

Debugging often uncovers gotchas and codebase-facts that are highly valuable for future sessions.


Retrospective (REQUIRED)

Follow the retrospective protocol from retrospective.md. Gate check -> structured questions -> TSV emit -> markdown append. If gate check skips: print "RETRO: skipped (trivial session)" and proceed to completion.


Completion Gate Check

Before printing the final output block, verify every item. Unfinished items = pipeline incomplete.

COMPLETION GATE CHECK
[ ] Bug category classified and printed: [logic/async/data/integration/test-failure]
[ ] Root cause identified at specific file:line (not just symptom)
[ ] Original reproduction confirmed RESOLVED
[ ] Regression test written with Q self-eval (>=16)
[ ] CQ self-eval on modified production files
[ ] Adversarial review ran on staged diff
[ ] Deferred adversarial findings recorded through backlog-add, each B- or F-id reported, or "none"
[ ] Drive-by findings recorded per drive-by-findings.md: the `Drive-by: N recorded (…)` line and every SEC in the final summary, and the `~/.zuvo/log-drive-by` receipt written — zeros allowed
[ ] Run: line printed and appended to log

Completion

After Phase 4 or Phase R verification passes:

DEBUG COMPLETE
----------------------------------------------------
Issue: [summary]
Mode: standard | regression-bisect
Root cause: [1-line explanation]
Breaking commit: [hash -- message] (regression mode only)
Files fixed: [list]
Regression test: [test file path]
Verification: targeted PASS | full suite PASS | repro RESOLVED
CQ: [score]/[applicable] | Q: [score]/[applicable]
Confidence: HIGH / MEDIUM / LOW
Recorded: [N (backlog: a, ledger: b) | "none"] [plus each NOT PERSISTED (<reason>) by name]
Backlog files written (unstaged): [wrote= paths | "none"]

Run: <ISO-8601-Z>\tdebug\t<project>\t<CQ>\t<Q>\t<VERDICT>\t-\t<DURATION>\t<NOTES>\t<BRANCH>\t<SHA7>\t<INCLUDES>\t<TIER>


Next steps:
  zuvo:review [fixed-files]  -- verify fix quality
  git commit -m "fix: [issue summary]"
----------------------------------------------------

Append via wrapper (REQUIRED). Never >> directly to ~/.zuvo/runs.log — the wrapper is the gate that verifies a retro entry exists for this run. Order: retro bash executed → wrapper invoked → completion claimed.

printf '%b\n' "$RUN_LINE" | ~/.zuvo/append-runlog

Expected stdout: OK: appended to runs.log (retro verified for <skill> on <project>). If exit 2 with RETRO_REQUIRED — go execute the retro bash from retrospective.md first; never bypass with ZUVO_SKIP_RETRO_GATE=1. After the wrapper succeeds, print a Logs: evidence line (tail -1 ~/.zuvo/retros.log, grep -c "^<!-- RETRO -->" ~/.zuvo/retros.md, tail -1 ~/.zuvo/runs.log) before claiming completion. Printing the markdown retro section without executing the bash leaves all three log files empty.

VERDICT: PASS / WARN / FAIL / BLOCKED / ABORTED only. CQ: from Phase 4.6 CQ self-eval on production fix (N/<applicable>, 40-gate set). Q: from Phase 4.5 Q self-eval on regression test (N/<applicable>, 25-gate set). TASKS: - (debug does not track task count). DURATION: mode label (e.g., standard, regression-bisect). NOTES: 1-line root cause summary (max 80 chars).


Tips for Better Input

  • Share the full stack trace, not just the last line. The root error is usually deeper in the chain.
  • "This used to work" -- use zuvo:debug --regression for automated git bisect.
  • "Only in prod" -- likely a missing env variable, production data edge case, or timezone issue.
  • "Random / flaky" -- likely a race condition, shared mutable state, or test-order dependency.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.