← Back to Autonomy

Diagnostics · Evidence · Method

Root-Cause Analysis Under Uncertain, Heterogeneous Evidence

A trouble code, a pile of telemetry, a few thousand lines of C, and a folder of customer complaints — none fully trustworthy. How to weigh them into one defensible cause.

Abstract

The worked RCA cases assume clean data. Real investigations begin with a heap of evidence of unequal trust: a DTC and its boilerplate description, ECU source code, a measurement log of uncertain provenance, dealer and customer symptom reports in plain English, and a maintenance and repair history that is part signal and part red herring. This monograph is the procedure for turning that heap into a root cause with a mechanism. The organizing principle is grade before you fuse: know what each source can and cannot establish before you let it move your belief. Eight steps follow — provenance grading, temporal-and-cohort anchoring, abductive framing, the impostor test, the physics-and-code referee, reliability-weighted Bayesian fusion, acceptance on convergence, and reporting with residual uncertainty.

§ 01 — The Pile

An investigation is a heap, not a dataset

The textbook diagram of fault diagnosis starts with a tidy matrix of measurements. The bay does not.

What actually lands on the analyst's desk is a heap of things that disagree. A diagnostic trouble code has fired — say a cell-imbalance code — with a one-line description copied from a standard catalog that was written before this vehicle program existed. There are measurement logs, but you are not sure which firmware they came from or whether the sensor that produced them was itself in spec. There are a few thousand lines of the responsible ECU's C source. There is a folder of dealer write-ups and customer complaints — "loses range in the cold," "clunk on startup," "dash light comes and goes" — vivid, human, and imprecise. And there is a maintenance and repair history showing which of the affected vehicles were touched, when, and for what.

Each of these is evidence. None of them is true in the way a physics equation is true. The DTC can fire for a cause it does not name. The customer can describe a symptom that has nothing to do with the failure. The repair record can show an intervention that caused the problem rather than addressing it. The measurement can be an artifact of the instrument. The code shows what the software can do, not what it did.

So the first thing to internalize is that the units of this investigation are not numbers — they are claims of varying reliability, and the job is to combine claims, not average numbers.

§ 02 — The Trap

Why the obvious moves fail

There are three intuitive ways to handle a pile of mixed evidence, and all three are wrong in a way worth naming.

Pour it all in and average. Treat every input as a vote of equal weight and go with the majority. This silently assumes the sources are equally reliable and mutually independent — and they are neither. It lets a hundred low-information complaints outvote one decisive measurement.

Trust the loudest. Anchor on the most vivid or most recent input — usually the customer's words or the DTC's description — and reason outward from it. This is availability, not inference. The DTC's prose in particular is a magnet for this error: it reads like a diagnosis.

Trust only the hard data. Discard the soft inputs entirely and reason from telemetry alone. Cleaner, but it throws away the testimony and history that carry most of the information about when it started and who it happened to — exactly the structure that later separates cause from coincidence.

The principle

The fix is one rule applied early: grade before you fuse. Establish what each source can and cannot tell you — and how much to trust it — before you let any of it move your belief about the cause. Everything in this monograph is an elaboration of that sentence.

§ 03 — Provenance Grading

Grade every input before you use it

Provenance grading is the step the case studies skip because their data is clean. In the field it is the most important step.

For each input family, settle three things in writing: what it can establish (the claim it is competent to support), what it cannot (the claim it is routinely mistaken for supporting), and a reliability weight — high, medium, or low — that will scale its influence in fusion. The point of writing it down is that it disciplines you against the §02 traps when the pressure to conclude rises.

Table 1 — Provenance grades for the six input families
SourceEstablishesDoes not establishTrust
DTC — status bits, freeze-frame, set-conditions That a monitored quantity crossed a calibrated threshold, and the conditions when it did The cause. A code is the ECU's hypothesis, scoped to what it can sense HIGH
DTC — text description A rough family of fault, and a search term Anything specific to this program; the prose is often generic catalog boilerplate LOW
ECU C source What the software can do — the reachable logic and its guards That the suspect path executed; reachability is not occurrence MED·HI
Telemetry / measurements Physical state over time — the signatures hypotheses must match Truth in the presence of sensor drift, bias, or wrong-firmware provenance MED·HI
Dealer / customer testimony That something was noticed, and roughly when — high recall What the cause is — low precision; descriptions map to many faults LOW
Maintenance / repair history What was changed and when — a real intervention timeline Direction of causation; a repair may be cause, fix, or coincidence MED
Reading the trust column: high-trust sources are competent to confirm a mechanism; low-trust sources are competent to propose one and to bound its timing. The single most common field error is reading the DTC's text row as if it were the DTC's status-bits row.

