← Back to Autonomy

Diagnostics · Fleet Scale · Method

Fleet-Scale Root-Cause Analysis

When the same trouble code lights up across a whole fleet and the evidence arrives in bulk — how to diagnose a population instead of a single car.

Abstract

A single car gives you one observation; a fleet gives you a distribution — and a hypothesis must now explain not just that the code fired, but how common it is, who it happened to, and when it started spreading. Those stronger constraints make impostors easier to kill, but they hide a trap: the same DTC across a fleet is usually a mixture of several root causes wearing one mask. So the fleet method begins by de-mixing the population, leans on the cohort boundary to name each cause, defends hard against confounding and Simpson’s paradox, aggregates batched evidence in two careful levels, reads the prevalence curve for change-points, and ends not with a fix but with a remediation scope — who gets an over-the-air update, who gets a recall, who gets nothing.

§ 01 — From a Car to a Population

You are explaining a distribution now

The biggest shift is also the simplest to state: with one car you ask what broke? With a fleet you ask what explains this whole pattern?

A single faulty vehicle is one data point. A fleet throwing the same code is a distribution, and any explanation you propose has to fit three features of it at once:

Figure 1 — One observation vs. a distribution
ONE CAR 1 observation → “what broke?” A FLEET — a distribution to explain prevalence how common stratification who fails onset when it spread
More constraints, not more confusion. A fleet hypothesis has three times the work to do — but that is good news. A story that explains one car’s failure yet cannot reproduce the prevalence, the affected subgroup, and the onset timing is wrong, and the fleet exposes it immediately.

Everything in the single-vehicle method still applies — grading, the impostor test, the physics referee, convergence. The fleet just adds population-level structure on top, and one new hazard we have to clear first.

Part A — One Code, Many Causes

The same code is rarely the same cause

A common trouble code is a symptom, and symptoms are shared. Treat the whole batch as one failure and you will average two real mechanisms into one that does not exist.

§ 02 — The Mixture Trap

One mask, several faces

Here is the scenario we carry through the post. A fleet of 6,000 EVs is throwing the same code — P0AE0, “reduced charge rate.” The batch of evidence: build records (plant, build week, firmware, charge-connector supplier lot), telemetry summaries, warranty claims, and service notes.

It is tempting to ask “what causes P0AE0?” as if there is one answer. But a charge-rate code can be tripped by many mechanisms, and across 6,000 cars more than one of them is probably active. In our fleet there are in fact two:

Cause 1 · a firmware charging bug

throttles charging in the cold · firmware ≥ v5.1 · all plants

Signature: reduced charge rate correlated with low temperature. Onset tracks the v5.1 software rollout.

Cause 2 · a bad connector lot

high-resistance charge connector · Supplier B, build weeks 12–18

Signature: reduced charge rate correlated with connector temperature and current. Onset tracks those build weeks entering service.

Both set the identical code. If you pool all 6,000 cars and fit one explanation, you get a blurry average that fits neither — a “cold-ish, connector-ish, sort-of” cause that no fix actually addresses. That is the mixture trap.

Figure 2 — One code, a mixture of causes
P0AE0 — reduced charge 6,000 cars, one code Cluster 1 — cold-correlated firmware ≥ v5.1 · all plants · ~340 cars Cluster 2 — connector-temp-correlated Supplier-B lot · build wk 12–18 · ~120 cars
De-mix before you diagnose. The single code fans out into two sub-populations with different fingerprints. Each is a clean single-cause problem; pooled together they are an unsolvable blur. The number-one fleet skill is seeing the mixture.
§ 03 — De-mix First

Cluster the population, then diagnose each cluster

The fix for a mixture is to split it into homogeneous groups before reasoning about cause. You do that by giving each car a short fingerprint and grouping cars whose fingerprints match.

For each vehicle, summarize the code event into a small signature: when did the throttling happen (cold? hot? high current?), how severe, how often, under what conditions. Cars driven by the same mechanism will have similar signatures and cluster together; the clusters are your candidate sub-populations. Then you run the ordinary single-vehicle method inside each cluster, where there really is one cause.

