Part XIII: Trust, Safety, Evaluation, and Operations
Chapter 68: Robustness, Sensor Spoofing, and Functional Safety

Safety cases for ML perception

"They asked whether my perception model was safe. I showed them 99.2 percent mAP. They asked again, more slowly, and I understood that a number is not an argument."

A Newly Humbled AI Agent

Prerequisites

This section builds on the standards of Section 68.5 (ISO 26262, ISO 21448/SOTIF, ISO/PAS 8800), the redundancy and safety-envelope patterns of Section 68.3, and the runtime monitors of Section 68.4, which supply the evidence a case leans on. It assumes the leakage-safe evaluation discipline of Chapter 65, the calibration and conformal-prediction machinery of Chapter 18, and the distribution-shift and OOD vocabulary of Chapter 66. We treat the model, the monitors, and the standards as given. This section is about the argument that ties them into a claim a safety authority will sign.

The Big Picture

A safety case is a structured, documented argument, backed by evidence, that a system is acceptably safe to operate in a defined context. It is not a test report and not a compliance checklist. It is a chain of reasoning: a top-level claim ("the perception function will not cause an unreasonable rate of missed pedestrians in the operational design domain"), decomposed through intermediate claims into evidence that discharges each leaf. For classical software this argument is well trodden. Machine-learned perception breaks it in a specific place: the behaviour is induced from data rather than specified in code, so there is no line-by-line specification to trace, the input space is astronomically large, and generalisation to unseen inputs is exactly what you cannot fully test. This section teaches how to write an argument that is honest about that gap and still convincing: the notations (GSN and CAE), the ML-specific argument pattern (AMLAS and ISO/PAS 8800), what counts as evidence for a perception claim, and why a modern safety case has to be a living document rather than a snapshot frozen at release.

Claims, arguments, and evidence: the anatomy of a case

Every safety case has the same three-layer skeleton, made explicit by the Claims-Arguments-Evidence (CAE) framework and, more graphically, by Goal Structuring Notation (GSN). A goal (claim) is a proposition to be shown true. A strategy explains how you decompose that goal into sub-goals. Context and assumptions bound what the claim means. A solution is a pointer to concrete evidence (a test result, a proof, a field-data statistic). The argument is valid only if every leaf goal is discharged by a solution and every decomposition strategy actually entails its parent given the stated context.

Why bother with the formality? Because the failure mode of an informal safety argument is the hidden inductive leap: a step where "we tested a lot" silently becomes "therefore it is safe." Writing the argument as an explicit tree forces each leap into the open where a reviewer, or an adversarial safety assessor, can attack it. The Standardisation of Assurance-case Metamodel (SACM) from the Object Management Group gives this a machine-readable form, so a case can be version-controlled, queried, and diffed like code rather than living as a 400-page PDF nobody can audit.

The perception claim sits inside a wider hazard argument. Hazard analysis (from Section 68.5) yields a target such as "the residual rate of a hazardous missed detection shall be below \(\lambda_{\text{tol}}\)." The case must show the delivered system meets it. A useful way to keep the target quantitative is to decompose the top hazard rate multiplicatively across the layers you actually built:

$$ \lambda_{\text{hazard}} \;\le\; p_{\text{miss}} \cdot \big(1 - c_{\text{monitor}}\big) \cdot \big(1 - c_{\text{redundancy}}\big) \cdot f_{\text{exposure}}, $$

where \(p_{\text{miss}}\) is the model's per-frame miss probability on the operational distribution, \(c_{\text{monitor}}\) the coverage of the runtime monitor that catches the miss, \(c_{\text{redundancy}}\) the independent-channel catch rate, and \(f_{\text{exposure}}\) the rate at which the hazardous scenario is encountered. Each factor becomes a sub-claim with its own evidence. The equation is the argument strategy made numeric: it shows exactly which measurement discharges which term, and it makes the reviewer's job checking that the numbers were co-measured on the same operational distribution rather than borrowed from three different reports.

Key Insight

