Assurance Case

July 10, 2026 · View on GitHub

The assurance subsystem composes existing SPO runtime evidence — audit-chain integrity, replay determinism, formal verification, twin-confidence scoring, and the conformal admission gate — into a single hash-sealed assurance-case bundle, and maps that evidence to the published clauses of three standards a regulated deployment is commonly measured against:

  • Regulation (EU) 2024/1689 (the EU AI Act) — high-risk requirements;
  • ISO/IEC 42001:2023 — AI management system clauses and Annex A controls;
  • ANSI/UL 4600 — claim-based safety case for autonomous products.

The bundle is review-only: actuation_permitted is always False, the bundle hash seals the evidence and conformance records deterministically, and a disclaimer states that the bundle is a technical evidence-mapping aid, not a legal conformity assessment. Clauses with no contributing technical evidence are recorded as not_addressed so coverage gaps are explicit rather than implied.

spo assurance-case --system my-deployment \
  --audit-log run.jsonl \
  --evidence-file twin_confidence.json \
  --output assurance_bundle.json \
  --report-out conformity_report.md \
  --report-pdf-out conformity_report.pdf

--report-out additionally renders a human-readable Markdown conformity report from the same sealed bundle — a per-standard, clause-by-clause table of conformance status, contributing evidence, and rationale, anchored to the bundle hash for traceability. --report-pdf-out renders the same report as a deterministic, dependency-free text PDF — the distributable artefact an assessor files.

For operator review packages, spo certification-evidence wraps the same assurance bundle with deterministic test vectors and a manifest:

spo certification-evidence --system my-deployment \
  --run-result run_summary.json \
  --output-dir review_package

--run-result takes a serialised SimulationResult summary and auto-derives the run's audit-stream integrity, conformal admission-gate, and closed-loop control-safety-envelope evidence (control mode, applied-action and boundary-violation totals, recorded when the policy feedback was active), so a package can be assembled from a run summary without hand-authoring evidence JSON (--audit-log and --evidence-file remain available and compose with it). With --audit-log, adding --verify-determinism re-executes the logged run and records a replay_determinism evidence item for the reproducibility clauses. --formal-package takes a serialised FormalVerificationPackage manifest (from the supervisor formal exporters) and adds a formal_verification evidence item for the formal-argument clauses, recording which model-checking properties were posed against which exported artefacts. --twin-confidence-file takes a serialised TwinConfidenceScore and adds a twin_confidence evidence item for the drift-monitoring clauses, restating the calibrated confidence, operator status, divergences, and content hash of the scored tick.

With --audit-log, --sign-envelope additionally writes signed_envelope.json — a deterministic binding of the package hash to the run's audit-chain tip, so the package is anchored to a specific, tamper-evident, replayable execution. --signing-seed-file supplies an ML-DSA seed (FIPS 204) and adds a post-quantum seal over that tip to the envelope, making the binding publicly verifiable (it implies --sign-envelope). The ML-DSA seal needs the pqc extra and an OpenSSL 3.5+ backend.

The package directory contains:

  • manifest.json — file digests, the assurance bundle hash, standards covered, coverage summary, package hash, and review-only disclaimers;
  • assurance_bundle.json — the existing scpn_assurance_case_bundle_v1 payload;
  • conformity_report.md — a human-readable, per-standard clause-by-clause conformity report rendered from the bundle and sealed into the manifest digest;
  • conformity_report.pdf — the same conformity report as a deterministic text PDF (the filable artefact), also sealed into the manifest digest;
  • test_vectors.json — recomputable evidence content-hash vectors and clause-rationale hash vectors;
  • signed_envelope.json(only with --sign-envelope) the package hash bound to the run's audit-chain tip, optionally carrying a post-quantum ML-DSA seal.

The package is standards-shaped evidence for reviewer triage. It does not claim legal compliance, certification, or runtime actuation permission.

Regulatory clause catalogue

scpn_phase_orchestrator.assurance.standards records each referenceable clause with its standard, identifier, official title, and a provenance note. Clause identifiers and titles are taken from the public structure of each standard; the clause text must be confirmed against the official standard before any external submission.

