Skill: /diagnose — Complex Bug Diagnostic Pipeline
When to invoke (and when NOT to)
Use /diagnose when:
- Bug reproduces but root cause is unclear after one read-pass of the failing code
- Previous fix attempts have been reverted ≥ 2 times (symptoms return)
- Failure is intermittent (flaky test, race condition, timing-dependent)
- Failure occurs in unfamiliar code (agent has no prior context)
- User has explicitly requested
/diagnoseor "deep investigation" - Circuit Breaker (Rule 14) tripped on the specialist agent that normally handles this domain
Do NOT use /diagnose when:
- Cause is obvious (null ref, typo, missing import, incorrect import path)
- Fix is < 10 LOC and has a clear success check
- Bug is in code you just wrote this session (read-pass + local reasoning is faster)
- User wants a quick patch and has accepted the tradeoff
Pipeline overview
Feedback Loop -> Investigation -> Verification -> Solution -> Lead Programmer
(signal) (hypothesis) (devil's adv.) (tradeoffs) (assign + exec)
repro/check command investigation.json verification.json solution.json implementation
(fast deterministic (root_cause, (status: confirmed | (3 options: (delegates to
pass/fail signal) evidence[], refuted | inconclusive, Quick/Strategic/ backend-developer,
confidence) reproduction_steps) Future-Proof) qa-engineer, etc.)
Each stage produces a required artifact saved to .investigations/<task_id>/ and a handoff contract (per Rule 16) to the next agent.
Stage 0 — Feedback Loop
Goal: Build the fastest reliable pass/fail signal for the exact symptom before explaining the cause.
The feedback loop is the highest-leverage part of diagnosis. Do not proceed to root-cause analysis until there is a loop that can reproduce the user's symptom or a documented reason why no loop is possible.
Try these in roughly this order:
- Failing test at the seam that reaches the bug.
- CLI or script invocation with fixture input and expected output.
- Curl/HTTP request against a running service.
- Headless browser script with DOM, console, or network assertions.
- Replay of a captured payload, event, HAR, log, or trace.
- Throwaway harness that calls the affected code path in isolation.
- Property/fuzz loop for broad wrong-output symptoms.
- Bisection or differential loop between known-good and known-bad states.
Improve the loop before investigating:
- Faster: remove unrelated setup and narrow the command.
- Sharper: assert the specific symptom, not merely "does not crash".
- More deterministic: pin time, seed randomness, isolate filesystem/network, or raise intermittent reproduction frequency with stress runs.
Do not treat Stage 0 as warm-up. It is the main leverage point. A bad loop produces fake certainty, weak hypotheses, and symptom-only fixes.
If no credible loop can be built, stop and report what was tried. Ask for access to the reproducing environment, a captured artifact, or permission to add temporary instrumentation. Do not proceed on a vibe.
Stage 1 — Investigation
Agent: diagnostics (Investigation role)
Goal: Produce ranked falsifiable root-cause hypotheses backed by empirical evidence.
Inputs
- Symptom description (from user or TODO.md bug ID)
- Reproduction steps (or "cannot reproduce" + environment)
- Relevant log lines, stack traces, error IDs
- Feedback loop command/check from Stage 0, or a documented reason no loop can currently be built
Required output — investigation.json
{
"task_id": "BUG-417",
"symptom": "POST /api/orders returns 500 when cart has ≥10 items",
"reproduction": {
"steps": ["...", "..."],
"frequency": "100% | intermittent (~30%) | once",
"environment": "staging-eu-west-1"
},
"feedback_loop": {
"command": "npm test -- checkout.e2e.test.ts",
"signal": "Fails with timeout before hydration marker appears",
"reliable": true
},
"ranked_hypotheses": [
{
"rank": 1,
"cause": "Test clicks #submit before React hydration completes on slow CI runners",
"prediction": "Waiting for the hydration marker will make the failure disappear without adding a fixed sleep"
},
{
"rank": 2,
"cause": "Submit button selector matches a hidden stale node",
"prediction": "Asserting the visible button count will expose multiple matching nodes"
}
],
"hypothesis": {
"root_cause": "OrderService.calculateTotal() N+1 query exhausts pool when cart.items.length > 9",
"confidence": "high | medium | low",
"falsifiable_by": "Run with pool_size=50; if error disappears, cause confirmed"
},
"evidence": [
{"type": "log", "ref": ".investigations/BUG-417/pg-pool-exhausted.log", "summary": "..."},
{"type": "code", "ref": "src/services/order.service.ts:142", "summary": "Unbounded .map+await"}
],
"unknowns": ["Why only eu-west-1?", "When did this start?"],
"next_agent": "diagnostics",
"next_stage": "verification"
}
Quality gate (Lead Programmer rejects if):
feedback_loopis missing and no blocked-loop explanation existsfeedback_loop.signalis vague, broad, or does not isolate the user's symptomranked_hypotheseshas fewer than 3 items unless the evidence makes a single cause unavoidable- Any hypothesis lacks a falsifiable prediction
hypothesis.falsifiable_byis vague ("check if it works")evidencehas fewer than 2 items (unverifiable)unknownsis empty butconfidence: low(contradictory)
Stage 2 — Verification
Agent: diagnostics (Verification role)
Goal: Attempt to refute the hypothesis. Only confirmed if refutation fails.
Inputs
investigation.json(from Stage 1)- Access to staging/test environment
- The Stage 0 feedback loop, rerun before and after each meaningful probe
Verification is invalid if it does not go back through the Stage 0 loop. A fix-looking local observation that bypasses the loop is not confirmation.
Required output — verification.json
{
"task_id": "BUG-417",
"status": "confirmed | refuted | inconclusive",
"triangulation": [
{"method": "reproduce_with_fix_applied", "result": "Error gone with pool_size=50"},
{"method": "reproduce_without_fix", "result": "Error returns at 10 items"},
{"method": "adjacent_test_case", "result": "9 items = OK, 10 items = fail → threshold confirmed"}
],
"counter_hypotheses_ruled_out": [
"DB slowness (ruled out: p99 < 50ms)",
"Network flaps (ruled out: no packet loss in window)"
],
"confidence": "high",
"recommendation": "Proceed to Solution stage — cause confirmed necessary AND sufficient"
}
Decision flow
status | Next action |
|---|---|
confirmed | Proceed to Solution stage (same diagnostics agent) |
refuted | Return to Investigation stage with counter-evidence. Max 2 round-trips. |
inconclusive | STOP. Surface to user with all evidence. Do NOT proceed to Solution stage. |
Stage 3 — Solution
Agent: diagnostics (Solution role)
Goal: Generate 3 solution options with explicit tradeoffs; never pick silently.
Required output — solution.json
{
"task_id": "BUG-417",
"options": [
{
"name": "Quick",
"description": "Increase pool_size from 20 → 50 in db.ts",
"scope_loc": 1,
"risk_tier": "Low",
"tradeoff": "Masks root cause; higher RAM; future growth hits same wall"
},
{
"name": "Strategic",
"description": "Rewrite calculateTotal() to batch via IN-clause",
"scope_loc": 40,
"risk_tier": "Medium",
"tradeoff": "Fixes N+1 permanently; requires regression test on discount l