Two grades deserve emphasis because they are routinely misread. The DTC splits into two rows: its machine-set status bits and freeze-frame are high-trust, while its human-readable description is low-trust. And the C source is high-trust for capability but silent on occurrence — it tells you a balancing routine can mis-trigger, never that it did on these cars. Keeping those distinctions sharp is most of the discipline.

§ 04 — Anchor

One timeline, one cohort

Most "clues" are not yet evidence. They become evidence when you place them in time and in a population.

Build a single timeline per affected vehicle and drop everything onto it: the moment the code set, the freeze-frame conditions, the onset date implied by each complaint, every maintenance and repair event, and the windows where measurements went out of band. Disagreements that looked like noise often resolve into structure here — a complaint that predates the code set by months means the code is a late symptom, not the origin.

Then define the cohort precisely: which vehicles are affected, which are not, and what distinguishes the two sets. This contrast is not a formality. It is the asset that later kills impostor explanations, because a true cause must explain not just that the failure happened but why it selected exactly this subpopulation and spared the rest. A hypothesis that cannot account for the boundary of the affected set is incomplete no matter how well it fits the failed cars.

Why this comes before interpretation

Interpreting a single input in isolation — "the code means X" — invites the §02 traps. Interpreting it against the timeline and cohort constrains it. The same cell-imbalance code means very different things if it sets only on cars built in one plant, or only after a particular OTA update, than if it sets uniformly across the fleet.

§ 05 — Abduction

Frame hypotheses as causal chains

Diagnosis is abduction — inference to the best explanation — not deduction from a code to a cause.

Enumerate candidate explanations honestly, and write each one not as a correlation but as a causal chain with three links:

root cause  →  mechanism  →  observable signature

The discipline this enforces is decisive: a hypothesis that predicts no distinguishing signature cannot be tested and does not belong on the list. "It's a firmware problem" is not a hypothesis. "A cell-balancing routine over-discharges the weakest cell during cold fast-charge (mechanism), which appears as elevated internal-resistance rise concentrated in cold-climate cars on firmware ≥ v4.2 (signature)" is — because it tells you exactly what to go measure and which cohort boundary it must reproduce.

Generate several such chains, including at least one boring one (normal wear, sensor artifact). The boring hypotheses are there to be the null the interesting ones must beat.

§ 06 — The Impostor

Kill the convincing correlation first

The most persuasive feature in the room is the prime suspect for being a fake.

This is the central hazard documented in the battery case: a feature that correlates beautifully with the failure but causes nothing, because it and the failure are both downstream of the true cause. Left unchallenged it ends investigations early and wrong — everyone in the room believes it, so no one tests it.

The gate is partial correlation: condition on the candidate true cause and ask whether the seductive feature still predicts the failure. If the association collapses once you control for the upstream variable, the feature was a co-effect — an impostor — and it leaves the suspect list. Run this before the expensive confirmation work of §07, because it is cheap and it routinely deletes the hypothesis you were about to spend a week proving.

Impostor — co-effect

correlation survives marginally · collapses under partial correlation

Drops out once you condition on the upstream cause. Convincing precisely because it shares the cause's footprint.

Candidate cause — survives conditioning

association persists after controlling for confounders

Earns the right to the physics-and-code referee in §07. Necessary, not yet sufficient.

§ 07 — The Referee

Let physics and code confirm the mechanism

A surviving hypothesis is a defendant, not a verdict. Confirmation comes from an independent referee, not from more of the same evidence.

Each surviving causal chain predicts a signature (§05). Confirmation means an independent model regenerates that signature from the proposed cause:

This is where the high-trust sources finally do their work, and why the grading of §03 mattered: low-trust testimony proposed the hypothesis and dated it; high-trust physics and code are what is allowed to confirm it. The referee is also adversarial by design — its job is to falsify the surviving chain, and a chain that survives a real attempt to break it is worth far more than one that merely fit the data it was built from.

Procedureconfirm(chain)

input chain = (cause → mechanism → signature), telemetry T, source S

output CONFIRMED · BROKEN · UNDETERMINED

predict ŝ ← model(cause) # physics or code regenerates the signature

if mechanism is physical:

compare ŝ against signature in T under matched conditions

if mechanism is software:

trace path in S; check reachability AND guard(freeze-frame)

return CONFIRMED if ŝ matches and path executes; else BROKEN / UNDETERMINED

§ 08 — Fusion

Combine by weight, not by vote

Now — and only now — combine the evidence. The combination is reliability-weighted, and it counts independent corroboration only.