::: scpn_phase_orchestrator.assurance.standards

Evidence items

scpn_phase_orchestrator.assurance.evidence wraps the JSON-safe audit record of an originating surface in a content-addressed EvidenceItem, so the bundle can reference evidence by a stable identifier and detect later mutation. The shared canonical hashing path accepts only strict JSON records: NaN, Infinity, and -Infinity are rejected before any digest is emitted, so hashes remain portable across JSON implementations and non-Python verifiers.

::: scpn_phase_orchestrator.assurance.evidence

Run-derived evidence

scpn_phase_orchestrator.assurance.run_evidence maps the trust-relevant fields of a serialised SimulationResult record — the close-time audit-stream integrity result and the conformal admission-gate decisions — into evidence items. It consumes the JSON-safe record (not the runtime object), so the assurance package stays free of the numeric runtime import chain, and it emits nothing for a surface that did not run.

::: scpn_phase_orchestrator.assurance.run_evidence

Formal-verification evidence

scpn_phase_orchestrator.assurance.formal_evidence maps a serialised FormalVerificationPackage.to_audit_record() manifest — the supervisor formal exporters' artefact hashes, model-checking property library, and non-executing checker commands — into a single formal_verification evidence item. Like the run-derived evidence, it consumes the JSON manifest (not the package object), so the assurance package stays free of the supervisor import chain, and it restates the manifest verbatim: it records which properties were posed against which artefacts, never that any external checker accepted them.

::: scpn_phase_orchestrator.assurance.formal_evidence

Twin-confidence evidence

scpn_phase_orchestrator.assurance.twin_confidence_evidence maps a serialised TwinConfidenceScore.to_audit_record() — calibrated confidence, operator status, raw divergences, one-sided z-scores, band flags, backend, and content hash — into a single twin_confidence evidence item, closing the one evidence category the clause map referenced without a producer. Like the run-derived and formal evidence it consumes the JSON record (not the score object) and restates it verbatim, rejecting a confidence outside [0, 1].

::: scpn_phase_orchestrator.assurance.twin_confidence_evidence

Bundle assembly

scpn_phase_orchestrator.assurance.case maps each catalogued clause to the evidence that addresses it, records the conformance status and rationale, and seals the result into a deterministic, fail-closed bundle.

::: scpn_phase_orchestrator.assurance.case

Certification evidence package

scpn_phase_orchestrator.assurance.certification assembles the review package around the assurance-case bundle. It keeps package assembly deterministic and hash-sealed while preserving the same review-only boundary as the underlying assurance case.

::: scpn_phase_orchestrator.assurance.certification

Signed certification envelope

scpn_phase_orchestrator.assurance.envelope binds a certification package to the run that produced it. A SignedCertificationEnvelope commits, in one deterministic record, to the package hash, the run's audit-chain tip (the SHA-256 commitment to the whole audit log, so the package is anchored to a specific, replayable, tamper- evident execution), and an optional post-quantum seal over that tip (scpn_phase_orchestrator.runtime.audit_pqc.AuditChainSeal, ML-DSA / FIPS 204). It reuses the audit seal verbatim and performs no signing or log reading itself — the CLI layer reads the tip and produces the seal — so the assurance leaf only validates and binds. verify_signed_certification_envelope re-derives the envelope hash, checks the package binding, and verifies any attached seal against a trusted public key.

::: scpn_phase_orchestrator.assurance.envelope

Supply-chain provenance (SLSA / DSSE)

The certification envelope attests to a run; the provenance layer attests to a build — which release artefacts were produced, from which resolved inputs, by which builder. scpn_phase_orchestrator.assurance.provenance assembles a deterministic in-toto Statement v1 carrying a SLSA provenance v1 predicate: the produced artefacts as digest-pinned subjects, the build definition (build type, external parameters, digest-pinned resolved dependencies), and the run details (builder identity and invocation). The run details also carry the optional builder.version map, the builder's own digest-pinned builderDependencies, and the build byproducts (for example a digest-pinned SBOM); each is omitted when empty, so a minimal statement is byte-identical to one without them. pypi_resolved_dependency turns a hash-pinned lock-file entry into a Package-URL-addressed resolved dependency, so the resolvedDependencies block can carry the full dependency tree. It reads no wall clock and makes no network call, so the same build inputs always serialise to the same statement.