A high benchmark score is evidence for a claim about the test set, not for the safety claim. The safety claim is about behaviour on the deployed input distribution, over the system lifetime, including inputs no one drew from the same barrel as the test data. The entire difficulty of an ML safety case is bridging that gap: from "the model scores 99.2 percent on a held-out split" to "the residual hazardous-error rate in the operational design domain is below \(\lambda_{\text{tol}}\)." You bridge it not with a bigger test set but with an argument, that the test distribution is representative of the ODD, that the ODD is monitored so out-of-scope inputs are detected, and that residual errors are caught downstream. Anyone who offers you an accuracy number as the safety case has skipped the argument.

The ML assurance gap and the AMLAS pattern

Classical assurance leans on a specification: the code is correct if it refines the spec, and coverage-directed testing exercises the spec's behaviours. Learned perception has no such spec. The "requirement" for pedestrian detection is a fuzzy human concept, the implementation is a weight tensor no human wrote, and the correctness proof would have to quantify over an input space of \(256^{H \times W \times 3}\) images. This is the assurance gap, and pretending it away is the single most common defect in early ML safety cases.

The AMLAS methodology (Assurance of Machine Learning for Autonomous Systems, from the University of York) and the emerging ISO/PAS 8800 both structure a case that confronts the gap directly. Rather than one claim about "the model," they decompose along the ML lifecycle, and require an argument at each stage that its output preserves the safety intent of the previous:

The subtle move is the confidence argument sitting beside the main one. For each leaf, you also state why the evidence is trustworthy: how much residual doubt remains, and why that doubt is tolerable. An "assurance deficit" that cannot be closed (for example, no test can cover every lighting condition) is not hidden; it is named, bounded, and mitigated by a downstream layer such as a monitor or a redundant channel. A case that lists its own deficits is stronger, not weaker, than one that claims none.

Practical Example: a delivery robot's crossing-detection case

A sidewalk delivery robot must yield at crossings. The top claim: "the robot will not enter an occupied crossing at an unreasonable rate within its ODD (daylight, dry-to-light-rain, mapped urban sidewalks)." The team decomposes it. The data sub-claim is discharged by a dataset stratified over the mapped routes with rare-case oversampling (occluded pedestrians, wheelchair users, dogs) and a leakage audit confirming no route or day appears in both train and test, exactly the discipline of Chapter 65. The verification sub-claim reports miss rate per slice, worst over slices, not the average, because the average hides the wheelchair slice. A named assurance deficit: heavy rain is out of the tested envelope. It is closed not by more data but by an ODD monitor (a rain estimator from the wiper and camera-blur signals) that pulls the robot to a safe stop when confidence drops, so the model is never trusted outside its evidence. The reviewer signs the case because the deficit is explicit and mitigated, and because the miss-rate numbers were co-measured on one operational-distribution replay, not stitched from three experiments.

What counts as evidence for a perception claim

Evidence is not one kind of thing, and a strong case triangulates several so that no single weak method carries the argument. The main families, each mapped to the doubt it reduces:

The discipline that ties these together is honest, single-pass measurement: the numbers that feed one argument branch must be co-computed on one model, one split, one operational replay, and saved as one artifact. A case that compares a miss rate from config A against a monitor coverage from config B has committed the exact audit-passes-but-invalid error the house evaluation rules warn against, and a competent assessor will find it.

from dataclasses import dataclass, field

@dataclass
class Node:
    id: str
    kind: str          # "goal", "strategy", or "solution"
    text: str
    children: list = field(default_factory=list)
    evidence: str = None   # only meaningful for solutions

def undischarged(node):
    """Return leaf goals with no supporting solution: the holes in the case."""
    holes = []
    if node.kind == "goal" and not node.children:
        holes.append(node.id)                       # a goal with nothing under it
    if node.kind == "solution" and not node.evidence:
        holes.append(node.id)                       # a solution pointing at no artifact
    for c in node.children:
        holes.extend(undischarged(c))
    return holes

case = Node("G1", "goal", "Miss rate in ODD < lambda_tol", children=[
    Node("S1", "strategy", "Argue over lifecycle stages", children=[
        Node("G2", "goal", "Data is relevant & complete", children=[
            Node("E1", "solution", "Leakage audit + slice coverage", evidence="rep_data.json")]),
        Node("G3", "goal", "Verification meets target", children=[
            Node("E2", "solution", "Per-slice held-out test", evidence="rep_eval.json")]),
        Node("G4", "goal", "Rain out-of-ODD is handled")   # deficit: no evidence yet
    ])])

