use std::fmt;
#[derive(Debug, Clone, Copy)]
pub struct SsiEProcessConfig {
pub alpha: f64,
pub p0: f64,
pub alt_mult: f64,
pub min_observations: u64,
pub min_clean_streak: u64,
pub periodic_sample_rate: f64,
}
impl Default for SsiEProcessConfig {
fn default() -> Self {
Self {
alpha: 1e-3,
p0: 1e-4,
alt_mult: 50.0,
min_observations: 64,
min_clean_streak: 32,
periodic_sample_rate: 0.05,
}
}
}
impl SsiEProcessConfig {
#[must_use]
pub fn with_alpha(mut self, alpha: f64) -> Option<Self> {
if alpha.is_finite() && alpha > 0.0 && alpha < 1.0 {
self.alpha = alpha;
Some(self)
} else {
None
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GateAlertState {
Clear,
Watching,
Alert,
}
impl fmt::Display for GateAlertState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Clear => f.write_str("clear"),
Self::Watching => f.write_str("watching"),
Self::Alert => f.write_str("ALERT"),
}
}
}
#[derive(Debug)]
pub struct SsiEProcessGate {
config: SsiEProcessConfig,
log_e: f64,
threshold: f64,
log_threshold: f64,
observations: u64,
clean_streak: u64,
peak_log_e: f64,
alert_count: u64,
skip_consultations: u64,
skip_grants: u64,
log_lr_one: f64,
log_lr_zero: f64,
}
impl SsiEProcessGate {
#[must_use]
pub fn new(mut config: SsiEProcessConfig) -> Self {
if !(config.alpha.is_finite() && config.alpha > 0.0 && config.alpha < 1.0) {
config.alpha = 1e-3;
}
if !(config.p0.is_finite() && config.p0 > 0.0 && config.p0 < 0.5) {
config.p0 = 1e-4;
}
if !(config.periodic_sample_rate.is_finite()
&& (0.0..=1.0).contains(&config.periodic_sample_rate))
{
config.periodic_sample_rate = 0.05;
}
let max_mult = (1.0 / config.p0 - 1.0).max(2.0);
if !config.alt_mult.is_finite() || config.alt_mult < 2.0 {
config.alt_mult = 50.0_f64.min(max_mult);
} else if config.alt_mult > max_mult {
config.alt_mult = max_mult;
}
let threshold = 1.0 / config.alpha;
let log_threshold = threshold.ln();
let q = (config.alt_mult * config.p0).min(0.999_999);
let log_lr_one = config.alt_mult.ln();
let log_lr_zero = ((1.0 - q) / (1.0 - config.p0)).ln();
Self {
config,
log_e: 0.0,
threshold,
log_threshold,
observations: 0,
clean_streak: 0,
peak_log_e: 0.0,
alert_count: 0,
skip_consultations: 0,
skip_grants: 0,
log_lr_one,
log_lr_zero,
}
}
pub fn observe(&mut self, conflict_detected: bool) {
let was_alert = self.is_alert();
self.observations = self.observations.saturating_add(1);
let delta = if conflict_detected {
self.clean_streak = 0;
self.log_lr_one
} else {
self.clean_streak = self.clean_streak.saturating_add(1);
self.log_lr_zero
};
self.log_e += delta;
if self.log_e > self.peak_log_e {
self.peak_log_e = self.log_e;
}
let is_alert_now = self.is_alert();
if !was_alert && is_alert_now {
self.alert_count = self.alert_count.saturating_add(1);
}
}
#[must_use]
pub fn alert_state(&self) -> GateAlertState {
if self.observations < self.config.min_observations {
return GateAlertState::Clear;
}
if self.log_e >= self.log_threshold {
GateAlertState::Alert
} else if self.log_e > 0.0 {
GateAlertState::Watching
} else {
GateAlertState::Clear
}
}
#[must_use]
pub fn is_alert(&self) -> bool {
self.log_e >= self.log_threshold && self.observations >= self.config.min_observations
}
#[must_use]
pub fn should_skip_ssi(&mut self, force_audit_hash: u64) -> bool {
self.skip_consultations = self.skip_consultations.saturating_add(1);
if self.is_alert() {
return false;
}
if self.observations < self.config.min_observations {
return false;
}
if self.clean_streak < self.config.min_clean_streak {
return false;
}
let rate = self.config.periodic_sample_rate.clamp(0.0, 1.0);
if rate > 0.0 {
let stride_f = (1.0 / rate).round();
let stride = if stride_f.is_finite() && stride_f >= 1.0 {
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
let s = stride_f as u64;
s.max(1)
} else {
1
};
if force_audit_hash.is_multiple_of(stride) {
return false;
}
}
self.skip_grants = self.skip_grants.saturating_add(1);
true
}
pub fn reset(&mut self) {
self.log_e = 0.0;
self.peak_log_e = 0.0;
self.observations = 0;
self.clean_streak = 0;
self.alert_count = 0;
self.skip_consultations = 0;
self.skip_grants = 0;
}
#[must_use]
pub fn e_value(&self) -> f64 {
self.log_e.exp()
}
#[must_use]
pub fn threshold(&self) -> f64 {
self.threshold
}
#[must_use]
pub fn observations(&self) -> u64 {
self.observations
}
#[must_use]
pub fn clean_streak(&self) -> u64 {
self.clean_streak
}
#[must_use]
pub fn alert_count(&self) -> u64 {
self.alert_count
}
#[must_use]
pub fn skip_consultations(&self) -> u64 {
self.skip_consultations
}
#[must_use]
pub fn skip_grants(&self) -> u64 {
self.skip_grants
}
#[must_use]
pub fn config(&self) -> &SsiEProcessConfig {
&self.config
}
#[must_use]
pub fn snapshot(&self) -> SsiEProcessSnapshot {
SsiEProcessSnapshot {
e_value: self.e_value(),
threshold: self.threshold,
observations: self.observations,
clean_streak: self.clean_streak,
alert_state: self.alert_state(),
peak_e_value: self.peak_log_e.exp(),
alert_count: self.alert_count,
skip_consultations: self.skip_consultations,
skip_grants: self.skip_grants,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct SsiEProcessSnapshot {
pub e_value: f64,
pub threshold: f64,
pub observations: u64,
pub clean_streak: u64,
pub alert_state: GateAlertState,
pub peak_e_value: f64,
pub alert_count: u64,
pub skip_consultations: u64,
pub skip_grants: u64,
}
impl fmt::Display for SsiEProcessSnapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"SsiEProcessGate[{}]: e={:.4} thr={:.1} obs={} streak={} peak={:.4} alerts={} \
skip_consults={} skip_grants={}",
self.alert_state,
self.e_value,
self.threshold,
self.observations,
self.clean_streak,
self.peak_e_value,
self.alert_count,
self.skip_consultations,
self.skip_grants,
)
}
}
#[cfg(test)]
mod tests {
use super::{GateAlertState, SsiEProcessConfig, SsiEProcessGate};
fn fast_open_config() -> SsiEProcessConfig {
SsiEProcessConfig {
alpha: 1e-3,
p0: 1e-3,
alt_mult: 100.0,
min_observations: 8,
min_clean_streak: 4,
periodic_sample_rate: 0.0,
}
}
#[test]
fn new_gate_starts_clear_and_locked() {
let mut gate = SsiEProcessGate::new(fast_open_config());
assert_eq!(gate.alert_state(), GateAlertState::Clear);
assert!(!gate.should_skip_ssi(0));
assert_eq!(gate.observations(), 0);
assert!((gate.e_value() - 1.0).abs() < f64::EPSILON);
}
#[test]
fn invalid_config_is_clamped_not_panic() {
let bad = SsiEProcessConfig {
alpha: -1.0,
p0: 42.0,
alt_mult: -5.0,
min_observations: 0,
min_clean_streak: 0,
periodic_sample_rate: 17.0,
};
let gate = SsiEProcessGate::new(bad);
assert!(gate.config().alpha > 0.0 && gate.config().alpha < 1.0);
assert!(gate.config().p0 > 0.0 && gate.config().p0 < 0.5);
assert!(gate.config().alt_mult >= 2.0);
assert!(
gate.config().periodic_sample_rate >= 0.0 && gate.config().periodic_sample_rate <= 1.0
);
}
#[test]
fn clean_history_opens_gate() {
let mut gate = SsiEProcessGate::new(fast_open_config());
for _ in 0..8 {
gate.observe(false);
}
assert_eq!(gate.alert_state(), GateAlertState::Clear);
assert!(gate.should_skip_ssi(1));
}
#[test]
fn single_conflict_resets_streak() {
let mut gate = SsiEProcessGate::new(fast_open_config());
for _ in 0..8 {
gate.observe(false);
}
assert!(gate.should_skip_ssi(1));
gate.observe(true); assert_eq!(gate.clean_streak(), 0);
assert!(!gate.should_skip_ssi(1));
}
#[test]
fn min_observations_gate_holds() {
let mut gate = SsiEProcessGate::new(SsiEProcessConfig {
min_observations: 100,
min_clean_streak: 1,
..fast_open_config()
});
for _ in 0..10 {
gate.observe(false);
}
assert!(!gate.should_skip_ssi(1));
}
#[test]
fn alert_fires_on_repeated_conflicts() {
let mut gate = SsiEProcessGate::new(SsiEProcessConfig {
alpha: 1e-3,
p0: 1e-4,
alt_mult: 1000.0, min_observations: 3,
min_clean_streak: 1,
periodic_sample_rate: 0.0,
});
for _ in 0..3 {
gate.observe(true);
}
assert!(gate.is_alert(), "snapshot={}", gate.snapshot());
assert_eq!(gate.alert_state(), GateAlertState::Alert);
assert!(!gate.should_skip_ssi(1));
assert!(gate.alert_count() >= 1);
}
#[test]
fn reset_clears_state() {
let mut gate = SsiEProcessGate::new(fast_open_config());
for _ in 0..8 {
gate.observe(false);
}
for _ in 0..3 {
gate.observe(true);
}
assert!(gate.is_alert(), "snap={}", gate.snapshot());
gate.reset();
assert!(!gate.is_alert());
assert_eq!(gate.observations(), 0);
assert!((gate.e_value() - 1.0).abs() < f64::EPSILON);
}
#[test]
fn periodic_sampling_forces_audit() {
let mut gate = SsiEProcessGate::new(SsiEProcessConfig {
periodic_sample_rate: 0.5, ..fast_open_config()
});
for _ in 0..8 {
gate.observe(false);
}
assert!(!gate.should_skip_ssi(0));
assert!(!gate.should_skip_ssi(2));
assert!(gate.should_skip_ssi(1));
assert!(gate.should_skip_ssi(3));
}
#[test]
fn supermartingale_under_null_stays_bounded() {
let mut gate = SsiEProcessGate::new(SsiEProcessConfig {
alpha: 1e-3,
p0: 1e-3,
alt_mult: 100.0,
min_observations: 1,
min_clean_streak: 1,
periodic_sample_rate: 0.0,
});
for _ in 0..1000 {
gate.observe(false);
}
assert!(gate.e_value() <= 1.0, "e={}", gate.e_value());
assert!(!gate.is_alert());
}
#[test]
fn snapshot_is_displayable() {
let mut gate = SsiEProcessGate::new(fast_open_config());
gate.observe(false);
let snap = gate.snapshot();
let s = format!("{snap}");
assert!(s.contains("SsiEProcessGate"));
assert!(s.contains("obs=1"));
}
#[test]
fn gate_alert_state_display() {
assert_eq!(format!("{}", GateAlertState::Clear), "clear");
assert_eq!(format!("{}", GateAlertState::Watching), "watching");
assert_eq!(format!("{}", GateAlertState::Alert), "ALERT");
}
#[test]
#[ignore = "microbench: run with `cargo test --profile release-perf -- --ignored bench_gate_hot_path`"]
fn bench_gate_hot_path() {
let n: u64 = 1_000_000;
let mut gate = SsiEProcessGate::new(SsiEProcessConfig::default());
let t0 = std::time::Instant::now();
for i in 0..n {
gate.observe(i % 10000 == 0); }
let sentinel = gate.e_value() + gate.observations() as f64;
assert!(sentinel.is_finite());
let obs_ns = {
#[allow(clippy::cast_precision_loss)]
let elapsed = t0.elapsed().as_nanos() as f64;
#[allow(clippy::cast_precision_loss)]
let denom = n as f64;
elapsed / denom
};
println!("observe(): {obs_ns:.1} ns/call");
gate.reset();
for _ in 0..1024 {
gate.observe(false);
}
let t0 = std::time::Instant::now();
let mut grants = 0u64;
for i in 0..n {
if gate.should_skip_ssi(i) {
grants += 1;
}
}
let skip_ns = {
#[allow(clippy::cast_precision_loss)]
let elapsed = t0.elapsed().as_nanos() as f64;
#[allow(clippy::cast_precision_loss)]
let denom = n as f64;
elapsed / denom
};
println!("should_skip_ssi(): {skip_ns:.1} ns/call, grants={grants}/{n}");
println!("snapshot: {}", gate.snapshot());
}
#[test]
fn with_alpha_validates() {
let cfg = SsiEProcessConfig::default();
assert!(cfg.with_alpha(0.5).is_some());
assert!(SsiEProcessConfig::default().with_alpha(-1.0).is_none());
assert!(SsiEProcessConfig::default().with_alpha(1.0).is_none());
assert!(SsiEProcessConfig::default().with_alpha(f64::NAN).is_none());
}
}