Maintain a belief — a posterior — over the competing causal chains. Each piece of evidence updates that posterior in proportion to two things: its likelihood ratio (how much more probable this evidence is if hypothesis H is true than if it is false) and its trust tier from §03 (a low-trust source is allowed only a small nudge; a high-trust confirmation is allowed a large one). In Bayesian terms each datum contributes a weighted log-likelihood-ratio to the running score for each hypothesis.

The rule that does the most work is independence. Ten customer complaints that all trace to the same root cause are one piece of evidence echoed ten times, not ten. Double-counting correlated evidence is how a pile of low-trust testimony stampedes an investigation. Before a datum updates the belief, ask what it is conditionally independent of — and if it shares a source with evidence already counted, discount it.

Figure 1 — Reliability-weighted fusion
EVIDENCE · BY TRUST DTC status bits · freeze-frame high trust — large weight telemetry signature · code path high trust — confirmers maintenance / repair history medium — watch confounds DTC text · customer reports low — propose & date only independence gate de-duplicate correlated echoes POSTERIOR OVER CHAINS H1 H2 H3 (impostor — fading)
The flow: sources enter scaled by trust, pass an independence gate that collapses correlated echoes into single updates, and shift a posterior over causal chains. High-trust confirmers move it hardest; the impostor (H3) decays as conditioning removes its support.

You do not need a full probabilistic model to use this. The discipline is what matters: weight by trust, update by likelihood ratio, never double-count. A scored table of hypotheses × evidence, with each cell marked for-or-against and the row trust noted, captures ninety percent of the value on a whiteboard.

§ 09 — Convergence

Accept on triangulation, not on a single gun

The acceptance test is not "do I have a smoking gun?" It is "does one mechanism explain everything at once?"

A root cause is accepted when a single causal chain simultaneously satisfies every independent line of evidence:

Accept the chain only if it explains all four at once
— the DTC pattern
the code sets when and where the mechanism predicts
— the measurement signature
telemetry matches the model-regenerated signature
— the executable path
the C path is reachable and its guards are met
— the cohort boundary
it explains exactly who was affected and who was spared
— and is not contradicted by
testimony & repair history (consistency, not proof)

Convergence of independent evidence types is the standard because it is hard to fake. A story can be tuned to fit the telemetry it was built from; it is far harder for the same story to also predict the cohort boundary and survive the code trace and not contradict the complaint timeline. When one chain does all of that and its rivals do not, you have a root cause. When two chains both survive, you do not yet — and the honest output is two hypotheses plus the discriminating measurement that would separate them.

§ 10 — Report

State the mechanism, its confidence, and its kill-switch

The deliverable is not a label. It is a chain, a confidence, and the one test that would still overturn it.

Write the verdict as the full causal chain — root cause → mechanism → signature — not as "DTC P0ABC, replace pack." Attach a confidence that reflects the weakest link, not the strongest. And state explicitly the single disconfirming test: the observation that, if it came back the wrong way, would break the chain. A conclusion you cannot say how to falsify is a conclusion you have not finished testing.

Root cause

the confirmed chain

Cell-balancing routine over-discharges the weakest cell during cold fast-charge on firmware ≥ v4.2 → accelerated internal-resistance rise → the SOH divergence and the imbalance DTC, concentrated in cold-climate cars.

Confidence & residual uncertainty

honest about the weakest link

High on mechanism (code path traced, physics reproduces signature); medium on population bound (cold-climate proxy is coarse). Stated, not buried.

Disconfirming test

the kill-switch

If affected cars on v4.2 that never cold-fast-charged show the same resistance rise, the mechanism is wrong. Run it before committing the fix.

From here the handoff to prognostics is clean: a confirmed mechanism is exactly what a degradation model needs to forecast remaining useful life with and without the intervention. Diagnosis answers why; prognosis turns that why into a maintenance decision.

§ 11 — Traps

The failure modes that catch everyone

Each of these is a specific way the procedure above gets short-circuited under deadline pressure.

The testimony cascade

A handful of vivid complaints set the team's hypothesis, and every later input is read in their light. Mitigation: testimony enters at low trust and only proposes and dates (§03); it never confirms.

Double-counting correlated evidence

Ten reports, one cause, counted as ten. The fleet "agrees" because it is echoing a single root cause. Mitigation: the independence gate (§08) collapses correlated echoes into one update.

Reading the DTC's prose as a diagnosis

The description is catalog boilerplate; the information is in the status bits and freeze-frame. Mitigation: the two-row split in Table 1 — trust the machine-set fields, discount the text.

Confirming a path that cannot execute

The suspect C code exists and looks guilty, but its guards are never satisfied in the recorded conditions. Mitigation: §07 demands reachability and guard-satisfaction under the freeze-frame, not mere existence.

Confound from the repair history itself

