You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Raised dependency security floors so no resolvable version is vulnerable: starlette ≥ 1.3.1 (requirements.txt + the queuewaves/dev extras), jupyterlab ≥ 4.5.9, and new floors jupyter-server ≥ 2.20.0, tornado ≥
6.5.7, bleach ≥ 6.4.0 (notebook extra), msgpack ≥ 1.2.1 (dev extra).
These are development/notebook-scope tools; the lockfiles already pinned the
patched versions, so the floors only tighten the declared ranges.
Upgraded transitive development dependencies in the Python 3.11, Python 3.13,
and Windows-FFI lockfiles: jupyter-server 2.18.0 → 2.20.0 and bleach 6.3.0 →
6.4.0 in all four, plus cryptography 47.0.0 → 49.0.0 and tornado 6.5.6 →
6.5.7 in the two Windows-FFI lockfiles. The primary dev-lock.txt already
carried the patched versions. The Windows-FFI lockfiles keep their Unix-only
exclusions (no uvloop).
Changed
The domainpack gallery now opens with a ⭐ try these first guide and badges
the three recommended starting packs (power_grid and neuroscience_eeg, each
one spo quickstart command, plus the minimal-spec minimal_domain) so a new
user has an obvious entry point into the 36-pack catalogue, which is searchable
from the docs search box.
Documented experiments/, fuzzers/ and bench/ as an explicit experimental
tier: each now carries a README stating that it is not part of the supported scpn_phase_orchestrator API, is outside the test (testpaths = ["tests"]) and
coverage (source = ["scpn_phase_orchestrator"]) scope, is held to relaxed
linting, and carries no stability or correctness guarantee. This makes the
already-implicit boundary explicit so the exploratory scripts, fuzzing
harnesses, and benchmark instruments are not mistaken for supported surface.
The Rust spo_kernel extension is now built as an abi3 stable-ABI wheel
(pyo3/abi3-py310): a single cp310-abi3 wheel per platform loads on CPython
3.10+ instead of one wheel per Python version, so the release matrix and
download surface shrink. The build is unchanged for cargo test
(--no-default-features); verified that the abi3 wheel imports and the Rust
Koopman backend runs on a newer interpreter than its 3.10 floor.
Added
Neural-supervisor-to-candidate bridge (nn.supervisor.candidate_bridge): supervisor_policy_to_candidate runs a differentiable supervisor policy
deterministically and maps its recommendation onto a KnobPolicyCandidate, so
a learned policy feeds the same review-only evidence pipeline as an offline
replay search. The mapping is by control meaning — the supervisor's global
coupling delta moves K, its damping delta moves zeta, and its per-layer
coupling deltas become channel_weights — applied relative to a base candidate
whose alpha, Psi, and cross_channel_gains are carried through unchanged.
The bridge actuates nothing. Closes the auditable RL supervisor candidate track.
spo supervisor-candidate CLI command: reads a JSON scenario (candidate,
baseline, incumbent, observations, constraints, safety tier, numeric
provenance), scores the candidate with the model-free reward over the
representative observation, assembles the sealed studio.supervisor_candidate.v1 bundle, prints a summary (reward delta, safe
and improved flags, evidence kind, the top-attributed knob), and optionally
writes the full record as JSON. It actuates nothing.
Auditable supervisor-candidate bundle (autotune.supervisor_candidate): build_supervisor_candidate_bundle glues a candidate's reward report, its
per-knob attribution, its safety certificate, and a lightweight comparison
against the incumbent into one sealed, review-only studio.supervisor_candidate.v1
record, stamped with the numeric provenance (active backend and parity
tolerance) and the safety tier and content-addressed by a canonical-JSON
SHA-256 seal. A safe_and_improved flag gives a reviewer a single gate. The
bundle is evidence, not an action — it proposes and actuates nothing. The third
slice of the auditable RL supervisor candidate track.
Candidate safety certificate for autotune candidates
(autotune.candidate_safety_certificate): certify_candidate_safety binds a
candidate to a control-barrier function over the states it visited in replay
(worst h(x) margin and the count of safe-set violations), to the
Lyapunov/STL/safety-cost bounds of a SafetyConstraintConfig (a required
constraint with missing evidence fails closed), and to an optional
forward-invariance BarrierCertificate. When the verification covers the
replay the evidence is reported as formally proven, otherwise as a measured
replay margin — kept as distinct modalities, not grades. The certificate is
content-addressed (canonical-JSON SHA-256) and actuates nothing. The second
slice of the auditable RL supervisor candidate track.
Per-knob attribution for autotune candidates (autotune.knob_attribution): attribute_knob_policy credits each knob that differs between a candidate and a
baseline with its Shapley contribution to the total reward and to every reward
component, plus its leave-one-out marginal — answering why this knob rather
than only how good overall. Shapley values are exact over all coalitions for a
small number of active knobs and deterministically Monte-Carlo sampled with a
reported standard error above a threshold; the value function is caller-supplied
(a fixed-observation reward, a replay evaluator, or any scorer), and the module
actuates nothing. The first slice of the auditable RL supervisor candidate
track.
Architecture-decisions document (docs/architecture_decisions.md): records the
major architectural decisions and their rationale — the four enforced product
tiers, review-only actuation, the fastest-first parity-gated polyglot chain,
optional heavy dependencies with deterministic fallbacks, the cited
Koopman→MPC→assurance dVOC chain, evidence-as-product, the two safety tiers, the
machine-checked public API, the two build backends with the abi3 wheel, and the
environment-aware coverage gate — so a new contributor understands why the code
is shaped this way, not just what it does.
Hard security scan for spo validate (binding.security_scan + spo validate --security --hard): in addition to the spec-level security pass, --hard statically scans the domainpack's Python scenarios and YAML
configuration for the patterns that let an untrusted domainpack run arbitrary
code — dynamic evaluation (eval / exec), insecure deserialisation
(pickle.load), unsafe YAML deep loads (yaml.load without a safe loader or !!python/ tags), and shell command execution — and reports each match with
its file, line and category. The scan is review-only: it never edits, executes
or imports the scanned files, so it is safe to run on a domainpack of unknown
provenance.
Grounded LLM operator copilot (reporting.operator_copilot): turns an ExplainabilityReport into a question-answering surface for a control-room
operator. It renders the audit evidence — regime distribution, transitions,
every control action with its recorded reason and evidence, the metric summary
— into the prompt and instructs the model to answer only from that evidence and
to decline when it is silent, so the model explains and locates what the audit
records rather than inventing control history or recommending actuation. The
model is any complete(prompt) -> str provider (a local HTTP model, or a stub
for tests), so no network backend is imposed and the prompt is fully testable.
FMI 3.0 co-simulation export of the Koopman MPC
(adapters.fmi_cosimulation): wraps the controller as an FMI 3.0
co-simulation slave so a simulation master (Dymola, OpenModelica, FMPy) can
drive the SPO controller as a block — set the measured state and set point,
call do_step, read back the proposed control. The slave, the modelDescription.xml generator and the .fmu packager are pure NumPy and
emit a conformant FMI 3.0 model interface; loading inside a third-party FMI
tool additionally needs the C-ABI binary shim from a separate toolchain. The
slave reproduces the wrapped controller's control exactly. The reverse import
direction is cosimulate, a co-simulation master that drives the controller
slave against a plant supplied as a step callable, closing the loop (an
external plant FMU plugs in by wrapping its FMI runtime such as fmpy as that
callable); on a coupled linear oscillator the master damps the plant.
Learned phase-autoencoder Koopman observables (monitor.phase_koopman): a
trained phase autoencoder (frozen to the pure-NumPy oscillators.phase_reduction
evaluator) is used as the Koopman observable map, so the EDMD fit and the
condensed Koopman MPC operate in the learned coordinate where a nonlinear
oscillator's dynamics are close to linear. LearnedKoopmanDictionary satisfies
the new KoopmanObservables protocol (which both the analytic dictionaries and
the learned map fulfil), and the state-inclusive lift keeps state reconstruction
exact; on a controlled Stuart–Landau oscillator the learned observables yield a
predictor competitive with the identity dictionary, typically cutting the
multi-step state-prediction error (RMSE ratio 0.58–0.88 across seeds). No JAX on
the control path.
spo koopman-mpc): an underdamped oscillator rings down and the matrix-pencil
estimator plus the NERC PRC screener flag its poorly-damped mode; an
EDMD-with-control Koopman predictor is fitted and driven in closed loop by the
Koopman MPC; the controlled ringdown is re-screened and the weakest mode is
better damped. The result carries both hash-sealed PRC evidence records, so the
damping improvement is auditable end to end. This closes the dVOC
monitor→model→control→assurance chain; it is review-only and offline.
Model-free phase reduction. nn.phase_autoencoder learns the asymptotic
phase, isochrons and phase-sensitivity function of a limit-cycle oscillator
from state time series (Yawata, Fukami, Taira & Nakao 2024): a JAX/equinox
encoder maps the state to a unit-circle latent that evolves by an
exactly-linear normal-form flow with learnable frequency and decay, trained
against a four-term loss. The trained weights are extracted to the new
pure-NumPy oscillators.phase_reduction evaluator, which reproduces the
asymptotic phase and the phase response curve Z(θ) with no JAX on the
control path; the analytic Z(θ) matches a finite-difference gradient to
~1e-10 and on Stuart–Landau data training recovers the true frequency.
One-command golden-path demo (spo quickstart power): validates, runs,
replays (audit hash-chain verification) and reports an end-to-end orchestration
on a bundled research-tier power-grid binding, composing the existing
validate/run/replay/report APIs. The bundled binding is research-tier so the
local runtime may execute it; the production power_grid domainpack still
requires the formal-export pipeline. The fastest path from install to a real
result.
Review-only Koopman model-predictive controller (actuation.koopman_mpc):
builds the condensed convex quadratic programme of a fitted Koopman predictor
(Korda & Mezić 2018, eq. 24) over a finite horizon with output tracking, input
effort, actuator bounds and optional move limits, and returns a content-hashed KoopmanMPCDecision whose first input is handed to the safety envelope. The
quadratic programme is solved by a deterministic operator-splitting (ADMM) QP
floor with adaptive step sizing (the OSQP algorithm of Stellato et al. 2020),
with an optional osqp backend (the mpc extra) held to the floor by a
parity gate. It composes with the foundation-model governor and the control
barrier filter.
Koopman EDMD-with-control linear predictor (monitor.koopman_edmd): fits a
data-driven linear model z_{k+1}=Az_k+Bu_k, x̂=Cz_k of a nonlinear
controlled system (Korda & Mezić 2018) from snapshot triples through
Tikhonov-regularised least squares, with identity / polynomial / RBF /
phase-Fourier observable dictionaries and a frozen KoopmanPredictor carrying (A, B, C). The least-squares solve runs on the five-language backend chain
(Rust, Mojo, Julia, Go, Python) at machine-precision cross-backend parity. It
is the model layer feeding the convex Koopman-MPC controller.
Foundation-model actuation governor (actuation.foundation_model_governor): FoundationModelGovernor.govern admits an externally-proposed (e.g.
foundation-model) scalar control only after running it through SPO's safety
envelope — actuator bounds, a rate limit, an optional Control Barrier Function
projection (flagging h(x) < 0), and named safety predicates that veto — and
seals each outcome into a content-addressed GovernorDecision
(admitted / constrained / rejected, with the applied stages and
violations). It competes on governance, not prediction, and is review-only: it
returns a safe action and an audited decision, never actuating a plant.
NERC PRC oscillation-monitoring compliance evidence (assurance.prc_oscillation): screen_oscillation_modes screens the damping ratios of detected modes against
the oscillation-monitoring practice underlying NERC PRC-028 / the proposed
PRC-030 (undamped and poorly-damped modes are flagged) and seals the result into
a content-addressed, review-only PRCOscillationEvidence record. The capture
timestamp is caller-supplied so the record is deterministic; it is a technical
evidence-mapping aid, not a legal conformity assessment, and never actuates.
Modal participation and damping controllability (monitor.modal_participation):
the model-based companion to the oscillation-mode estimator. phase_network_jacobian builds the Sakaguchi–Kuramoto small-signal Jacobian at
an operating point, and analyse_network_modes eigen-decomposes any
continuous-time state matrix into modes carrying frequency, damping ratio, mode
shape, participation factors (Pérez-Arriaga, Verghese & Schweppe 1982), and
per-input modal controllability (Kundur 1994). It answers which oscillators
swing in a poorly-damped inter-area mode and which actuator damps it best;
conjugate pairs report one non-negative-frequency mode, and a defective state
matrix is rejected. Diagnostic only.
Inter-area oscillation mode estimator (monitor.oscillation_modes): the
matrix-pencil method (Hua & Sarkar 1990) recovers the damped-sinusoid modes of
a grid ringdown — frequency, damping ratio, amplitude, and phase per mode — and
flags modes whose damping ratio falls below a screening threshold
(DEFAULT_DAMPING_THRESHOLD = 0.03, NERC PRC-028). Conjugate pairs merge into
one positive-frequency mode; unstable modes report a negative damping ratio.
Diagnostic only.
Verified neural Control Barrier Function safety filter
(actuation.control_barrier): a barrier h(x) ≥ 0 defines a safe set and the
filter admits the supervisor action closest to its proposal that still
satisfies the discrete-time CBF condition — an analytic projection onto a
state-dependent half-space plus an actuator-bounds clip, strictly stronger than
a fixed clamp. NeuralBarrier is a pure-NumPy ReLU network (value, reverse-mode
gradient, sound interval-bound-propagation bounds); verify_forward_invariance
returns a sound BarrierCertificate (IBP over a state-box partition, never a
false guarantee). Review-only: it shapes a proposed action, never actuates.
Post-quantum seal over the audit hash chain (runtime.audit_pqc): seal_audit_log signs the chain tip (the SHA-256 commitment to the whole log)
with ML-DSA (FIPS 204, via cryptography), and verify_audit_log_seal
rejects the seal if the log's tip or record count changed after sealing. This
is an additive, publicly verifiable, post-quantum complement to the existing
symmetric HMAC record signing — it does not change the HMAC flow. ML-DSA-65 is
the default (ML-DSA-44/87 selectable); the seal records its algorithm so
SLH-DSA (FIPS 205) can be added later without breaking existing seals.
Deterministic (bounded-jitter, hard-deadline) execution mode
(runtime.deterministic): run_deterministic_loop drives any per-step
callable against a fixed period on the monotonic clock, times each step
against a worst-case execution-time budget (recording or, under miss_policy='abort', raising on a deadline miss), and freezes and disables
the cyclic garbage collector for the hot path so GC pauses leave the jitter
budget. Returns an ExecutionTimingReport with per-step latencies and jitters
plus mean / max / p99 latency, max absolute jitter, and deadline-miss counts.
Timing-only and non-actuating.
Ordinal-pattern transition entropy monitor (monitor.opt_entropy, monitor.explosive_sync): Bandt–Pompe ordinal patterns and the normalised
Shannon entropy of the consecutive-pattern transition distribution, with a
five-language backend chain (Rust, Mojo, Julia, Go, Python) at bit-exact
parity. explosive_sync_warning slides this entropy across a multi-node
signal and raises an early warning when it collapses ahead of a first-order
(explosive) synchronisation onset, where variance / autocorrelation
indicators react late. Review-only: it emits a warning record, never actuates.
Supply-chain provenance for released artefacts, signed keylessly through
sigstore: PyPI wheels and sdist use PEP 740 attestations; the GitHub-release
sdist and CycloneDX SBOM are attested with actions/attest-build-provenance;
the container image is pushed with BuildKit provenance and SBOM attestations,
attested, and signed with cosign. Verification commands are in SECURITY.md.
Conformal twin-confidence admission gate (monitor.twin_conformal_gate): turns
the twin-confidence score into a coverage-valid admit/flag gate. From a nominal
calibration window it learns a distribution-free threshold on the composite
z-deviation (target 1 − alpha coverage) and adapts it online by Adaptive
Conformal Inference (Gibbs & Candès, 2021), optionally conditioned per detected
regime. Review-only: a flagged tick signals the twin drifted beyond its
calibrated band and autonomy should narrow.
Chaos-engineering resilience injection (runtime.chaos, spo chaos): inject
non-actuating faults — coupling drops, frequency drift, sensor noise, and drive
dropout — into a controlled simulation via the scenario_hook boundary, then
score recovery time, peak coherence drop, stability-margin erosion, and final
deviation by comparing the nominal and perturbed order-parameter trajectories.
Review-only; the heavy compute reuses the existing multi-language UPDE engine.
Online digital-twin confidence scoring (monitor.twin_confidence): a
review-only health observable that turns model–observation disagreement into a
calibrated confidence in [0, 1] plus an operator status, from a phase
Jensen–Shannon divergence and an order-parameter Wasserstein-1 distance. Ships
the fastest-first polyglot divergence kernel (Rust, Mojo, Julia, Go, NumPy)
with bit-exact Rust/Julia/Go parity and a documented 1e-8 Mojo
text-protocol budget, a calibrator with normal-quantile operating bands, a
composite-z confidence map, deterministic audit records, multi-angle algorithm
/ parity / stability tests, a Python dispatcher benchmark plus a Rust criterion
benchmark, and an API reference page.
Interactive WASM Kuramoto playground (spo-kernel/crates/spo-wasm/example):
the console demo is replaced by a browser simulator with sliders for the
oscillator count, coupling, time step, and frequency spread, a live phase-ring
and mean-field canvas, and an order-parameter time series, driven by the WasmEngine class. Page logic is factored into a pure simulation.mjs helper
module with a node --test suite (covering the helpers and a WASM
synchronisation cross-check) bridged into the Python test run.
MQTT edge bridge (adapters.mqtt_bridge, mqtt extra): read-only ingestion of
edge/IoT sensor measurements from MQTT topics, decoding raw or JSON payloads and
mapping each topic's sampled waveform to a physical-channel phase state via the
Hilbert transform. Config, decoding, ingestion, and extraction work without a
broker; collect_live subscribes through paho-mqtt. Extends the real-time
edge-bridge track (ROS2/MQTT/OPC-UA).
OPC-UA SCADA bridge (adapters.opcua_bridge, opcua extra): read-only
ingestion of industrial process tags (temperatures, pressures, flow rates)
from an OPC-UA server, mapped to physical-channel phase states via the Hilbert
transform. OpcUaTag / OpcUaBridgeConfig validate the endpoint and tag
mapping; extract_phases and collect_samples work without a network
dependency, and read_live / collect_live read from a connected asyncua
client. Closes the OPC-UA adapter request (issue #27).
Twin-confidence operator surfaces: a TwinConfidenceSummary aggregate and
Prometheus renderer, a RuntimeObservability.twin_confidence_prometheus_text
exporter, and the spo twin-confidence CLI command that scores a JSONL
observation stream against a calibrated baseline with human / JSON / Prometheus
output and a --fail-on-critical gate.
Repository hygiene
Version bumped to 0.10.0 across package metadata, citation metadata, the Rust
workspace, public release docs, and generated capability inventory.
Enabled strict mypy ([tool.mypy] strict = true) and parametrised the
generic annotations it surfaced across the runtime, binding, adapter,
reporting, and autotune modules; the package type-checks clean over 502
source files.
Adopted NumPy-convention docstrings (ruff D) on the public library
surface under src/, with the docstring gate scoped away from tests,
scripts, benchmarks, vertical packs, fuzz harnesses, examples, and
notebooks.