Figure 3 — The de-mixing pipeline
batch 6,000 cars per-car signature when/how it throttles cluster group by fingerprint Cluster 1 → single-car RCA firmware cause Cluster 2 → single-car RCA connector cause
Reduce, group, then diagnose. Each car becomes a small signature; cars with matching signatures form clusters; each cluster is handed to the ordinary single-cause method. The hard fleet step is the middle one — everything after it is familiar.
Algorithm 1de_mix(fleet, code)

input fleet of cars with the same code · batch evidence

output sub-populations, each with (likely) one cause

for car in affected(fleet):

sig[car] signature(car) # conditions, severity, timing of the event

clusters cluster(sig) # group similar fingerprints (mixture model / k-means)

for C in clusters:

check C is homogeneous # one tight signature, not a smear

single_vehicle_rca(C) # now there is one cause to find

return clusters with their causes

When is a cluster “real”?

A genuine sub-population has a tight, separable signature and a sensible size — not a fuzzy blob you split by eye. If the clusters overlap heavily, you may have one cause with a spread of severities, not two causes. Treat clustering as a hypothesis to be confirmed by the cohort boundary in §04, not as the answer.

Part B — The Cohort Contrast

Let the boundary name the cause

On one car, comparing affected to unaffected was a luxury. Across a fleet it is the main engine — the line between who fails and who doesn’t usually points straight at the mechanism.

§ 04 — The Boundary Names the Cause

Stratify, and read the split

Within a cluster, line the affected cars up against the healthy ones and ask: what attribute best separates them? Build plant, firmware version, build week, supplier lot, climate. The attribute that cleanly divides failed from healthy is your prime suspect.

For Cluster 1, the dividing line is sharp: every affected car runs firmware ≥ v5.1, across all plants, and healthy cars run older firmware. For Cluster 2, the line is Supplier-B connectors from build weeks 12–18, at one plant. Two clusters, two clean boundaries, two causes — exactly what de-mixing was for.

Figure 4 — A stratification tree finds each boundary
fleet · 6,000 code rate 7.7% fw < v5.1 fw ≥ v5.1 older firmware rate ~1% · healthy fw ≥ v5.1 (all plants) Cluster 1 — cold throttle split by connector lot lot A / other rate ~0.4% · healthy Supplier-B · wk 12–18 Cluster 2 — connector each high-rate leaf is a cohort boundary — and a cause
The split is the diagnosis. Recursively dividing the population by build attributes isolates the high-rate leaves. A leaf that is almost all failures, defined by one or two attributes, hands you the affected-population definition and the cause in the same stroke. (This is a decision tree doing causal triage.)

Notice what the boundary gives you for free that one car never could: the exact affected-population definition — a rule over VINs (“firmware ≥ v5.1” or “Supplier-B connector, weeks 12–18”). That rule is what a remediation campaign in §09 will be written against.

§ 05 — Confounding & Simpson’s Paradox

A fleet-wide trend can lie

The impostor from the single-car method comes back at fleet scale — bigger and better disguised. A correlation across the whole fleet can point the wrong way, and even reverse once you look inside the subgroups.

Suppose you tally the raw code rate by plant and find Plant A at 6%, Plant B at 4%. Plant A looks like the problem. But split each plant by firmware and the story flips:

Table 1 — The same numbers, two opposite conclusions
GroupPlant APlant BWho’s worse?
Older firmware2%3%B
Firmware ≥ v5.19%10%B
Aggregate (all cars)6%4%A?!
Within every subgroup, Plant B is worse — yet in total Plant A looks worse. The reversal happens because Plant A simply built more of the high-rate firmware-≥-v5.1 cars. The plant was never the cause; firmware was, and the plant mix faked a plant effect.
Figure 5 — Simpson’s paradox, drawn
aggregate (misleading) A6% B4% “Plant A is worse” stratified by firmware (true) old fw A2% B3% new fw A9% B10% “Plant B is worse — in both strata”
Always stratify before you accuse. A fleet correlation is not a cause until it survives conditioning on the obvious confounders — firmware, build date, climate, usage. Simpson’s paradox is the impostor of §06 in the single-car post, scaled to a population.
The fleet rule

