Skip to main content

ruvector_dag/healing/
strategies.rs

1//! Repair Strategies
2
3use super::anomaly::{Anomaly, AnomalyType};
4
5#[derive(Debug, Clone)]
6pub struct RepairResult {
7    pub strategy_name: String,
8    pub success: bool,
9    pub duration_ms: f64,
10    pub details: String,
11}
12
13pub trait RepairStrategy: Send + Sync {
14    fn name(&self) -> &str;
15    fn can_repair(&self, anomaly: &Anomaly) -> bool;
16    fn repair(&self, anomaly: &Anomaly) -> RepairResult;
17}
18
19pub struct IndexRebalanceStrategy {
20    target_recall: f64,
21}
22
23impl IndexRebalanceStrategy {
24    pub fn new(target_recall: f64) -> Self {
25        Self { target_recall }
26    }
27}
28
29impl RepairStrategy for IndexRebalanceStrategy {
30    fn name(&self) -> &str {
31        "index_rebalance"
32    }
33
34    fn can_repair(&self, anomaly: &Anomaly) -> bool {
35        matches!(anomaly.anomaly_type, AnomalyType::LatencySpike)
36    }
37
38    fn repair(&self, anomaly: &Anomaly) -> RepairResult {
39        let start = std::time::Instant::now();
40
41        // Simulate rebalancing
42        // In real implementation, would call index rebuild
43        std::thread::sleep(std::time::Duration::from_millis(10));
44
45        RepairResult {
46            strategy_name: self.name().to_string(),
47            success: true,
48            duration_ms: start.elapsed().as_secs_f64() * 1000.0,
49            details: format!(
50                "Rebalanced index for component: {} (target recall: {:.2})",
51                anomaly.component, self.target_recall
52            ),
53        }
54    }
55}
56
57pub struct PatternResetStrategy {
58    quality_threshold: f64,
59}
60
61impl PatternResetStrategy {
62    pub fn new(quality_threshold: f64) -> Self {
63        Self { quality_threshold }
64    }
65}
66
67impl RepairStrategy for PatternResetStrategy {
68    fn name(&self) -> &str {
69        "pattern_reset"
70    }
71
72    fn can_repair(&self, anomaly: &Anomaly) -> bool {
73        matches!(
74            anomaly.anomaly_type,
75            AnomalyType::PatternDrift | AnomalyType::LearningStall
76        )
77    }
78
79    fn repair(&self, anomaly: &Anomaly) -> RepairResult {
80        let start = std::time::Instant::now();
81
82        // Reset low-quality patterns
83        std::thread::sleep(std::time::Duration::from_millis(5));
84
85        RepairResult {
86            strategy_name: self.name().to_string(),
87            success: true,
88            duration_ms: start.elapsed().as_secs_f64() * 1000.0,
89            details: format!(
90                "Reset patterns below quality {} for component: {}",
91                self.quality_threshold, anomaly.component
92            ),
93        }
94    }
95}
96
97pub struct CacheFlushStrategy;
98
99impl RepairStrategy for CacheFlushStrategy {
100    fn name(&self) -> &str {
101        "cache_flush"
102    }
103
104    fn can_repair(&self, anomaly: &Anomaly) -> bool {
105        matches!(
106            anomaly.anomaly_type,
107            AnomalyType::CacheEviction | AnomalyType::MemoryPressure
108        )
109    }
110
111    fn repair(&self, anomaly: &Anomaly) -> RepairResult {
112        let start = std::time::Instant::now();
113
114        // Flush caches
115        std::thread::sleep(std::time::Duration::from_millis(2));
116
117        RepairResult {
118            strategy_name: self.name().to_string(),
119            success: true,
120            duration_ms: start.elapsed().as_secs_f64() * 1000.0,
121            details: format!(
122                "Flushed attention and pattern caches for component: {}",
123                anomaly.component
124            ),
125        }
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn test_index_rebalance_strategy() {
135        let strategy = IndexRebalanceStrategy::new(0.95);
136        let anomaly = Anomaly {
137            anomaly_type: AnomalyType::LatencySpike,
138            z_score: 4.5,
139            value: 100.0,
140            expected: 10.0,
141            timestamp: std::time::Instant::now(),
142            component: "hnsw_index".to_string(),
143        };
144
145        assert!(strategy.can_repair(&anomaly));
146        let result = strategy.repair(&anomaly);
147        assert!(result.success);
148        assert!(result.duration_ms > 0.0);
149    }
150
151    #[test]
152    fn test_pattern_reset_strategy() {
153        let strategy = PatternResetStrategy::new(0.8);
154        let anomaly = Anomaly {
155            anomaly_type: AnomalyType::PatternDrift,
156            z_score: 3.2,
157            value: 0.5,
158            expected: 0.9,
159            timestamp: std::time::Instant::now(),
160            component: "pattern_cache".to_string(),
161        };
162
163        assert!(strategy.can_repair(&anomaly));
164        let result = strategy.repair(&anomaly);
165        assert!(result.success);
166    }
167
168    #[test]
169    fn test_cache_flush_strategy() {
170        let strategy = CacheFlushStrategy;
171        let anomaly = Anomaly {
172            anomaly_type: AnomalyType::MemoryPressure,
173            z_score: 5.0,
174            value: 95.0,
175            expected: 60.0,
176            timestamp: std::time::Instant::now(),
177            component: "memory".to_string(),
178        };
179
180        assert!(strategy.can_repair(&anomaly));
181        let result = strategy.repair(&anomaly);
182        assert!(result.success);
183    }
184}