Assurance Case¶
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 existingscpn_assurance_case_bundle_v1payload;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.
standards ¶
Reference catalogue of regulatory clauses for assurance-case mapping.
The catalogue records the clause identifiers and official titles of the three standards an SPO deployment is most often 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.
Each :class:RegulatoryClause carries a provenance note identifying the
source the identifier and title were taken from. The catalogue is a structured
reference aid for assembling evidence; it is not a legal interpretation, and
clause text must be confirmed against the official standard before any external
submission. See :data:REGULATORY_DISCLAIMER.
Classes¶
RegulatoryClause
dataclass
¶
A single referenceable clause of a regulatory standard.
Parameters¶
standard:
Human-readable standard name (e.g. "EU AI Act 2024/1689").
clause_id:
Stable clause identifier within the standard (e.g. "Article 12",
"Clause 9", "A.6", "data-integrity").
title:
Official clause title.
provenance:
Note identifying the source of the identifier and title.
Functions:¶
clause_catalogue ¶
Return every catalogued clause across all supported standards.
Returns¶
tuple[RegulatoryClause, ...] The full clause catalogue.
Source code in src/scpn_phase_orchestrator/assurance/standards.py
clause_for_key ¶
Return the clause registered under key.
Parameters¶
key:
A standard::clause_id key.
Returns¶
RegulatoryClause The matching clause.
Raises¶
KeyError
If no clause is registered under key.
Source code in src/scpn_phase_orchestrator/assurance/standards.py
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.
evidence ¶
Typed, content-addressed evidence items for the assurance-case bundle.
An :class:EvidenceItem wraps the JSON-safe audit record produced by an
existing SPO surface (audit-chain integrity, replay determinism, formal
verification, twin-confidence, the conformal admission gate, or the closed-loop
control envelope) together with a content hash, so the bundle can reference
evidence by a stable identifier and detect any later mutation.
Classes¶
EvidenceItem
dataclass
¶
EvidenceItem(
evidence_id: str,
category: str,
summary: str,
record: Mapping[str, object],
content_hash: str = "",
)
One content-addressed piece of assurance evidence.
Parameters¶
evidence_id:
Stable identifier, unique within a bundle (e.g.
"audit-chain-integrity").
category:
One of :data:EVIDENCE_CATEGORIES.
summary:
Short human-readable description of what the evidence shows.
record:
The JSON-safe audit record produced by the originating surface.
content_hash:
SHA-256 of the canonical serialisation of record. Defaults to the
computed hash; an explicit mismatching value is rejected.
Methods:¶
__post_init__ ¶
Validate the evidence metadata and compute or verify its content hash.
Source code in src/scpn_phase_orchestrator/assurance/evidence.py
to_audit_record ¶
Return a JSON-safe evidence record.
Returns¶
dict[str, object] A JSON-safe evidence record.
Source code in src/scpn_phase_orchestrator/assurance/evidence.py
Functions:¶
build_evidence_item ¶
build_evidence_item(
evidence_id: str,
category: str,
summary: str,
record: Mapping[str, object],
) -> EvidenceItem
Construct an :class:EvidenceItem with a computed content hash.
Parameters¶
evidence_id:
Stable identifier, unique within a bundle.
category:
One of :data:EVIDENCE_CATEGORIES.
summary:
Short human-readable description.
record:
The JSON-safe audit record.
Returns¶
EvidenceItem The constructed evidence item.
Source code in src/scpn_phase_orchestrator/assurance/evidence.py
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.
run_evidence ¶
Derive assurance evidence directly from a serialised simulation run record.
A completed run produces a JSON-safe SimulationResult.to_record() summary.
This module maps the trust-relevant fields of that record — the close-time audit
event-stream integrity result, the conformal twin-confidence admission-gate
decisions, and the closed-loop control-safety envelope (control mode, applied
actions, and boundary-violation totals) — into
:class:~scpn_phase_orchestrator.assurance.evidence.EvidenceItem records, so a
deployment can assemble a conformity package from a run record without
hand-authoring evidence JSON.
The helper consumes the serialised record (a Mapping), not the
SimulationResult object, so the assurance package stays free of the heavy
runtime/numeric import chain and can run against a persisted run summary. Fields
that are absent or describe an inactive gate produce no evidence item — the
mapping never fabricates evidence for a surface that did not run.
Classes¶
Functions:¶
build_run_evidence ¶
Build assurance evidence from a serialised simulation run record.
Parameters¶
run_record:
A JSON-safe SimulationResult.to_record() mapping.
Returns¶
tuple[EvidenceItem, ...]
Evidence for the trust surfaces the run attests: the audit event-stream
integrity result (audit-chain) when an event stream was written, the
conformal admission-gate decisions (conformal-gate) when the gate
scored at least one tick, and the closed-loop control-safety envelope
(control-envelope) when the policy feedback was active. Empty if the
run attests none of them.
Source code in src/scpn_phase_orchestrator/assurance/run_evidence.py
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.
formal_evidence ¶
Derive formal-verification assurance evidence from a verification-package manifest.
The supervisor formal exporters
(:mod:scpn_phase_orchestrator.supervisor.formal_export) assemble a deterministic
:class:~scpn_phase_orchestrator.supervisor.formal_export.FormalVerificationPackage
— exported PRISM/TLA/SMT artefact hashes, the model-checking property library, and
the exact (non-executing) checker commands — whose
to_audit_record() is a JSON-safe manifest. This module maps that manifest into a
single :class:~scpn_phase_orchestrator.assurance.evidence.EvidenceItem in the
formal_verification category, so a conformity package can attest the formal
argument the supervisor produced.
The helper consumes the serialised manifest (a Mapping), not the
FormalVerificationPackage object, mirroring
:func:~scpn_phase_orchestrator.assurance.run_evidence.build_run_evidence: the
assurance package stays free of the supervisor import chain and can attest a
manifest persisted to disk. It restates the manifest verbatim and never fabricates
properties or checker results — it records which properties were posed against which
artefacts, not that any checker accepted them.
Classes¶
Functions:¶
build_formal_verification_evidence ¶
Build a formal-verification evidence item from a verification-package manifest.
Parameters¶
package_record:
A JSON-safe FormalVerificationPackage.to_audit_record() mapping. It
must carry a non-empty package_name and package_hash, a list of
properties, and an artifact_hashes mapping.
Returns¶
EvidenceItem
A formal_verification evidence item whose record is the manifest
verbatim, summarising how many properties were posed against how many
exported artefacts.
Raises¶
ValueError If the manifest is missing a required field or a field has the wrong type.
Source code in src/scpn_phase_orchestrator/assurance/formal_evidence.py
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].
twin_confidence_evidence ¶
Derive twin-confidence assurance evidence from a serialised confidence score.
The twin-confidence monitor
(:mod:scpn_phase_orchestrator.monitor.twin_confidence) scores each digital-twin
tick against a calibrated baseline and produces a
:class:~scpn_phase_orchestrator.monitor.twin_confidence.TwinConfidenceScore
whose to_audit_record() is a JSON-safe mapping (calibrated confidence,
operator status, raw divergences, one-sided z-scores, band flags, backend, and a
content hash). This module maps that record into a single
:class:~scpn_phase_orchestrator.assurance.evidence.EvidenceItem in the
twin_confidence category, so a conformity package can attest the live drift
monitoring the deployment ran — the one evidence category the assurance-case
clause map references but no producer previously emitted.
The helper consumes the serialised score (a Mapping), not the
TwinConfidenceScore object, mirroring
:func:~scpn_phase_orchestrator.assurance.formal_evidence.build_formal_verification_evidence
and :func:~scpn_phase_orchestrator.assurance.run_evidence.build_run_evidence:
the assurance package stays free of the monitor's numeric import chain and can
attest a score persisted to disk. It restates the score verbatim and never
fabricates a confidence value — a record missing a required field or carrying a
confidence outside [0, 1] is rejected rather than coerced.
Classes¶
Functions:¶
build_twin_confidence_evidence ¶
Build a twin-confidence evidence item from a serialised confidence score.
Parameters¶
score_record:
A JSON-safe TwinConfidenceScore.to_audit_record() mapping. It must
carry a confidence in [0, 1], a non-empty status, and a
non-empty score_hash.
Returns¶
EvidenceItem
A twin_confidence evidence item whose record is the score verbatim,
summarising the operator status and calibrated confidence.
Raises¶
ValueError If the score is not a mapping, a required field is missing, or a field has the wrong type or an out-of-range value.
Source code in src/scpn_phase_orchestrator/assurance/twin_confidence_evidence.py
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.
case ¶
Assemble SPO runtime evidence into a hash-sealed assurance-case bundle.
The bundle links each catalogued regulatory clause
(:mod:scpn_phase_orchestrator.assurance.standards) to the SPO evidence that
addresses it, records the conformance status and rationale, and seals the whole
into a deterministic hash. The bundle is review-only: actuation_permitted is
always False as documentary review metadata, not as a runtime actuation gate.
Live runtime limits remain in the actuation projector and safety-tier checks.
The bundle carries the
:data:~scpn_phase_orchestrator.assurance.standards.REGULATORY_DISCLAIMER.
Classes¶
ClauseConformance
dataclass
¶
ClauseConformance(
clause: RegulatoryClause,
status: str,
evidence_ids: tuple[str, ...],
rationale: str,
)
Conformance status of one clause against the bundle's evidence.
Parameters¶
clause:
The catalogued regulatory clause.
status:
One of :data:CONFORMANCE_STATUSES.
evidence_ids:
Evidence identifiers addressing the clause (empty iff not_addressed).
rationale:
Explanation linking the evidence to the clause.
Methods:¶
__post_init__ ¶
Validate status, evidence references, and rationale text.
Source code in src/scpn_phase_orchestrator/assurance/case.py
to_audit_record ¶
Return a JSON-safe conformance record.
Returns¶
dict[str, object] A JSON-safe conformance record.
Source code in src/scpn_phase_orchestrator/assurance/case.py
AssuranceCaseBundle
dataclass
¶
AssuranceCaseBundle(
system_name: str,
version: str,
evidence: tuple[EvidenceItem, ...],
conformance: tuple[ClauseConformance, ...],
standards_covered: tuple[str, ...],
bundle_hash: str = "",
schema: str = ASSURANCE_CASE_SCHEMA,
disclaimer: str = REGULATORY_DISCLAIMER,
actuation_permitted: bool = False,
)
A hash-sealed, review-only assurance-case evidence bundle.
Parameters¶
system_name:
Name of the system the bundle describes.
version:
Bundle schema instance version (semantic, e.g. "1.0.0").
evidence:
The collected evidence items (unique evidence_id).
conformance:
Per-clause conformance, one entry per catalogued clause.
standards_covered:
Standards the clause catalogue spans.
bundle_hash:
SHA-256 over the canonical bundle seed; recomputed and checked.
schema:
Schema identifier; fixed to :data:ASSURANCE_CASE_SCHEMA.
disclaimer:
Regulatory disclaimer; fixed to REGULATORY_DISCLAIMER.
actuation_permitted:
Always False as a documentary review flag. The live actuation path
does not consult assurance bundles; runtime permission remains governed
by the safety-tier checks and :class:ActionProjector constraints.
Methods:¶
__post_init__ ¶
Validate bundle invariants and compute or verify the bundle hash.
Source code in src/scpn_phase_orchestrator/assurance/case.py
coverage_summary ¶
Return per-standard counts of clause conformance statuses.
Returns¶
dict[str, dict[str, int]]
Maps each standard to addressed / partially_addressed /
not_addressed / total counts.
Source code in src/scpn_phase_orchestrator/assurance/case.py
to_audit_record ¶
Return a JSON-safe bundle record.
Returns¶
dict[str, object] A JSON-safe bundle record.
Source code in src/scpn_phase_orchestrator/assurance/case.py
Functions:¶
build_assurance_case_bundle ¶
build_assurance_case_bundle(
system_name: str,
evidence: Sequence[EvidenceItem],
*,
version: str = "1.0.0",
) -> AssuranceCaseBundle
Assemble an assurance-case bundle from collected evidence.
Each catalogued clause is mapped to the evidence addressing it via
:data:DEFAULT_EVIDENCE_CLAUSE_MAP; clauses with no contributing evidence
are recorded as not_addressed so gaps are explicit.
Parameters¶
system_name:
Name of the system the bundle describes.
evidence:
The evidence items to include (unique evidence_id).
version:
Bundle instance version.
Returns¶
AssuranceCaseBundle The sealed bundle.
Raises¶
ValueError
If evidence_id values are not unique.
Source code in src/scpn_phase_orchestrator/assurance/case.py
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.
certification ¶
Assemble review packages from assurance-case evidence bundles.
The package writer is deliberately narrow: it wraps the existing assurance-case bundle with deterministic hash test vectors and a manifest that seals every emitted file. The output is a technical evidence package for human review, not a certification claim or live actuation gate.
Classes¶
CertificationEvidencePackage
dataclass
¶
CertificationEvidencePackage(
assurance_bundle: AssuranceCaseBundle,
test_vectors: Mapping[str, object],
manifest: Mapping[str, object],
file_contents: Mapping[str, bytes],
)
A deterministic standards-shaped review package.
Parameters¶
assurance_bundle:
The underlying hash-sealed assurance-case bundle.
test_vectors:
JSON-safe deterministic vectors that let reviewers recompute evidence
hashes and clause-conformance rationale hashes.
manifest:
JSON-safe package manifest containing file digests and package digest.
file_contents:
Mapping from relative package paths to deterministic file bytes. Text
artefacts are UTF-8 encoded; conformity_report.pdf is raw PDF bytes.
Functions:¶
build_certification_evidence_package ¶
build_certification_evidence_package(
system_name: str,
evidence: Sequence[EvidenceItem],
*,
version: str = "1.0.0",
) -> CertificationEvidencePackage
Build a deterministic review package from assurance evidence.
Parameters¶
system_name: Name of the reviewed system. evidence: Assurance evidence items to include. version: Package schema instance version.
Returns¶
CertificationEvidencePackage The assembled package with deterministic file bytes (JSON, Markdown, and the rendered conformity-report PDF).
Source code in src/scpn_phase_orchestrator/assurance/certification.py
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | |
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.
envelope ¶
Bind a certification package to the run that produced it, optionally PQC-signed.
A :class:~scpn_phase_orchestrator.assurance.certification.CertificationEvidencePackage
is hash-sealed but free-floating: its package_hash proves the package's own
contents are consistent, yet nothing ties it to the specific run whose evidence
it carries. This module adds that outer binding.
A :class:SignedCertificationEnvelope commits, in one deterministic record, to:
- the package's
package_hash(which run-evidence the package describes); - the audit-chain tip of the run — the SHA-256 commitment to the whole audit
log (
_hashof the last record), so the envelope is anchored to a specific, tamper-evident execution that can be replayed and re-verified; and - an optional post-quantum seal over that tip
(:class:
~scpn_phase_orchestrator.runtime.audit_pqc.AuditChainSeal, ML-DSA / FIPS 204), making the binding publicly verifiable long after the run.
The envelope reuses the audit seal verbatim — the seal genuinely commits to an
audit-chain tip under its own domain, so there is no cross-protocol confusion: the
envelope merely records that the package describes that sealed run. It performs
no signing or log reading itself (the CLI layer reads the tip and produces the seal
with a signing key); it validates the pieces, requires any attached seal to commit
to the same tip and record count, and seals the binding with a deterministic
envelope_hash. Verification re-derives the hash, checks the package binding, and
— when a seal is present — verifies it against a trusted public key.
Classes¶
SignedCertificationEnvelope
dataclass
¶
SignedCertificationEnvelope(
package_hash: str,
audit_chain_tip: str,
audit_record_count: int,
seal: Mapping[str, str | int] | None,
envelope_hash: str = "",
)
A deterministic binding of a certification package to its run.
Attributes¶
package_hash:
The package_hash of the bound certification package (SHA-256 hex).
audit_chain_tip:
The run's audit-chain tip — _hash of the last audit record, the
SHA-256 commitment to the whole log (32-byte digest, hex).
audit_record_count:
The number of records in the sealed audit chain.
seal:
The post-quantum seal over the tip as a JSON-safe mapping
(:meth:~scpn_phase_orchestrator.runtime.audit_pqc.AuditChainSeal.to_dict),
or None for an unsigned (anchor-only) envelope.
envelope_hash:
SHA-256 over the canonical serialisation of the schema, package hash,
audit tip, record count, and seal. Defaults to the computed hash; an
explicit mismatching value is rejected.
Methods:¶
__post_init__ ¶
Validate the fields and compute or check the sealing envelope_hash.
Source code in src/scpn_phase_orchestrator/assurance/envelope.py
to_record ¶
Return a JSON-safe record of the envelope.
Returns¶
dict[str, object]
The schema tag, package hash, audit anchor, optional seal, and the
sealing envelope_hash.
Source code in src/scpn_phase_orchestrator/assurance/envelope.py
Functions:¶
build_signed_certification_envelope ¶
build_signed_certification_envelope(
package_hash: str,
audit_chain_tip: str,
audit_record_count: int,
*,
seal: AuditChainSeal | None = None,
) -> SignedCertificationEnvelope
Bind a certification package hash to a run's audit-chain tip.
Parameters¶
package_hash:
The package_hash of the certification package to anchor (SHA-256 hex).
audit_chain_tip:
The run's audit-chain tip hash (32-byte SHA-256 digest, hex).
audit_record_count:
The number of records in the sealed audit chain.
seal:
An optional post-quantum seal over the same tip. When given, it must
commit to audit_chain_tip and audit_record_count.
Returns¶
SignedCertificationEnvelope The deterministic, optionally signed binding.
Raises¶
ValueError If a field is malformed or a supplied seal commits to a different tip or record count than the anchor.
Source code in src/scpn_phase_orchestrator/assurance/envelope.py
verify_signed_certification_envelope ¶
verify_signed_certification_envelope(
envelope: SignedCertificationEnvelope,
*,
package_hash: str,
trusted_public_key_hex: str | None = None,
) -> bool
Verify an envelope binds a package and, if signed, carries a valid seal.
Parameters¶
envelope:
The envelope to verify.
package_hash:
The package_hash of the package the envelope is expected to bind. The
envelope is rejected if it anchors a different package.
trusted_public_key_hex:
The hex-encoded raw ML-DSA public key the verifier trusts. Required when
the envelope carries a seal; ignored for an anchor-only envelope.
Returns¶
bool
True only if the envelope hash re-derives, the bound package hash
matches, and any attached seal verifies under the trusted key for the
anchored tip. False otherwise (including a sealed envelope verified
without a trusted key).
Source code in src/scpn_phase_orchestrator/assurance/envelope.py
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.
provenance ¶
Build a deterministic SLSA v1 provenance statement for released artefacts.
The audit-chain seal (:mod:scpn_phase_orchestrator.runtime.audit_pqc) and the
certification envelope (:mod:scpn_phase_orchestrator.assurance.envelope) both
attest to a run: what the software did once it executed. This module attests to
the build: which artefacts were produced, from which resolved inputs, by which
builder. That is the supply-chain provenance a downstream consumer needs to answer
"is this wheel the one that came out of the declared build, and nothing else?".
The output is an in-toto Statement v1
<https://in-toto.io/Statement/v1> carrying a SLSA provenance v1
<https://slsa.dev/provenance/v1> predicate:
subject— the produced artefacts, each pinned by SHA-256 digest;predicate.buildDefinition— the build type, the external parameters that drove it, optional internal parameters, and the resolved dependencies (source commit, toolchain), each itself digest-pinned;predicate.runDetails— the builder identity and the invocation metadata.
Everything is derived from caller-supplied values only — there are no wall-clock
reads, environment probes, or network calls — so the same build inputs always
serialise to the same statement and the same :func:provenance_statement_hash.
Signing lives in :mod:scpn_phase_orchestrator.assurance.dsse; this module produces
the payload that gets signed. The statement makes no live-actuation or conformity
claim: it is a factual record of a build, meeting the content obligation of SLSA
Build Level 2 (signed provenance describing the build), with the signing and
provenance-generation obligations met by the DSSE layer and the hosting build
service respectively.
Classes¶
ArtifactSubject
dataclass
¶
A produced artefact pinned by its SHA-256 digest.
Attributes¶
name: The artefact name (e.g. the wheel filename), non-empty. sha256: The artefact's SHA-256 digest, lowercase hex (64 characters).
ResourceDescriptor
dataclass
¶
A resolved build input pinned by digest (source commit, toolchain, dependency).
Attributes¶
uri:
The resource locator (e.g. git+https://…@<commit> or a package URL),
non-empty.
sha256:
The resource's SHA-256 digest, lowercase hex (64 characters).
name:
An optional human-readable name; the empty string omits it from the output.
Methods:¶
__post_init__ ¶
Validate the resource locator and digest.
to_dict ¶
Return the in-toto resource-descriptor mapping.
Returns¶
dict[str, object]
The uri + digest.sha256 mapping, carrying name when set.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
BuildDefinition
dataclass
¶
BuildDefinition(
build_type: str,
external_parameters: Mapping[str, object],
internal_parameters: Mapping[str, object] = dict(),
resolved_dependencies: tuple[
ResourceDescriptor, ...
] = (),
)
The reproducible definition of how the artefacts were built.
Attributes¶
build_type: A URI naming the build type / recipe convention, non-empty. external_parameters: The externally supplied parameters that fully drove the build (JSON object). internal_parameters: Builder-internal parameters, defaulting to an empty object. resolved_dependencies: The digest-pinned inputs the build resolved (source, toolchain, deps).
Methods:¶
__post_init__ ¶
Validate the build type and parameter blocks.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
to_dict ¶
Return the SLSA buildDefinition mapping.
resolvedDependencies is sorted by (uri, name) so the same set of
inputs always serialises identically. internalParameters is omitted when
empty to keep the statement minimal.
Returns¶
dict[str, object]
The buildType / externalParameters / resolvedDependencies
mapping, carrying internalParameters when non-empty.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
RunDetails
dataclass
¶
RunDetails(
builder_id: str,
invocation_id: str,
started_on: str = "",
finished_on: str = "",
builder_version: Mapping[str, str] = dict(),
builder_dependencies: tuple[
ResourceDescriptor, ...
] = (),
byproducts: tuple[ResourceDescriptor, ...] = (),
)
The identity of the builder and the invocation that produced the artefacts.
Attributes¶
builder_id:
A URI identifying the build platform / builder, non-empty.
invocation_id:
A stable identifier for this build invocation, non-empty.
started_on:
Optional RFC 3339 build-start timestamp; the empty string omits it. Supplied
by the caller (never read from the wall clock) to preserve determinism.
finished_on:
Optional RFC 3339 build-finish timestamp; the empty string omits it.
builder_version:
Optional str-to-str map of the builder's own component versions
(e.g. the runner image and toolchain versions); omitted when empty.
builder_dependencies:
The builder's own digest-pinned dependencies — the actions, images, and
toolchains the build platform itself resolved, distinct from the sources the
build consumed. Omitted when empty.
byproducts:
Digest-pinned artefacts the build produced that are not release subjects —
the SBOM, build logs, or intermediate manifests. Omitted when empty.
Methods:¶
__post_init__ ¶
Validate the builder identity, invocation id, and version map.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
to_dict ¶
Return the SLSA runDetails mapping.
The builder block always carries its id and adds version and
builderDependencies only when supplied. The metadata block always
carries invocationId and adds startedOn / finishedOn only when
the caller supplied them. byproducts is added to runDetails only when
non-empty, so a statement without them is byte-identical to the prior format.
Returns¶
dict[str, object]
The builder + metadata mapping, carrying byproducts when
non-empty.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
SlsaProvenanceStatement
dataclass
¶
SlsaProvenanceStatement(
subjects: tuple[ArtifactSubject, ...],
build_definition: BuildDefinition,
run_details: RunDetails,
)
A complete in-toto Statement v1 carrying a SLSA provenance v1 predicate.
Attributes¶
subjects: The produced artefacts, each digest-pinned; must be non-empty. build_definition: How the artefacts were built. run_details: Who built them and under which invocation.
Methods:¶
__post_init__ ¶
Reject an empty subject list; the sub-objects self-validate.
to_statement ¶
Return the JSON-safe in-toto Statement.
subject is sorted by artefact name so a given set of artefacts always
serialises identically.
Returns¶
dict[str, object]
The _type / subject / predicateType / predicate mapping,
ready to canonicalise, hash, and wrap in a DSSE envelope.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
Functions:¶
build_slsa_provenance_statement ¶
build_slsa_provenance_statement(
subjects: tuple[ArtifactSubject, ...],
build_definition: BuildDefinition,
run_details: RunDetails,
) -> SlsaProvenanceStatement
Assemble a validated SLSA provenance statement.
Parameters¶
subjects: The produced artefacts (non-empty), each digest-pinned. build_definition: The reproducible build definition. run_details: The builder identity and invocation metadata.
Returns¶
SlsaProvenanceStatement The validated statement.
Raises¶
ValueError If the subject list is empty or any field is malformed.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
pypi_resolved_dependency ¶
Return a digest-pinned resolved dependency for a PyPI package.
Turns one hash-pinned lock-file entry into a :class:ResourceDescriptor whose
uri is a Package URL <https://github.com/package-url/purl-spec>_
(pkg:pypi/<name>@<version>). The package name is normalised to the PyPI form
(lowercased, runs of ./-/_ collapsed to a single -, per PEP 503)
for the URL, while the original name is preserved in the descriptor name so
the resolved-dependency tree records exactly what the lock pinned. Assembling one
descriptor per pinned artefact yields the fuller resolvedDependencies block a
consumer needs to reproduce the build's inputs.
Parameters¶
name: The package name as written in the lock file, non-empty. version: The pinned package version, non-empty. sha256: The pinned artefact's SHA-256 digest, lowercase hex (64 characters).
Returns¶
ResourceDescriptor
The digest-pinned dependency, ready to include in a
:class:BuildDefinition.
Raises¶
ValueError If the name or version is empty, or the digest is malformed.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
provenance_statement_hash ¶
Return the canonical SHA-256 digest of a provenance statement.
Parameters¶
statement: The statement to hash.
Returns¶
str Lowercase hexadecimal SHA-256 over the canonical statement JSON.
Source code in src/scpn_phase_orchestrator/assurance/provenance.py
dsse ¶
Wrap a SLSA provenance statement in a post-quantum-signed DSSE envelope.
DSSE <https://github.com/secure-systems-lab/dsse> (Dead Simple Signing
Envelope) is the wire format sigstore/cosign <https://docs.sigstore.dev> produces
for cosign attest and consumes for cosign verify-attestation: a base64
payload, its payloadType, and a list of signatures over the DSSE
pre-authentication encoding (PAE) of the payload. Signing the PAE — rather than the
raw JSON — is what makes the signature bind the payload type as well as the bytes, so
an attestation cannot be re-labelled as a different document type.
This module carries the SLSA provenance statement from
:mod:scpn_phase_orchestrator.assurance.provenance as the DSSE payload
(payloadType application/vnd.in-toto+json) and signs the PAE with ML-DSA
(FIPS 204), reusing the single post-quantum primitive in
:mod: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 will be
added once the cryptography backend ships it (it does not as of the pinned
version, so no SLH-DSA claim is made here).
The envelope is deterministic and offline: it holds no timestamps and makes no
network call. Verification is self-contained — the verifier supplies the trusted
public key, whose short id must match the signature keyid — so an attestation can
be checked long after the build and against a future quantum adversary. Pushing the
same envelope to a Rekor transparency log or verifying it with cosign is an
optional operator step that needs network and OIDC, and is therefore out of this
deterministic core.
Classes¶
DsseSignature
dataclass
¶
One signature over a DSSE envelope's pre-authentication encoding.
Attributes¶
keyid:
Short identifier of the signing public key (SHA-256 prefix), matching
:func:~scpn_phase_orchestrator.runtime.audit_pqc.public_key_id.
algorithm:
The signature scheme (an ML-DSA variant), recorded so a second scheme can
be added without ambiguity.
signature_b64:
The raw signature, standard-base64 encoded.
Methods:¶
__post_init__ ¶
Validate the algorithm and that the signature is decodable base64.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
to_dict ¶
Return the DSSE signature mapping (keyid / algorithm / sig).
Returns¶
dict[str, str]
The keyid / algorithm / sig wire mapping.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
from_dict
classmethod
¶
Return a signature parsed from a DSSE signature mapping.
Parameters¶
data:
A mapping carrying keyid, algorithm, and sig.
Returns¶
DsseSignature The reconstructed signature.
Raises¶
ValueError If a required field is missing or malformed.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
DsseEnvelope
dataclass
¶
A DSSE v1 envelope carrying a base64 payload and its signatures.
Attributes¶
payload_b64:
The statement JSON, standard-base64 encoded.
payload_type:
The payload media type (application/vnd.in-toto+json).
signatures:
The signatures over the payload's pre-authentication encoding.
Methods:¶
__post_init__ ¶
Validate a decodable base64 payload and at least one signature.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
payload_bytes ¶
Return the decoded payload bytes.
Returns¶
bytes The base64-decoded payload (the canonical statement JSON bytes).
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
statement ¶
Return the wrapped in-toto statement as a mapping.
Returns¶
dict[str, object] The decoded, JSON-parsed statement.
Raises¶
ValueError If the payload is not valid JSON object bytes.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
to_dict ¶
Return the DSSE wire mapping (payload / payloadType / signatures).
Returns¶
dict[str, object]
The payload / payloadType / signatures wire mapping.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
from_dict
classmethod
¶
Return an envelope parsed from a DSSE wire mapping.
Parameters¶
data:
A mapping carrying payload, payloadType, and signatures.
Returns¶
DsseEnvelope The reconstructed envelope.
Raises¶
ValueError If a required field is missing or the signatures are malformed.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
Functions:¶
sign_provenance_statement ¶
sign_provenance_statement(
statement: SlsaProvenanceStatement,
private_key: Any,
*,
algorithm: str = DEFAULT_VARIANT,
) -> DsseEnvelope
Wrap a provenance statement in a DSSE envelope and sign it with ML-DSA.
Parameters¶
statement:
The SLSA provenance statement to attest.
private_key:
An ML-DSA private key matching algorithm (see
:func:~scpn_phase_orchestrator.runtime.audit_pqc.signing_key_from_seed).
algorithm:
The ML-DSA variant; must match private_key.
Returns¶
DsseEnvelope The signed attestation envelope.
Raises¶
ValueError If the algorithm or private key is invalid.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
verify_dsse_envelope ¶
Verify that an envelope carries a valid signature under a trusted key.
The verifier supplies the public key it trusts; the envelope is accepted only if
a signature whose keyid matches that key verifies over the payload's
pre-authentication encoding. This binds the attestation to a known signer, so a
forged envelope signed under a different key is rejected.
Parameters¶
envelope: The DSSE envelope to verify. trusted_public_key_hex: The hex-encoded raw ML-DSA public key the verifier trusts.
Returns¶
bool
True if a matching signature verifies, else False.
Raises¶
ValueError If the trusted key is not a hex string.
Source code in src/scpn_phase_orchestrator/assurance/dsse.py
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.
report ¶
Render an assurance-case bundle as a human-readable conformity report.
The certification evidence package seals machine-readable JSON (the bundle, the hash test vectors, and a manifest). A regulatory assessor, however, reads a document: this module renders the same sealed evidence as a deterministic Markdown conformity report — a per-standard, clause-by-clause table of conformance status, contributing evidence, and rationale, prefixed by the coverage rollup and the regulatory disclaimer and anchored to the bundle hash for traceability.
The report is review-only and adds no new claims: every status, evidence
identifier, and rationale is read verbatim from the
:class:~scpn_phase_orchestrator.assurance.case.AssuranceCaseBundle. Rendering is
deterministic — standards, clauses, and evidence are emitted in a stable sort
order so the report digest is reproducible.
Classes¶
Functions:¶
render_conformity_report ¶
Render an assurance-case bundle as a Markdown conformity report.
The report restates the bundle verbatim — coverage rollup, per-standard
clause conformance (status, contributing evidence, rationale), and the
evidence inventory — under the regulatory disclaimer and anchored to the
bundle hash. It adds no claim not already present in bundle and is
review-only. Rendering is deterministic for a given bundle.
Parameters¶
bundle: The hash-sealed assurance-case bundle to render.
Returns¶
str The Markdown conformity report, terminated by a single newline.
Source code in src/scpn_phase_orchestrator/assurance/report.py
render_conformity_report_pdf ¶
Render the conformity report as a deterministic, dependency-free PDF.
Produces the same content as :func:render_conformity_report in a minimal
single-font text PDF — the distributable artefact an assessor files. The
bytes carry no timestamp and are reproducible for a given bundle. The text
PDF renderer is imported lazily so importing this module stays light.
Parameters¶
bundle: The hash-sealed assurance-case bundle to render.
Returns¶
bytes The rendered conformity report PDF.
Source code in src/scpn_phase_orchestrator/assurance/report.py
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.
prc_oscillation ¶
NERC PRC oscillation-monitoring compliance evidence from detected modes.
This is the audit-package end of the dVOC grid pack. The matrix-pencil estimator
(:mod:~scpn_phase_orchestrator.monitor.oscillation_modes) detects the
electromechanical modes of a ringdown and their damping ratios;
:func:screen_oscillation_modes screens those damping ratios for NERC
PRC-028-1 disturbance-data analysis and PRC-030-1 unexpected IBR event mitigation
workflows: a mode whose damping ratio sits below a few percent is poorly damped,
and a mode with non-positive damping is undamped (growing). The screening also
preserves an engineering mode-family label for each finding, so inter-area and
sub-synchronous signals stay visible in the hash-sealed, review-only
:class:PRCOscillationEvidence record.
The record is content-addressed with the same canonical-JSON SHA-256 hashing the assurance-case bundle uses, so it can be referenced by a stable digest and any later mutation is detectable. The capture timestamp is supplied by the caller (it is the measurement time of the PMU/ringdown event, not a wall-clock reading taken here) so the record is deterministic and reproducible.
This is a technical evidence-mapping aid, not a legal conformity assessment: it
links measured modal damping to the disturbance-monitoring and unexpected-event
mitigation workflows those standards support. The exact identifiers, thresholds,
and reporting obligations must be confirmed against the issued standards — see
:data:PRC_OSCILLATION_DISCLAIMER. The screening is review-only: it reads
detected modes and reports findings; it never changes bindings, layers, or
coupling.
References¶
- NERC PRC-028-1 (disturbance monitoring and reporting for inverter-based resources) and PRC-030-1 (unexpected inverter-based resource event mitigation), developed under FERC Order 901.
Classes¶
PRCModeFinding
dataclass
¶
PRCModeFinding(
mode_index: int,
frequency_hz: float,
damping_ratio: float,
amplitude: float,
mode_family: str,
classification: str,
flagged: bool,
)
The screening outcome for a single detected mode.
Attributes¶
mode_index : int
Position of the mode in the screened sequence.
frequency_hz : float
Modal oscillation frequency in hertz.
damping_ratio : float
Dimensionless damping ratio of the mode.
amplitude : float
Modal amplitude in the units of the source signal.
mode_family : str
Engineering oscillation family such as inter_area or
sub_synchronous.
classification : str
One of :data:UNDAMPED, :data:POORLY_DAMPED, or :data:ACCEPTABLE.
flagged : bool
Whether the mode breaches a screening threshold (undamped or poorly
damped).
Methods:¶
to_audit_record ¶
Return a JSON-safe mapping of the finding.
Returns¶
dict[str, object] The mode index, frequency, damping ratio, amplitude, classification, and flagged status.
Source code in src/scpn_phase_orchestrator/assurance/prc_oscillation.py
PRCOscillationEvidence
dataclass
¶
PRCOscillationEvidence(
event_id: str,
captured_at: str,
signal_source: str,
sampling_rate_hz: float,
poorly_damped_threshold: float,
undamped_threshold: float,
findings: tuple[PRCModeFinding, ...],
mode_family_counts: Mapping[str, int],
flagged_count: int,
worst_damping_ratio: float | None,
verdict: str,
standard: str,
disclaimer: str,
)
A hash-sealed oscillation-monitoring compliance-evidence record.
Attributes¶
event_id : str
Caller-assigned identifier for the oscillation event.
captured_at : str
Measurement timestamp of the event, supplied by the caller.
signal_source : str
Identifier of the screened signal (a bus, tie-line, or order parameter).
sampling_rate_hz : float
Sampling rate of the ringdown the modes were estimated from.
poorly_damped_threshold : float
Damping ratio below which a positively-damped mode is flagged.
undamped_threshold : float
Damping ratio at or below which a mode is flagged undamped (growing).
findings : tuple[PRCModeFinding, ...]
Per-mode screening outcomes, in the order screened.
mode_family_counts : Mapping[str, int]
Read-only number of screened modes by engineering family.
flagged_count : int
Number of findings flagged for review.
worst_damping_ratio : float | None
Lowest damping ratio across the findings, or None when no modes were
detected.
verdict : str
:data:FLAGGED_FOR_REVIEW if any mode is flagged, else
:data:NO_EXCEEDANCE.
standard : str
The standard family the record is mapped to.
disclaimer : str
The review-only regulatory disclaimer.
content_hash : str
SHA-256 of the canonical record (excluding this field); computed on
construction.
Methods:¶
__post_init__ ¶
Compute the content hash from the canonical evidence payload.
Source code in src/scpn_phase_orchestrator/assurance/prc_oscillation.py
Functions:¶
screen_oscillation_modes ¶
screen_oscillation_modes(
modes: Sequence[OscillationMode],
*,
event_id: str,
captured_at: str,
signal_source: str,
sampling_rate_hz: float,
poorly_damped_threshold: float = DEFAULT_DAMPING_THRESHOLD,
undamped_threshold: float = 0.0,
) -> PRCOscillationEvidence
Screen detected oscillation modes into a PRC compliance-evidence record.
Parameters¶
modes : Sequence[OscillationMode]
Modes recovered from a ringdown, e.g. by
:func:~scpn_phase_orchestrator.monitor.oscillation_modes.estimate_oscillation_modes.
event_id : str
Caller-assigned identifier for the oscillation event.
captured_at : str
Measurement timestamp of the event, supplied by the caller.
signal_source : str
Identifier of the screened signal.
sampling_rate_hz : float
Sampling rate of the ringdown, in hertz (> 0).
poorly_damped_threshold : float
Damping ratio below which a positively-damped mode is flagged poorly
damped.
undamped_threshold : float
Damping ratio at or below which a mode is flagged undamped; must be below
poorly_damped_threshold.
Returns¶
PRCOscillationEvidence The hash-sealed, review-only screening record.
Raises¶
ValueError
If an identifier is empty, the sampling rate is not positive, the
thresholds are not ordered finite reals, or an element is not an
:class:~scpn_phase_orchestrator.monitor.oscillation_modes.OscillationMode.
Source code in src/scpn_phase_orchestrator/assurance/prc_oscillation.py
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.
prc_ride_through ¶
Review-only NERC PRC-029 ride-through evidence screening.
This module maps operator-provided high-side transformer voltage and frequency time series into deterministic, hash-sealed evidence for NERC PRC-029-1 review. It implements the published Attachment 1 voltage ride-through tables for AC-connected wind IBRs and all other IBRs, plus the Attachment 2 frequency ride-through table, then records only technical screening findings. It does not assert conformance, evaluate real/reactive-current performance, apply hardware limitation exemptions, or replace qualified assessor review.
Classes¶
PRCRideThroughFinding
dataclass
¶
PRCRideThroughFinding(
channel: str,
band: str,
operation_region: str,
start_s: float,
end_s: float,
duration_s: float,
window_duration_s: float,
observed_min: float,
observed_max: float,
minimum_ride_through_s: float | None,
window_s: float | None,
classification: str,
flagged: bool,
)
One aggregated PRC-029 voltage or frequency ride-through observation.
Attributes¶
channel : str
"voltage" or "frequency".
band : str
Deterministic threshold-band identifier.
operation_region : str
Operation-region class from the PRC-029 ride-through tables.
start_s, end_s : float
First and last time covered by the aggregate observation.
duration_s : float
Total observed duration in the band across the trace.
window_duration_s : float
Maximum cumulative duration inside the relevant PRC-029 assessment
window.
observed_min, observed_max : float
Minimum and maximum observed measurement values inside the band.
minimum_ride_through_s : float | None
Published minimum ride-through duration for the band, or None for
may-trip zones.
window_s : float | None
Assessment window used for cumulative-duration screening.
classification : str
Screening classification. This is review language, not a legal verdict.
flagged : bool
Whether the observation needs qualified assessor review.
Methods:¶
to_audit_record ¶
Return a JSON-safe mapping of the finding.
Returns¶
dict[str, object] Stable audit fields for one ride-through observation.
Source code in src/scpn_phase_orchestrator/assurance/prc_ride_through.py
PRCRideThroughEvidence
dataclass
¶
PRCRideThroughEvidence(
event_id: str,
captured_at: str,
signal_source: str,
ibr_category: str,
sample_count: int,
duration_s: float,
findings: tuple[PRCRideThroughFinding, ...],
channel_counts: Mapping[str, int],
flagged_count: int,
verdict: str,
standard: str,
disclaimer: str,
)
Hash-sealed PRC-029 ride-through screening evidence.
Attributes¶
event_id : str
Caller-assigned event identifier.
captured_at : str
Measurement timestamp supplied by the caller.
signal_source : str
Operator-facing source label.
ibr_category : str
PRC-029 voltage-table category: :data:AC_WIND_IBR or
:data:OTHER_IBR.
sample_count : int
Number of time-series samples consumed.
duration_s : float
Elapsed time from first to last sample.
findings : tuple[PRCRideThroughFinding, ...]
Aggregated voltage and frequency screening observations.
channel_counts : Mapping[str, int]
Read-only number of observations by channel.
flagged_count : int
Number of observations that require qualified review.
verdict : str
Review-only verdict string.
standard : str
Standard family the record is mapped to.
disclaimer : str
Review-only disclaimer.
content_hash : str
SHA-256 of the canonical record excluding this field.
Methods:¶
__post_init__ ¶
Freeze channel counts and compute the canonical content hash.
Source code in src/scpn_phase_orchestrator/assurance/prc_ride_through.py
Functions:¶
screen_ride_through_samples ¶
screen_ride_through_samples(
time_s: Sequence[object],
voltage_pu: Sequence[object],
frequency_hz: Sequence[object],
*,
event_id: str,
captured_at: str,
signal_source: str,
ibr_category: str = OTHER_IBR,
) -> PRCRideThroughEvidence
Screen voltage and frequency samples into PRC-029 review evidence.
Parameters¶
time_s : Sequence[object]
Monotonic sample times in seconds.
voltage_pu : Sequence[object]
Voltage measurements in per unit at the applicable PRC-029 measurement
point.
frequency_hz : Sequence[object]
Frequency measurements in hertz at the applicable PRC-029 measurement
point.
event_id : str
Caller-assigned event identifier.
captured_at : str
Measurement timestamp stamped into the evidence.
signal_source : str
Operator-facing source label.
ibr_category : str
Voltage ride-through table selector, either :data:AC_WIND_IBR or
:data:OTHER_IBR.
Returns¶
PRCRideThroughEvidence Deterministic, review-only PRC-029 screening evidence.
Raises¶
ValueError If identifiers, category, samples, or time ordering are invalid.
Source code in src/scpn_phase_orchestrator/assurance/prc_ride_through.py
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 | |
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_v1from the offline dVOC/Koopman-MPC damping screen;scpn_pmu_ringdown_prc_audit_v1from an operator PMU frequency ringdown CSV;scpn_ibr_ride_through_prc029_audit_v1from 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.
power_grid_prc_bundle ¶
Hash-sealed power-grid PRC assessor bundles.
The power-grid review lane emits several independent evidence records: the dVOC oscillation-damping audit, an operator PMU ringdown screen, and an IBR ride-through screen. This module binds those records into one deterministic, review-only handoff package. It verifies each child content hash before the bundle is sealed, so an assessor can detect both source-file mutation and evidence-record mutation.
Classes¶
PowerGridPRCInputArtifact
dataclass
¶
PowerGridPRCInputArtifact(
role: str,
source_name: str,
source_sha256: str,
record: Mapping[str, object],
)
A source evidence record prepared for bundle assembly.
Attributes¶
role : str
Required evidence role in the power-grid PRC bundle.
source_name : str
Operator-facing basename or label of the evidence JSON source.
source_sha256 : str
SHA-256 digest of the exact evidence JSON bytes consumed by the bundle
builder.
record : Mapping[str, object]
Parsed evidence record. Its own content_hash is rechecked before the
bundle is emitted.
PowerGridPRCArtifact
dataclass
¶
PowerGridPRCArtifact(
role: str,
source_name: str,
source_sha256: str,
evidence_schema: str,
evidence_hash: str,
record: Mapping[str, object],
)
A validated evidence artifact inside the assessor bundle.
Attributes¶
role : str
Required evidence role in the bundle.
source_name : str
Source evidence JSON basename or label.
source_sha256 : str
SHA-256 digest of the exact evidence JSON bytes consumed.
evidence_schema : str
Schema identifier in the child evidence record.
evidence_hash : str
Validated child content_hash.
record : Mapping[str, object]
Parsed child evidence record, preserved verbatim for assessor replay.
Methods:¶
to_audit_record ¶
Return a JSON-safe mapping of the artifact.
Returns¶
dict[str, object] Stable source metadata plus the preserved child evidence record.
Source code in src/scpn_phase_orchestrator/assurance/power_grid_prc_bundle.py
PowerGridPRCAuditBundle
dataclass
¶
PowerGridPRCAuditBundle(
schema: str,
bundle_id: str,
created_at: str,
operator_context: str,
artifacts: tuple[PowerGridPRCArtifact, ...],
evidence_hashes: Mapping[str, str],
claim_boundary: str = POWER_GRID_PRC_CLAIM_BOUNDARY,
review_only: bool = True,
disclaimer: str = POWER_GRID_PRC_AUDIT_BUNDLE_DISCLAIMER,
)
A hash-sealed power-grid PRC assessor handoff bundle.
Attributes¶
schema : str
Bundle schema identifier.
bundle_id : str
Operator-assigned bundle identifier.
created_at : str
Timestamp supplied by the caller.
operator_context : str
Human-readable review context for the assessor handoff.
artifacts : tuple[PowerGridPRCArtifact, ...]
Validated child artifacts in required role order.
evidence_hashes : Mapping[str, str]
Read-only map from role to child evidence hash.
claim_boundary : str
Review-only claim boundary.
review_only : bool
Always True for this bundle.
disclaimer : str
Regulatory and live-actuation disclaimer.
content_hash : str
SHA-256 of the canonical bundle payload excluding this field.
Methods:¶
__post_init__ ¶
Freeze hash maps and compute the canonical bundle digest.
Source code in src/scpn_phase_orchestrator/assurance/power_grid_prc_bundle.py
Functions:¶
build_power_grid_prc_audit_bundle ¶
build_power_grid_prc_audit_bundle(
*,
bundle_id: str,
created_at: str,
operator_context: str,
artifacts: Sequence[PowerGridPRCInputArtifact],
) -> PowerGridPRCAuditBundle
Build a deterministic power-grid PRC assessor handoff bundle.
Parameters¶
bundle_id : str Operator-assigned bundle identifier. created_at : str Timestamp supplied by the caller. operator_context : str Human-readable review context. artifacts : Sequence[PowerGridPRCInputArtifact] Candidate child evidence records with source-file digests.
Returns¶
PowerGridPRCAuditBundle Hash-sealed bundle containing exactly the required child roles.
Raises¶
ValueError If identifiers, source metadata, child schemas, child hashes, or the role set are invalid.
Source code in src/scpn_phase_orchestrator/assurance/power_grid_prc_bundle.py
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.
early_warning_evidence ¶
Hash-sealed, claim-bounded assurance evidence for an early-warning alarm.
The early-warning detector suite — critical slowing down
(:mod:~scpn_phase_orchestrator.monitor.critical_slowing_down), rising
synchronisation (:mod:~scpn_phase_orchestrator.monitor.synchronisation), and
ordinal-transition entropy (:mod:~scpn_phase_orchestrator.monitor.explosive_sync)
— reads a passive observable and emits a warning record. A fair head-to-head
(bench/early_warning_leadtime.py) established that the detection is a
commodity: none of these indicators beats the others by a decisive margin. What
is not a commodity, and what this module supplies, is the auditable envelope
around the alarm: 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 (this is a review-only technical
artefact, not a clinical/operational/safety decision or 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.
The record is content-addressed with the same canonical-JSON SHA-256 hashing the
assurance-case bundle and the NERC PRC oscillation evidence use
(:func:~scpn_phase_orchestrator.assurance._hashing.canonical_record_hash), so a
sealed alarm can be referenced by a stable digest and any later mutation is
detectable. The capture timestamp and the ground-truth onset are supplied by the
caller (they are properties of the measured event, not wall-clock readings taken
here) so the record is deterministic and reproducible.
:func:seal_early_warning is the neutral primitive — it depends only on the
alarm decision, the provenance, and a pre-extracted set of
:class:EarlyWarningIndicator contributions, so it seals any present or future
detector (including the real-EEG harness) without importing detector internals.
The three seal_*_alarm adapters bridge each concrete suite detector's warning
dataclass onto that primitive.
References¶
- Scheffer et al. 2009, Nature 461, 53 — generic early-warning signals for critical transitions (the framework the sealed indicators contribute to).
Classes¶
EarlyWarningIndicator
dataclass
¶
EarlyWarningIndicator(
name: str,
direction: str,
robust_z: float,
baseline_median: float,
z_threshold: float,
breached: bool,
)
A single indicator's contribution to an early-warning alarm.
Attributes¶
name : str
Indicator label, e.g. variance, lag1_autocorrelation,
order_parameter, or transition_entropy.
direction : str
:data:RISE if the indicator warns by rising above its baseline, or
:data:DROP if it warns by falling below it.
robust_z : float
Median / MAD robust z-score of the indicator at the reported window (the
alarm window if the detector triggered, else the closest approach among
the post-baseline windows).
baseline_median : float
Median of the indicator over the leading baseline windows.
z_threshold : float
Robust z-score magnitude at or beyond which the indicator breaches its
gate.
breached : bool
Whether robust_z crossed the gate in the indicator's alarm direction
at the reported window.
Methods:¶
to_audit_record ¶
Return a JSON-safe mapping of the indicator contribution.
Returns¶
dict[str, object] The indicator label, alarm direction, robust z-score, baseline median, gate threshold, and breach status.
Source code in src/scpn_phase_orchestrator/assurance/early_warning_evidence.py
EarlyWarningEvidence
dataclass
¶
EarlyWarningEvidence(
detector: str,
observable: str,
signal_source: str,
captured_at: str,
sampling_rate_hz: float,
window: int,
step: int,
persistence: int,
n_baseline_windows: int,
warning_triggered: bool,
warning_window: int | None,
warning_sample: int | None,
transition_onset_sample: int | None,
lead_samples: int | None,
lead_seconds: float | None,
lead_is_early: bool,
indicators: tuple[EarlyWarningIndicator, ...],
verdict: str,
framework: str,
disclaimer: str,
)
A hash-sealed, review-only early-warning assurance record.
Attributes¶
detector : str
Detector family label, e.g. critical_slowing_down,
synchronisation, or transition_entropy.
observable : str
The physical quantity the detector read (a bus-frequency variance, a
cross-channel order parameter, a per-channel phase field, ...).
signal_source : str
Provenance identifier of the screened signal (dataset, event, or channel
set).
captured_at : str
Measurement timestamp of the event, supplied by the caller.
sampling_rate_hz : float
Sampling rate of the screened signal, in hertz; converts a sample lead
into seconds.
window, step : int
Echoed analysis window length and hop, in samples.
persistence : int
Echoed number of consecutive breaching windows required to alarm.
n_baseline_windows : int
Number of leading windows the detector fitted its baseline on.
warning_triggered : bool
Whether the detector raised a sustained alarm.
warning_window : int | None
Index of the first window of the triggering run, or None.
warning_sample : int | None
Sample index of the triggering window, or None.
transition_onset_sample : int | None
Caller-supplied ground-truth onset sample, or None when unknown.
lead_samples : int | None
transition_onset_sample - warning_sample when both are known, else
None. Positive means an early alarm; non-positive means late or
coincident.
lead_seconds : float | None
lead_samples / sampling_rate_hz when defined, else None.
lead_is_early : bool
True only when the lead is defined and strictly positive.
indicators : tuple[EarlyWarningIndicator, ...]
Per-indicator contributions at the reported window.
verdict : str
:data:EARLY_WARNING_FLAGGED if the detector alarmed, else
:data:NO_EARLY_WARNING.
framework : str
The early-warning framework the record maps to.
disclaimer : str
The review-only claim boundary.
content_hash : str
SHA-256 of the canonical record (excluding this field); computed on
construction.
Methods:¶
__post_init__ ¶
Compute the content hash from the canonical evidence payload.
Functions:¶
seal_early_warning ¶
seal_early_warning(
*,
detector: str,
observable: str,
signal_source: str,
captured_at: str,
sampling_rate_hz: float,
window: int,
step: int,
persistence: int,
n_baseline_windows: int,
warning_triggered: bool,
warning_window: int | None,
warning_sample: int | None,
indicators: Sequence[EarlyWarningIndicator],
transition_onset_sample: int | None = None,
) -> EarlyWarningEvidence
Seal an early-warning alarm into a hash-addressed evidence record.
This is the neutral primitive: it depends only on the alarm decision, the provenance, and a pre-extracted set of indicator contributions, so it seals any detector without importing its internals.
Parameters¶
detector : str
Detector family label.
observable : str
The physical quantity the detector read.
signal_source : str
Provenance identifier of the screened signal.
captured_at : str
Measurement timestamp of the event, supplied by the caller.
sampling_rate_hz : float
Sampling rate of the screened signal, in hertz (> 0).
window, step, persistence : int
Echoed analysis parameters; each must be a positive integer.
n_baseline_windows : int
Number of leading windows the detector fitted its baseline on; must be a
positive integer.
warning_triggered : bool
Whether the detector raised a sustained alarm.
warning_window, warning_sample : int | None
Triggering window and sample indices; both must be present when
warning_triggered is true and absent otherwise.
indicators : Sequence[EarlyWarningIndicator]
At least one indicator contribution; each direction must be
:data:RISE or :data:DROP and each numeric field finite.
transition_onset_sample : int | None
Caller-supplied ground-truth onset sample; enables the lead computation.
Returns¶
EarlyWarningEvidence The hash-sealed, review-only early-warning record.
Raises¶
ValueError If an identifier is empty, a count is not a positive integer, a sample index is negative, the alarm flags are inconsistent, the indicators are empty or malformed, or the sampling rate is not positive.
Source code in src/scpn_phase_orchestrator/assurance/early_warning_evidence.py
286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | |
seal_critical_slowing_down_alarm ¶
seal_critical_slowing_down_alarm(
warning: CriticalSlowingDownWarning,
*,
observable: str,
signal_source: str,
captured_at: str,
sampling_rate_hz: float,
transition_onset_sample: int | None = None,
detector: str = "critical_slowing_down",
) -> EarlyWarningEvidence
Seal a critical-slowing-down alarm, pinning both rising indicators.
The record carries the variance and lag-one autocorrelation contributions — the two second-moment indicators of critical slowing down — at the reported window, so an auditor sees which indicator carried the alarm.
Parameters¶
warning : CriticalSlowingDownWarning
The detector output to seal.
observable, signal_source, captured_at : str
Provenance of the screened signal, forwarded to :func:seal_early_warning.
sampling_rate_hz : float
Sampling rate of the screened signal, in hertz.
transition_onset_sample : int | None
Caller-supplied ground-truth onset sample.
detector : str
Detector family label to seal; defaults to critical_slowing_down.
Pass critical_slowing_down_multiscale when sealing the multi-scale
variant so audit records distinguish the two.
Returns¶
EarlyWarningEvidence The sealed record for the critical-slowing-down alarm.
Raises¶
ValueError
If warning is not a
:class:~scpn_phase_orchestrator.monitor.critical_slowing_down.CriticalSlowingDownWarning
or the forwarded provenance is invalid.
Source code in src/scpn_phase_orchestrator/assurance/early_warning_evidence.py
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | |
seal_synchronisation_alarm ¶
seal_synchronisation_alarm(
warning: SynchronisationWarning,
*,
observable: str,
signal_source: str,
captured_at: str,
sampling_rate_hz: float,
transition_onset_sample: int | None = None,
) -> EarlyWarningEvidence
Seal a rising-synchronisation alarm on the Kuramoto order parameter.
Parameters¶
warning : SynchronisationWarning
The detector output to seal.
observable, signal_source, captured_at : str
Provenance of the screened signal, forwarded to :func:seal_early_warning.
sampling_rate_hz : float
Sampling rate of the screened signal, in hertz.
transition_onset_sample : int | None
Caller-supplied ground-truth onset sample.
Returns¶
EarlyWarningEvidence The sealed record for the synchronisation alarm.
Raises¶
ValueError
If warning is not a
:class:~scpn_phase_orchestrator.monitor.synchronisation.SynchronisationWarning
or the forwarded provenance is invalid.
Source code in src/scpn_phase_orchestrator/assurance/early_warning_evidence.py
seal_transition_entropy_alarm ¶
seal_transition_entropy_alarm(
warning: ExplosiveSyncWarning,
*,
observable: str,
signal_source: str,
captured_at: str,
sampling_rate_hz: float,
transition_onset_sample: int | None = None,
) -> EarlyWarningEvidence
Seal an ordinal-transition-entropy alarm (a regularisation drop).
Parameters¶
warning : ExplosiveSyncWarning
The detector output to seal.
observable, signal_source, captured_at : str
Provenance of the screened signal, forwarded to :func:seal_early_warning.
sampling_rate_hz : float
Sampling rate of the screened signal, in hertz.
transition_onset_sample : int | None
Caller-supplied ground-truth onset sample.
Returns¶
EarlyWarningEvidence The sealed record for the transition-entropy alarm.
Raises¶
ValueError
If warning is not an
:class:~scpn_phase_orchestrator.monitor.explosive_sync.ExplosiveSyncWarning
or the forwarded provenance is invalid.
Source code in src/scpn_phase_orchestrator/assurance/early_warning_evidence.py
seal_ensemble_alarm ¶
seal_ensemble_alarm(
ensemble: EnsembleWarning,
*,
observable: str,
signal_source: str,
captured_at: str,
sampling_rate_hz: float,
window: int,
step: int,
transition_onset_sample: int | None = None,
) -> EarlyWarningEvidence
Seal a fused ensemble alarm, pinning every member's contribution.
Each fused member becomes an indicator carrying its native robust z-score at
the reported window, so an auditor sees exactly which detectors drove — or
failed to drive — the fused decision. The suite is run on one window grid, so
window and step are supplied by the caller that ran it.
Parameters¶
ensemble : EnsembleWarning
The fused decision to seal.
observable, signal_source, captured_at : str
Provenance of the screened signal, forwarded to :func:seal_early_warning.
sampling_rate_hz : float
Sampling rate of the screened signal, in hertz.
window, step : int
Analysis window length and hop the suite was run with.
transition_onset_sample : int | None
Caller-supplied ground-truth onset sample.
Returns¶
EarlyWarningEvidence The sealed record for the fused ensemble alarm.
Raises¶
ValueError
If ensemble is not an
:class:~scpn_phase_orchestrator.monitor.ensemble_warning.EnsembleWarning
or the forwarded provenance is invalid.
Source code in src/scpn_phase_orchestrator/assurance/early_warning_evidence.py
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.
grid_early_warning_advisory ¶
A hash-sealed, review-only operator advisory for a live grid instability alarm.
This is the step from a live alarm to a decision surface — the pinnacle the streaming
monitor was built toward — done honestly. When the certified streaming monitor
(:class:~scpn_phase_orchestrator.monitor.grid_modal_stream.GridModalStreamMonitor)
raises a :class:~scpn_phase_orchestrator.monitor.grid_modal_stream.StreamAlarm, this
module turns it into a claim-bounded advisory record an operator can read: 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 same fail-closed stance the STL
runtime actuation gate takes. It exists to inform a human decision, not to make one.
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 —
critically — the absence of an advisory is not evidence of stability.
The record is content-addressed with the same canonical-JSON SHA-256 seal the
early-warning evidence, the assurance-case bundle, and the NERC PRC oscillation evidence
use (:func:~scpn_phase_orchestrator.assurance._hashing.canonical_record_hash). The
capture timestamp and any ground-truth onset are supplied by the caller (they are
properties of the measured event, not wall-clock readings taken here), so the record is
deterministic and reproducible; a reported lead is honest, including a non-positive lead
when the alarm was coincident with or later than the onset.
:func:seal_grid_early_warning_advisory is the neutral primitive;
:func:advise_from_stream_alarm is the thin adapter that reads the alarm claims and the
certified operating point straight off a live monitor.
References¶
- Kundur 1994, Power System Stability and Control — small-signal (modal) stability:
the growth rate
σthe advisory surfaces is the dominant mode's eigenvalue.
Classes¶
GridEarlyWarningAdvisory
dataclass
¶
GridEarlyWarningAdvisory(
detector: str,
observable: str,
signal_source: str,
captured_at: str,
sampling_rate_hz: float,
window_seconds: float,
step_seconds: float,
persistence: int,
aggregation: str,
recency_top: float,
r2_gate: float,
warning_sample: int,
warning_time_s: float,
growth_rate: float,
growth_rate_threshold: float,
most_unstable_bus: int,
transition_onset_sample: int | None,
lead_samples: int | None,
lead_seconds: float | None,
lead_is_early: bool,
certified_recall: float,
certified_false_alarm: float,
certified_operating_point: str,
non_actuating: bool,
actuating: bool,
verdict: str,
framework: str,
disclaimer: str,
)
A hash-sealed, review-only grid early-warning operator advisory.
Attributes¶
detector : str
The detector family label, e.g. grid_modal_growth_stream.
observable : str
The physical quantity the detector read.
signal_source : str
Provenance identifier of the live stream (feed, event, or scenario).
captured_at : str
Measurement timestamp of the alarm, supplied by the caller.
sampling_rate_hz : float
Stream sampling rate in hertz.
window_seconds, step_seconds : float
The certified streaming operating point: window length and re-scoring hop.
persistence : int
Consecutive above-threshold windows required before the alarm fired.
aggregation : str
The certified aggregation ("focal" or "mean").
recency_top : float
The certified recency weighting the growth rate was fitted under.
r2_gate : float
The certified fit-quality gate; 0.0 when off.
warning_sample : int
Stream sample index the alarm fired at.
warning_time_s : float
Alarm time in seconds from the stream start.
growth_rate : float
The growth rate σ at the alarm window.
growth_rate_threshold : float
The certified matched-false-alarm threshold σ crossed.
most_unstable_bus : int
The most-unstable bus, or :data:WHOLE_NETWORK_BUS under the mean aggregation.
transition_onset_sample : int | None
Caller-supplied ground-truth onset sample, or None when unknown.
lead_samples : int | None
transition_onset_sample - warning_sample when both are known, else None.
lead_seconds : float | None
lead_samples / sampling_rate_hz when defined, else None.
lead_is_early : bool
True only when the lead is defined and strictly positive.
certified_recall : float
The honest fraction of growing-instability episodes the detector leads at the
certified operating point — sealed so the operator sees the miss rate.
certified_false_alarm : float
The matched stream false-alarm rate the threshold was certified at.
certified_operating_point : str
Provenance of the certified operating point (the sealed artefact it came from).
non_actuating : bool
Always True: the advisory never actuates.
actuating : bool
Always False: no actuation path exists.
verdict : str
:data:GRID_ADVISORY_RAISED.
framework : str
The stability framework the advisory maps to.
disclaimer : str
The review-only claim boundary.
content_hash : str
SHA-256 of the canonical record (excluding this field); set on construction.
Methods:¶
__post_init__ ¶
Compute the content hash from the canonical advisory payload.
Functions:¶
seal_grid_early_warning_advisory ¶
seal_grid_early_warning_advisory(
*,
detector: str,
observable: str,
signal_source: str,
captured_at: str,
sampling_rate_hz: float,
window_seconds: float,
step_seconds: float,
persistence: int,
aggregation: str,
recency_top: float,
r2_gate: float,
warning_sample: int,
warning_time_s: float,
growth_rate: float,
growth_rate_threshold: float,
most_unstable_bus: int,
certified_recall: float,
certified_false_alarm: float,
certified_operating_point: str,
transition_onset_sample: int | None = None,
) -> GridEarlyWarningAdvisory
Seal a live grid instability alarm into a hash-addressed, review-only advisory.
The neutral primitive: it depends only on the alarm claims and the certified operating point, so it seals any monitor configuration without importing its internals. It hard-wires the non-actuating stance and computes the honest lead.
Parameters¶
detector, observable, signal_source, captured_at, certified_operating_point : str
The detector label, the read quantity, the stream provenance, the
caller-supplied timestamp, and the operating-point provenance; each non-empty.
sampling_rate_hz, window_seconds, step_seconds : float
The stream rate and the operating-point window and hop in seconds; each > 0.
persistence : int
The certified persistence; a positive integer.
aggregation : str
"focal" or "mean".
recency_top : float
The certified recency weighting; a finite number >= 1.
r2_gate, certified_recall, certified_false_alarm : float
The certified fit-quality gate and the honest recall and false-alarm rate; each
a finite number in [0, 1].
warning_sample : int
The alarm's stream sample index; non-negative.
warning_time_s, growth_rate, growth_rate_threshold : float
The alarm time and the growth rate and threshold; each finite.
most_unstable_bus : int
The most-unstable bus, or :data:WHOLE_NETWORK_BUS under the mean aggregation.
transition_onset_sample : int | None
Caller-supplied ground-truth onset sample; enables the lead computation.
Returns¶
GridEarlyWarningAdvisory The hash-sealed, review-only advisory.
Raises¶
ValueError
If an identifier is empty, a rate or window is not positive, persistence is
not a positive integer, aggregation is unknown, a bounded rate leaves
[0, 1], recency_top is below one, a sample index is negative, the bus is
below the whole-network sentinel, or a reported real is not finite.
Source code in src/scpn_phase_orchestrator/assurance/grid_early_warning_advisory.py
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 | |
advise_from_stream_alarm ¶
advise_from_stream_alarm(
alarm: StreamAlarm,
monitor: GridModalStreamMonitor,
*,
signal_source: str,
captured_at: str,
certified_recall: float,
certified_false_alarm: float,
certified_operating_point: str,
observable: str = GRID_EARLY_WARNING_OBSERVABLE,
detector: str = "grid_modal_growth_stream",
transition_onset_sample: int | None = None,
) -> GridEarlyWarningAdvisory
Seal an advisory straight from a live monitor's alarm and operating point.
Reads the alarm claims (growth rate, threshold, most-unstable bus, sample and time)
off the :class:~scpn_phase_orchestrator.monitor.grid_modal_stream.StreamAlarm and
the certified operating point (rate, window, step, persistence, aggregation, recency
weighting, gate) off the live monitor, so the advisory records exactly what fired
with no hand-set constants beyond the caller-supplied provenance and honest rates.
Parameters¶
alarm : StreamAlarm The lead event the monitor raised. monitor : GridModalStreamMonitor The monitor that raised it, read for its certified operating point. signal_source, captured_at, certified_operating_point : str The stream provenance, the caller-supplied capture timestamp, and the certified-operating-point provenance. certified_recall, certified_false_alarm : float The honest recall and matched false-alarm rate of the certified operating point. observable, detector : str The read-quantity and detector labels sealed into the record. transition_onset_sample : int | None Caller-supplied ground-truth onset sample; enables the lead computation.
Returns¶
GridEarlyWarningAdvisory The hash-sealed, review-only advisory for the alarm.