scpn_phase_orchestrator.assurance.dsse wraps that statement in a DSSE envelope — the wire format cosign attest produces — and signs its pre-authentication encoding with ML-DSA (FIPS 204), reusing the single post-quantum primitive in scpn_phase_orchestrator.runtime.audit_pqc. Each signature records its algorithm so a second scheme can be added without breaking existing envelopes; SLH-DSA (FIPS 205 / SPHINCS+) is the reserved hash-based alternative and is added once the cryptography backend ships it. Verification is offline and self-contained: the verifier supplies the trusted public key, whose short id must match the signature.

spo provenance-attest build_provenance.json \
  --signing-seed-file signing.seed > attestation.json

spo provenance-verify attestation.json --public-key-file signer.pub

Signing needs the pqc extra and an OpenSSL 3.5+ backend. Publishing the envelope to a Rekor transparency log or verifying it with cosign is an optional operator step that needs network and OIDC, and is left to the operator; the envelope itself is deterministic and verifiable without either.

The release workflow (.github/workflows/release.yml) wires this into the build: after building the sdist and SBOM it runs tools/build_release_provenance_spec.py to assemble the spec — the sdist as a subject, the SBOM as a byproduct, the hash-pinned lock files as resolved dependencies, and the tag, commit, and runner metadata as the build definition and run details — then signs it with spo provenance-attest using the SPO_PROVENANCE_SIGNING_SEED repository secret, and attaches provenance_attestation.json and provenance_signing_key.pub to the GitHub Release. The seed is written to a private file, used, and deleted within the step; it is never committed. When the secret is not configured the step is skipped and the release still carries GitHub's own keyless build-provenance attestation. Consumers should obtain the public key from a trusted channel before pinning it.

::: scpn_phase_orchestrator.assurance.provenance

::: scpn_phase_orchestrator.assurance.dsse

Conformity report

scpn_phase_orchestrator.assurance.report renders an assurance-case bundle as a deterministic Markdown conformity report — the document a regulatory assessor reads. It restates the sealed bundle verbatim (coverage rollup, per-standard clause conformance with status, evidence, and rationale, and the evidence inventory) under the regulatory disclaimer and anchored to the bundle hash. It adds no claim beyond the bundle and is review-only. The certification evidence package seals the rendered report as conformity_report.md. render_conformity_report_pdf renders the same content as a deterministic, dependency-free text PDF — the distributable artefact an assessor files — built on the reusable scpn_phase_orchestrator.reporting.markdown_to_pdf_bytes helper.

::: scpn_phase_orchestrator.assurance.report

Oscillation-Monitoring Evidence (NERC PRC-028-1 / PRC-030-1)

scpn_phase_orchestrator.assurance.prc_oscillation is the audit-package end of the dVOC grid pack. screen_oscillation_modes takes the modes recovered by the matrix-pencil estimator, screens each damping ratio for PRC-028-1 disturbance-data analysis and PRC-030-1 unexpected IBR event mitigation workflows, and seals the screening into a content-addressed, review-only PRCOscillationEvidence record. Undamped modes and positive but poorly damped modes are flagged for operator review. Each finding also carries the engineering mode family from the matrix-pencil estimator, and the record aggregates mode_family_counts, so inter-area and sub-synchronous oscillation signals are visible in the same sealed package. The capture timestamp is supplied by the caller, so the record is deterministic and reproducible. Like the assurance-case bundle, it is a technical evidence-mapping aid, not a legal conformity assessment, and it never actuates.

::: scpn_phase_orchestrator.assurance.prc_oscillation

Ride-Through Evidence (NERC PRC-029-1)