A prior service action is the actual cause, or masks the onset, yet is read as background. Mitigation: place repairs on the §04 timeline as events that can themselves be causes, and check causation direction before trusting them.

§ 12 — The Procedure

The whole method on one page

Run any investigation against this. Each rung is a step you can refuse to skip.

1
grade

Provenance-grade every input

For each source, write what it can establish, what it cannot, and a trust tier. Split the DTC into status-bits (high) and text (low).

2
anchor

One timeline, one cohort

Place every code-set, complaint, repair, and measurement excursion on a per-vehicle timeline. Define affected vs. spared precisely.

3
frame

Hypotheses as causal chains

Write each candidate as cause → mechanism → signature. Discard any that predicts no distinguishing signature. Include a boring null.

4
break

Kill the impostor

Partial-correlation gate: condition on the candidate cause; drop features whose association collapses. Do this before expensive confirmation.

5
referee

Physics and code confirm

The model must regenerate the signature; the code path must be reachable and guard-satisfied under the freeze-frame. The referee tries to falsify.

6
fuse

Weight, don't vote

Update belief by trust × likelihood ratio. Enforce independence — correlated echoes count once.

7
converge

Accept on triangulation

One chain must explain the DTC pattern, the signature, the executable path, and the cohort boundary at once — uncontradicted by testimony.

8
report

Chain · confidence · kill-switch

State the full chain, a confidence set by the weakest link, and the single disconfirming test. Then hand off to prognosis.

The one-sentence version

Grade before you fuse; let the weak evidence propose and the strong evidence confirm; accept only the one mechanism that explains everything at once — and say what would prove you wrong.

Part II — Worked Example

The Method in Action — A Battery Case, End to End

One fleet, one anomaly, and the full pile of mockup evidence. We run all eight steps and let the figures carry the argument. Every input below is fabricated for illustration, but each is shaped like the real artifact it stands in for — and the data hides a known ground truth so the analysis can grade its own detective work.

§ 13 — The Procedure, Drawn

The whole method as one flowchart

Before the case, the procedure as a single diagram — the path every piece of evidence takes from the pile to the verdict, including the three gates where hypotheses die.

Figure 2 — Master procedure flowchart
THE EVIDENCE PILE — DTC · C source · telemetry · testimony · history 1 GRADE · provenance + trust 2 ANCHOR · timeline + cohort 3 FRAME · causal chains 4 IMPOSTOR GATE · partial corr 5 REFEREE GATE · physics + code 6 FUSE · weight × likelihood 7 CONVERGE GATE · all evidence 8 REPORT · chain + conf + test → PROGNOSIS / RUL co-effect → drop (§06) broken → re-frame ↺ (§07) 2 survive → discriminate
Three gates, not one funnel. Steps 1–3 prepare the evidence and the hypothesis set. The impostor gate (4) drops co-effects; the referee gate (5) sends unconfirmed chains back to be re-framed; the convergence gate (7) refuses to commit when two chains still survive. Only a chain that clears all three reaches the verdict.

The same procedure as an algorithm

Drawn as a flowchart it is a path; written as pseudocode it is a loop with guards. The two gates that can reject — the referee and convergence — are why this is iterative, not a straight line.

Algorithm 1root_cause(E)

input E = { DTC, C-source, telemetry, testimony, history }

output a confirmed causal chain, or two chains + a discriminating test

G grade(E) # §03 provenance + trust tier per source

T anchor(G) # §04 one timeline, one cohort

H frame(T) # §05 chains: cause → mechanism → signature

H { h ∈ H : partial_corr_survives(h, T) } # §06 drop impostors

for h in H:

h.state confirm(h, telemetry, C-source) # §07 physics + code referee

if h.state = BROKEN: continue # falsified → re-frame

H { h ∈ H : h.state = CONFIRMED }

P fuse(H, G) # §08 Σ trust(e)·logLR(e|h), independence-gated

if converges(argmax P): # §09 explains DTC ∧ signature ∧ code ∧ cohort

return report(argmax P) # §10 chain · confidence · kill-switch

else:

return discriminating_test(top2(P))

§ 14 — The Evidence

The pile, coloured by trust

Six source classes land on the desk. Step one (§03) is to grade them — before reading a single value for meaning.

Figure 3 — Evidence intake and grading
DTC · status bits + freeze-frame HIGH DTC · text description LOW ECU C source HIGH·cap Telemetry / measurements MED·HI Maintenance / repair history MED Dealer / customer testimony LOW STEP 1 · GRADE → trust-weighted pile
The split that matters most: the DTC enters as two sources — its machine-set fields (HIGH) and its catalog prose (LOW). The C source is HIGH for capability only. Testimony enters LOW: it will be allowed to propose and to date, never to confirm.

