Skip to content

v0.10.0

Choose a tag to compare

@github-actions github-actions released this 25 Jun 21:10
· 699 commits to main since this release

Security

  • 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.
  • Closed-loop Koopman-MPC oscillation damping (runtime.dvoc_oscillation_damping
    • 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.