From Symptom to Root Cause
The diagnostic chain — Symptom → Signal → Measurement → Hypothesis → Evidence → Root Cause → Change → Validation → Regression Check — and the discipline that makes it work: write the hypothesis down before you look, so you can be wrong out loud instead of quietly.
Frame the diagnosis
Performance work starts from a symptom and a signal — never from a resource dashboard.
The chain
A symptom is what someone experiences: checkout feels slow, the export never finishes, the mobile app times out. A signal is the telemetry that corresponds to it. A measurement is a specific reading of that signal — a number, a percentile, a window. Only then does a hypothesis become possible, and a hypothesis is a claim about *mechanism*: "requests are queueing for database connections because the pool is smaller than the concurrency".
Evidence is the measurement that discriminates between hypotheses. This is the step most investigations skip: they look for data consistent with their theory rather than data that would rule it out. If the pool-saturation hypothesis is right, wait-time-for-connection should be high while database CPU stays low. If database CPU is also pegged, the hypothesis is wrong and you have learned something in one reading.
Root cause is the mechanism you can explain end to end without hand-waving. Change follows. Validation is the same measurement from step three, taken again. Regression check is the guard that stops the same failure returning silently in three months. An investigation that stops at "we restarted it and it went away" has completed none of the last three steps.
Write the hypothesis down before you look
The single highest-leverage habit in incident debugging costs thirty seconds: before opening the next dashboard, write down what you expect to see and what it would mean. Not because writing is magic, but because it forces the hypothesis to be falsifiable and it makes you notice when you are pattern-matching instead of reasoning.
Without it, confirmation bias runs unopposed. Every dashboard has some line that is moving; an investigator with an unstated theory will find one that fits. With the expectation written first, "database CPU is at 30%" is a *refutation* of the database theory rather than an ambiguous data point that gets quietly reinterpreted.
This also fixes the handoff problem. An incident that changes hands at shift boundary is a disaster when the state is "we looked at some things". It is manageable when the state is a numbered list of hypotheses with each one marked confirmed, refuted, or untested, and the next measurement named.
114:12 "checkout is slow, looking into it"214:15 [screenshot of CPU dashboard]314:19 "db cpu looks kinda high?"414:24 [screenshot of a different dashboard]514:31 "might be the deploy"614:38 "restarting the payment workers"714:47 "seems better now?"8 9# What do we currently believe? Unknown.10# What would prove us wrong? Never stated.11# Did the restart fix it, or did traffic drop? Unanswerable.12# Handoff at 15:00 starts from zero.114:12 SYMPTOM checkout p99 240ms -> 1.8s since ~14:03. Traffic flat.214:14 H1 Payment provider degraded.3 Predicts: payment span p99 up, our CPU flat.4 CHECK: trace breakdown by span.514:17 H1 CONFIRMED payment span p99 1.6s (was 90ms). Our CPU 22%.614:18 H2 Provider-side, or our new retry loop in v2.4?7 Predicts (retry loop): outbound payment RPS up ~3x.8 CHECK: outbound request rate to provider.914:21 H2 CONFIRMED outbound RPS 3.1x baseline since 14:03 deploy.1014:23 ROOT CAUSE v2.4 retries on 200-with-pending, tripling load.1114:26 CHANGE disable retry flag.1214:31 VALIDATION checkout p99 back to 260ms at comparable traffic.1314:35 REGRESSION alert on outbound-provider RPS ratio; load test case.The second log is not longer because the engineer typed more — it is shorter per step. Each entry names a belief and the measurement that tests it, so at any moment the current state is legible, the handoff is trivial, and "did the change work?" has an answer rather than a vibe.
Knowing when to stop
Two failure modes bracket this process. Stopping too early gives you a mitigation mistaken for a root cause: the restart worked, the symptom is gone, and the mechanism is still there waiting. Stopping too late means chasing an interesting mechanism past the point of usefulness while the incident is still burning.
The practical split is mitigate first, diagnose fully second — but only if the mitigation is recorded as a mitigation. A restart that clears a memory leak buys time; it is not the fix, and the incident should not be closed on it (see Memory Leaks: Growth That Does Not Come Back). Writing "MITIGATED, root cause unknown" is a genuinely different statement from "RESOLVED", and the distinction is what stops the same page firing next week.
The stopping rule for the diagnosis itself: you can explain the causal chain from the change to the symptom, every link is supported by a measurement, and you can predict what *else* that mechanism would cause — and then confirm it. That last part is the strongest available check. If the theory is "the retry loop tripled outbound load", the theory also predicts elevated provider error rates and a specific pattern in retry-attempt counters. Checking a prediction the theory did not need to make is how you catch a plausible-but-wrong root cause.
| State | What is true | What is not yet true | Right next move |
|---|---|---|---|
| Symptom confirmed | A measurement shows the problem is real and bounded in time | The layer is unknown | Get a breakdown by layer |
| Layer located | One component accounts for the time | The mechanism inside it is unknown | USE readings on that component |
| Mitigated | Users are no longer affected | The mechanism still exists | Keep the incident open; diagnose |
| Root cause found | A supported causal chain explains the symptom | Nothing prevents recurrence | Ship the fix, then the guard |
| Validated | The metric moved at comparable traffic | A future change could undo it silently | Add the alert / benchmark |
Key points
- Symptom → Signal → Measurement → Hypothesis → Evidence → Root Cause → Change → Validation → Regression Check.
- Write the hypothesis and its falsifying measurement down *before* opening the dashboard; confirmation bias is otherwise unopposed.
- Evidence means a reading that discriminates between hypotheses, not another reading consistent with your favourite one.
- "Mitigated" and "resolved" are different states — recording a restart as a fix guarantees the page returns.
- The strongest check on a root cause is a prediction the theory did not need to make, confirmed afterwards.
Follow the diagnosis
The causal chain, hop by hop — and the readings that invite the wrong conclusion.
- 1Symptom → investigator: "checkout is slow" arrives with no percentile, window or scope.
- 2Investigator → dashboards: panels are opened in sequence without a stated expectation, so every moving line looks like a candidate.
- 3Investigator → theory: an early plausible theory attracts confirming data and is never given a chance to fail.
- 4Change → symptom: a mitigation coincides with a traffic dip; the symptom clears and the mechanism survives untouched.
- 5Next incident → team: the same failure recurs and the previous investigation left no record of what was ruled out.
- • "The symptom went away after we restarted, so the restart fixed it." Post hoc is not propter hoc; leaks, caches and traffic cycles all produce this pattern (see Correlation Is Not the Root Cause).
- • "This dashboard line is elevated, so that is the cause." Under load, many lines move together. Elevated is not causal.
- • "We found a bug, so we found the root cause." You found *a* bug. Whether it explains the measured symptom is a separate question that needs a measurement.
- • "The theory explains everything we have seen." A theory that explains everything and forbids nothing is not testable — ask what it predicts that has not been checked.
Measure, fix, validate
An optimization is not finished until the metric that motivated it has moved.
- • For each hypothesis, name the single reading that would refute it, and take that reading before taking any other.
- • Bound the symptom in time first: when did the metric change, and what is the pre-change baseline?
- • Check whether traffic changed alongside latency — a load-driven slowdown and a code-driven slowdown look identical on a latency chart alone.
- • Keep a running written state of hypotheses: confirmed, refuted, untested.
- • Adopt a written investigation log: symptom, numbered hypotheses, predicted readings, actual readings, verdicts.
- • Take the discriminating measurement first, before any confirming one.
- • Separate mitigation from resolution explicitly in incident state, so a buying-time action never closes the incident.
- • Confirm one prediction the root-cause theory did not need to make before declaring it.
- • Carry the log into the postmortem so what was ruled out is preserved, not just what was found.
- • The metric that defined the symptom returns to baseline at comparable traffic — not merely at a quieter hour.
- • The mechanism explanation survives being written down: each link in the chain points at a specific reading.
- • A colleague who was not in the incident can read the log and reach the same conclusion without re-deriving it.
- • Writing hypotheses down costs minutes during an incident and feels like overhead exactly when pressure is highest.
- • Discriminating measurements are sometimes harder to get than confirming ones, so discipline can slow the first hour.
- • Keeping incidents open after mitigation is organizationally unpopular; the alternative is silent recurrence.
- • Every confirmed root cause produces one guard: an alert, an SLO burn-rate rule, a CI benchmark or a load-test case (see Alerts Worth Waking Someone For).
- • Track "recurrence of a previously diagnosed incident" as its own metric — it measures whether regression checks are real.
- • Keep refuted hypotheses in the postmortem; the next investigator saves the time you already spent.
Accuracy
Performance numbers are conditional. These are the conditions.
- ILLUSTRATIVEThe two incident logs are constructed to contrast method, not transcribed from a real incident. The numbers exist to make the reasoning concrete.
- ENVIRONMENT-SPECIFICHow much process is appropriate scales with blast radius. A two-person team debugging a staging issue does not need a formal hypothesis log; a payments incident does.