Input 1 — the DTC & freeze-frame  bits: HIGH text: LOW

# dtc_freeze_frame.json  (vehicle EV-201)
dtc:    P0A80-0F  "Replace Hybrid/EV Battery Pack"   # generic boilerplate — LOW
        B2C1-17   "Cell voltage imbalance, pack 1"  # mfr-specific  — MEDIUM
status: 0x2F  # testFailed=1 confirmedDTC=1 warningIndicator=1
freeze_frame:
   odometer        38420 km
   pack_temp       -8.4 °C        <-- cold
   soc             18 %
   charge_mode     DC_FAST_CHARGE     <-- charging hard
   pack_current    -142 A
   balancing_state ACTIVE             <-- balancing while cold-charging
   fw_version      4.2.1

Ignore the P0A80 prose; it is a parts-replacement banner. The freeze-frame is the gold: the code set during DC fast-charge, at −8.4 °C, with cell balancing ACTIVE. Three high-trust facts that, together, already point a finger — balancing is not supposed to be running in those conditions.

Input 2 — the ECU C source  HIGH for capability, silent on occurrence

/* bms_balance.c — passive cell-balancing scheduler (fw 4.2.1) */
void balance_step(Pack *p) {
    int16_t t = p->temp_dC;            /* pack temp, signed deci-°C */
    if (t > BAL_TMAX_dC) return;       /* hot guard: OK */
    /* BUG (fw 4.2.0): negative temp cast to unsigned wraps high, */
    /* so the cold guard never fires below 0 °C.               */
    if ((uint16_t)t < BAL_TMIN_dC)     /* -84 -> 65452, NOT < 50 => no skip */
        return;
    for (int i = 0; i < p->n; i++)
        if (p->cell_mV[i] - p->min_mV > BAL_THRESH_mV)
            bleed_on(i);               /* drains the weak cell cold */
}

The suspect path exists: a signed/unsigned cast makes the cold cut-off unreachable, so balancing can run below freezing. But the code only proves the bug is possible. Whether it fired on these cars is a §07 question — answered by checking its guards against the freeze-frame.

Input 3 — fleet telemetry  MED·HIGH

VehiclefwClimateCold FCIR rise %/yrGroup
EV-2014.2.1cold449.6affected
EV-0174.2.1cold479.2affected
EV-0664.2.1cold397.9affected
EV-1294.1.0cold412.4ok
EV-1454.1.0cold462.6ok
EV-1034.2.1temperate32.1ok
EV-1184.2.1temperate22.3ok

Read the rows against each other, not in isolation. The affected cars share fw ≥ 4.2 × cold × many cold fast-charges. Crucially, EV-129 and EV-145 fast-charge in the cold just as hard but sit on fw 4.1 — and they are fine. Same usage, different firmware, different outcome.

Input 4 — dealer & customer reports  LOW

Verbatim — propose & date only

2026-01-09 · EV-017 — “Range dropped a lot this winter and it charges slower at the fast charger than in the fall.”

2026-02-11 · EV-201 — “Battery warning light came on right after a cold-morning fast charge.”

2026-02-27 · EV-044 — “Loses range when it’s freezing. Better on warm days.”

Imprecise, but the unprompted common thread — cold + fast charge — is a free hypothesis and an onset date. That is exactly what low-trust testimony is for.

Input 5 — maintenance & repair history  MEDIUM

DateEventDetailRelevance
2025-09-02OTAfw 4.1.0 → 4.2.0 (balancing rewrite)suspect change
2025-10-30OTAfw 4.2.0 → 4.2.1 fleet-widetimeline anchor
2025-11-14repair12V auxiliary battery replacedred herring
2026-03-18repairimbalance DTC cleared (recurred)confound watch

History earns its medium trust here: the balancing rewrite at fw 4.2.0 is the suspect change that dates the whole problem, while the 12V battery swap is a red herring — a real repair on an affected car that has nothing to do with the high-voltage pack. Putting both on one timeline keeps them from being confused.

§ 15 — Anchor

One timeline, one cohort

Now drop every dated fact onto a single axis, and plot the cohort. Most of the answer is visible before any modelling.

