Skip to content

v0.12.0

Choose a tag to compare

@github-actions github-actions released this 07 Jul 19:59
· 368 commits to main since this release

Added

  • scpn_phase_orchestrator.evaluation is the detector-agnostic honest
    early-warning auditor
    , the productised form of the matched-false-alarm
    methodology. audit_detector(event_scores, null_scores, …) scores any detector's
    event-vs-null skill at a matched false-alarm rate with a label-permutation p-value
    and returns a DetectorAudit; seal_detector_audit binds a verdict to its corpus
    provenance under a SHA-256 canonical-JSON hash (AuditRecord); the skill
    primitives (calibrate_score_threshold, matched_false_alarm_rate,
    permutation_significance_from_alarms, surrogate_rank_pvalue) are public for
    callers composing their own harness. It audits the SCPN suite, an AR(1)/Kendall-τ
    baseline, or a black-box classifier on identical footing, from per-segment scores
    alone. Pinned by tests/test_evaluation_skill.py,
    tests/test_evaluation_auditor.py, and tests/test_evaluation_record.py.
  • spo audit-detector audits a detector from a JSON scores file without writing
    Python — matched-false-alarm threshold, permutation p-value, and, given a corpus
    id and capture timestamp, a hash-sealed record. Strict score parsing (a missing
    key, empty list, or non-numeric/non-finite entry is an error, never a silently
    dropped score). Pinned by tests/test_cli_evaluation.py.
  • bench/auditor_detector_head_to_head.py audits the real SCPN modal
    envelope-growth detector against the AR(1)/Kendall-τ competitor through the public
    auditor, on two synthetic-but-honest regimes (oscillatory instability, monotone
    rising autocorrelation). The auditor objectively surfaces regime-dependent skill —
    envelope growth leads the oscillatory regime, AR(1)/Kendall-τ the monotone one —
    the eigenvalue-regime-map finding adjudicated by one matched-false-alarm +
    permutation test. bench/honest_auditor_worked_example.py is the toy-scorer
    counterpart. Pinned by tests/test_auditor_detector_head_to_head.py.
  • scpn_phase_orchestrator.monitor.critical_slowing_down implements the classical
    critical-slowing-down early-warning indicator (rising variance and lag-one
    autocorrelation, robust-z alarm) as a passive monitor — the literature baseline
    detector and the first member of the early-warning detector suite.
  • scpn_phase_orchestrator.monitor.synchronisation implements the rising-
    synchronisation early-warning indicator (the windowed Kuramoto order parameter
    climbing above its baseline, robust-z alarm) as a passive monitor — the
    first-moment, order-parameter member of the suite, complementary to the
    critical-slowing-down (second-moment) and transition-entropy (regularisation)
    detectors, and the indicator that carries the leading precursor on a real
    scalp-EEG seizure. It shares the suite's alarm contract.
  • bench/early_warning_leadtime.py is a fair, matched-false-alarm head-to-head
    between the ordinal-transition-entropy detector and critical slowing down on a
    controlled inertial-vs-overdamped Kuramoto transition, with a falsification
    gate. Each detector reads the observable it is designed for and shares the alarm
    rule, so the comparison isolates the indicator. The tested logic (alarm rule,
    calibration, lead-time evaluation, verdict) is pinned in
    tests/test_early_warning_leadtime.py.
  • scpn_phase_orchestrator.assurance.early_warning_evidence seals any suite
    detector's alarm into a hash-addressed, review-only EarlyWarningEvidence
    record: the contributing indicators and their robust z-scores at the alarm
    window, the screened-signal provenance, the claim boundary, and — against a
    caller-supplied ground-truth onset — the honest lead time, including a
    non-positive lead when the alarm was late. seal_early_warning is a
    detector-neutral primitive; seal_critical_slowing_down_alarm,
    seal_synchronisation_alarm, and seal_transition_entropy_alarm bridge the
    three suite detectors onto it. This is the assurance envelope the fair
    head-to-head identified as the differentiator once detection proved a commodity.
  • scpn_phase_orchestrator.monitor.ensemble_warning fuses the detector suite into
    one decision over a shared window grid, with two rules: weighted (a weighted
    mean of the members' oriented z-scores against a single scalar threshold, so it
    calibrates continuously to a matched false-alarm rate) and vote (an alarm when
    at least min_votes members breach their own gate). The fused baseline is the
    widest member's, and both rules require a persistence run; the gain must be shown
    as matched-false-alarm lead time, never a raw detection rate. Three adapters
    (member_from_critical_slowing_down, member_from_synchronisation,
    member_from_transition_entropy) build the aligned member evidence, and
    assurance.early_warning_evidence.seal_ensemble_alarm seals a fused alarm —
    pinning every member's native contribution — into an EarlyWarningEvidence.
  • scpn_phase_orchestrator.monitor.early_warning_suite makes the suite
    domain-adaptable: SuiteObservables is the neutral phase-observable bundle
    every member reads (per-node phases, their sin(phase) projection, and the
    cross-node Kuramoto order parameter), a DomainObservableAdapter protocol is a
    domain's bridge from raw signals to that bundle, and run_early_warning_suite
    runs the three members and the weighted fusion over the bundle with no knowledge
    of the domain that produced it. observables_from_phases derives the projection
    and order parameter so an adapter need only supply per-node phases. A scalp-EEG
    seizure, a grid coherence collapse, and a cardiac arrhythmia are then screened
    by the same suite because each is a synchronisation transition in a population
    of coupled oscillators. Pinned on synthetic arrays in
    tests/test_early_warning_suite.py.
  • bench/analytic_phase_pipeline.py is the shared raw-signal to analytic-phase
    pipeline every capstone adapter reuses: a zero-phase Butterworth bandpass, the
    per-channel Hilbert analytic_phase, and decimate_analytic_phase (anti-aliased
    decimation of a wrapped phase field via its continuous sin/cos components,
    reconstructed with atan2). Extracted from the scalp-EEG capstone once the
    cardiac adapter needed the same three steps with different parameters. Pinned on
    synthetic tones in tests/test_analytic_phase_pipeline.py.
  • bench/early_warning_domain.py is the domain-neutral matched-false-alarm
    lead-time harness the per-domain capstones share: it segments a recording
    (slice_observables, null_trials), calibrates each detector to a matched
    false-alarm rate on a no-transition null (detector_trajectories,
    calibrate_detectors), measures the honest lead of each alarm against an
    annotated onset (seizure_lead_samples), seals every alarm or silence
    (evaluate_seizure), and reads the detection-count-first verdict
    (domain_verdict). It reads only the neutral SuiteObservables, so scalp EEG,
    cardiac ECG, and grid PMU capstones reuse it unchanged behind their own
    adapters. Pinned on synthetic observables in tests/test_early_warning_domain.py.
  • bench/early_warning_leadtime_eeg.py is the real scalp-EEG capstone — the
    scalp-EEG adapter onto that shared harness. Its EEG-specific half turns a
    CHB-MIT recording into one decimated analytic-phase field (band-pass 4–30 Hz,
    Hilbert phase, phase-consistent decimation 256→32 Hz) and packages it as an
    EEGPhaseAdapter producing the neutral SuiteObservables; the segmentation,
    matched-false-alarm calibration, lead measurement, sealing, and verdict are the
    shared harness. Each seizure is scored on a fixed pre-onset segment (a leading
    baseline plus a detection horizon ending at onset) so the baseline is guaranteed
    clean and every alarm is a genuine lead; an onset too early for a clean baseline
    is excluded and reported, never counted as a silent null. The matched false-alarm
    threshold is calibrated over many equal-length interictal null trials, not a
    handful of whole recordings. The gain from fusion is reported as
    matched-false-alarm lead, never a raw detection rate. The raw EDF is
    citation-only and never redistributed; the pipeline, adapter, and EDF ingestion
    are pinned on synthetic arrays in tests/test_early_warning_leadtime_eeg.py. EDF
    ingestion needs the optional eeg extra (pip install -e .[eeg], pyedflib); its
    tests are gated on that extra, as the suite gates jax and juliacall tests.
  • examples/real_data/chb01_seizures/ is the empirical capstone's sealed
    artefact: the suite and fusion run on the real CHB-MIT chb01 seizures, with an
    EarlyWarningEvidence per detector per seizure and an aggregate results record.
    The honest matched-false-alarm result is sparse detection with no robust
    advantage
    — one of six evaluated seizures is led (rising synchronisation and
    the fusion, ≈ 7.4 min before onset on chb01_04), critical slowing down and
    transition entropy lead none, and the fusion detects no more seizures than its
    best member; a longer lead on one seizure is not a robust advantage. This is the
    strategy made concrete: detection is a commodity, so the deliverable is the
    auditable sealed evidence, not the lead. tests/test_chb01_seizure_evidence.py
    recomputes every seal, pins the leading detection's digest, and guards the
    sparse-detection result; the raw EDF is citation-only and never redistributed.
  • bench/early_warning_leadtime_cardiac.py is the second-domain capstone — the
    cardiac-ECG adapter onto the shared harness — proving the early-warning design
    is domain-adaptable: the same suite and matched-false-alarm harness screen the
    onset of atrial fibrillation in the two-lead surface ECG through nothing but a
    different adapter. CardiacPhaseAdapter band-passes 5–20 Hz, takes the per-lead
    Hilbert analytic phase, and decimates 250 → 50 Hz to the neutral bundle; the
    WFDB reader and rhythm-annotation parsing find each (AFIB onset and the longest
    sinus stretch for the null. It carries two honest caveats: only two ECG leads
    (a thin oscillator population) and AF onset being a desynchronisation (opposite
    to a seizure's synchronisation rise). Pinned on synthetic arrays and a synthetic
    WFDB record in tests/test_early_warning_leadtime_cardiac.py; WFDB ingestion
    needs the optional cardiac extra (pip install -e .[cardiac], wfdb), and its
    tests are gated on that extra.
  • examples/real_data/afdb_atrial_fibrillation/ is the cardiac capstone's sealed
    artefact: the suite and fusion run on six real MIT-BIH AFDB onsets, sealed per
    detector per onset. The honest matched-false-alarm result is again sparse
    detection with no robust advantage
    — two of six onsets led (04043, 04908),
    the fusion leading no more onsets than its best single member — mirroring the
    scalp-EEG finding across an independent physiological domain and confirming the
    deliverable is the auditable sealed evidence, not the lead.
    tests/test_afdb_af_evidence.py recomputes every seal, pins the two led onsets'
    digests, and guards the sparse-detection result; the raw ECG is citation-only
    and never redistributed.
  • The cardiac optional dependency extra installs wfdb for the cardiac-ECG
    early-warning capstone's WFDB ingestion.
  • bench/early_warning_leadtime_grid.py is the third-domain capstone — the
    power-grid adapter onto the shared harness — completing the domain-adaptable
    proof across brain, heart, and grid. GridPhaseAdapter band-passes the 23
    transmission-bus voltages to the electromechanical mode band (0.2–5 Hz), takes
    the per-bus Hilbert analytic phase, and reads the cross-bus order parameter (a
    genuine 23-node spatial population, and a synchronisation rise — the direction
    the suite was built for). The transition is a gen_trip scenario whose
    oscillation grows between the trip and the annotated end (the onset), and the
    false-alarm null is the damped bus_fault / branch_trip scenarios, so the
    calibration asks whether the suite leads a growing instability more often than it
    false-alarms on a stable disturbance. Reads PSML CSV scenarios (bus_voltages,
    oscillation_info, oscillation_growth_ratio, classify_scenario,
    discover_scenarios). Pinned on synthetic arrays and synthetic PSML-format
    scenarios in tests/test_early_warning_leadtime_grid.py.
  • examples/real_data/psml_grid_oscillation/ is the grid capstone's sealed
    artefact: the suite and fusion run on twelve real PSML growing-oscillation
    scenarios, sealed per detector per instability. The honest matched-false-alarm
    result is once more sparse detection with no robust advantage — critical
    slowing down (the classical variance rise) leads the most (7 / 12), the fusion no
    more (5 / 12), rising synchronisation none — the same conclusion a third time,
    across an independent physical domain. It is byte-reproducible (two independent
    runs produce identical sealed records, verified by diff).
    tests/test_psml_grid_evidence.py recomputes every seal, pins two led
    instabilities' digests, and guards the sparse-detection result; the raw PSML data
    (CC BY 4.0) is citation-only and never redistributed.

Changed

  • Renamed the SSGF tcbo observable to topological_integration
    (TopologicalIntegrationObserver, is_consciousis_integrated) across code,
    tests, and docs. The H1 persistent-homology maths is unchanged; the consciousness
    framing is dropped and honest disclaimers kept.
  • bench/early_warning_domain re-exports calibrate_score_threshold from the new
    scpn_phase_orchestrator.evaluation package rather than defining its own copy
    (no behaviour change; the calibrator is now the single installable source).
  • Documentation aligned with the shipped auditor and recalibrated for honest
    positioning: the docs homepage now surfaces the validated grid niche, the
    at-chance-on-real-data stance, and the auditor; the applications tables mark which
    domain is externally validated versus a scaffold; self-congratulatory superlatives
    were removed from public docs, tests, and code comments; stale references
    (tcbo, capability counts) were refreshed.
  • bench/early_warning_domain.calibrate_threshold now sets each detector's
    matched-false-alarm threshold continuously — the quantile of the null
    trajectories' alarm scores (:func:_null_alarm_score), the highest threshold at
    which a null still alarms — instead of scanning a fixed 0.25 … 10.0 grid. This
    matches the target false-alarm rate exactly (up to the null resolution) with no
    ceiling: a detector whose nulls need a threshold above the old grid maximum is no
    longer silently clipped to it. calibrate_detectors now returns a Calibration
    (thresholds plus the achieved false-alarm rate per detector), and each capstone's
    aggregate records achieved_false_alarm so the operating point is transparent.
    All three sealed artefacts (chb01_seizures, afdb_atrial_fibrillation,
    psml_grid_oscillation) were regenerated at the exact matched rate and remain
    byte-reproducible; the honest sparse-detection conclusion holds in every domain.
    The grid result is corrected downward — critical slowing down leads 3 / 12, not
    the 7 / 12 the clipped grid over-counted — because its variance-heavy
    damped-disturbance nulls need a threshold far above any bounded grid.
  • bench/competitive_kuramoto.py is retired as a head-to-head: it compares an
    active SPO supervisor that changes the dynamics against passive SciPy — a
    different-task comparison, not a fair benchmark. It now points to the fair
    early-warning lead-time head-to-head.