Coverage arguments for a space you cannot enumerate
Test and evaluation · July 20, 2026 · 6 min read
Structural coverage — lines, branches, conditions — answers the question did the tests execute this code. For an autonomy stack that is the wrong question. The code executes. The risk is that it executes correctly, on inputs nobody anticipated, and produces a behaviour that is defensible line by line and wrong as a whole. Full branch coverage of a planner tells you approximately nothing about whether the planner does something sensible when two moving obstacles and a degraded position estimate arrive together.
The input space rules out the obvious alternatives. It is continuous, it has too many dimensions to grid, and in the applications this site is about it is populated by parties actively looking for the corner you did not test. Enumeration is off the table. So, mostly, is uniform random sampling: the failure sets are thin — measure-zero in the limit — so uniform sampling finds them at a rate indistinguishable from never, and then reports a large number of passing trials, which is worse than finding nothing because it looks like evidence.
Four things replace enumeration, and they work together rather than individually.
The first is a written operating domain. Not a marketing sentence about environments — an explicit statement of the conditions under which the claim is being made: sea states, illumination, closing speeds, traffic densities, position uncertainty, permitted degradation of each input. A system with no stated domain cannot be shown adequate, because adequate for what has not been asked. This is also the only mechanism that turns an unbounded testing problem into a bounded one: you are not testing the system, you are testing a claim, and the claim has edges.
The second is parameterised scenario families instead of scripted scenarios. A script is a point. A family is a region with named parameters — approach geometry, relative speed, sensor occlusion fraction, time of first detection — and a region can be sampled, swept and searched. Scripts accumulate; families compose. Two hundred scripts is a smaller amount of evidence than a dozen families, and it is harder to reason about because nobody can say what the two hundred points have in common.
The third is directed search for failure rather than sampling for confidence. This requires giving up the pass/fail predicate and replacing it with a signed margin: not did it collide but what was the minimum separation, and by how much did it exceed or fall short of the requirement. A predicate gives an optimiser nothing to work with — it is flat almost everywhere. A margin gives a gradient, and the search can then walk downhill toward the parameter combinations that make the margin small. The purpose of the exercise is not to accumulate passes. It is to find the region of the parameter space where the margin approaches zero, and then to look at that region and decide whether it is inside the stated domain, outside it, or an argument for narrowing the domain.
The fourth is coverage measured over behaviour, not only over parameters. Wide regions of parameter space frequently collapse onto the same behaviour, so parameter coverage overstates what has been explored; conversely a small parameter change can flip the planner into a qualitatively different manoeuvre, so parameter coverage also understates the risk near those boundaries. Both errors are visible if you cluster the resulting trajectories and count what came out, rather than counting what went in.
Simulation is evidence for some claims and not others
The fidelity of a simulator is not uniform across the stack, and treating it as though it were is the most common way an autonomy test campaign becomes worthless. Rigid-body dynamics and control response are usually modelled well, because the physics is well understood and the parameters are measurable. Perception is usually modelled badly, because the model of the sensor is a model of a model, and the failure modes that matter — the unusual reflectance, the degenerate geometry, the artefact that appears once per thousand frames — are precisely the ones nobody put in.
So partition the argument. Say explicitly which claims rest on simulation, which rest on hardware in the loop, which rest on physical trials, and which rest on analysis. The honest post-mortem of a simulation failure is almost never “the simulator was wrong”. It is “we never wrote down what the simulator was assumed to be right about”, which meant nobody could notice that a claim had been attached to the wrong evidence.
For rare events the arithmetic is unforgiving: a failure rate low enough to be acceptable is generally too low to demonstrate by direct trials at any budget. There are two ways out. One is stressed sampling with a correction — sample where failures are likely, then reweight — which works when you understand the distribution well enough to weight correctly, and quietly fails when you do not. The other is structural, and it is the one that carries most of the load in practice: wrap the complicated component in a monitor that is simple enough to be verified, give the monitor authority to force a bounded fallback, and move the argument from the planner is safe to the monitor detects the conditions under which the planner is unsafe, and the fallback is safe. That trade is only honest if the monitor is genuinely simpler than the thing it monitors, is independent of it in its failure modes, and has a real control path. A monitor that shares the planner’s state estimate has moved the problem rather than solved it.
Decisions you cannot reconstruct cannot be reviewed
Accountability for a machine decision is usually discussed as a legal or ethical question. Underneath it there is a plain engineering precondition: nobody can review a decision that cannot be reproduced. If the answer to “why did it turn there” is a shrug, the question of who is answerable for the turn has no surface to attach to.
Making decisions reconstructable costs real design effort, and it is best paid before it is needed. Record the inputs actually presented to each decision at the moment it was made — not the raw sensor stream alone, but the fused state the decision consumed, with its timestamps and its uncertainties. Record the identity of every component version and configuration value in the path, because a behaviour reproduced against a different parameter set has not been reproduced. Record the seeds, and prefer designs whose non-determinism has identifiable sources: fixed message ordering, logged clocks, deterministic arbitration between equal-priority inputs. Where exact replay is genuinely unattainable — thread scheduling, floating-point differences across hardware — say so, and bound the divergence rather than pretending it is zero.
The dividend is that a question asked after the fact is answerable, which is also what makes the next design cycle possible. And it produces the correct final posture on all of this: coverage is an argument, not a number. State the domain, the sampling strategy, which evidence supports which claim, and where the argument is thin. The thin parts are known to the engineers already. Writing them down is the difference between an assurance case and a brochure.