Figure 4 — The investigation timeline
accelerated IR-rise window (first hard freeze →) SepOctNov DecJanFeb MarAprMay fw 4.2.0(rewrite) fw 4.2.1 OTA IR divergencebegins first complaints DTC sets (EV-201) code recurs
The shape jumps out: the balancing rewrite ships (Sep), the divergence starts with the first hard freeze (Dec) — not with the OTA date and not with any single car’s service visit — and the code and complaints follow mid-winter. A firmware-plus-cold story already fits the calendar; a pure-usage story does not explain the seasonal onset.
Figure 5 — The cohort: cold fast-charges vs. resistance rise
IR rise (%/yr) cold fast-charge count 0510 02555 affected: fw≥4.2 × cold same usage, fw 4.1 → fine affected (fw≥4.2, cold) ok (fw 4.1, cold) ok (fw≥4.2, temperate)
The cohort boundary is two-dimensional. Heavy cold fast-charging alone does not separate the groups — the fw 4.1 cars (slate, bottom-right) charge just as hard and stay healthy. Only firmware × climate isolates the affected set. This figure quietly pre-empts the impostor of §16: usage is shared across healthy and sick cars alike.
§ 16 — Frame & Break

Four chains, and the impostor among them

Write the candidates as causal chains, each with a signature you can go check. Then attack the most convincing one first.

H0 · Calendar + cycle aging null

cause: ordinary degradation → signature: smooth, unimodal, ~2%/yr fleet-wide

The null the others must beat. Contradicted on sight by the bimodal cohort (Fig 5) — aging does not split a fleet in two.

H1 · Cold-balancing firmware bug survives

cause: signed/unsigned cold-guard bug (fw≥4.2.0) → balancing runs cold → weak-cell over-discharge → IR rise

Signature: IR rise concentrated in fw≥4.2 × cold × high cold-FC, with balancing ACTIVE in cold freeze-frames. Matches every figure so far.

H2 · Fast-charging stress impostor?

cause: DC-fast-charge lithium plating → IR rise → signature: IR ∝ total fast-charge count, any fw/climate

The story the whole room believes — “fast charging wears batteries.” It correlates. It is also the prime suspect for being a co-effect.

H3 · Cell-supplier defect drops

cause: bad cell lot → signature: IR rise tracks supplier, not fw/climate

Plausible until you notice affected and healthy cars share the supplier; the split is firmware×climate, not lot. Conditioning removes it.

The partial-correlation gate

H2 is the dangerous one because its correlation is real. The test: does fast-charging still predict IR rise once we condition on the cohort — look only within a single firmware×climate stratum?

Figure 6 — The impostor, broken by conditioning
Marginal — whole fleet IR rise total fast-charge count r = 0.78 Conditioned — within fw 4.1 × cold IR rise fast-charge count (same stratum) r = 0.06
The association evaporates. Across the fleet, fast-charging predicts IR rise (left, r = 0.78) — because the buggy-firmware cold cars happen to fast-charge a lot. Hold firmware and climate fixed (right) and the relationship vanishes (r = 0.06). H2 was a co-effect of the true cause. Impostor dropped.

Two hypotheses are now gone for the price of one cheap test plus one scatter: H2 by conditioning, H3 and H0 by the cohort. Only H1 walks into the referee.

§ 17 — The Referee

Code and physics confirm H1

H1 has earned a hearing. Confirmation is two independent checks: the code path must execute under the recorded conditions, and the physics must regenerate the signature.

Check 1 — trace the C path against the freeze-frame

The freeze-frame recorded pack_temp = −8.4 °C with balancing_state = ACTIVE. Does balance_step() actually run there?

Tracebalance_step @ freeze-frame

given pack_temp = -8.4 °C → t = temp_dC = -84

hot guard t > 450 ? -84 > 450 → false, continue

cold guard (uint16_t)t < 50 ? (uint16_t)(-84) = 65452

65452 < 50 → FALSE → guard does NOT skip

result falls through to bleed loop → balancing RUNS at -8.4 °C

# matches freeze-frame balancing_state = ACTIVE ✓ reachable AND guarded-in

The path is not merely present in the source — it executes in exactly the conditions the high-trust freeze-frame captured. This is the distinction §07 insists on: capability became occurrence the moment the guard was shown to pass under the recorded state.

Check 2 — regenerate the signature

Drive the battery-aging model with the H1 mechanism (extra cold over-discharge cycles on the weakest cell) and compare its predicted IR-rise trajectory against the measured one.

Figure 7 — Model-regenerated signature vs. measurement
internal resistance (norm.) months since fw 4.2.0 H1 model · measured (affected) calendar-aging model · measured (healthy)
The model built from the bug reproduces the data it never saw. Feeding H1’s cold over-discharge into the aging model yields the steep affected curve (rust); plain calendar aging yields the flat healthy curve (teal). Measured points fall on their respective curves. A confirmed mechanism is one an independent model can regenerate — this is that.
§ 18 — Fuse

Score the evidence by trust, not by count

Lay every piece of evidence against every surviving hypothesis, mark for-or-against, and weight the row by its trust tier. The posterior falls out.

