Files
rutster/crates/rutster-sim/src/lib.rs
Aaron D. Lee ee3938864b
Some checks failed
CI / fmt (push) Has been cancelled
CI / clippy (push) Has been cancelled
CI / test (1.85) (push) Has been cancelled
CI / test (stable) (push) Has been cancelled
CI / deny (push) Has been cancelled
CI / sim-bench (stable) (push) Has been cancelled
CI / twilio-live (manual only) (push) Has been cancelled
slice-4½: rutster-sim seed + CI-regressed thresholds (S1-S8) (#18)
Co-authored-by: Aaron D. Lee <himself@adlee.work>
Co-committed-by: Aaron D. Lee <himself@adlee.work>
2026-07-05 16:21:07 +00:00

71 lines
3.3 KiB
Rust

//! # rutster-sim — the self-hostable benchmark + simulation harness
//!
//! **Status:** spearhead step 4½ (ADR-0010). The wedge's measurement surface.
//!
//! This crate drives synthetic callers through the SAME media-leg path real
//! callers use, measures p50/p99 mouth-to-ear latency + barge-in kill-time
//! against slice-4's ≤60 ms kill budget, and runs the same measurements at
//! 1 / 10 / 50 concurrent calls. A separate CI job
//! (`cargo test --all --features=sim-bench`) asserts thresholds per commit;
//! a latency regression fails the build (ADR-0010).
//!
//! # Why this crate exists (the FOB differentiator)
//!
//! Slice-4 ships a reflex loop + a synthetic e2e test. SIM-BENCH is the
//! artifact that turns arithmetic latency claims into CI-regressed
//! measurement. See
//! [`docs/superpowers/specs/2026-07-05-slice-4-half-benchmark-sim-design.md`]
//! for the design.
//!
//! # Why a separate crate (not in-tree tests)
//!
//! The harness is hot-path-adjacent + differentiating (ADR-0008 FOB) — it
//! earns cratehood the same way `rutster-tap` did. The dep direction is
//! clean: `rutster-sim` → `rutster-media` + `rutster`. The harness
//! consumes types; it doesn't ride on the binary's internal plumbing.
//!
//! # Module map (lands across S1-S7)
//!
//! - [`scenario`] (S1) — `Scenario` + `ScenarioStep` TOML-deserializable
//! scripted-caller data types. Determinism is the point.
//! - [`sim_audio_pipe`] (S2) — `SimAudioPipe: AudioPipe` test-double that
//! IS the caller; captures both clocks (`Instant::now()` at onset +
//! receipt). The measurement boundary (spec §2.2).
//! - [`latency`] (S3) — `LatencyProbe`: post-hoc p50/p99 kill + mouth-to-ear
//! computation from the `Capture` event stream.
//! - [`runner`] (S4) — `SimCall` + `ScenarioRunner`: drives one synthetic
//! caller end-to-end against the FOB reflex loop standalone in tokio
//! (no `MediaThread` extension per S4 standalone-path conclusion).
//! - [`concurrency`] (S5) — `ConcurrencyRunner`: N concurrent `SimCall`s
//! against the same MockRealtimeBrain; aggregates per-call latencies
//! into a `SweepReport`.
//! - [`tick_lag`] (S6) — `TickLagGauge`: the ADR-0010 doctrine-drift
//! detector. Surfaces `tick_overruns` / `last_tick_micros` in the
//! `SweepReport`.
//! - [`thresholds`] (S7) — Threshold consts + the `#[cfg(feature =
//! "sim-bench")] #[tokio::test]` assertion tests. A latency regression
//! fails the build.
// All modules declared upfront so the lib.rs is stable across task
// commits; each module file grows from a `//! stub` header to its full
// impl as its task lands. Only the `pub use` re-exports for landed
// modules are present — they grow as each task's symbols become available.
pub mod concurrency;
pub mod latency;
pub mod runner;
pub mod scenario;
pub mod sim_audio_pipe;
pub mod thresholds;
pub mod tick_lag;
pub use concurrency::{ConcurrencyRunner, PerConcurrencyReport, SweepReport};
pub use latency::LatencyProbe;
pub use runner::{ScenarioRunner, SimCall};
pub use scenario::{Scenario, ScenarioError, ScenarioStep};
pub use sim_audio_pipe::{Capture, SimAudioPipe};
pub use thresholds::{
BARGE_IN_KILL_TIME_P99_MS, MOUTH_TO_EAR_P99_MS, SWEEP_CONCURRENCIES, TICK_LAG_MAX_MS,
TICK_OVERRUN_PCT_MAX,
};
pub use tick_lag::{TickLagGauge, TickLagStats};