Skip to main content
Version: Next

Telemetry

Each frame the UI polls a telemetry snapshot from the simulation. The shape of that snapshot is a contract shared between Rust (which produces it) and TypeScript (which consumes it), and it is locked by a Vitest test.

Two telemetry sources

EXEPERT has two independent telemetry paths that both drive the brain:

  1. Simulation telemetry (this page): per-frame snapshots from the Rust World.telemetry_snapshot(), polled by the UI for activity meters, response indices, and region bars.
  2. Observability telemetry (Plan 007, see Frontend modules): trace/span data from Supabase, mapped into TelemetrySnapshot signals by src/map/trace-to-brain.ts and replayed through the brain by src/map/live-brain.ts (Realtime bridge), map/session-rollup.ts (replaySession), and the compare-mode diff grid. Region health is additionally tinted by eval annotations (annotationsToRegionScores).

Both paths feed into the same TelemetrySnapshot shape so the brain UI doesn't need to distinguish the source.

The snapshot contract

The TypeScript type is the source of truth for the shape:

src/sim/types.ts
export interface TelemetrySnapshot {
activeSignals: number
firedThisFrame: number
releasedSignalsThisFrame: number
signalVelocityMean: number
corticalResponseIndex: number
onsetResponse: number
sustainedActivation: number
focusDrift: number
regionActivity: Record<RegionKey, number>
rolling: {
oneSec: RollingWindow
threeSec: RollingWindow
fifteenSec: RollingWindow
}
}

export interface RollingWindow {
activeSignalsAvg: number
firedNeurons: number
releasedSignals: number
signalVelocityMean: number
regionActivity: Record<RegionKey, number>
}

The Rust telemetry_snapshot() serializes a matching structure with serde-wasm-bindgen, so the JavaScript side receives a plain object that satisfies TelemetrySnapshot:

src/brain.ts
getTelemetrySnapshot(): TelemetrySnapshot {
return this.world.telemetry_snapshot() as TelemetrySnapshot
}
Contract test

src/__tests__/telemetry-contract.test.ts asserts the snapshot shape. If the Rust serialization and the TypeScript type drift apart, pnpm test fails. Keep both in sync when adding a field.

Fields

Instantaneous (this frame):

FieldMeaning
activeSignalsCurrently live signals.
firedThisFrameNeurons that fired this frame.
releasedSignalsThisFrameSignals released this frame.
signalVelocityMeanMean travel speed of live signals.
regionActivityPer-region activity counts.

Derived response metrics:

FieldMeaning
corticalResponseIndexHeadline "responsiveness" score.
onsetResponseSharpness of response right after a stimulus.
sustainedActivationActivity held over time.
focusDriftHow much the dominant region wanders.

Rolling windows

Three rolling windows: oneSec, threeSec, fifteenSec: accumulate averages over their respective time spans. Each RollingWindow carries an average active signal count, fired-neuron and released-signal counts, mean velocity, and per-region activity. The UI uses these to draw the activity-window bars.

Active load and the response index

The response index is built partly from "active load": how full the pool is relative to the live cap:

rust/brain_sim/src/lib.rs
let active_load =
(self.pool.active_count() as f32
/ self.settings.current_max_signals.max(1) as f32) * 100.0;

Because this normalizes against current_max_signals (default 16_000), the load percentage moves as you change the max-signals setting. The UI's activity bars normalize against the configured cap as well, so they read as a fraction of capacity rather than an absolute count.