Table 2 — Evidence × hypothesis, trust-weighted
Evidence (trust)H0 ageH1 bugH2 fast-chgH3 supplier
Freeze-frame: cold + balancing ACTIVE HI0+ +0
C path executes at −8.4°C HI+ +
Signature match (Fig 7) HI+ +00
Cohort = fw×climate (Fig 5) MED·HI− −+− −
Partial-corr collapse (Fig 6) MED·HI0+− −0
Seasonal onset (Fig 4) MED+00
Complaints: “cold + fast” LOW0++0
12V battery repair LOW0000
Note the discipline: the three complaints are one row, not three (independence — they echo a single cause). The 12V repair scores zero everywhere — a real event with no causal bearing. The high-trust rows do the heavy lifting; the low-trust row only nudges.
Figure 8 — Posterior over hypotheses
H1 · firmware bug 0.86 H3 · supplier 0.08 H2 · fast-charge 0.04 H0 · aging 0.02
After trust-weighted, independence-gated updating, H1 carries the belief. Not because more evidence pointed at it, but because the high-trust, independent evidence did — and the impostor’s support was actively removed.
§ 19 — Converge & Report

One mechanism explains everything — then forecast

H1 is accepted only because a single chain satisfies four independent lines at once, with the testimony consistent and nothing contradicting.

Figure 9 — Convergence on a single cause
DTC freeze-frame: cold + ACTIVE telemetry signature match C path executes at -8.4°C cohort = fw × climate H1 cold-balancing cast bug ROOT CAUSE testimony: consistent (not proof)
Convergence, not a single gun. Four independent channels — each hard to fake on its own — all point at the same mechanism, and the low-trust testimony is consistent with it. A rival chain would have to explain all four simultaneously; none does.

The verdict

Root cause

the confirmed chain

A signed→unsigned cast in the cold balancing guard (introduced fw 4.2.0) lets passive balancing run during cold fast-charge → the weakest cell is repeatedly over-discharged → accelerated internal-resistance rise → the SOH divergence and imbalance DTC, confined to fw ≥ 4.2 × cold-climate vehicles.

Confidence & residual uncertainty

set by the weakest link

High on mechanism (code path traced to the freeze-frame; physics regenerates the signature). Medium on the exact population bound — “cold” is a coarse proxy; the true trigger is cell temperature at charge, which a few cars may hit in mild climates.

Disconfirming test

the kill-switch

Pull fw ≥ 4.2 cold-climate cars that have never cold-fast-charged. H1 predicts they are clean. If they show the same IR rise, the mechanism is wrong — run this before shipping the fix.

Handoff to prognosis

A confirmed mechanism is exactly what a degradation model needs. The same aging model from §17, now trusted, forecasts each affected car’s remaining useful life with and without the OTA patch.

Figure 10 — Prognosis: SOH with and without the fix
SOH (%) months from today 1008570 01224 warranty floor (75%) today no fix → hits warranty floor ~18 mo OTA fix today → reverts to normal aging
Diagnosis becomes a decision. Untreated, affected packs cross the 75% warranty floor in roughly eighteen months; the OTA patch halts the cold over-discharge and returns them to the normal aging slope. The cost of waiting a quarter is now a number, not a worry — which is the whole point of carrying a confirmed mechanism forward into prognostics.
What the worked case demonstrates

Every step earned its keep. Grading kept the DTC prose and the 12V repair from misleading us; anchoring exposed the seasonal onset; framing turned vague worry into testable chains; the impostor gate deleted the fleet’s favourite theory; the referee turned a plausible bug into a confirmed one; fusion let one high-trust fact outweigh ten low-trust echoes; convergence justified commitment; and the report carried a mechanism — not a code — into a maintenance decision.

§ 20 — Practical Notes

Field rules for unequal-trust evidence

The method distilled into habits you can carry into the investigation room.

1
grade first

Write the trust tier before you read the values

For every source, note what it can establish, what it can’t, and how far you trust it — before any number moves your belief. Grading after the fact is how the loudest clue wins.

2
two rows

Split the DTC into machine fields and prose

Trust the status bits and freeze-frame; treat the human-readable description as a search term, not a diagnosis. They deserve opposite trust tiers.

3
anchor

One timeline, one cohort — before interpreting anything

Place every code-set, complaint, repair, and excursion on a single timeline, and define affected vs. spared precisely. Most “clues” only become evidence once anchored in time and population.

4
kill the lead

Name the most convincing correlation and attack it first

The feature everyone believes is the prime suspect for being a co-effect. Run the partial-correlation test on it before you spend a week proving it.

5
referee

Capability is not occurrence

Source code and physics show what can happen. Confirm it did — trace the path under the recorded conditions, or regenerate the measured signature from the cause.