print("Undischarged nodes:", undischarged(case))   # -> ['G4']
A safety case rendered as a GSN tree of goals, strategies, and solutions. The undischarged walk flags every leaf goal with no evidence and every solution citing no artifact, so the case's holes surface automatically. Here it correctly reports G4, the rain deficit, as the one open claim to be closed by a runtime ODD monitor.

The snippet above shows why a machine-readable case matters: an argument you can traverse is an argument you can check. The undischarged function is the assurance analogue of a coverage report, it names the goals that reasoning has not yet reached, which is precisely where a rushed case papers over the gap.

Library Shortcut

Hand-rolling GSN parsing, cross-referencing, well-formedness checks, and diagram rendering is a few hundred lines and a maintenance burden. Tools built on the OMG SACM metamodel (for example the open-source gsn2x renderer, or Eclipse-based AdvoCATE-style toolchains) take a YAML or SACM description and give you validation, undischarged-goal detection, versioned diffs, and publishable diagrams in a few lines of configuration. A one-file argument.yaml plus gsn2x argument.yaml replaces the roughly 300 lines of tree-walking, layout, and consistency logic you would otherwise write, and it produces the same PDF a certification body expects to review.

Living safety cases: through-life assurance

A learned model's environment drifts, its data ages, and it may be updated after release, so a safety case frozen at launch decays. Two ideas keep it alive. First, the case is version-controlled and traceable: every claim links to the exact model hash, dataset version, and monitor configuration that discharges it, so when any of those changes you can query which claims are now stale. Second, the dynamic safety case treats runtime monitors (Section 68.4) as continuous evidence gatherers: field statistics on ODD coverage, monitor trigger rates, and drift indicators feed back to confirm, or invalidate, the assumptions the case rests on. When shadow-mode data shows the operational distribution moving away from the tested one (the shift detection of Chapter 66), the case flags the affected data and verification claims for re-argument before a hazard materialises. This closes the loop with the reliability-engineering patterns of the next section and with the fleet operations of Chapter 69, where re-training triggers and monitoring are the machinery that keeps the argument true after deployment.

Research Frontier

The state of the art is consolidating fast. ISO/PAS 8800 (AI safety for road vehicles, published 2024) is the first standard to give ML-specific safety-case guidance that dovetails with ISO 26262 and SOTIF, and its uptake is now the practical question. The AMLAS pattern from York remains the most cited academic scaffold, extended by work on dynamic assurance cases and runtime certificates that update confidence from live monitors. Open problems: quantifying confidence in an argument (moving beyond qualitative "sufficient" to calibrated argument-level uncertainty), assuring foundation-model and open-vocabulary perception whose ODD is effectively unbounded, and machine-checkable cases where an assessor's queries run against a SACM database rather than a PDF. Regulators, UL 4600 for autonomous products and the EU AI Act's high-risk conformity route, are converging on the assurance-case form, so this is becoming the lingua franca of deployable perception, not an academic exercise.

Exercise

Take a wearable fall-detection classifier (accelerometer plus barometer) intended to summon help after a fall. (1) Write the top-level safety claim, naming the ODD (who wears it, what activities, what environments). (2) Decompose it with an AMLAS-style strategy into data, verification, and deployment sub-goals. (3) For each sub-goal, name one concrete piece of evidence and one residual assurance deficit. (4) Identify the deficit you cannot close with more data, and propose a runtime monitor or redundant channel that mitigates it. (5) State the one measurement that, if it came from a different model version than the others, would silently invalidate your case.

Self-Check

1. Why is a 99 percent benchmark accuracy evidence for a claim about the test set but not, on its own, for the safety claim? 2. In the multiplicative hazard-rate decomposition, what goes wrong if \(p_{\text{miss}}\) and \(c_{\text{monitor}}\) are measured on different operational distributions? 3. Why does explicitly listing an assurance deficit make a safety case stronger rather than weaker, and what must accompany the deficit for a reviewer to accept it?

What's Next

In Section 68.7, we turn the argument into engineering practice: the reliability-engineering patterns, FMEA and fault trees, graceful degradation, watchdogs, health management, and defense in depth, that make the sub-claims of a safety case actually true in silicon and field, and that generate the through-life evidence a living case feeds on.