Never act on a raw fleet-wide rate. Condition on the structural confounders first — plant, firmware, build week, supplier, climate, usage — and only trust a difference that holds inside the strata. The cohort boundary of §04 and this stratification are the same discipline doing double duty.

Part C — Aggregating Batched Evidence

Volume is not the same as confidence

A batch of millions of rows feels authoritative. But carelessly piled together it produces false certainty just as easily as insight. The cure is to aggregate in two disciplined levels.

§ 06 — Two Levels, Not One

Summarize per car, then reason across cars

The single biggest aggregation mistake is to throw every row from every car into one pile and let the counts speak. A car that logged 50,000 rows would then shout fifty thousand times louder than one that logged ten — for no good reason.

Do it in two levels. Level one: reduce each car’s raw evidence to a single tidy summary — its signature, its build attributes, and its outcome (did the code fire, how badly). One car, one row. Level two: reason across those rows — stratify, fit a model, compare cohorts. This keeps every vehicle to one vote and stops a few data-heavy cars from hijacking the conclusion. It is the independence rule from the prequel, enforced by structure.

Figure 6 — Two-level aggregation
LEVEL 1 — per car car 1: 41k rows car 2: 9k rows car 3: 88k rows … 6,000 cars summarize 1 car → 1 row LEVEL 2 — across cars fleet table: one row per car signature · plant · fw · lot · climate · outcome stratify · hierarchical model → cause, with honest uncertainty one car = one vote — not one row = one vote
Reduce first, reason second. Collapsing each car to a single summary row makes every vehicle count once, regardless of how chatty its logger was. Then the fleet-level analysis — stratifying or fitting a multilevel model — sees a clean, balanced table instead of a volume-weighted blur.
§ 07 — Messy by Default

The batch is biased before you open it

Fleet data is never a clean random sample. It is filtered by who reports, who comes in for service, and who is still alive to log — and each filter bends the picture.

Three biases to name out loud, because they quietly distort prevalence and stratification:

Figure 7 — Your batch is the narrow end of a funnel
all cars on the road · 6,000 cars that report telemetry ← survivorship drops the dead ones cars brought in for service ← who noticed & acted warranty claims = your batch
What lands on your desk is filtered three times. Treat the batch as a biased sample, not the population. When you can, estimate what the filters removed — a known reporting rate lets you correct prevalence upward; silent cars warrant a deliberate check rather than a healthy assumption.

Part D — Time & the Decision

When it started, and what you do about it

A fleet has a clock. The shape of the failure over time often pins the cause to a specific event — and the end product is not a fix but a campaign.

§ 08 — Read the Curve

Prevalence over time pins the cause

Plot how many new cases appear each week and the picture often tells you the cause before any deep analysis. A sudden change in slope — a change-point — usually lines up with something real: a software rollout, a supplier switch, a season.

In our fleet the curve has two separate take-offs, and that alone confirms the mixture. One rise begins exactly when firmware v5.1 starts rolling out over the air; a second, later rise begins as the Supplier-B build-week-12–18 cars reach the field. Two change-points, two causes, each tied to its own event.

Figure 8 — Onset curve with two change-points (and the forecast)
new cases / month time → v5.1 OTA lot 12–18 in service today Cluster 1 (firmware) — starts at the OTA Cluster 2 (connector) — starts later
The clock confirms the mixture. Two distinct take-offs, each aligned to its own event, are strong independent evidence that you really have two causes — not one. Extending the curves (dashed) is the forecast: how many more cars each cause will claim if nothing is done.
§ 09 — From Cause to Campaign

The output is a remediation scope

On one car you end with a repair. On a fleet you end with a decision about thousands of cars: who needs fixing, by what means, and how urgently. The de-mixing pays off here most of all — because the two causes need completely different campaigns.

The affected-population rules from §04 become the campaign’s targeting. The onset and forecast from §08 set the urgency. And the nature of each cause sets the method:

Figure 9 — Two causes, two campaigns
Cluster 1 — firmware bug target: all cars on fw ≥ v5.1 OTA software campaign push v5.2 patch · remote · days · low cost scope: ~all ≥v5.1 cars · no service visit Cluster 2 — connector lot target: Supplier-B, wk 12–18 targeted recall replace connector · service visit · weeks · high cost scope: ~120 VINs only · not the whole fleet
One code, two completely different responses. Had we never de-mixed, we would have either recalled 6,000 cars for a connector most of them never had, or pushed a software patch that does nothing for the bad connectors. Splitting the population is what makes a proportionate remediation possible — fix exactly who needs it, by the cheapest means that works.
The decision is an economic one

Scope each campaign by weighing the forecasted failures it prevents (§08) against its cost and the risk of the remedy itself — exactly the cost-aware logic from the sufficiency post, now spending recall dollars instead of measurements. A narrow, well-targeted recall beats a fleet-wide panic on every axis that matters.

§ 10 — The Fleet Procedure

The whole method as one flowchart

The fleet method is the single-car method wrapped in two new moves: de-mix at the front, decide a campaign at the back — and stratify relentlessly in between.

Figure 10 — The fleet RCA loop
batch + one common code DE-MIX → clusters (§03) COHORT BOUNDARY (§04) CONFOUNDING CHECK (§05) CONFIRM MECHANISM (referee) ONSET · FORECAST (§08) REMEDIATION SCOPE (§09) blurry → re-cluster reverses in strata → drop the impostor for each cluster
Two new bookends, a familiar middle. De-mixing and the campaign decision are the fleet-specific moves; the per-cluster loop in the center — boundary, confounding check, referee — is the single-vehicle method you already know, run once per sub-population.
Algorithm 2cohort_boundary(cluster)

input cluster cars with build attributes A · outcome (affected?)

output the rule over attributes that best separates failed from healthy

for attr in A: # plant, firmware, build-week, supplier lot, climate

score[attr] separation(split cars by attr) # e.g. information gain

best argmax score

if leaf(best) is near-pure: return rule = best # the affected-population definition

else: recurse on the impure child # a second attribute may be needed

Algorithm 3fleet_rca(fleet, code)

clusters de_mix(fleet, code) # §03 — split the mixture

for C in clusters:

rule cohort_boundary(C) # §04 — who fails

if not holds_within_strata(rule): continue # §05 — drop confounded impostor

confirm_mechanism(C) # referee — single-car method

onset, forecast time_analysis(C) # §08 — change-point + projection

plan[C] remediation_scope(rule, forecast) # §09 — OTA / recall / targeted

return plan per cluster

§ 11 — A Worked Scenario

The 6,000-car fleet, start to finish

Putting it together on the running example, in one pass.

De-mix (§03). All 6,000 cars share P0AE0. Reducing each affected car to a signature and clustering reveals two tight groups: ~340 cars that throttle in the cold, and ~120 that throttle when the connector runs hot. One code, two sub-populations.

Cohort boundary (§04). Cluster 1’s affected cars are exactly those on firmware ≥ v5.1, every plant. Cluster 2’s are exactly the Supplier-B connectors from build weeks 12–18. Two clean rules over VINs.

Confounding check (§05). The raw rate made Plant A look worst — but stratifying by firmware reversed it: Plant A only shipped more v5.1 cars. The “plant” signal was an impostor; firmware is the real axis. Dropped.

Confirm (referee). Inside each cluster, the single-car method closes it out: Cluster 1’s charging logic throttles below a temperature threshold in v5.1 (trace the code); Cluster 2’s connectors show high resistance and heating under load (measure the joint). Two confirmed mechanisms.

Onset & forecast (§08). The curve take-offs line up with the v5.1 rollout and the lot entering service — independent confirmation of two causes — and project a few hundred more cases if nothing is done.

Cluster 1 — verdict & campaign

firmware cold-throttle bug · fw ≥ v5.1 · all plants

OTA software campaign: push v5.2 to all ≥v5.1 cars. Remote, days, low cost, no service visit. Kill-switch: post-patch cold-charge rates return to normal.

Cluster 2 — verdict & campaign

high-resistance connector · Supplier-B · build wk 12–18

Targeted recall: replace the connector on ~120 specific VINs only. Service visit, higher cost, but bounded. Kill-switch: replaced joints stop heating and throttling.