6
weight, don’t count

Independent corroboration beats volume

Ten complaints tracing to one cause are one piece of evidence, not ten. Before a datum updates your belief, ask what it is independent of.

7
don’t average

A clash between two trusted sources is a finding

When high-trust sources disagree, re-audit provenance — a bad sensor, a wrong-firmware log, a mismatch. Resolving the conflict usually is the discovery.

8
ship the chain

Report a mechanism with a kill-switch, and keep the trail

Deliver cause → mechanism → signature, a confidence set by the weakest link, and the single test that would overturn it. Keep the evidence trail auditable — diagnoses get re-litigated.

§ 21 — References & Further Reading

Where these ideas come from

The method braids together abductive reasoning, causal inference, evidence combination, and engineering fault diagnosis. Entry points, grouped by the part of the method they ground.

Abduction — inference to the best explanation

C. S. Peirce, on abduction (Collected Papers). The original account of reasoning from a surprising observation to the hypothesis that would best explain it — the engine of §05.

P. Lipton, Inference to the Best Explanation (2nd ed., 2004). The modern philosophical treatment of how we rank competing explanations.

Correlation, causation & the impostor

J. Pearl, Causality: Models, Reasoning, and Inference (2nd ed., 2009). Confounding, partial correlation, and why a feature can predict an outcome it does not cause — the formal backbone of §06.

H. Reichenbach, The Direction of Time (1956). The common-cause principle: a correlation between two effects of one cause. The impostor, named at its root.

Combining evidence of unequal trust

E. T. Jaynes, Probability Theory: The Logic of Science (2003). Bayesian updating as the calculus of reasoning under uncertainty — the trust-weighted, likelihood-ratio fusion of §08.

G. Shafer, A Mathematical Theory of Evidence (1976). Belief functions and the explicit handling of sources with different, partial reliability.

Model-based & consistency diagnosis

R. Reiter, “A Theory of Diagnosis from First Principles” (1987). Diagnoses as explanations consistent with the observations; the formal notion of a conflict.

J. de Kleer & B. C. Williams, “Diagnosing Multiple Faults” (1987). Candidate generation and reasoning about more than one fault — the discipline behind disciplined hypothesis sets.

Fault diagnosis & prognostics in engineering

R. Isermann, Fault-Diagnosis Systems (2006). Residuals, analytical redundancy, and the sensor/actuator/process fault distinctions underneath the referee step.

M. Blanke, M. Kinnaert, J. Lunze & M. Staroswiecki, Diagnosis and Fault-Tolerant Control (Springer). Structural diagnosability — when measurements can, in principle, separate faults at all.

Measurement, provenance & automotive diagnostics

JCGM / BIPM, Guide to the Expression of Uncertainty in Measurement (GUM). The standard vocabulary for the uncertainty that every measured input carries — the reason telemetry is high-trust but never infallible.

ISO 14229 (UDS) & SAE J1979 (OBD-II). The diagnostic protocols and DTC structure behind §03’s split of the trouble code into machine fields and prose.

Root-cause analysis in practice

K. Ishikawa, Guide to Quality Control. Cause-and-effect (fishbone) analysis — the shop-floor ancestor of structured hypothesis generation.

C. H. Kepner & B. B. Tregoe, The New Rational Manager. Systematic problem analysis: specifying what is and isn’t affected — the cohort discipline of §04.

T. Ohno, Toyota Production System (1988). The “Five Whys” — chasing a symptom back to its mechanism rather than stopping at the first cause.

A note on these references

These are orientation points into large literatures, cited to show the lineage of the method rather than as the source of any single claim here. Titles and years are given so you can find them.

§ — The Series

The Diagnosis Series

Nine connected parts, from one car’s evidence to a fleet campaign and back to prevention. See the full map & reading guide →

1

Root-Cause Analysis Under Uncertain, Heterogeneous Evidence  you are here

Grade, anchor, and fuse messy, unequal-trust clues into one cause.

2

When Is the Evidence Enough?

The sufficiency gate, value of information, and handling conflict.

3

Harder Cases in Diagnosis

Multiple faults, intermittency, and lying sensors.

4

Fleet-Scale Root-Cause Analysis

One code across a population: de-mix, stratify, remediate.

5

Fleet RCA, Made Rigorous

Significance, surveillance, forecasting, closing the loop.

6

Proving Cause with Experiments

Turn observation into proof with staged rollouts.

7

Diagnosis on the Vehicle

Real-time fault detection at the edge, feeding the fleet.

8

The Data Plumbing Behind Fleet Diagnosis

Joining, aligning, and cleaning the data that makes it work.

9

From Root Cause to No Cause

Prevention and the corrective-action loop — engineer it out.