---
title: "Assurance Cases"
description: "An assurance case is a machine-checkable argument — in the GSN/SACM/CAE tradition — that a system meets a goal, where every claim ultimately rests on…"
canonical: https://novafabric.ai/docs/assurance-cases/
last_updated: 2026-10-22
source: https://github.com/MSKazemi/novafabric/blob/main/docs/assurance-cases.md
---

# Assurance Cases

An **assurance case** is a machine-checkable argument — in the GSN/SACM/CAE
tradition — that a system meets a goal, where every claim ultimately rests on
**sealed capsule evidence referenced by digest**. NovaFabric models the
argument graph, checks its structure, tracks whether its evidence is still
current, maps it onto named standards as *receipts*, and records challenges
(*defeaters*) — all offline
([ADR-0166](https://novafabric.ai/docs/decisions/)).

**Status: experimental** (first slices of ADR-0166 D1–D6, shipped
2026-07-16). The honest scope note up front: ADR-0166's larger
**continuous-assurance loop is proposed design direction, not a shipped,
running system** — see [What remains future design](#7-what-remains-future-design).

Several commands share the `assure` prefix; they are different things:

| Command | What it is |
|---|---|
| `nova assure <capsule>` | OWASP LLM Top 10 (2025) evidence checks against a **single capsule** — an older, separate surface (exits 1 if any check fails) |
| `nova assure-case <document>` / `nova assure-coverage <document>` | The ADR-0166 assurance-case surface documented on this page |
| `nova assure-baseline` / `assure-run` / `assure-impact` / `assure-alarm` / `assure-canary` | ADR-0147 continuous-assurance slices (NF-153/154/156/159/160), **experimental**, each run by hand — see `nova <command> --help` |

---

## 1. The argument graph (D1)

Node types: `goal`, `strategy`, `solution`, `context`, `assumption`,
`justification`. `solution` leaves bind to sealed capsule roots via
`evidence_refs` — **`{ref, digest}` only, never clause bodies, findings text,
or PII**.

Structural invariants, enforced by validation:

- exactly one **top goal** (a `goal` node nothing else supports),
- the `supported_by` graph is **acyclic**,
- **no orphan** — every node is reachable from the top goal,
- ids unique, every `supported_by` reference resolves.

A `solution` node whose evidence doesn't resolve is reported as an
`unsupported_leaf` — recorded, **not fatal** — so an in-progress argument
stays valid while honestly flagging its gaps.

## 2. Checking a case: nova assure-case

The document is a JSON bundle: `case` (required — `{case_id, nodes[]}`) plus
optional `resolvable_digests` (evidence digests that currently resolve),
`currency` (a D2 ledger — requires `--as-of`), `conformance` (D3 clause
mappings), and `defeaters` (D4 challenges).

```bash
$ cat case.json
{"case": {"case_id": "acme-triage-v1", "nodes": [
   {"id": "G1", "type": "goal",
    "statement": "The support-triage agent operates within its approved policy envelope.",
    "supported_by": ["S1"]},
   {"id": "S1", "type": "strategy",
    "statement": "Argue over sealed run evidence from the July eval window.",
    "supported_by": ["E1", "E2"]},
   {"id": "E1", "type": "solution",
    "statement": "Sealed eval-suite capsule shows the policy gate passing.",
    "evidence_refs": [{"ref": "capsule:run-2041", "digest": "a3f1c2d4…abcd"}]},
   {"id": "E2", "type": "solution",
    "statement": "Sealed redaction report for the same window.",
    "evidence_refs": [{"ref": "capsule:run-2042", "digest": "b4e2d3c5…bcde"}]}]},
 "resolvable_digests": ["a3f1c2d4…abcd"]}

$ nova assure-case case.json
Assurance case: acme-triage-v1  (4 nodes)
Structure: VALID   top goal: G1
  unsupported leaf: E2
```

Exit codes: `0` — case OK; `1` — structurally invalid **or** any defeater is
open (the argument is defeated); `2` — bad input. `--json` emits the full
machine-readable report.

**The `--as-of` rule.** If the document carries a currency ledger, the
command refuses to run without an explicit `--as-of <ISO-8601>` — currency is
**never inferred from the system clock**. Evaluate at a sealed timestamp so
the result is a pure, reproducible function of the ledger plus that time.

## 3. Currency — arguments go stale (D2)

Each `solution` node's evidence has a validity window (`last_refreshed` +
`evidence_window`). At the supplied `--as-of` instant, each node is
`current`, `due` (inside the due-lead before expiry — refresh soon), or
`overdue` (no longer current). Overdue nodes yield `stale` drift records
(reason `evidence_expired`) — an assurance-case drift record defined in
`assure/currency.py` (its own shape, not the [drift detection
subsystem](https://novafabric.ai/docs/drift-gate/)'s records), so staleness is recorded evidence, not a
silent re-decision.

## 4. Conformance receipts — never verdicts (D3)

A `conformance` map binds `goal`/`strategy` nodes to named external standard
clauses (supported identifiers today: `iso_iec_42001`, `iso_iec_42005`,
`ul_4600`, `eu_ai_act`, `nist_ai_rmf`, `iso_iec_ieee_15026`). The output is a
**conformance-receipt** shaped like an OSCAL assessment-results document:
each mapped node becomes an `observation`; a mapping to an absent node, or to
an unsupported evidence leaf, becomes a `gap`.

This is deliberately **not a certificate**: it records that an argument was
*assembled against* a clause — never that the clause is *met*. NovaFabric
produces evidence that supports compliance workflows; it does not certify
compliance with any regulation.

## 5. Defeaters — recorded challenges (D4)

A **defeater** is a recorded challenge to a node: a *rebuttal* (the claim is
false) or an *undercut* (the inference doesn't hold). While `open`, it
undermines its target and `nova assure-case` exits `1` — the argument is
honestly *defeated at that node*. Clearing requires `withdrawn` or
`rebutted`, and a rebuttal **must** bind the evidence that answers it
(`resolved_by`) — you cannot declare a challenge answered without saying
what answered it. Open defeaters also emit `defeater_open` drift records.

## 6. Coverage — counts and gaps, never a grade: nova assure-coverage

```bash
nova assure-coverage case.json
nova assure-coverage case.json --as-of 2026-06-01T00:00:00Z --json
```

Reports the **structural** coverage of the argument: `total_goals`,
`goals_with_resolvable_leaf`, `unsupported_leaves`, `open_defeaters`,
`overdue_nodes`. Per the ADR there is deliberately **no grade, score, or
pass/fail field** — an "assurance score" would read as a verdict. The command
exits `0` whenever it renders: open defeaters and unsupported leaves are
coverage *facts* here (contrast `assure-case`, which treats an open defeater
as a failing state).

## 7. What remains future design

Per the ADR-0166 status record, be precise about what you can rely on:

- **Shipped experimental:** the D1 graph model + validation, the D2 currency
  ledger (explicit `--as-of` only), the D3 conformance receipt, the D4
  defeater model and coverage, the `nova assure-case` / `nova assure-coverage`
  read-side CLIs, and the D5 assessor-package **models** (package
  composition, deterministic digest, renewal delta — Python API only).
- **Future design (not implemented):**
  - sealing the assessor package through the Evidence-Bundle DSSE+timestamp
    path, and the `nova assure-case package` / `renewal` CLI surface;
  - the **continuous-assurance loop** itself — the ADR's vision of drift
    detection continuously feeding argument currency (ADR-0147) — is
    **future design**: no standing loop runs. Individual pieces (NF-153/154/
    156/159/160) ship as the experimental `assure-*` commands above, which you
    run yourself; today you re-run `assure-case` against sealed timestamps;
  - any automated evidence collection — evidence digests, currency
    timestamps, and defeaters are all supplied in the document by you.

Do not represent an assurance-case report as a certification artifact; it is
a machine-checked argument over evidence you assembled.

---

## See also

- [Trust surfaces](https://novafabric.ai/docs/trust-surfaces/) — the verification projections whose
  outputs feed `solution` evidence
- [Drift detection](https://novafabric.ai/docs/drift-gate/) — the drift-record model reused for
  staleness and defeaters
- [User guide — trust layer](https://novafabric.ai/docs/user-guide/) — sealing and evidence bundles
- `nova assure-case --help`, `nova assure-coverage --help` — exact document
  schemas