One trouble code; two causes; two proportionate fixes touching 460 cars instead of 6,000. That gap — between a blind fleet-wide recall and a precise, de-mixed response — is the entire value of doing fleet RCA properly.

§ 12 — Practical Notes

Field rules for population-scale diagnosis

1
de-mix first

Treat one code as a mixture until proven single

Cluster the affected cars by signature before asking “what causes this code.” Pooling distinct mechanisms produces an average cause that no fix addresses.

2
the split is the answer

Let the cohort boundary name the cause

The build attribute that cleanly separates failed from healthy — firmware, lot, plant, climate — is your prime suspect and your affected-population rule in one.

3
never a raw rate

Stratify before you accuse; beware Simpson’s paradox

A fleet-wide correlation can reverse inside subgroups. Trust a difference only if it survives conditioning on plant, firmware, build week, supplier, and climate.

4
one car, one vote

Summarize per vehicle before aggregating

Reduce each car to a single row first, so a chatty logger can’t outvote the fleet. Volume is not confidence.

5
the batch lies low

Assume selection and survivorship bias

Warranty batches over-represent severe, reporting cars and can miss the cars that failed hardest and went silent. Absence of signal is not absence of fault.

6
read the clock

Change-points pin causes to events

Plot new cases over time. A take-off aligned to an OTA, a supplier switch, or a season is strong, cheap evidence — and two take-offs mean two causes.

7
scope, not fix

Deliver an affected-population rule, a forecast, and a campaign

The fleet output is a decision about thousands of cars: who, by what means, how urgently — not a single repair.

8
be proportionate

Fix exactly who needs it, by the cheapest means that works

De-mixing is what lets you OTA the firmware group and recall only the bad-lot VINs — instead of a fleet-wide overreaction or an under-reaction that misses a real hazard.

§ 13 — References & Further Reading

Where these ideas come from

Fleet RCA borrows from epidemiology, reliability engineering, and statistics as much as from diagnosis. Entry points, grouped.

Population thinking & confounding

K. J. Rothman, S. Greenland & T. L. Lash, Modern Epidemiology (3rd ed., 2008). Case-control reasoning, confounding, and stratified analysis — the discipline of comparing affected to unaffected populations.

N. Mantel & W. Haenszel, “Statistical Aspects of the Analysis of Data From Retrospective Studies of Disease” (1959). The classic stratified estimate that combines subgroup evidence without the Simpson reversal.

E. H. Simpson, “The Interpretation of Interaction in Contingency Tables” (1951). The paradox of §05, at its source.

J. Pearl, Causality: Models, Reasoning, and Inference (2nd ed., 2009). When a stratified or adjusted comparison does and does not recover a causal effect.

Mixtures & clustering

G. McLachlan & D. Peel, Finite Mixture Models (2000). The formal account of data generated by several hidden sub-populations — the de-mixing of §03.

T. Hastie, R. Tibshirani & J. Friedman, The Elements of Statistical Learning (2nd ed., 2009). Clustering, mixture models, and the decision trees behind the stratification of §04.

Reliability, survival & warranty data

W. Q. Meeker & L. A. Escobar, Statistical Methods for Reliability Data (1998). Field-failure and warranty analysis, hazard and life distributions — the forecasting of §08–§09.

W. Nelson, Applied Life Data Analysis (1982). Practical life-data and failure-rate estimation for fielded populations.

J. F. Lawless, Statistical Models and Methods for Lifetime Data (2nd ed., 2003). Recurrent events and lifetime modeling underlying fleet prognosis.

Hierarchical models & change detection

A. Gelman & J. Hill, Data Analysis Using Regression and Multilevel/Hierarchical Models (2007). The two-level aggregation of §06 done properly — vehicle within fleet.

M. Basseville & I. Nikiforov, Detection of Abrupt Changes (1993). The change-point detection behind reading the onset curve in §08.

Diagnosis foundations (from the series)

J. de Kleer & B. C. Williams, “Diagnosing Multiple Faults” (1987); R. Reiter, “A Theory of Diagnosis from First Principles” (1987). The multiple-cause reasoning that, at population scale, becomes the mixture problem.

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

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  you are here

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.