v1.0.0
First stable release. The public Python API — the symbols exported from
scpn_phase_orchestrator.__all__ — is now covered by semantic-versioning
guarantees; future backward-incompatible changes to it will bump the major
version.
Added
- The
spo --versionoption, which reports the installed package version. - The full text of the GNU Affero General Public License v3
(LICENSES/AGPL-3.0-or-later.txt), so the distribution conveys its licence in
full alongside the grant notice inLICENSE. - A canonical Control Engineer onboarding notebook
(notebooks/21_control_engineer_onboarding.ipynb): a ~15-minute guided golden
path over the public Python API — validate a shipped binding spec, sweep the
coupling strength to see the synchronisation transition (coherenceRresponds
to the control knob), then audit and replay a run and verify its SHA-256
hash-chain integrity and bit-exact determinism. Runs on the pure-Python path
from a barepip install scpn-phase-orchestrator; listed in the notebook
execution matrix and the notebooks-and-demos gallery, and executed by the CI
notebook suite. - A machine-readable
validation_tieron every domainpack binding spec
(scaffold,partial, orexternally_validated; seeVALID_VALIDATION_TIERS
inbinding.types), recording how much external evidence a binding scaffold
carries — distinct fromsafety_tier(the deployment risk class). A binding is
a reusable scaffold, not a validated detector, soscaffoldis the honest
default: the loader defaults an undeclared spec to it and the validator rejects
any unknown tier. All 36 shipped domainpacks declarevalidation_tier: scaffold
— none carries an independent end-to-end validation trail. The resolved binding
summary surfaces the tier, and a newbinding.gallerymodule
(select_specs_by_validation_tier,group_specs_by_validation_tier) lets a
Studio Hub filter or group packs by tier so a broad gallery is never mistaken
for a broad set of validated solutions. Documented in the Domainpack validation
tiers guide and the binding API reference; guarded by
tests/test_binding_validation_tier.pyand per-pack drift guards in
tests/test_domainpack_validation.py. - A machine-readable monitor validation-status registry
(monitor.validation_status) recording, per monitor family, how much external
evidence it carries:EXTERNALLY_VALIDATED(external),SYNTHETIC_ONLY
(synthetic-only), orRESEARCH(research). It restates theREADME
§Evidence status verbatim in structured form — only the grid modal-growth
detector and its streaming form are externally validated; the generic
early-warning suite is synthetic-only; the remaining monitors are research. The
package exportsMonitorValidationStatus,MonitorValidationRecord,
MONITOR_VALIDATION,validation_record,monitors_by_status, and
validation_summary, documented in the Monitor validation status guide and
API reference. A drift guard fails closed if a new public monitor module is left
neither classified nor explicitly excluded, so the honest posture cannot rot.
Guarded bytests/test_monitor_validation_status.pyand
tests/test_docs_monitor_validation_status.py. - A Module Federation studio remote under
studio-web/(Vite +
@module-federation/vite) that buildsremoteEntry.jsfor the SCPN Studio
Hub. It exposes./SpoStudioPanel, a pure renderer of the committed
evidence-coverage snapshot — how each of SPO's six assurance evidence
categories contributes to EU AI Act, ISO/IEC 42001 and ANSI/UL 4600 clauses,
at the honestaddressed/partially_addressedboundary; a malformed
snapshot renders as a loudunverifiableblock. The Python
studio.federation_manifestnow declares the remote throughui_module, a new
studio.panel_dataproducer is the single source of truth for the snapshot
(regenerated bytools/build_studio_panel_data.py, drift-guarded in CI), and a
studio-webCI job typechecks, tests (100% coverage), and builds the remote. assurance.build_twin_confidence_evidencemaps a serialised
TwinConfidenceScoreinto atwin_confidenceevidence item, closing the one
assurance-case evidence category that the clause map referenced but no producer
emitted. Thespo assurance-case/certification-evidencecommands gain a
repeatable--twin-confidence-fileoption that surfaces it for the
drift-monitoring clauses (EU AI Act Articles 9/15/72, ISO/IEC 42001 Clause 9 /
A.8, UL 4600 metrics-conformance). Guarded by
tests/test_assurance_twin_confidence_evidence.pyand
tests/test_cli_assurance.py.- A
control_envelopeassurance evidence category and a run-derived
control-safety-envelope evidence item.assurance.build_run_evidencenow emits
arun-control-envelopeitem (control mode, applied-action and
boundary-violation totals, final regime) when a run record has the closed-loop
policy feedback active, mapped to EU AI Act Articles 9/14/15, ISO/IEC 42001
Clause 8, and UL 4600 safety-case/risk-analysis clauses. The
spo assurance-case/certification-evidence--run-resultpath surfaces it
automatically. Guarded bytests/test_assurance_run_evidence.pyand
tests/test_cli_assurance.py. bench/honest_dataset_audit.pyis a reusable honest-audit harness that
generalises the CAP/Sleep-EDF audit pattern. It accepts a dataset manifest, a
detector registry, and a domain-specific loader/label-extractor, then emits
sealed audit records, per-recording summaries, an aggregate comparison JSON,
and a data-driven recommendation.bench/cap_multichannel_n3_vs_wake.pyis
refactored to use the harness utilities (run_audit,compute_aggregate,
write_aggregate,file_sha256) and still reproduces the committed CAP
sealed-audit hashes exactly. Guarded by
tests/test_honest_dataset_audit.py.bench/synthetic_honest_audit_demo.py,
docs/studies/synthetic_honest_audit_demo.md, and
examples/real_data/synthetic_honest_audit_demo/demonstrate the harness on a
deterministic synthetic corpus (AR(1) events vs white-noise nulls). The
autocorrelation detector beats chance at matched false-alarm 0.10 while the
window-mean control does not, showing the harness generalises beyond sleep EEG.
Guarded bytests/test_synthetic_honest_audit_demo_evidence.py.bench/cap_multichannel_n3_vs_wake.pyand
docs/studies/cap_multichannel_n3_vs_wake.mdextend the honest sleep-staging
audit to a true multi-channel EEG corpus, the PhysioNet CAP Sleep Database.
Three detectors — normalized delta-band Hilbert envelope (multi-channel mean),
multi-channel delta-phase Kuramoto order parameter, and an SNR-weighted
Kuramoto variant — are audited at the same matched false-alarm operating
point (target_false_alarm = 0.10) on a four-recording panel (controls
n1/n2, bruxismbrux2, narcolepsynarco2). Sealed audit records,
summaries, a manifest, an aggregate comparison JSON, and a data-driven
detector recommendation are committed under
examples/real_data/cap_multichannel_staging/and guarded by
tests/test_cap_multichannel_staging_evidence.py.bench/cap_kuramoto_diagnostic.pyand
docs/studies/cap_kuramoto_diagnostic.mddiagnose why the multi-channel
delta-phase Kuramoto detector wins onn2but under-performs on the other
CAP recordings. Per-epoch signal properties (delta SNR, phase circular
variance, artifact proxies, Kuramoto R statistics) are correlated with the
detector gap; the committedcap_kuramoto_diagnostic.jsonrecommends an
SNR-weighted Kuramoto variant as the next refinement. Guarded by extended
tests intests/test_cap_multichannel_staging_evidence.py.- The recommended SNR-weighted delta-phase Kuramoto detector is implemented in
bench/cap_multichannel_n3_vs_wake.pyand honestly audited on the same CAP
panel. The sqrt-softened per-epoch SNR weights do not improve over the simple
mean-R Kuramoto detector (mean detection rate 0.175 vs 0.184 at matched
false-alarm 0.10), so the aggregate recommendation is to stop refining this
exact spatial-R feature and consider a different direction such as adaptive
channel selection or temporal-stability criteria. The new artefacts and
updated documentation are pinned bytests/test_cap_multichannel_staging_evidence.py.
Changed
- Raised the supported Python floor to 3.11 — the versions CI actually exercises
(3.11, 3.12, 3.13). The previously advertised but untested 3.10 support was
removed fromrequires-pythonand the packaging classifiers. - Removed the REUSE-compliant README badge: the repository is not yet fully
REUSE-compliant (reuse lintstill reports uncovered files), so the claim was
unearned. The full licence text is now shipped underLICENSES/regardless. spo doctorand the install guide now describe the PyPI-availability boundary
honestly (external-validation finding E0.1). When the Rust backend is absent,
the doctor previously advised "install the 'rust' extra (spo-kernel)", but
spo-kernelis not on public PyPI (it is the project's own in-repo Rust
acceleration), so an outsider could not follow that hint. The doctor now states
that the acceleration is not on public PyPI — build it from the in-repo
spo-kernel/workspace with maturin or obtain the commercial wheel — and that
the pure-Python path is used automatically. The Install Profiles guide gains a
PyPI availability boundary section listing the three extras (rust,fusion,
scpn-all) that depend on packages not on public PyPI, so the boundary is
explicit rather than discovered at install time. A new
tests/test_docs_install_profiles.pydrift guard derives the private-backed
extras frompyproject.tomland fails if the guide stops naming any of them.- The V&V report and testing guide now publish the measured coverage
(94.34% line, 93.22% branch, from the CI coverage lanes) and the real gate — a
per-domain no-decrease ratchet enforced bytools/coverage_guard.py— in
place of the misleading "gated at 60%" framing, which was only the floor held
during the dedicated-test-surface rebuild (audit finding SPO-G04). A new
tests/test_docs_coverage_report.pydrift guard ties the published floors to
coverage_guard_thresholds.json/coverage_guard_branch_thresholds.json, so a
raised ratchet forces the docs to be updated rather than silently going stale. runtime.simulatenow fails closed by default on a broken audit
event-stream (audit finding SPO-T01). When the audit logger owns a protobuf
event stream whose close-time integrity check fails,simulateraises
AuditErrorinstead of returning a result carrying an unenforced
audit_event_stream_integrityfield — a tampered or corrupted run can no longer
return a green result. A normal run (whose freshly written stream always
verifies) is unaffected; pass the new keywordstrict_audit_integrity=Falseto
restore the advisory-attach behaviour. Guarded bytests/test_simulation_core.py.