Skip to main content
The nimbus-bci 0.8 safety layer (nimbus_bci.safety) provides dependency-light state machines that gate online adaptation. While trial rejection (BrainState.rejected) gates individual predictions, the safety module gates adaptation — preventing runaway updates, label budget exhaustion, adaptation during drift storms, and silent model degradation.
Safety posture: safety=None (the default) keeps all adaptation paths byte-identical to previous releases. Opting in with SafetyConfig turns silent adaptation drops into explicit, actionable refusals (AdaptationRefusedError).

Core Architecture

Quick Start: Governed Adaptation

To enforce safety controls, supply a SafetyConfig at Personalizer construction:
When safety= is configured, every adaptation call (partial_fit, adapt_pseudo, adapt_trunk, adapt_async, and unsupervised adapt) consults the governor before modifying head state:

Safety Components

1. LabelBudget

LabelBudget tracks and enforces label expenditure across sessions:
  • All-or-nothing spend: If a batch requires 10 labels but only 8 remain in the budget, the entire spend refuses without partial side effects.
  • Lifetime hard_cap: budget.reset() clears session spend but never restores a lifetime hard cap.
  • Monitoring floor exemption (floor_exempt): A reserved quota of label queries that pass uncharged, ensuring diagnostic monitoring never starves even when the operational budget is spent.

2. AdaptationGovernor

AdaptationGovernor manages adaptation timing and pacing through a pure check() and atomic commit() pattern:
  • Burn-in (burn_in): Requires observing a minimum number of stream trials before permitting any parameter updates.
  • Cooldown (cooldown_trials): Mandates a spacing interval between updates so the system can evaluate transient effects.
  • Max adaptations (max_adaptations): Caps total adaptation count per session.
  • Multi-control visibility: When multiple controls bind simultaneously, check() returns a GovernorDecision naming all violated controls, not just the first.

3. DriftMonitor

DriftMonitor runs persistent run-length surveillance over embedding mean-shift and covariance statistics:
  • Tracks independent consecutive-exceedance runs across mean and covariance metrics against user-defined thresholds (tau_mean, tau_cov).
  • Non-latching alarms notify you when embedding geometry enters an unstable drift state.

4. SafetyMonitor (Regret CUSUM)

SafetyMonitor is a sequential change-point watchdog over verified prediction outcomes:
  • Uses a Bernoulli log-likelihood ratio (LLR) CUSUM statistic on a sliding window.
  • Calibrated with Monte Carlo simulation (fa=0.05, miss=0.20, min_window=10, max_window=40) achieving a measured 0.0510 false-alarm rate.
  • Emits a SafetyVerdict with should_revert=True when cumulative regret indicates that recent adaptation harmed classification accuracy.
Monitoring Best Practice: Always keep the monitor’s baseline fixed mid-session. Blending the baseline toward a collapsing stream disarms the alarm that must catch the collapse. In addition, reset the monitor at each adaptation cycle to preserve the nominal false alarm rate.

Head Snapshot & Exact Rollback

When SafetyMonitor flags degradation (verdict.should_revert), restore the head to a known healthy state:

Guarantees of restore_head

  • Byte-exact: Post-restore predict_proba and predict outputs are identical (np.array_equal) to pre-snapshot outputs.
  • Repeatable: Restoring deep-copies the snapshot payload; the HeadSnapshot instance remains pristine and reusable.
  • Protected: Fails fast with loud exceptions if attempted while an adapt_async job is in flight, or if head family or embedding dimensions have changed.
  • Trunk generation warning: Restoring a head snapshot across an encoder swap or trunk adaptation emits a UserWarning, alerting you that the restored head was fitted on a different geometry manifold.

Ungoverned Surfaces by Design

The following surfaces do not consult the governor:
  • update_from_prediction(): Verified single-trial labels represent the high-priority remediation channel that safety controls protect.
  • adapt_errp() and fit_tent(): Label-free self-supervision operates outside the label ledger. If desired, wrap these calls in your own LabelBudget.spend() invocations.
  • save() / load(): SafetyConfig and pacing counters are session-scoped and not persisted. A loaded profile starts ungoverned; attach a fresh SafetyConfig at load time.

Live Safety Dashboard

Nimbus provides a complete runnable example demonstrating all safety signals in action:
The script streams a synthetic session featuring a mislabeled batch, CUSUM threshold crossing, automated restore_head rollback, full accuracy recovery, and eventual budget exhaustion.

Next Read

Personalizer Overview

The Personalizer product wedge and integration patterns

API Reference: Safety

Signatures and parameter defaults for all safety classes

Migration to 0.8

Adopting the 0.8 safety layer in existing pipelines

BrainState & Decision Presets

Per-trial rejection and confidence gating