use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct AnomalyEvent { pub pred_count: f32, pub power_mw: f32, pub query_memory: bool, pub overshoot: bool, pub violation_kind: String, } impl AnomalyEvent { pub fn new(pred_count: f32, power_mw: f32, violation_kind: impl Into) -> Self { let overshoot = pred_count > 100.0 || power_mw > 500.0; Self { pred_count, power_mw, query_memory: true, overshoot, violation_kind: violation_kind.into(), } } pub fn is_critical(&self) -> bool { self.overshoot && self.power_mw > 1000.0 } } #[cfg(test)] mod tests { use super::*; #[test] fn test_anomaly_normal_state() { let normal = AnomalyEvent::new(12.5, 45.0, "None"); assert!(!normal.overshoot); assert!(!normal.is_critical()); assert_eq!(normal.violation_kind, "None"); } #[test] fn test_anomaly_critical_overshoot() { let critical = AnomalyEvent::new(150.0, 1200.0, "InfiniteReplicationLoop"); assert!(critical.overshoot); assert!(critical.is_critical()); assert_eq!(critical.violation_kind, "InfiniteReplicationLoop"); } #[test] fn test_fatigue_resets_trigger() { let mut pred_count = 120.0f32; let event_before = AnomalyEvent::new(pred_count, 300.0, "WTA_Lock"); assert!(event_before.overshoot); pred_count -= 10.0 * 3.0; let event_after = AnomalyEvent::new(pred_count, 300.0, "WTA_Lock"); assert!(!event_after.overshoot); } }