aimds_response/
meta_learning.rs

1//! Meta-learning engine using strange-loop for recursive self-improvement
2
3use std::collections::HashMap;
4use midstreamer_strange_loop::{StrangeLoop, StrangeLoopConfig, MetaLevel, MetaKnowledge};
5use crate::{MitigationOutcome, FeedbackSignal};
6use serde::{Deserialize, Serialize};
7
8/// Adaptive rule learned from threat incidents
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct AdaptiveRule {
11    pub id: String,
12    pub pattern: ThreatPattern,
13    pub confidence: f64,
14    pub created_at: chrono::DateTime<chrono::Utc>,
15    pub updated_at: chrono::DateTime<chrono::Utc>,
16    pub success_count: u64,
17    pub failure_count: u64,
18}
19
20/// Threat pattern representation
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct ThreatPattern {
23    pub features: HashMap<String, f64>,
24    pub threat_type: String,
25    pub severity_threshold: f64,
26}
27
28impl Default for ThreatPattern {
29    fn default() -> Self {
30        Self {
31            features: HashMap::new(),
32            threat_type: "unknown".to_string(),
33            severity_threshold: 0.5,
34        }
35    }
36}
37
38impl ThreatPattern {
39    pub fn from_features(features: &HashMap<String, f64>) -> Self {
40        Self {
41            features: features.clone(),
42            threat_type: "detected".to_string(),
43            severity_threshold: 0.5,
44        }
45    }
46}
47
48/// Meta-learning engine for autonomous response optimization
49pub struct MetaLearningEngine {
50    /// Strange-loop meta-learner (25 levels validated)
51    learner: StrangeLoop,
52
53    /// Learned patterns from successful detections
54    learned_patterns: Vec<AdaptiveRule>,
55
56    /// Pattern effectiveness tracking
57    pattern_effectiveness: HashMap<String, EffectivenessMetrics>,
58
59    /// Current optimization level (0-25)
60    current_level: usize,
61
62    /// Learning rate for pattern updates
63    learning_rate: f64,
64}
65
66impl MetaLearningEngine {
67    /// Create new meta-learning engine
68    pub fn new() -> Self {
69        let config = StrangeLoopConfig {
70            max_meta_depth: 25,
71            enable_self_modification: true,
72            max_modifications_per_cycle: 10,
73            safety_check_enabled: true,
74        };
75
76        Self {
77            learner: StrangeLoop::new(config),
78            learned_patterns: Vec::new(),
79            pattern_effectiveness: HashMap::new(),
80            current_level: 0,
81            learning_rate: 0.1,
82        }
83    }
84
85    /// Learn from mitigation outcome
86    pub async fn learn_from_outcome(&mut self, outcome: &MitigationOutcome) {
87        // Extract pattern from outcome
88        let pattern = self.extract_pattern(outcome);
89
90        // Update pattern effectiveness
91        self.update_pattern_effectiveness(&pattern, outcome.success);
92
93        // Apply meta-learning if pattern is significant
94        if self.is_significant_pattern(&pattern) {
95            self.apply_meta_learning(pattern).await;
96        }
97    }
98
99    /// Learn from threat incident
100    pub async fn learn_from_incident(&mut self, incident: &ThreatIncident) {
101        // Extract features from incident
102        let features = self.extract_incident_features(incident);
103
104        // Create adaptive rule
105        let rule = AdaptiveRule {
106            id: uuid::Uuid::new_v4().to_string(),
107            pattern: ThreatPattern::from_features(&features),
108            confidence: 0.5, // Initial confidence
109            created_at: chrono::Utc::now(),
110            updated_at: chrono::Utc::now(),
111            success_count: 0,
112            failure_count: 0,
113        };
114
115        // Add to learned patterns
116        self.learned_patterns.push(rule);
117
118        // Trigger meta-learning optimization
119        self.optimize_patterns().await;
120    }
121
122    /// Optimize strategies based on feedback signals
123    pub fn optimize_strategy(&mut self, feedback: &[FeedbackSignal]) {
124        for signal in feedback {
125            // Update effectiveness metrics
126            if let Some(metrics) = self.pattern_effectiveness.get_mut(&signal.strategy_id) {
127                metrics.update(signal.effectiveness_score, signal.success);
128            }
129        }
130
131        // Apply recursive optimization
132        self.recursive_optimize(self.current_level);
133
134        // Advance optimization level if ready
135        if self.should_advance_level() {
136            self.current_level = (self.current_level + 1).min(25);
137        }
138    }
139
140    /// Get count of learned patterns
141    pub fn learned_patterns_count(&self) -> usize {
142        self.learned_patterns.len()
143    }
144
145    /// Get current optimization level
146    pub fn current_optimization_level(&self) -> usize {
147        self.current_level
148    }
149
150    /// Extract pattern from mitigation outcome
151    fn extract_pattern(&self, outcome: &MitigationOutcome) -> LearnedPattern {
152        LearnedPattern {
153            id: uuid::Uuid::new_v4().to_string(),
154            strategy_id: outcome.strategy_id.clone(),
155            threat_type: outcome.threat_type.clone(),
156            features: outcome.features.clone(),
157            success: outcome.success,
158            timestamp: chrono::Utc::now(),
159        }
160    }
161
162    /// Update pattern effectiveness tracking
163    fn update_pattern_effectiveness(&mut self, pattern: &LearnedPattern, success: bool) {
164        let metrics = self.pattern_effectiveness
165            .entry(pattern.id.clone())
166            .or_insert_with(EffectivenessMetrics::new);
167
168        metrics.update(if success { 1.0 } else { 0.0 }, success);
169    }
170
171    /// Check if pattern is significant enough for meta-learning
172    fn is_significant_pattern(&self, pattern: &LearnedPattern) -> bool {
173        if let Some(metrics) = self.pattern_effectiveness.get(&pattern.id) {
174            metrics.total_applications >= 5 && metrics.average_score > 0.6
175        } else {
176            false
177        }
178    }
179
180    /// Apply meta-learning to pattern
181    async fn apply_meta_learning(&mut self, pattern: LearnedPattern) {
182        // Use strange-loop's learn_at_level for meta-learning
183        let meta_level = MetaLevel(self.current_level);
184        let confidence = self.calculate_pattern_confidence(&pattern);
185
186        // Create knowledge strings from pattern
187        let knowledge_data = vec![
188            format!("pattern_id: {}", pattern.id),
189            format!("threat_type: {}", pattern.threat_type),
190            format!("confidence: {}", confidence),
191        ];
192
193        // Apply meta-learning at current level
194        if let Ok(meta_knowledge_vec) = self.learner.learn_at_level(
195            meta_level,
196            &knowledge_data,
197        ) {
198            // Update learned patterns with first meta-knowledge (if any)
199            if let Some(meta_knowledge) = meta_knowledge_vec.first() {
200                self.update_learned_patterns_from_knowledge(&pattern.id, meta_knowledge.clone());
201            }
202        }
203    }
204
205    /// Calculate confidence for pattern
206    fn calculate_pattern_confidence(&self, pattern: &LearnedPattern) -> f64 {
207        if let Some(metrics) = self.pattern_effectiveness.get(&pattern.id) {
208            metrics.average_score
209        } else {
210            0.5
211        }
212    }
213
214    /// Update learned patterns from meta-knowledge
215    fn update_learned_patterns_from_knowledge(&mut self, pattern_id: &str, knowledge: MetaKnowledge) {
216        // Find and update existing rule or create new one
217        if let Some(rule) = self.learned_patterns.iter_mut()
218            .find(|r| r.id == pattern_id) {
219            rule.confidence = knowledge.confidence;
220            rule.updated_at = chrono::Utc::now();
221        }
222    }
223
224    /// Extract features from incident
225    fn extract_incident_features(&self, incident: &ThreatIncident) -> HashMap<String, f64> {
226        let mut features = HashMap::new();
227
228        features.insert("severity".to_string(), incident.severity as f64);
229        features.insert("confidence".to_string(), incident.confidence);
230
231        // Add type-specific features
232        match &incident.threat_type {
233            ThreatType::Anomaly(score) => {
234                features.insert("anomaly_score".to_string(), *score);
235            }
236            ThreatType::Attack(attack_type) => {
237                features.insert("attack_type_id".to_string(), attack_type.to_id() as f64);
238            }
239            ThreatType::Intrusion(level) => {
240                features.insert("intrusion_level".to_string(), *level as f64);
241            }
242        }
243
244        features
245    }
246
247    /// Optimize patterns using meta-learning
248    async fn optimize_patterns(&mut self) {
249        // Apply strange-loop recursive optimization
250        for level in 0..=self.current_level {
251            self.recursive_optimize(level);
252        }
253
254        // Prune low-confidence patterns
255        self.learned_patterns.retain(|p| p.confidence > 0.3);
256    }
257
258    /// Recursive optimization at given level
259    fn recursive_optimize(&mut self, level: usize) {
260        // Meta-meta-learning: optimize the optimization strategy itself
261        let optimization_effectiveness = self.calculate_optimization_effectiveness();
262
263        // Adjust learning rate based on effectiveness
264        if optimization_effectiveness > 0.8 {
265            self.learning_rate *= 1.1; // Increase learning rate
266        } else if optimization_effectiveness < 0.4 {
267            self.learning_rate *= 0.9; // Decrease learning rate
268        }
269
270        // Apply recursive pattern refinement
271        let learning_rate = self.learning_rate;
272        for pattern in &mut self.learned_patterns {
273            // Apply recursive refinement inline to avoid borrow checker issues
274            let refinement = learning_rate * (level as f64 / 25.0);
275            pattern.confidence = (pattern.confidence + refinement).clamp(0.0, 1.0);
276        }
277    }
278
279    /// Calculate optimization effectiveness
280    fn calculate_optimization_effectiveness(&self) -> f64 {
281        if self.pattern_effectiveness.is_empty() {
282            return 0.5;
283        }
284
285        let total: f64 = self.pattern_effectiveness.values()
286            .map(|m| m.average_score)
287            .sum();
288
289        total / self.pattern_effectiveness.len() as f64
290    }
291
292    /// Refine confidence at given optimization level
293    #[allow(dead_code)]
294    fn refine_confidence(&self, current: f64, level: usize) -> f64 {
295        // Apply recursive refinement
296        let refinement = self.learning_rate * (level as f64 / 25.0);
297        (current + refinement).clamp(0.0, 1.0)
298    }
299
300    /// Check if should advance to next optimization level
301    fn should_advance_level(&self) -> bool {
302        let effectiveness = self.calculate_optimization_effectiveness();
303        effectiveness > 0.75 && self.learned_patterns.len() >= 10
304    }
305}
306
307impl Default for MetaLearningEngine {
308    fn default() -> Self {
309        Self::new()
310    }
311}
312
313/// Pattern learned from mitigation outcomes
314#[derive(Debug, Clone, Serialize, Deserialize)]
315struct LearnedPattern {
316    id: String,
317    strategy_id: String,
318    threat_type: String,
319    features: HashMap<String, f64>,
320    success: bool,
321    timestamp: chrono::DateTime<chrono::Utc>,
322}
323
324/// Metrics for pattern effectiveness tracking
325#[derive(Debug, Clone)]
326struct EffectivenessMetrics {
327    total_applications: u64,
328    successful_applications: u64,
329    average_score: f64,
330    last_updated: chrono::DateTime<chrono::Utc>,
331}
332
333impl EffectivenessMetrics {
334    fn new() -> Self {
335        Self {
336            total_applications: 0,
337            successful_applications: 0,
338            average_score: 0.0,
339            last_updated: chrono::Utc::now(),
340        }
341    }
342
343    fn update(&mut self, score: f64, success: bool) {
344        self.total_applications += 1;
345        if success {
346            self.successful_applications += 1;
347        }
348
349        // Update running average
350        self.average_score = (self.average_score * (self.total_applications - 1) as f64 + score)
351            / self.total_applications as f64;
352
353        self.last_updated = chrono::Utc::now();
354    }
355}
356
357/// Threat incident for meta-learning
358#[derive(Debug, Clone)]
359pub struct ThreatIncident {
360    pub id: String,
361    pub threat_type: ThreatType,
362    pub severity: u8,
363    pub confidence: f64,
364    pub timestamp: chrono::DateTime<chrono::Utc>,
365}
366
367/// Threat type enumeration
368#[derive(Debug, Clone)]
369pub enum ThreatType {
370    Anomaly(f64),
371    Attack(AttackType),
372    Intrusion(u8),
373}
374
375/// Attack type enumeration
376#[derive(Debug, Clone)]
377pub enum AttackType {
378    DDoS,
379    SqlInjection,
380    XSS,
381    CSRF,
382    Other(String),
383}
384
385impl AttackType {
386    fn to_id(&self) -> u8 {
387        match self {
388            AttackType::DDoS => 1,
389            AttackType::SqlInjection => 2,
390            AttackType::XSS => 3,
391            AttackType::CSRF => 4,
392            AttackType::Other(_) => 99,
393        }
394    }
395}
396
397#[cfg(test)]
398mod tests {
399    use super::*;
400
401    #[tokio::test]
402    async fn test_meta_learning_creation() {
403        let engine = MetaLearningEngine::new();
404        assert_eq!(engine.current_level, 0);
405        assert_eq!(engine.learned_patterns_count(), 0);
406    }
407
408    #[tokio::test]
409    async fn test_pattern_learning() {
410        let mut engine = MetaLearningEngine::new();
411
412        let incident = ThreatIncident {
413            id: "test-1".to_string(),
414            threat_type: ThreatType::Anomaly(0.85),
415            severity: 7,
416            confidence: 0.9,
417            timestamp: chrono::Utc::now(),
418        };
419
420        engine.learn_from_incident(&incident).await;
421        assert!(engine.learned_patterns_count() > 0);
422    }
423
424    #[test]
425    fn test_effectiveness_metrics() {
426        let mut metrics = EffectivenessMetrics::new();
427
428        metrics.update(0.8, true);
429        assert_eq!(metrics.total_applications, 1);
430        assert_eq!(metrics.successful_applications, 1);
431        assert_eq!(metrics.average_score, 0.8);
432
433        metrics.update(0.6, false);
434        assert_eq!(metrics.total_applications, 2);
435        assert_eq!(metrics.successful_applications, 1);
436        assert_eq!(metrics.average_score, 0.7);
437    }
438
439    #[test]
440    fn test_optimization_level_advancement() {
441        let mut engine = MetaLearningEngine::new();
442
443        // Add sufficient patterns
444        for i in 0..15 {
445            engine.learned_patterns.push(AdaptiveRule {
446                id: format!("rule-{}", i),
447                pattern: ThreatPattern::default(),
448                confidence: 0.8,
449                created_at: chrono::Utc::now(),
450                updated_at: chrono::Utc::now(),
451                success_count: 10,
452                failure_count: 2,
453            });
454        }
455
456        // Should be ready to advance
457        assert!(engine.should_advance_level());
458    }
459}