The critical-path foundation for the benchmark + simulation harness. Scenario is a TOML-deserializable scripted-caller data type; ScenarioStep covers speak_loud / speak_quiet / pause / await_reply / end. Determinism is the point -- reproducible thresholds in CI (ADR-0010). All other sim modules land as stubs here + fill in across S2-S7. Threshold consts (BARGE_IN_KILL_TIME_P99_MS = 80.0, MOUTH_TO_EAR_P99_MS = 700.0, TICK_LAG_MAX_MS = 10.0, TICK_OVERRUN_PCT_MAX = 1.0, SWEEP_CONCURRENCIES = [1,10,50]) land now per the plan's S1 step 2 note (used by S5/S6/S7 wiring). Adds toml = 0.8 to workspace.dependencies (the first consumer; spec §1.1 claim of pre-existing membership was inaccurate). Task S1 of slice-4½ -- everything else depends on this landing. Signed-off-by: Aaron D. Lee <himself@adlee.work>
59 lines
2.9 KiB
Rust
59 lines
2.9 KiB
Rust
//! # thresholds — CI-regressed latency thresholds + sim-bench assertion tests
|
||
//!
|
||
//! See `docs/superpowers/specs/2026-07-05-slice-4-half-benchmark-sim-design.md`
|
||
//! §5.1 + §5.5.
|
||
//!
|
||
//! The threshold consts land here at S1 (per the plan's S1 step 2 note:
|
||
//! "the consts as immediate module-level `pub const` items per spec §5.1 —
|
||
//! they're used by S5/S6/S7 wiring"). The `#[cfg(feature = "sim-bench")]
|
||
//! #[tokio::test]` assertion tests land at S7.
|
||
//!
|
||
//! # Why these numbers
|
||
//!
|
||
//! See spec §5.1 for the budget-vs-assertion-slack reasoning. Each const
|
||
//! is paired with a doc-comment explaining the budget it enforces + the
|
||
//! slack rationale (so a future maintainer who needs to bump one knows
|
||
//! *why* the current value is what it is, not just *what* it is).
|
||
|
||
/// Slice-4 spec §5.1 + §7 done-criteria #8: kill-time budget is
|
||
/// ≤60 ms (3 debounce frames × 20 ms tick + 1 tick to drain + apply).
|
||
/// Observer slack to make CI deterministic-but-not-flaky on a slow
|
||
/// runner: effective CI assertion ≤80 ms (60 ms budget + 20 ms slack).
|
||
///
|
||
/// A regression here is the red X ADR-0010 demands — the wedge's
|
||
/// "local real-time reflexes that don't need the brain" claim is
|
||
/// arithmetic until this assertion fires on every PR.
|
||
pub const BARGE_IN_KILL_TIME_P99_MS: f64 = 80.0;
|
||
|
||
/// Slice-1 + slice-3 mouth-to-ear budget: 200 ms (slice-1 notification
|
||
/// budget) + 250 ms mock brain round-trip + 100 ms playout buffer.
|
||
/// CI assertion ceiling: 700 ms (allowance for CI runner variance
|
||
/// against the dev machine — the mock brain is deterministic but the
|
||
/// harness adds observer cost; the dev machine usually lands ~600 ms).
|
||
pub const MOUTH_TO_EAR_P99_MS: f64 = 700.0;
|
||
|
||
/// Slice-5/seams tick-lag gauge: the meta-tick must stay under 10 ms
|
||
/// (the loop's nominal period). At 1 call: ≤2 ms expected. At 50
|
||
/// calls: ≤10 ms expected. Tick overruns (count of ticks exceeding
|
||
/// 10 ms) at p50 across the sweep: ≤1% of total ticks per
|
||
/// `TICK_OVERRUN_PCT_MAX`.
|
||
///
|
||
/// If a concurrency sweep shows `tick_overrun_pct > 1.0` at 50 calls,
|
||
/// **the FOB reflex loop's single-thread debt is real and the
|
||
/// dedicated-threadpool-shard graduation (slice-4 §1.2 deferral #2)
|
||
/// gets its data-driven case.** That finding is the slice's
|
||
/// load-bearing output regardless of whether the latency thresholds
|
||
/// pass — the doctrine-drift detector worked.
|
||
pub const TICK_LAG_MAX_MS: f64 = 10.0;
|
||
pub const TICK_OVERRUN_PCT_MAX: f64 = 1.0;
|
||
|
||
/// Concurrency-sweep sample sizes per spec §2.4: 1 isolates the
|
||
/// baseline (cold-path latency with zero concurrency pressure —
|
||
/// slice-4's §5.1 ≤60 ms kill budget asserted here); 10 is the
|
||
/// warm working set (~peak spearhead-scale); 50 is the saturation
|
||
/// point (ADR-0010's "single-poll-task head-of-line-blocking debt"
|
||
/// lives here). We do NOT test 100/500/5000 — that's fleet-scale
|
||
/// (rung 3). 50 is the upper edge of the spearhead's "one binary,
|
||
/// one city" claim.
|
||
pub const SWEEP_CONCURRENCIES: &[usize] = &[1, 10, 50];
|