entrenar/monitor/inference/safety_andon/
emergency.rs1use crate::monitor::andon::AlertLevel;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub enum EmergencyCondition {
9 CollisionImminent {
11 time_to_collision_ms: f32,
13 },
14
15 SensorDegraded {
17 sensor: String,
19 quality: f32,
21 },
22
23 AuditChainBroken,
25
26 DecisionTimeout {
28 max_ms: f32,
30 },
31
32 ConsecutiveLowConfidence {
34 count: usize,
36 threshold: f32,
38 },
39
40 InvalidOutput,
42}
43
44impl EmergencyCondition {
45 pub fn alert_level(&self) -> AlertLevel {
47 match self {
48 EmergencyCondition::CollisionImminent { .. } => AlertLevel::Critical,
49 EmergencyCondition::SensorDegraded { quality, .. } if *quality < 0.3 => {
50 AlertLevel::Critical
51 }
52 EmergencyCondition::SensorDegraded { .. } => AlertLevel::Error,
53 EmergencyCondition::AuditChainBroken => AlertLevel::Critical,
54 EmergencyCondition::DecisionTimeout { .. } => AlertLevel::Error,
55 EmergencyCondition::ConsecutiveLowConfidence { .. } => AlertLevel::Warning,
56 EmergencyCondition::InvalidOutput => AlertLevel::Critical,
57 }
58 }
59
60 pub fn message(&self) -> String {
62 match self {
63 EmergencyCondition::CollisionImminent { time_to_collision_ms } => {
64 format!("Collision imminent in {time_to_collision_ms:.1}ms")
65 }
66 EmergencyCondition::SensorDegraded { sensor, quality } => {
67 let quality_pct = quality * 100.0;
68 format!("Sensor {sensor} degraded: quality={quality_pct:.1}%")
69 }
70 EmergencyCondition::AuditChainBroken => "Audit chain integrity failure".to_string(),
71 EmergencyCondition::DecisionTimeout { max_ms } => {
72 format!("Decision timeout: exceeded {max_ms:.1}ms limit")
73 }
74 EmergencyCondition::ConsecutiveLowConfidence { count, threshold } => {
75 let threshold_pct = threshold * 100.0;
76 format!("{count} consecutive decisions below {threshold_pct:.1}% confidence")
77 }
78 EmergencyCondition::InvalidOutput => "NaN or Inf detected in model output".to_string(),
79 }
80 }
81}