scpn_phase_orchestrator.assurance.prc_ride_through screens operator-provided high-side transformer voltage and frequency samples against the approved NERC PRC-029-1 ride-through tables. It carries both voltage categories from Attachment 1 — AC-connected wind IBRs and all other IBRs — plus the Attachment 2 frequency bands. The screener aggregates cumulative duration inside the standard's voltage and frequency review windows, records the operation region, minimum ride-through duration, observed value range, and review classification for each non-nominal band, then seals the record as PRCRideThroughEvidence.

The record is review-only. It does not evaluate real/reactive-current performance, phase-jump exceptions, hardware-limit exemptions, reporting duties, or legal compliance. Observations outside the review envelope use assessor_review_required, not pass/fail language.

::: scpn_phase_orchestrator.assurance.prc_ride_through

Power-Grid PRC Assessor Bundle

scpn_phase_orchestrator.assurance.power_grid_prc_bundle binds the three power-grid PRC review artefacts into one deterministic handoff package:

  • scpn_dvoc_oscillation_damping_audit_v1 from the offline dVOC/Koopman-MPC damping screen;
  • scpn_pmu_ringdown_prc_audit_v1 from an operator PMU frequency ringdown CSV;
  • scpn_ibr_ride_through_prc029_audit_v1 from an operator voltage/frequency ride-through CSV.

The builder verifies the source JSON SHA-256 metadata, exact child schema, review-only claim boundary, and each child content_hash before sealing the bundle as scpn_power_grid_prc_audit_bundle_v1. The bundle keeps the full child records for assessor replay and carries no live-actuation or conformity claim.

::: scpn_phase_orchestrator.assurance.power_grid_prc_bundle

Early-Warning Assurance Evidence

scpn_phase_orchestrator.assurance.early_warning_evidence is the auditable envelope around the early-warning detector suite. A fair head-to-head established that early-warning detection is a commodity — no single indicator beats the others by a decisive margin — so what this module supplies is not a better detector but a content-addressed record that pins which indicators contributed and their robust z-scores at the alarm window, the provenance of the screened signal, the claim boundary (a review-only technical artefact, not a clinical, operational, or safety decision, nor a certification), and, when a ground-truth transition onset is supplied, the honest lead time — including a non-positive lead when the alarm was late rather than suppressing it.

seal_early_warning is the detector-neutral primitive: it depends only on the alarm decision, the provenance, and a pre-extracted set of EarlyWarningIndicator contributions, so it seals any present or future detector (including the real-EEG capstone) without importing detector internals. The seal_*_alarm adapters bridge each concrete suite detector — and the fused ensemble — onto that primitive. The record is content-addressed with the same canonical-JSON SHA-256 the assurance-case bundle and the NERC PRC oscillation evidence use, so a sealed alarm can be referenced by a stable digest and any later mutation is detectable. It never actuates.

::: scpn_phase_orchestrator.assurance.early_warning_evidence

Grid Early-Warning Advisory

scpn_phase_orchestrator.assurance.grid_early_warning_advisory is the step from a live grid instability alarm to an operator decision surface — the pinnacle the streaming monitor was built toward — done honestly. When the certified streaming monitor raises a StreamAlarm, this module turns it into a claim-bounded advisory record: the growth rate σ that crossed the certified threshold, the most-unstable bus, the alarm time, the certified operating point, and — as a first-class sealed field — the detector's honest recall, so the reader knows how much the detector misses.

The advisory is passive and review-only. It never actuates: every record carries non_actuating = True and actuating = False, the fail-closed stance of the STL runtime actuation gate. The sealed recall is the point: at its certified streaming operating point the detector leads only about a quarter of growing-instability episodes at a matched ten-percent stream false alarm, so an advisory is a reason to look, never a guarantee, and the absence of an advisory is not evidence of stability. seal_grid_early_warning_advisory is the neutral primitive; advise_from_stream_alarm reads the alarm claims and the certified operating point straight off a live monitor. The record is content-addressed with the same canonical-JSON SHA-256 seal, so any later mutation is detectable.

::: scpn_phase_orchestrator.assurance.grid_early_warning_advisory