Tracing root causes
Explain outcomes through evidence, not narrative, and fix causes rather
than symptoms. The failure mode this prevents: jumping from symptom to
favorite explanation, collecting only confirming evidence, then patching
where the error surfaced.
The iron law
NO FIX WITHOUT A ROOT CAUSE FIRST
A fix proposed before the cause is known is a guess wearing a diff.
This holds hardest exactly where it feels most expensive — during an
outage, at hour four, with a senior engineer already typing.
Two things it does not forbid:
- Mitigation under a live incident. Stopping the bleeding is
legitimate — a rollback, a circuit breaker, a feature flag. It is
named as mitigation, kept reversible, and it does not end the
investigation or get recorded as the cause.
- Doing what you were asked. If the owner has heard the concern and
still wants their fix, write it, state the assumption it rests on and
what would falsify it, and move on. State a disagreement once, plainly
— never twice, and never as silent compliance.
The phases
Run them in order. A phase skipped is a phase paid for later.
1. Reproduce
- Read the error completely — full message, full stack, line
numbers, codes. It frequently names the answer.
- Restate exactly what was observed — which artifact, what behavior,
when. If you catch yourself rewriting the observation to fit a theory,
stop.
- Trigger it reliably. What are the exact steps? Every time, or one
run in five? Not reproducible is a finding, not a dead end: it points
at timing, environment, or shared state.
- Check what changed — recent commits, dependency bumps, config and
environment differences between where it fails and where it doesn't.
2. Isolate
Narrow the failure to one component before explaining it.
- Instrument the boundaries. In a multi-component system (CI → build
→ sign, API → service → database), log what enters and what leaves
each boundary, run once, and read which hop breaks. Evidence about
where beats speculation about why.
- Compare against something that works. Find the nearest working
case and list every difference, however small. "That can't matter" is
a hypothesis, not an observation.
- Check what it depends on — the services, config, environment, and
assumptions the broken path needs to work at all. A missing or changed
dependency looks exactly like broken logic from the inside.
- Trace backward to the origin — see
references/techniques.md for backward
tracing, instrumenting a dangerous operation, and bisecting a test
suite to find which test dirties the tree.
3. Hypothesize
- Compete the explanations. Hold ≥2 from deliberately different
frames: code path, config/environment, measurement artifact, external
dependency, timing, shared state. "The measurement is wrong" is always
a candidate.
- Rank evidence by strength. Strongest to weakest: controlled repro
/ discriminating experiment → primary artifact with tight provenance
(timestamped logs, git history, file:line behavior) → independent
sources converging → single-source inference that fits →
circumstantial (naming, temporal proximity, stack position, "this same
fix worked on another service") → intuition, seniority, confidence.
When tiers conflict the higher tier wins; never treat support as flat.
- Name what you don't understand. "I don't know how X works yet" is a
finding, not a confession — say it, then go read X completely. A
hypothesis resting on an unread component is a guess about that
component, and a confident verdict about code nobody has read is the
most expensive kind of wrong.
4. Disconfirm
- Ask the two questions of each serious hypothesis: "what should we
observe if this were true — do we?" and "what observation would be
hard to explain if this were true?" A hypothesis that survives only
because nobody looked for counter-evidence keeps LOW confidence.
- Run a rebuttal round. Let the strongest alternative challenge the
leader with its best contrary evidence before you conclude. Down-rank
explanations that need fresh unverified assumptions to survive, and
don't merge hypotheses that merely sound alike (fake convergence).
- Test minimally. One variable, the smallest change that
discriminates. A bigger timeout after a failed timeout is not a new
hypothesis — it is the same one, retried louder.
- Name the critical unknown — the single missing fact behind most of
the remaining uncertainty — and the ONE probe that best separates the
top hypotheses. Prefer probes that discriminate over probes that
gather more of the same support, and pick the cheapest one that still
discriminates — under time pressure that is often minutes of reading
the actual implementation, not the full investigation someone is
refusing to fund.
5. Fix
- Write the failing reproduction first. Simplest case that fails;
a test if there's a framework, a script if there isn't. It proves the
cause and proves the fix.
- Fix at the source, not where the error surfaced. One change, one
concern — no bundled refactor, no "while I'm here".
- Then make it impossible. Add validation at the layers the bad
value crossed — entry, business logic, environment guard,
instrumentation (references/techniques.md
— defense in depth, and condition-based waiting when the cause was
timing).
- Verify, then hand off. Confirm the reproduction now passes and
nothing else broke — then stop; see Where this ends.
Three strikes → question the architecture
Count fix attempts. At three failures, the problem is no longer the
hypothesis:
- Each fix reveals a new problem somewhere else.
- Each fix needs "just a bit of refactoring" to land.
- The same symptom keeps returning in a new costume.
Stop. Say plainly that this looks structural, name the pattern you think
is wrong, and get a decision before attempt four. This is not a failed
hypothesis — it is a wrong architecture, and more fixes make it worse.
When the investigation stalls
Reachable evidence is spent and the phase-4 critical unknown is a fact
this seat cannot produce — access it lacks, knowledge a human holds, a
decision that is the owner's. That is a stall, and its one honest exit
is to ask. Never a silent guess, never a silent stop: a deadline bounds
which probes you can afford, not whether you report.
- Earn the ask. An affordable discriminating probe still on the
table means run it, not ask — minutes of reading the implementation
outrun waiting for an answer. Escalate when the next probe is one
you cannot run.
- Name the recipient — the owner, or the parent that dispatched
you. "Owner: someone else", written inside a document you then
submit, is an assignment, not a question.
- Use a channel that waits — a blocking ask upward, an interactive
question in a live session. A file read after the lane closes is a
record, not a channel.
- Carry the evidence; it is the price of asking. Hypotheses tried
and the observation that disconfirmed each, the exact point of the
stall, the ONE fact you need, and the probe that runs the moment it
comes back. A bare "I'm stuck" hands the answerer your investigation
to redo.
When the cause really is environmental
Sometimes the honest verdict is timing, an external dependency, or a
platform difference, with no defect to fix. That verdict is earned,
not reached by running out of patience — most "no root cause" is
incomplete investigation. When the trace genuinely lands there:
- Record what was ruled out, and how. The next person starts from
your shortlist instead of from zero.
- Handle it deliberately — a bounded retry, a timeout, a clear
error message. Deliberate handling is a design decision with a
rationale; a swallowed error is not.
- Add the monitoring that would make the next occurrence legible,
because there will be a next occurrence.
Rationalizations
| Thought |
Reality |
| "Emergency — no time for process" |
Systematic is FASTER than guess-and-check thrashing. The process is the short path out, not a tax on the outage. |
| "It's simple, it doesn't need this" |
Simple bugs have causes too, and the process is quick on them. |
| "Quick fix now, investigate after" |
The first fix sets the pattern, and "after" rarely arrives. |
| "Just try it and see if it works" |
A change that fixes a symptom you don't understand hides the cause. |
| "It's probably X, let me fix that" |
Seeing a symptom is not understanding a cause. |
| "This same fix worked last week elsewhere" |
A pattern match on a different system is circumstantial evidence about this one. |
| "It broke right after the deploy" |
Temporal proximity is bottom-tier evidence. Correlate with changed code paths and rollout timing before believing it. |
| "The senior engineer is sure" |
Experience raises a prior; it is not an observation. Ask what would show it. |
| "One more attempt" (after 2+) |
Three failures is an architecture signal. Stop and say so. |
| "Four hours in — I can't waste them" |
Sunk cost. Those hours are spent either way; only the next hour is a choice. |
| "Bigger timeout, then ship it" |
A passing sleep is a race CI will lose. Wait on the condition. |
| "Multiple fixes at once saves time" |
You cannot tell which one worked, and you added new bugs. |
| "The reference is long, I'll adapt it" |
Partial understanding guarantees bugs. Read it completely. |
| "No root cause — it's just flaky" |
95% of "no root cause" is incomplete investigation. Prove environmental before accepting it. |
Redirection from a human — "is that not happening?", "stop
guessing", "we're stuck?" — means the same thing: return to phase 1.
Output shape
Ranked hypothesis table (confidence + evidence strength + why it
survives), evidence for AND against each, current best explanation
(explicitly provisional when evidence is incomplete), critical unknown,
discriminating probe. When a fix follows, the reproduction, the change,
and what it means if the change didn't help.
Blocked by missing evidence? The ranked shortlist plus the probe IS the
deliverable, not a failure — and it is delivered to someone, not filed;
see When the investigation stalls.
Where this ends
This skill investigates and fixes. It does not certify.
- Evidence lands in the lane's
PROGRESS.md — the reproduction, the
ranked hypotheses, the probe results, the change. Not a scratch
debugging log, not the chat alone.
work-verify owns the completion gate. Hand off there. "The test
passes now" is a result to be verified, never a verdict.
work-handoff closes the lane. This skill never declares work
done, fixed, or shippable on its own authority.
Judgment notes
- Investigation only? Stop after phase 4 and deliver the trace. Asked to
fix as well? Finish the trace first, then fix — the phases are the
order, not a menu.
- Framing pressure ("confirm it was the deploy so we can roll back") is
a request for a conclusion, not for analysis. Give the analysis; if it
supports the framing, say so with the evidence.
- This skill supersedes
superpowers:systematic-debugging, whose
machinery it absorbed. Superpowers remains installed as the fallback
where this library is not.
1---2name: tracing-root-causes3description: Owns debugging end to end — reproduce, isolate, hypothesize, disconfirm, fix — with competing hypotheses, evidence ranked by strength, active disconfirmation, and a fix at the source rather than the symptom. Use for any bug, test failure, crash, regression, flaky or intermittent failure, performance problem, build failure, or unexpected behavior, BEFORE proposing or applying a fix; and for explaining why something happened (production incidents, surprising benchmark results) when no fix is on the table yet. Especially when an "obvious culprit" is tempting, when a previous fix did not work, or when time pressure makes guessing attractive. Supersedes superpowers:systematic-debugging as the house debugging skill.4---56# Tracing root causes78<!-- Methodology distilled from OMC's tracer agent (MIT), 2026-07-30.9 Provenance: Context-Engineering repo, docs/adrs/ADR-002-omc-salvage.md.10 Absorbed superpowers' systematic-debugging (v6.3.0), 2026-08-19: the11 phased spine, the iron law, the rationalization tables, and four12 techniques (references/techniques.md). MAT-46.13 Phase 3.4's "ask for help" beat, held back by MAT-46 D8, carried14 2026-08-19 as bounded stall-escalation. MAT-93.15 Sections `### 2. Isolate`, `### 5. Fix`,16 `## Three strikes → question the architecture`,17 `## When the cause really is environmental`, and `## Rationalizations`18 are derived from superpowers' systematic-debugging/SKILL.md (v6.3.0),19 MIT License, Copyright (c) 2025 Jesse Vincent; base and remaining20 sections are original. Classified substantial-in-part (MAT-94);21 evidence: https://github.com/bygama/skills/blob/002ef05fd8b9aceab6f7ed9f14cb8b8fa076441b/work/mat-94-attribution-skills/DECISIONS.md. Full upstream22 permission notice: NOTICE (repo root). -->2324Explain outcomes through evidence, not narrative, and fix causes rather25than symptoms. The failure mode this prevents: jumping from symptom to26favorite explanation, collecting only confirming evidence, then patching27where the error surfaced.2829## The iron law3031```32NO FIX WITHOUT A ROOT CAUSE FIRST33```3435A fix proposed before the cause is known is a guess wearing a diff.36This holds hardest exactly where it feels most expensive — during an37outage, at hour four, with a senior engineer already typing.3839Two things it does **not** forbid:4041- **Mitigation under a live incident.** Stopping the bleeding is42 legitimate — a rollback, a circuit breaker, a feature flag. It is43 named as mitigation, kept reversible, and it does not end the44 investigation or get recorded as the cause.45- **Doing what you were asked.** If the owner has heard the concern and46 still wants their fix, write it, state the assumption it rests on and47 what would falsify it, and move on. State a disagreement once, plainly48 — never twice, and never as silent compliance.4950## The phases5152Run them in order. A phase skipped is a phase paid for later.5354### 1. Reproduce5556- **Read the error completely** — full message, full stack, line57 numbers, codes. It frequently names the answer.58- **Restate exactly what was observed** — which artifact, what behavior,59 when. If you catch yourself rewriting the observation to fit a theory,60 stop.61- **Trigger it reliably.** What are the exact steps? Every time, or one62 run in five? Not reproducible is a finding, not a dead end: it points63 at timing, environment, or shared state.64- **Check what changed** — recent commits, dependency bumps, config and65 environment differences between where it fails and where it doesn't.6667### 2. Isolate6869Narrow the failure to one component before explaining it.7071- **Instrument the boundaries.** In a multi-component system (CI → build72 → sign, API → service → database), log what enters and what leaves73 each boundary, run once, and read which hop breaks. Evidence about74 *where* beats speculation about *why*.75- **Compare against something that works.** Find the nearest working76 case and list every difference, however small. "That can't matter" is77 a hypothesis, not an observation.78- **Check what it depends on** — the services, config, environment, and79 assumptions the broken path needs to work at all. A missing or changed80 dependency looks exactly like broken logic from the inside.81- **Trace backward to the origin** — see82 [references/techniques.md](references/techniques.md) for backward83 tracing, instrumenting a dangerous operation, and bisecting a test84 suite to find which test dirties the tree.8586### 3. Hypothesize8788- **Compete the explanations.** Hold ≥2 from deliberately different89 frames: code path, config/environment, measurement artifact, external90 dependency, timing, shared state. "The measurement is wrong" is always91 a candidate.92- **Rank evidence by strength.** Strongest to weakest: controlled repro93 / discriminating experiment → primary artifact with tight provenance94 (timestamped logs, git history, file:line behavior) → independent95 sources converging → single-source inference that fits →96 circumstantial (naming, temporal proximity, stack position, "this same97 fix worked on another service") → intuition, seniority, confidence.98 When tiers conflict the higher tier wins; never treat support as flat.99- **Name what you don't understand.** "I don't know how X works yet" is a100 finding, not a confession — say it, then go read X completely. A101 hypothesis resting on an unread component is a guess about that102 component, and a confident verdict about code nobody has read is the103 most expensive kind of wrong.104105### 4. Disconfirm106107- **Ask the two questions** of each serious hypothesis: "what should we108 observe if this were true — do we?" and "what observation would be109 hard to explain if this were true?" A hypothesis that survives only110 because nobody looked for counter-evidence keeps LOW confidence.111- **Run a rebuttal round.** Let the strongest alternative challenge the112 leader with its best contrary evidence before you conclude. Down-rank113 explanations that need fresh unverified assumptions to survive, and114 don't merge hypotheses that merely sound alike (fake convergence).115- **Test minimally.** One variable, the smallest change that116 discriminates. A bigger timeout after a failed timeout is not a new117 hypothesis — it is the same one, retried louder.118- **Name the critical unknown** — the single missing fact behind most of119 the remaining uncertainty — and the ONE probe that best separates the120 top hypotheses. Prefer probes that discriminate over probes that121 gather more of the same support, and pick the cheapest one that still122 discriminates — under time pressure that is often minutes of reading123 the actual implementation, not the full investigation someone is124 refusing to fund.125126### 5. Fix127128- **Write the failing reproduction first.** Simplest case that fails;129 a test if there's a framework, a script if there isn't. It proves the130 cause and proves the fix.131- **Fix at the source**, not where the error surfaced. One change, one132 concern — no bundled refactor, no "while I'm here".133- **Then make it impossible.** Add validation at the layers the bad134 value crossed — entry, business logic, environment guard,135 instrumentation ([references/techniques.md](references/techniques.md)136 — defense in depth, and condition-based waiting when the cause was137 timing).138- **Verify, then hand off.** Confirm the reproduction now passes and139 nothing else broke — then stop; see *Where this ends*.140141## Three strikes → question the architecture142143Count fix attempts. At three failures, the problem is no longer the144hypothesis:145146- Each fix reveals a new problem somewhere else.147- Each fix needs "just a bit of refactoring" to land.148- The same symptom keeps returning in a new costume.149150Stop. Say plainly that this looks structural, name the pattern you think151is wrong, and get a decision before attempt four. This is not a failed152hypothesis — it is a wrong architecture, and more fixes make it worse.153154## When the investigation stalls155156Reachable evidence is spent and the phase-4 critical unknown is a fact157this seat cannot produce — access it lacks, knowledge a human holds, a158decision that is the owner's. That is a stall, and its one honest exit159is to ask. Never a silent guess, never a silent stop: a deadline bounds160which probes you can afford, not whether you report.161162- **Earn the ask.** An affordable discriminating probe still on the163 table means run it, not ask — minutes of reading the implementation164 outrun waiting for an answer. Escalate when the next probe is one165 you cannot run.166- **Name the recipient** — the owner, or the parent that dispatched167 you. "Owner: someone else", written inside a document you then168 submit, is an assignment, not a question.169- **Use a channel that waits** — a blocking ask upward, an interactive170 question in a live session. A file read after the lane closes is a171 record, not a channel.172- **Carry the evidence; it is the price of asking.** Hypotheses tried173 and the observation that disconfirmed each, the exact point of the174 stall, the ONE fact you need, and the probe that runs the moment it175 comes back. A bare "I'm stuck" hands the answerer your investigation176 to redo.177178## When the cause really is environmental179180Sometimes the honest verdict is timing, an external dependency, or a181platform difference, with no defect to fix. That verdict is *earned*,182not reached by running out of patience — most "no root cause" is183incomplete investigation. When the trace genuinely lands there:1841851. **Record what was ruled out**, and how. The next person starts from186 your shortlist instead of from zero.1872. **Handle it deliberately** — a bounded retry, a timeout, a clear188 error message. Deliberate handling is a design decision with a189 rationale; a swallowed error is not.1903. **Add the monitoring** that would make the next occurrence legible,191 because there will be a next occurrence.192193## Rationalizations194195| Thought | Reality |196|---|---|197| "Emergency — no time for process" | Systematic is FASTER than guess-and-check thrashing. The process is the short path out, not a tax on the outage. |198| "It's simple, it doesn't need this" | Simple bugs have causes too, and the process is quick on them. |199| "Quick fix now, investigate after" | The first fix sets the pattern, and "after" rarely arrives. |200| "Just try it and see if it works" | A change that fixes a symptom you don't understand hides the cause. |201| "It's probably X, let me fix that" | Seeing a symptom is not understanding a cause. |202| "This same fix worked last week elsewhere" | A pattern match on a different system is circumstantial evidence about this one. |203| "It broke right after the deploy" | Temporal proximity is bottom-tier evidence. Correlate with changed code paths and rollout timing before believing it. |204| "The senior engineer is sure" | Experience raises a prior; it is not an observation. Ask what would show it. |205| "One more attempt" (after 2+) | Three failures is an architecture signal. Stop and say so. |206| "Four hours in — I can't waste them" | Sunk cost. Those hours are spent either way; only the next hour is a choice. |207| "Bigger timeout, then ship it" | A passing sleep is a race CI will lose. Wait on the condition. |208| "Multiple fixes at once saves time" | You cannot tell which one worked, and you added new bugs. |209| "The reference is long, I'll adapt it" | Partial understanding guarantees bugs. Read it completely. |210| "No root cause — it's just flaky" | 95% of "no root cause" is incomplete investigation. Prove environmental before accepting it. |211212Redirection from a human — *"is that not happening?"*, *"stop213guessing"*, *"we're stuck?"* — means the same thing: return to phase 1.214215## Output shape216217Ranked hypothesis table (confidence + evidence strength + why it218survives), evidence for AND against each, current best explanation219(explicitly provisional when evidence is incomplete), critical unknown,220discriminating probe. When a fix follows, the reproduction, the change,221and what it means if the change didn't help.222223Blocked by missing evidence? The ranked shortlist plus the probe IS the224deliverable, not a failure — and it is delivered to someone, not filed;225see *When the investigation stalls*.226227## Where this ends228229This skill investigates and fixes. It does not certify.230231- **Evidence lands in the lane's `PROGRESS.md`** — the reproduction, the232 ranked hypotheses, the probe results, the change. Not a scratch233 debugging log, not the chat alone.234- **`work-verify` owns the completion gate.** Hand off there. "The test235 passes now" is a result to be verified, never a verdict.236- **`work-handoff` closes the lane.** This skill never declares work237 done, fixed, or shippable on its own authority.238239## Judgment notes240241- Investigation only? Stop after phase 4 and deliver the trace. Asked to242 fix as well? Finish the trace first, then fix — the phases are the243 order, not a menu.244- Framing pressure ("confirm it was the deploy so we can roll back") is245 a request for a conclusion, not for analysis. Give the analysis; if it246 supports the framing, say so with the evidence.247- This skill supersedes `superpowers:systematic-debugging`, whose248 machinery it absorbed. Superpowers remains installed as the fallback249 where this library is not.