ricecoder_learning/
manager.rs

1/// Core learning manager that orchestrates all learning operations
2use crate::analytics_engine::AnalyticsEngine;
3use crate::conflict_resolver::ConflictResolver;
4use crate::decision_logger::DecisionLogger;
5use crate::error::{LearningError, Result};
6use crate::models::{Decision, DecisionContext, LearnedPattern, LearningConfig, Rule, RuleScope};
7use crate::pattern_capturer::PatternCapturer;
8use crate::pattern_validator::PatternValidator;
9use crate::rule_promoter::RulePromoter;
10use crate::rule_storage::RuleStorage;
11use crate::rule_validator::RuleValidator;
12use crate::scope_config::{ScopeConfiguration, ScopeConfigurationLoader, ScopeFilter};
13use std::collections::HashMap;
14use std::path::PathBuf;
15use std::sync::Arc;
16use tokio::sync::RwLock;
17
18/// Central coordinator for all learning operations
19pub struct LearningManager {
20    /// Configuration for the learning system
21    config: Arc<RwLock<LearningConfig>>,
22    /// Scope configuration with learning control flags
23    scope_config: Arc<RwLock<ScopeConfiguration>>,
24    /// Decision logger for capturing and retrieving decisions
25    decision_logger: Arc<DecisionLogger>,
26    /// Rule storage for persisting rules
27    rule_storage: Arc<RuleStorage>,
28    /// Rule validator for validating rules before storage
29    rule_validator: Arc<RuleValidator>,
30    /// Pattern capturer for extracting patterns from decisions
31    pattern_capturer: Arc<PatternCapturer>,
32    /// Pattern validator for validating patterns against decisions
33    pattern_validator: Arc<PatternValidator>,
34    /// Rule promoter for managing rule promotion workflow
35    rule_promoter: Arc<RwLock<RulePromoter>>,
36    /// In-memory storage for patterns
37    patterns: Arc<RwLock<HashMap<String, LearnedPattern>>>,
38    /// Analytics engine for tracking rule metrics
39    analytics_engine: Arc<AnalyticsEngine>,
40}
41
42impl LearningManager {
43    /// Create a new learning manager with the specified scope
44    pub fn new(scope: RuleScope) -> Self {
45        let config = LearningConfig::new(scope);
46        let scope_config = ScopeConfiguration::new(scope);
47        Self {
48            config: Arc::new(RwLock::new(config.clone())),
49            scope_config: Arc::new(RwLock::new(scope_config)),
50            decision_logger: Arc::new(DecisionLogger::new()),
51            rule_storage: Arc::new(RuleStorage::new(scope)),
52            rule_validator: Arc::new(RuleValidator::new()),
53            pattern_capturer: Arc::new(PatternCapturer::new()),
54            pattern_validator: Arc::new(PatternValidator::new()),
55            rule_promoter: Arc::new(RwLock::new(RulePromoter::new())),
56            patterns: Arc::new(RwLock::new(HashMap::new())),
57            analytics_engine: Arc::new(AnalyticsEngine::new()),
58        }
59    }
60
61    /// Create a new learning manager with custom configuration
62    pub fn with_config(config: LearningConfig) -> Result<Self> {
63        config.validate()?;
64        let scope = config.scope;
65        let scope_config = ScopeConfiguration::new(scope);
66        Ok(Self {
67            config: Arc::new(RwLock::new(config)),
68            scope_config: Arc::new(RwLock::new(scope_config)),
69            decision_logger: Arc::new(DecisionLogger::new()),
70            rule_storage: Arc::new(RuleStorage::new(scope)),
71            rule_validator: Arc::new(RuleValidator::new()),
72            pattern_capturer: Arc::new(PatternCapturer::new()),
73            pattern_validator: Arc::new(PatternValidator::new()),
74            rule_promoter: Arc::new(RwLock::new(RulePromoter::new())),
75            patterns: Arc::new(RwLock::new(HashMap::new())),
76            analytics_engine: Arc::new(AnalyticsEngine::new()),
77        })
78    }
79
80    /// Get the current configuration
81    pub async fn get_config(&self) -> LearningConfig {
82        self.config.read().await.clone()
83    }
84
85    /// Update the configuration
86    pub async fn set_config(&self, config: LearningConfig) -> Result<()> {
87        config.validate()?;
88        *self.config.write().await = config;
89        Ok(())
90    }
91
92    /// Get the current learning scope
93    pub async fn get_scope(&self) -> RuleScope {
94        self.config.read().await.scope
95    }
96
97    /// Check if learning is enabled
98    pub async fn is_enabled(&self) -> bool {
99        self.config.read().await.enabled
100    }
101
102    /// Enable or disable learning
103    pub async fn set_enabled(&self, enabled: bool) {
104        let mut config = self.config.write().await;
105        config.enabled = enabled;
106    }
107
108    // ============================================================================
109    // Scope Configuration Methods (Task 8.1, 8.2, 8.3)
110    // ============================================================================
111
112    /// Load scope configuration from project/user/defaults hierarchy
113    pub async fn load_scope_configuration(&self) -> Result<ScopeConfiguration> {
114        let scope = self.get_scope().await;
115        let config = ScopeConfigurationLoader::load_configuration(scope).await?;
116        *self.scope_config.write().await = config.clone();
117        Ok(config)
118    }
119
120    /// Get the current scope configuration
121    pub async fn get_scope_configuration(&self) -> ScopeConfiguration {
122        self.scope_config.read().await.clone()
123    }
124
125    /// Update the scope configuration
126    pub async fn set_scope_configuration(&self, config: ScopeConfiguration) -> Result<()> {
127        config.validate()?;
128        *self.scope_config.write().await = config;
129        Ok(())
130    }
131
132    /// Check if learning is enabled for the current scope
133    pub async fn is_scope_learning_enabled(&self) -> bool {
134        self.scope_config.read().await.learning_enabled
135    }
136
137    /// Enable or disable learning for the current scope
138    pub async fn set_scope_learning_enabled(&self, enabled: bool) {
139        let mut config = self.scope_config.write().await;
140        config.learning_enabled = enabled;
141    }
142
143    /// Check if project-only learning is enabled
144    pub async fn is_project_only_learning(&self) -> bool {
145        self.scope_config.read().await.project_only
146    }
147
148    /// Enable or disable project-only learning
149    pub async fn set_project_only_learning(&self, project_only: bool) {
150        let mut config = self.scope_config.write().await;
151        config.project_only = project_only;
152    }
153
154    /// Check if approval is required for new rules
155    pub async fn is_approval_required(&self) -> bool {
156        self.scope_config.read().await.approval_required
157    }
158
159    /// Enable or disable approval requirement for new rules
160    pub async fn set_approval_required(&self, required: bool) {
161        let mut config = self.scope_config.write().await;
162        config.approval_required = required;
163    }
164
165    /// Get the maximum number of rules for the current scope
166    pub async fn get_max_rules(&self) -> usize {
167        self.scope_config.read().await.max_rules
168    }
169
170    /// Set the maximum number of rules for the current scope
171    pub async fn set_max_rules(&self, max_rules: usize) -> Result<()> {
172        if max_rules == 0 {
173            return Err(LearningError::ConfigurationError(
174                "max_rules must be greater than 0".to_string(),
175            ));
176        }
177        let mut config = self.scope_config.write().await;
178        config.max_rules = max_rules;
179        Ok(())
180    }
181
182    /// Get the retention period in days for the current scope
183    pub async fn get_retention_days(&self) -> u32 {
184        self.scope_config.read().await.retention_days
185    }
186
187    /// Set the retention period in days for the current scope
188    pub async fn set_retention_days(&self, retention_days: u32) -> Result<()> {
189        if retention_days == 0 {
190            return Err(LearningError::ConfigurationError(
191                "retention_days must be greater than 0".to_string(),
192            ));
193        }
194        let mut config = self.scope_config.write().await;
195        config.retention_days = retention_days;
196        Ok(())
197    }
198
199    /// Save scope configuration to project-level config file
200    pub async fn save_scope_configuration_to_project(&self) -> Result<()> {
201        let config = self.scope_config.read().await.clone();
202        ScopeConfigurationLoader::save_project_config(&config).await
203    }
204
205    /// Save scope configuration to user-level config file
206    pub async fn save_scope_configuration_to_user(&self) -> Result<()> {
207        let config = self.scope_config.read().await.clone();
208        ScopeConfigurationLoader::save_user_config(&config).await
209    }
210
211    /// Get rules filtered by current scope
212    pub async fn get_rules_for_scope(&self) -> Result<Vec<Rule>> {
213        let scope = self.get_scope().await;
214        let all_rules = self.get_rules().await?;
215        Ok(ScopeFilter::get_rules_with_precedence(&all_rules, scope))
216    }
217
218    /// Get rules filtered by specific scope
219    pub async fn get_rules_by_scope(&self, scope: RuleScope) -> Result<Vec<Rule>> {
220        let all_rules = self.get_rules().await?;
221        Ok(ScopeFilter::filter_by_scope(&all_rules, scope))
222    }
223
224    /// Check if rules from different scopes interfere
225    pub async fn check_scope_interference(
226        &self,
227        scope1: RuleScope,
228        scope2: RuleScope,
229    ) -> Result<bool> {
230        let all_rules = self.get_rules().await?;
231        let rules1 = ScopeFilter::filter_by_scope(&all_rules, scope1);
232        let rules2 = ScopeFilter::filter_by_scope(&all_rules, scope2);
233        Ok(ScopeFilter::check_scope_interference(&rules1, &rules2))
234    }
235
236    /// Capture a decision with full metadata
237    pub async fn capture_decision(&self, decision: Decision) -> Result<String> {
238        if !self.is_enabled().await {
239            return Err(LearningError::DecisionCaptureFailed(
240                "Learning is disabled".to_string(),
241            ));
242        }
243
244        self.decision_logger.log_decision(decision).await
245    }
246
247    /// Get all captured decisions
248    pub async fn get_decisions(&self) -> Vec<Decision> {
249        self.decision_logger.get_history().await
250    }
251
252    /// Get decisions by type
253    pub async fn get_decisions_by_type(&self, decision_type: &str) -> Vec<Decision> {
254        self.decision_logger.get_history_by_type(decision_type).await
255    }
256
257    /// Get decisions by context
258    pub async fn get_decisions_by_context(&self, context: &DecisionContext) -> Vec<Decision> {
259        self.decision_logger.get_history_by_context(context).await
260    }
261
262    /// Get a specific decision by ID
263    pub async fn get_decision(&self, decision_id: &str) -> Result<Decision> {
264        self.decision_logger.get_decision(decision_id).await
265    }
266
267    /// Replay decisions for validation
268    pub async fn replay_decisions(&self) -> Vec<Decision> {
269        self.decision_logger.replay_decisions().await
270    }
271
272    /// Replay decisions for a specific context
273    pub async fn replay_decisions_for_context(&self, context: &DecisionContext) -> Vec<Decision> {
274        self.decision_logger.replay_decisions_for_context(context).await
275    }
276
277    /// Get the number of captured decisions
278    pub async fn decision_count(&self) -> usize {
279        self.decision_logger.decision_count().await
280    }
281
282    /// Clear all decisions
283    pub async fn clear_decisions(&self) {
284        self.decision_logger.clear().await;
285    }
286
287    /// Get decision statistics
288    pub async fn get_decision_statistics(&self) -> crate::decision_logger::DecisionStatistics {
289        self.decision_logger.get_statistics().await
290    }
291
292    /// Store a rule (with validation)
293    pub async fn store_rule(&self, rule: Rule) -> Result<String> {
294        // Validate the rule before storage
295        self.rule_validator.validate(&rule)?;
296
297        // Check for conflicts with existing rules
298        let existing_rules = self.rule_storage.list_rules().await?;
299        self.rule_validator.check_conflicts(&rule, &existing_rules)?;
300
301        // Store the validated rule
302        self.rule_storage.store_rule(rule).await
303    }
304
305    /// Get a rule by ID
306    pub async fn get_rule(&self, rule_id: &str) -> Result<Rule> {
307        self.rule_storage.get_rule(rule_id).await
308    }
309
310    /// Get all rules
311    pub async fn get_rules(&self) -> Result<Vec<Rule>> {
312        self.rule_storage.list_rules().await
313    }
314
315    /// Delete a rule
316    pub async fn delete_rule(&self, rule_id: &str) -> Result<()> {
317        self.rule_storage.delete_rule(rule_id).await
318    }
319
320    /// Update a rule (with validation)
321    pub async fn update_rule(&self, rule: Rule) -> Result<String> {
322        // Validate the rule before update
323        self.rule_validator.validate(&rule)?;
324
325        // Store the validated rule
326        self.rule_storage.update_rule(rule).await
327    }
328
329    /// Validate a rule without storing it
330    pub fn validate_rule(&self, rule: &Rule) -> Result<()> {
331        self.rule_validator.validate(rule)
332    }
333
334    /// Get a detailed validation report for a rule
335    pub fn validate_rule_with_report(&self, rule: &Rule) -> crate::rule_validator::ValidationReport {
336        self.rule_validator.validate_with_report(rule)
337    }
338
339    /// Check if a rule conflicts with existing rules
340    pub async fn check_rule_conflicts(&self, rule: &Rule) -> Result<()> {
341        let existing_rules = self.rule_storage.list_rules().await?;
342        self.rule_validator.check_conflicts(rule, &existing_rules)
343    }
344
345    /// Get rules by pattern
346    pub async fn get_rules_by_pattern(&self, pattern: &str) -> Result<Vec<Rule>> {
347        self.rule_storage.get_rules_by_pattern(pattern).await
348    }
349
350    /// Get rules by source
351    pub async fn get_rules_by_source(&self, source: crate::models::RuleSource) -> Result<Vec<Rule>> {
352        self.rule_storage.get_rules_by_source(source).await
353    }
354
355    /// Get rules by confidence
356    pub async fn get_rules_by_confidence(&self, min_confidence: f32) -> Result<Vec<Rule>> {
357        self.rule_storage.get_rules_by_confidence(min_confidence).await
358    }
359
360    /// Get rules sorted by usage
361    pub async fn get_rules_by_usage(&self) -> Result<Vec<Rule>> {
362        self.rule_storage.get_rules_by_usage().await
363    }
364
365    /// Get rules by usage count
366    pub async fn get_rules_by_usage_count(&self, min_usage: u64) -> Result<Vec<Rule>> {
367        self.rule_storage.get_rules_by_usage_count(min_usage).await
368    }
369
370    /// Get rules by success rate
371    pub async fn get_rules_by_success_rate(&self, min_success_rate: f32) -> Result<Vec<Rule>> {
372        self.rule_storage.get_rules_by_success_rate(min_success_rate).await
373    }
374
375    /// Get rule count
376    pub async fn rule_count(&self) -> Result<usize> {
377        self.rule_storage.rule_count().await
378    }
379
380    /// Clear all rules
381    pub async fn clear_rules(&self) -> Result<()> {
382        self.rule_storage.clear_all().await
383    }
384
385    /// Load all rules into cache
386    pub async fn load_rules(&self) -> Result<()> {
387        self.rule_storage.load_all().await
388    }
389
390    /// Detect if two rules conflict
391    pub fn detect_rule_conflict(rule1: &Rule, rule2: &Rule) -> bool {
392        ConflictResolver::detect_conflict(rule1, rule2)
393    }
394
395    /// Find all conflicts in the current rules
396    pub async fn find_rule_conflicts(&self) -> Result<Vec<(Rule, Rule)>> {
397        let rules = self.get_rules().await?;
398        Ok(ConflictResolver::find_conflicts(&rules))
399    }
400
401    /// Check if a rule conflicts with existing rules before storage
402    pub async fn check_rule_conflicts_before_storage(&self, rule: &Rule) -> Result<()> {
403        let existing_rules = self.get_rules().await?;
404        ConflictResolver::check_conflicts(rule, &existing_rules)
405    }
406
407    /// Apply scope precedence to get the highest priority rule for a pattern
408    pub async fn get_rule_by_pattern_with_precedence(&self, pattern: &str) -> Result<Option<Rule>> {
409        let rules = self.get_rules().await?;
410        Ok(ConflictResolver::get_highest_priority_rule(&rules, pattern))
411    }
412
413    /// Get all rules for a pattern, applying scope precedence
414    pub async fn get_rules_by_pattern_with_precedence(&self, pattern: &str) -> Result<Vec<Rule>> {
415        let rules = self.get_rules().await?;
416        Ok(ConflictResolver::get_rules_by_pattern_with_precedence(&rules, pattern))
417    }
418
419    /// Resolve conflicts in all rules by applying scope precedence
420    pub async fn resolve_all_conflicts(&self) -> Result<Vec<Rule>> {
421        let rules = self.get_rules().await?;
422        ConflictResolver::resolve_conflicts(&rules)
423    }
424
425    /// Check for conflicts between project and global rules
426    pub async fn check_cross_scope_conflicts(
427        &self,
428        project_rules: &[Rule],
429        global_rules: &[Rule],
430    ) -> Vec<(Rule, Rule)> {
431        ConflictResolver::check_cross_scope_conflicts(project_rules, global_rules)
432    }
433
434    /// Log conflict resolution decision
435    pub fn log_conflict_resolution(selected_rule: &Rule, conflicting_rules: &[Rule]) -> String {
436        ConflictResolver::log_conflict_resolution(selected_rule, conflicting_rules)
437    }
438
439    /// Store a pattern
440    pub async fn store_pattern(&self, pattern: LearnedPattern) -> Result<String> {
441        let pattern_id = pattern.id.clone();
442        let mut patterns = self.patterns.write().await;
443        patterns.insert(pattern_id.clone(), pattern);
444
445        Ok(pattern_id)
446    }
447
448    /// Get a pattern
449    pub async fn get_pattern(&self, pattern_id: &str) -> Result<LearnedPattern> {
450        let patterns = self.patterns.read().await;
451        patterns
452            .get(pattern_id)
453            .cloned()
454            .ok_or_else(|| LearningError::PatternNotFound(pattern_id.to_string()))
455    }
456
457    /// Get all patterns
458    pub async fn get_patterns(&self) -> Vec<LearnedPattern> {
459        self.patterns
460            .read()
461            .await
462            .values()
463            .cloned()
464            .collect()
465    }
466
467    /// Get patterns by type
468    pub async fn get_patterns_by_type(&self, pattern_type: &str) -> Vec<LearnedPattern> {
469        self.patterns
470            .read()
471            .await
472            .values()
473            .filter(|p| p.pattern_type == pattern_type)
474            .cloned()
475            .collect()
476    }
477
478    /// Delete a pattern
479    pub async fn delete_pattern(&self, pattern_id: &str) -> Result<()> {
480        let mut patterns = self.patterns.write().await;
481        patterns
482            .remove(pattern_id)
483            .ok_or_else(|| LearningError::PatternNotFound(pattern_id.to_string()))?;
484        Ok(())
485    }
486
487    /// Get the storage path for a given scope
488    pub fn get_scope_path(&self, scope: RuleScope) -> Result<PathBuf> {
489        match scope {
490            RuleScope::Global => {
491                let home = dirs::home_dir()
492                    .ok_or_else(|| LearningError::PathResolutionFailed("Home directory not found".to_string()))?;
493                Ok(home.join(".ricecoder").join("rules"))
494            }
495            RuleScope::Project => Ok(PathBuf::from(".ricecoder/rules")),
496            RuleScope::Session => Err(LearningError::PathResolutionFailed(
497                "Session scope has no persistent path".to_string(),
498            )),
499        }
500    }
501
502    /// Extract patterns from decision history
503    pub async fn extract_patterns(&self) -> Result<Vec<LearnedPattern>> {
504        let decisions = self.get_decisions().await;
505        let patterns = self.pattern_capturer.extract_patterns(&decisions)?;
506        Ok(patterns)
507    }
508
509    /// Extract patterns from decision history with detailed analysis
510    pub async fn extract_patterns_with_analysis(
511        &self,
512    ) -> Result<Vec<(LearnedPattern, crate::pattern_capturer::PatternAnalysis)>> {
513        let decisions = self.get_decisions().await;
514        let results = self.pattern_capturer.extract_patterns_with_analysis(&decisions)?;
515        Ok(results)
516    }
517
518    /// Validate a pattern against historical decisions
519    pub async fn validate_pattern(&self, pattern: &LearnedPattern) -> Result<f32> {
520        let decisions = self.get_decisions().await;
521        let validation_score = self.pattern_capturer.validate_pattern(pattern, &decisions)?;
522        Ok(validation_score)
523    }
524
525    /// Update pattern confidence based on validation results
526    pub async fn update_pattern_confidence(
527        &self,
528        pattern_id: &str,
529        validation_score: f32,
530    ) -> Result<()> {
531        let mut patterns = self.patterns.write().await;
532        if let Some(pattern) = patterns.get_mut(pattern_id) {
533            self.pattern_capturer.update_confidence(pattern, validation_score)?;
534            Ok(())
535        } else {
536            Err(LearningError::PatternNotFound(pattern_id.to_string()))
537        }
538    }
539
540    /// Validate a pattern using the pattern validator
541    pub async fn validate_pattern_comprehensive(
542        &self,
543        pattern: &LearnedPattern,
544    ) -> Result<crate::pattern_validator::ValidationResult> {
545        let decisions = self.get_decisions().await;
546        let validation_result = self.pattern_validator.validate_pattern(pattern, &decisions)?;
547        Ok(validation_result)
548    }
549
550    /// Validate multiple patterns
551    pub async fn validate_patterns(
552        &self,
553        patterns: &[LearnedPattern],
554    ) -> Result<Vec<crate::pattern_validator::ValidationResult>> {
555        let decisions = self.get_decisions().await;
556        let validation_results = self.pattern_validator.validate_patterns(patterns, &decisions)?;
557        Ok(validation_results)
558    }
559
560    /// Get validation statistics for all stored patterns
561    pub async fn get_pattern_validation_statistics(
562        &self,
563    ) -> Result<crate::pattern_validator::ValidationStatistics> {
564        let patterns: Vec<_> = self.patterns.read().await.values().cloned().collect();
565        let validation_results = self.validate_patterns(&patterns).await?;
566        let stats = self.pattern_validator.get_validation_statistics(&validation_results);
567        Ok(stats)
568    }
569
570    /// Validate and update pattern confidence based on validation results
571    pub async fn validate_and_update_pattern(
572        &self,
573        pattern_id: &str,
574    ) -> Result<crate::pattern_validator::ValidationResult> {
575        let pattern = self.get_pattern(pattern_id).await?;
576        let validation_result = self.validate_pattern_comprehensive(&pattern).await?;
577
578        // Update pattern confidence based on validation recommendation
579        self.update_pattern_confidence(pattern_id, validation_result.confidence_recommendation)
580            .await?;
581
582        Ok(validation_result)
583    }
584
585    /// Capture patterns from recent decisions and store them
586    pub async fn capture_and_store_patterns(&self) -> Result<Vec<String>> {
587        let patterns = self.extract_patterns().await?;
588        let mut pattern_ids = Vec::new();
589
590        for pattern in patterns {
591            let pattern_id = pattern.id.clone();
592            self.store_pattern(pattern).await?;
593            pattern_ids.push(pattern_id);
594        }
595
596        Ok(pattern_ids)
597    }
598
599    /// Get patterns by confidence threshold
600    pub async fn get_patterns_by_confidence(&self, min_confidence: f32) -> Vec<LearnedPattern> {
601        self.patterns
602            .read()
603            .await
604            .values()
605            .filter(|p| p.confidence >= min_confidence)
606            .cloned()
607            .collect()
608    }
609
610    /// Get patterns sorted by confidence
611    pub async fn get_patterns_by_confidence_sorted(&self) -> Vec<LearnedPattern> {
612        let mut patterns: Vec<_> = self.patterns.read().await.values().cloned().collect();
613        patterns.sort_by(|a, b| b.confidence.partial_cmp(&a.confidence).unwrap_or(std::cmp::Ordering::Equal));
614        patterns
615    }
616
617    /// Get patterns sorted by occurrences
618    pub async fn get_patterns_by_occurrences(&self) -> Vec<LearnedPattern> {
619        let mut patterns: Vec<_> = self.patterns.read().await.values().cloned().collect();
620        patterns.sort_by(|a, b| b.occurrences.cmp(&a.occurrences));
621        patterns
622    }
623
624    /// Get pattern count
625    pub async fn pattern_count(&self) -> usize {
626        self.patterns.read().await.len()
627    }
628
629    /// Clear all patterns
630    pub async fn clear_patterns(&self) {
631        self.patterns.write().await.clear();
632    }
633
634    /// Request promotion of a rule from project to global scope
635    pub async fn request_rule_promotion(&self, rule: Rule) -> Result<crate::rule_promoter::RuleReview> {
636        // Get global rules for conflict checking
637        let global_rules = self.rule_storage.list_rules().await?;
638
639        // Request promotion
640        let mut promoter = self.rule_promoter.write().await;
641        promoter.request_promotion(rule, &global_rules)
642    }
643
644    /// Get a pending promotion for review
645    pub async fn get_pending_promotion(&self, rule_id: &str) -> Result<crate::rule_promoter::RuleReview> {
646        let promoter = self.rule_promoter.read().await;
647        promoter.get_pending_promotion(rule_id)
648    }
649
650    /// Get all pending promotions
651    pub async fn get_pending_promotions(&self) -> Vec<crate::rule_promoter::RuleReview> {
652        let promoter = self.rule_promoter.read().await;
653        promoter.get_pending_promotions()
654    }
655
656    /// Get the number of pending promotions
657    pub async fn pending_promotion_count(&self) -> usize {
658        let promoter = self.rule_promoter.read().await;
659        promoter.pending_promotion_count()
660    }
661
662    /// Approve a pending promotion and store the promoted rule
663    pub async fn approve_promotion(
664        &self,
665        rule_id: &str,
666        reason: Option<String>,
667    ) -> Result<Rule> {
668        // Approve the promotion
669        let mut promoter = self.rule_promoter.write().await;
670        let promoted_rule = promoter.approve_promotion(rule_id, reason)?;
671
672        // Validate the promoted rule
673        promoter.validate_promotion(&promoted_rule, &self.rule_storage.list_rules().await?)?;
674
675        // Store the promoted rule in the appropriate scope storage
676        // If the promoted rule is Global-scoped, use a Global-scoped storage
677        if promoted_rule.scope == RuleScope::Global {
678            let global_storage = RuleStorage::new(RuleScope::Global);
679            global_storage.store_rule(promoted_rule.clone()).await?;
680        } else {
681            self.rule_storage.store_rule(promoted_rule.clone()).await?;
682        }
683
684        Ok(promoted_rule)
685    }
686
687    /// Reject a pending promotion
688    pub async fn reject_promotion(
689        &self,
690        rule_id: &str,
691        reason: Option<String>,
692    ) -> Result<()> {
693        let mut promoter = self.rule_promoter.write().await;
694        promoter.reject_promotion(rule_id, reason)
695    }
696
697    /// Get promotion history
698    pub async fn get_promotion_history(&self) -> Vec<crate::rule_promoter::PromotionHistoryEntry> {
699        let promoter = self.rule_promoter.read().await;
700        promoter.get_promotion_history()
701    }
702
703    /// Get promotion history for a specific rule
704    pub async fn get_promotion_history_for_rule(
705        &self,
706        rule_id: &str,
707    ) -> Vec<crate::rule_promoter::PromotionHistoryEntry> {
708        let promoter = self.rule_promoter.read().await;
709        promoter.get_promotion_history_for_rule(rule_id)
710    }
711
712    /// Get approved promotions from history
713    pub async fn get_approved_promotions(&self) -> Vec<crate::rule_promoter::PromotionHistoryEntry> {
714        let promoter = self.rule_promoter.read().await;
715        promoter.get_approved_promotions()
716    }
717
718    /// Get rejected promotions from history
719    pub async fn get_rejected_promotions(&self) -> Vec<crate::rule_promoter::PromotionHistoryEntry> {
720        let promoter = self.rule_promoter.read().await;
721        promoter.get_rejected_promotions()
722    }
723
724    /// Clear all pending promotions
725    pub async fn clear_pending_promotions(&self) {
726        let mut promoter = self.rule_promoter.write().await;
727        promoter.clear_pending_promotions();
728    }
729
730    /// Clear promotion history
731    pub async fn clear_promotion_history(&self) {
732        let mut promoter = self.rule_promoter.write().await;
733        promoter.clear_promotion_history();
734    }
735
736    // ============================================================================
737    // Rule Application Methods (Task 9)
738    // ============================================================================
739
740    /// Apply a single rule to a generation context
741    pub async fn apply_rule_to_context(
742        &self,
743        rule: &Rule,
744        context: &crate::rule_application::GenerationContext,
745    ) -> crate::rule_application::RuleApplicationResult {
746        crate::rule_application::RuleApplicationEngine::apply_rule(rule, context)
747    }
748
749    /// Apply multiple rules to a generation context
750    pub async fn apply_rules_to_context(
751        &self,
752        rules: &[Rule],
753        context: &crate::rule_application::GenerationContext,
754    ) -> Vec<crate::rule_application::RuleApplicationResult> {
755        crate::rule_application::RuleApplicationEngine::apply_rules(rules, context)
756    }
757
758    /// Apply rules with precedence to get the best matching rule
759    pub async fn apply_rules_with_precedence(
760        &self,
761        rules: &[Rule],
762        context: &crate::rule_application::GenerationContext,
763    ) -> Option<crate::rule_application::RuleApplicationResult> {
764        crate::rule_application::RuleApplicationEngine::apply_rules_with_precedence(rules, context)
765    }
766
767    /// Chain multiple rules together for sequential application
768    pub async fn chain_rules(
769        &self,
770        rules: &[Rule],
771        context: &crate::rule_application::GenerationContext,
772    ) -> Result<Vec<crate::rule_application::RuleApplicationResult>> {
773        crate::rule_application::RuleApplicationEngine::chain_rules(rules, context)
774    }
775
776    /// Compose multiple rules into a single action
777    pub async fn compose_rules(
778        &self,
779        rules: &[Rule],
780        context: &crate::rule_application::GenerationContext,
781    ) -> Result<Option<String>> {
782        crate::rule_application::RuleApplicationEngine::compose_rules(rules, context)
783    }
784
785    /// Validate that a rule can be applied to a context
786    pub async fn validate_rule_application(
787        &self,
788        rule: &Rule,
789        context: &crate::rule_application::GenerationContext,
790    ) -> Result<()> {
791        crate::rule_application::RuleApplicationEngine::validate_rule_application(rule, context)
792    }
793
794    /// Get all matching rules for a context
795    pub async fn get_matching_rules(
796        &self,
797        context: &crate::rule_application::GenerationContext,
798    ) -> Result<Vec<Rule>> {
799        let rules = self.get_rules().await?;
800        Ok(crate::rule_application::RuleApplicationEngine::get_matching_rules(&rules, context))
801    }
802
803    /// Get matching rules sorted by confidence
804    pub async fn get_matching_rules_sorted(
805        &self,
806        context: &crate::rule_application::GenerationContext,
807    ) -> Result<Vec<Rule>> {
808        let rules = self.get_rules().await?;
809        Ok(crate::rule_application::RuleApplicationEngine::get_matching_rules_sorted(&rules, context))
810    }
811
812    /// Get matching rules sorted by usage
813    pub async fn get_matching_rules_by_usage(
814        &self,
815        context: &crate::rule_application::GenerationContext,
816    ) -> Result<Vec<Rule>> {
817        let rules = self.get_rules().await?;
818        Ok(crate::rule_application::RuleApplicationEngine::get_matching_rules_by_usage(&rules, context))
819    }
820
821    /// Get matching rules sorted by success rate
822    pub async fn get_matching_rules_by_success(
823        &self,
824        context: &crate::rule_application::GenerationContext,
825    ) -> Result<Vec<Rule>> {
826        let rules = self.get_rules().await?;
827        Ok(crate::rule_application::RuleApplicationEngine::get_matching_rules_by_success(&rules, context))
828    }
829
830    /// Apply learned rules to guide code generation
831    pub async fn apply_learned_rules_to_generation(
832        &self,
833        context: &crate::rule_application::GenerationContext,
834    ) -> Result<Option<String>> {
835        // Get all rules for the current scope
836        let rules = self.get_rules_for_scope().await?;
837
838        // Apply rules with precedence to get the best matching rule
839        if let Some(result) = crate::rule_application::RuleApplicationEngine::apply_rules_with_precedence(&rules, context) {
840            Ok(result.action)
841        } else {
842            Ok(None)
843        }
844    }
845
846    /// Apply learned rules and get all matching actions
847    pub async fn apply_learned_rules_get_all(
848        &self,
849        context: &crate::rule_application::GenerationContext,
850    ) -> Result<Vec<String>> {
851        // Get all rules for the current scope
852        let rules = self.get_rules_for_scope().await?;
853
854        // Apply all rules and collect matching actions
855        let results = crate::rule_application::RuleApplicationEngine::apply_rules(&rules, context);
856        let actions: Vec<String> = results
857            .iter()
858            .filter(|r| r.matched)
859            .filter_map(|r| r.action.clone())
860            .collect();
861
862        Ok(actions)
863    }
864
865    /// Apply learned rules with context-based matching
866    pub async fn apply_learned_rules_with_context(
867        &self,
868        generation_type: String,
869        language: String,
870        input: String,
871    ) -> Result<Option<String>> {
872        let context = crate::rule_application::GenerationContext::new(
873            generation_type,
874            language,
875            input,
876        );
877
878        self.apply_learned_rules_to_generation(&context).await
879    }
880
881    // ============================================================================
882    // Analytics Methods (Task 10)
883    // ============================================================================
884
885    /// Record a rule application in analytics
886    pub async fn record_rule_application(
887        &self,
888        rule_id: String,
889        success: bool,
890        application_time_ms: f64,
891    ) -> Result<()> {
892        self.analytics_engine
893            .record_application(rule_id, success, application_time_ms)
894            .await
895    }
896
897    /// Get metrics for a specific rule
898    pub async fn get_rule_metrics(&self, rule_id: &str) -> Result<Option<crate::analytics_engine::RuleMetrics>> {
899        self.analytics_engine.get_rule_metrics(rule_id).await
900    }
901
902    /// Get all rule metrics
903    pub async fn get_all_rule_metrics(&self) -> Result<Vec<crate::analytics_engine::RuleMetrics>> {
904        self.analytics_engine.get_all_metrics().await
905    }
906
907    /// Update rule confidence based on validation results
908    pub async fn update_rule_confidence(&self, rule_id: &str, new_confidence: f32) -> Result<()> {
909        self.analytics_engine.update_confidence(rule_id, new_confidence).await
910    }
911
912    /// Generate analytics insights
913    pub async fn generate_analytics_insights(&self) -> Result<crate::analytics_engine::AnalyticsInsights> {
914        self.analytics_engine.generate_insights().await
915    }
916
917    /// Clear all analytics metrics
918    pub async fn clear_analytics_metrics(&self) -> Result<()> {
919        self.analytics_engine.clear_metrics().await
920    }
921
922    /// Get metrics for rules in a specific scope
923    pub async fn get_metrics_for_scope(
924        &self,
925        scope: RuleScope,
926    ) -> Result<Vec<crate::analytics_engine::RuleMetrics>> {
927        let rules = self.get_rules().await?;
928        self.analytics_engine.get_metrics_by_scope(&rules, scope).await
929    }
930
931    /// Export rules with metrics to JSON
932    pub async fn export_rules_with_metrics(&self, description: Option<String>) -> Result<String> {
933        let rules = self.get_rules().await?;
934        crate::rule_exchange::RuleExporter::export_to_json(rules, description)
935    }
936
937    /// Export rules with metrics to file
938    pub async fn export_rules_to_file(
939        &self,
940        path: &std::path::Path,
941        description: Option<String>,
942    ) -> Result<()> {
943        let rules = self.get_rules().await?;
944        crate::rule_exchange::RuleExporter::export_to_file(rules, path, description)
945    }
946
947    /// Import rules from JSON with validation
948    pub async fn import_rules_from_json(&self, json: &str) -> Result<Vec<Rule>> {
949        crate::rule_exchange::RuleImporter::import_from_json(json)
950    }
951
952    /// Import rules from file with validation
953    pub async fn import_rules_from_file(&self, path: &std::path::Path) -> Result<Vec<Rule>> {
954        crate::rule_exchange::RuleImporter::import_from_file(path)
955    }
956
957    /// Import and validate rules, returning both valid and invalid rules
958    pub async fn import_and_validate_rules(
959        &self,
960        json: &str,
961    ) -> Result<(Vec<Rule>, Vec<String>)> {
962        crate::rule_exchange::RuleImporter::import_and_validate(json)
963    }
964
965    /// Store imported rules
966    pub async fn store_imported_rules(&self, rules: Vec<Rule>) -> Result<Vec<String>> {
967        let mut stored_ids = Vec::new();
968        for rule in rules {
969            let id = self.store_rule(rule).await?;
970            stored_ids.push(id);
971        }
972        Ok(stored_ids)
973    }
974}
975
976#[cfg(test)]
977mod tests {
978    use super::*;
979    use crate::models::{DecisionContext, RuleSource};
980
981    #[tokio::test]
982    async fn test_learning_manager_creation() {
983        let manager = LearningManager::new(RuleScope::Global);
984        assert_eq!(manager.get_scope().await, RuleScope::Global);
985        assert!(manager.is_enabled().await);
986    }
987
988    #[tokio::test]
989    async fn test_learning_manager_with_config() {
990        let config = LearningConfig::new(RuleScope::Project);
991        let manager = LearningManager::with_config(config).expect("Failed to create manager");
992        assert_eq!(manager.get_scope().await, RuleScope::Project);
993    }
994
995    #[tokio::test]
996    async fn test_capture_decision() {
997        let manager = LearningManager::new(RuleScope::Session);
998
999        let context = DecisionContext {
1000            project_path: PathBuf::from("/project"),
1001            file_path: PathBuf::from("/project/src/main.rs"),
1002            line_number: 10,
1003            agent_type: "test_agent".to_string(),
1004        };
1005
1006        let decision = Decision::new(
1007            context,
1008            "test_type".to_string(),
1009            serde_json::json!({}),
1010            serde_json::json!({}),
1011        );
1012
1013        let decision_id = decision.id.clone();
1014        let result = manager.capture_decision(decision).await;
1015
1016        assert!(result.is_ok());
1017        assert_eq!(result.unwrap(), decision_id);
1018
1019        let decisions = manager.get_decisions().await;
1020        assert_eq!(decisions.len(), 1);
1021    }
1022
1023    #[tokio::test]
1024    async fn test_capture_decision_disabled() {
1025        let manager = LearningManager::new(RuleScope::Session);
1026        manager.set_enabled(false).await;
1027
1028        let context = DecisionContext {
1029            project_path: PathBuf::from("/project"),
1030            file_path: PathBuf::from("/project/src/main.rs"),
1031            line_number: 10,
1032            agent_type: "test_agent".to_string(),
1033        };
1034
1035        let decision = Decision::new(
1036            context,
1037            "test_type".to_string(),
1038            serde_json::json!({}),
1039            serde_json::json!({}),
1040        );
1041
1042        let result = manager.capture_decision(decision).await;
1043        assert!(result.is_err());
1044    }
1045
1046    #[tokio::test]
1047    async fn test_get_decisions_by_type() {
1048        let manager = LearningManager::new(RuleScope::Session);
1049
1050        let context = DecisionContext {
1051            project_path: PathBuf::from("/project"),
1052            file_path: PathBuf::from("/project/src/main.rs"),
1053            line_number: 10,
1054            agent_type: "test_agent".to_string(),
1055        };
1056
1057        let decision1 = Decision::new(
1058            context.clone(),
1059            "type_a".to_string(),
1060            serde_json::json!({}),
1061            serde_json::json!({}),
1062        );
1063
1064        let decision2 = Decision::new(
1065            context.clone(),
1066            "type_b".to_string(),
1067            serde_json::json!({}),
1068            serde_json::json!({}),
1069        );
1070
1071        let decision3 = Decision::new(
1072            context,
1073            "type_a".to_string(),
1074            serde_json::json!({}),
1075            serde_json::json!({}),
1076        );
1077
1078        manager.capture_decision(decision1).await.unwrap();
1079        manager.capture_decision(decision2).await.unwrap();
1080        manager.capture_decision(decision3).await.unwrap();
1081
1082        let type_a_decisions = manager.get_decisions_by_type("type_a").await;
1083        assert_eq!(type_a_decisions.len(), 2);
1084
1085        let type_b_decisions = manager.get_decisions_by_type("type_b").await;
1086        assert_eq!(type_b_decisions.len(), 1);
1087    }
1088
1089    #[tokio::test]
1090    async fn test_store_rule() {
1091        let manager = LearningManager::new(RuleScope::Session);
1092
1093        let rule = Rule::new(
1094            RuleScope::Session,
1095            "pattern".to_string(),
1096            "action".to_string(),
1097            RuleSource::Learned,
1098        );
1099
1100        let rule_id = rule.id.clone();
1101        let result = manager.store_rule(rule).await;
1102
1103        assert!(result.is_ok());
1104        assert_eq!(result.unwrap(), rule_id);
1105
1106        let retrieved = manager.get_rule(&rule_id).await;
1107        assert!(retrieved.is_ok());
1108    }
1109
1110    #[tokio::test]
1111    async fn test_store_pattern() {
1112        let manager = LearningManager::new(RuleScope::Session);
1113
1114        let pattern = LearnedPattern::new(
1115            "code_generation".to_string(),
1116            "Test pattern".to_string(),
1117        );
1118
1119        let pattern_id = pattern.id.clone();
1120        let result = manager.store_pattern(pattern).await;
1121
1122        assert!(result.is_ok());
1123        assert_eq!(result.unwrap(), pattern_id);
1124
1125        let retrieved = manager.get_pattern(&pattern_id).await;
1126        assert!(retrieved.is_ok());
1127    }
1128
1129    #[tokio::test]
1130    async fn test_get_patterns_by_type() {
1131        let manager = LearningManager::new(RuleScope::Session);
1132
1133        let pattern1 = LearnedPattern::new(
1134            "code_generation".to_string(),
1135            "Pattern 1".to_string(),
1136        );
1137
1138        let pattern2 = LearnedPattern::new(
1139            "refactoring".to_string(),
1140            "Pattern 2".to_string(),
1141        );
1142
1143        let pattern3 = LearnedPattern::new(
1144            "code_generation".to_string(),
1145            "Pattern 3".to_string(),
1146        );
1147
1148        manager.store_pattern(pattern1).await.unwrap();
1149        manager.store_pattern(pattern2).await.unwrap();
1150        manager.store_pattern(pattern3).await.unwrap();
1151
1152        let code_gen_patterns = manager.get_patterns_by_type("code_generation").await;
1153        assert_eq!(code_gen_patterns.len(), 2);
1154
1155        let refactoring_patterns = manager.get_patterns_by_type("refactoring").await;
1156        assert_eq!(refactoring_patterns.len(), 1);
1157    }
1158
1159    #[tokio::test]
1160    async fn test_get_scope_path() {
1161        let manager = LearningManager::new(RuleScope::Global);
1162
1163        let global_path = manager.get_scope_path(RuleScope::Global);
1164        assert!(global_path.is_ok());
1165        let path = global_path.unwrap();
1166        assert!(path.to_string_lossy().contains(".ricecoder"));
1167
1168        let project_path = manager.get_scope_path(RuleScope::Project);
1169        assert!(project_path.is_ok());
1170        assert_eq!(project_path.unwrap(), PathBuf::from(".ricecoder/rules"));
1171
1172        let session_path = manager.get_scope_path(RuleScope::Session);
1173        assert!(session_path.is_err());
1174    }
1175
1176    #[tokio::test]
1177    async fn test_enable_disable_learning() {
1178        let manager = LearningManager::new(RuleScope::Session);
1179
1180        assert!(manager.is_enabled().await);
1181
1182        manager.set_enabled(false).await;
1183        assert!(!manager.is_enabled().await);
1184
1185        manager.set_enabled(true).await;
1186        assert!(manager.is_enabled().await);
1187    }
1188
1189    #[tokio::test]
1190    async fn test_clear_decisions() {
1191        let manager = LearningManager::new(RuleScope::Session);
1192
1193        let context = DecisionContext {
1194            project_path: PathBuf::from("/project"),
1195            file_path: PathBuf::from("/project/src/main.rs"),
1196            line_number: 10,
1197            agent_type: "test_agent".to_string(),
1198        };
1199
1200        let decision = Decision::new(
1201            context,
1202            "test_type".to_string(),
1203            serde_json::json!({}),
1204            serde_json::json!({}),
1205        );
1206
1207        manager.capture_decision(decision).await.unwrap();
1208        assert_eq!(manager.get_decisions().await.len(), 1);
1209
1210        manager.clear_decisions().await;
1211        assert_eq!(manager.get_decisions().await.len(), 0);
1212    }
1213
1214    #[tokio::test]
1215    async fn test_get_decisions_by_context() {
1216        let manager = LearningManager::new(RuleScope::Session);
1217
1218        let context1 = DecisionContext {
1219            project_path: PathBuf::from("/project1"),
1220            file_path: PathBuf::from("/project1/src/main.rs"),
1221            line_number: 10,
1222            agent_type: "agent1".to_string(),
1223        };
1224
1225        let context2 = DecisionContext {
1226            project_path: PathBuf::from("/project2"),
1227            file_path: PathBuf::from("/project2/src/main.rs"),
1228            line_number: 20,
1229            agent_type: "agent2".to_string(),
1230        };
1231
1232        let decision1 = Decision::new(
1233            context1.clone(),
1234            "type_a".to_string(),
1235            serde_json::json!({}),
1236            serde_json::json!({}),
1237        );
1238
1239        let decision2 = Decision::new(
1240            context2.clone(),
1241            "type_b".to_string(),
1242            serde_json::json!({}),
1243            serde_json::json!({}),
1244        );
1245
1246        let decision3 = Decision::new(
1247            context1.clone(),
1248            "type_a".to_string(),
1249            serde_json::json!({}),
1250            serde_json::json!({}),
1251        );
1252
1253        manager.capture_decision(decision1).await.unwrap();
1254        manager.capture_decision(decision2).await.unwrap();
1255        manager.capture_decision(decision3).await.unwrap();
1256
1257        let context1_decisions = manager.get_decisions_by_context(&context1).await;
1258        assert_eq!(context1_decisions.len(), 2);
1259
1260        let context2_decisions = manager.get_decisions_by_context(&context2).await;
1261        assert_eq!(context2_decisions.len(), 1);
1262    }
1263
1264    #[tokio::test]
1265    async fn test_get_decision() {
1266        let manager = LearningManager::new(RuleScope::Session);
1267
1268        let context = DecisionContext {
1269            project_path: PathBuf::from("/project"),
1270            file_path: PathBuf::from("/project/src/main.rs"),
1271            line_number: 10,
1272            agent_type: "test_agent".to_string(),
1273        };
1274
1275        let decision = Decision::new(
1276            context,
1277            "test_type".to_string(),
1278            serde_json::json!({}),
1279            serde_json::json!({}),
1280        );
1281
1282        let decision_id = decision.id.clone();
1283        manager.capture_decision(decision).await.unwrap();
1284
1285        let retrieved = manager.get_decision(&decision_id).await;
1286        assert!(retrieved.is_ok());
1287        assert_eq!(retrieved.unwrap().id, decision_id);
1288    }
1289
1290    #[tokio::test]
1291    async fn test_replay_decisions() {
1292        let manager = LearningManager::new(RuleScope::Session);
1293
1294        let context = DecisionContext {
1295            project_path: PathBuf::from("/project"),
1296            file_path: PathBuf::from("/project/src/main.rs"),
1297            line_number: 10,
1298            agent_type: "test_agent".to_string(),
1299        };
1300
1301        let decision1 = Decision::new(
1302            context.clone(),
1303            "type_a".to_string(),
1304            serde_json::json!({}),
1305            serde_json::json!({}),
1306        );
1307
1308        let decision2 = Decision::new(
1309            context.clone(),
1310            "type_b".to_string(),
1311            serde_json::json!({}),
1312            serde_json::json!({}),
1313        );
1314
1315        manager.capture_decision(decision1).await.unwrap();
1316        manager.capture_decision(decision2).await.unwrap();
1317
1318        let replayed = manager.replay_decisions().await;
1319        assert_eq!(replayed.len(), 2);
1320        assert_eq!(replayed[0].decision_type, "type_a");
1321        assert_eq!(replayed[1].decision_type, "type_b");
1322    }
1323
1324    #[tokio::test]
1325    async fn test_replay_decisions_for_context() {
1326        let manager = LearningManager::new(RuleScope::Session);
1327
1328        let context = DecisionContext {
1329            project_path: PathBuf::from("/project"),
1330            file_path: PathBuf::from("/project/src/main.rs"),
1331            line_number: 10,
1332            agent_type: "test_agent".to_string(),
1333        };
1334
1335        let decision1 = Decision::new(
1336            context.clone(),
1337            "type_a".to_string(),
1338            serde_json::json!({}),
1339            serde_json::json!({}),
1340        );
1341
1342        let decision2 = Decision::new(
1343            context.clone(),
1344            "type_b".to_string(),
1345            serde_json::json!({}),
1346            serde_json::json!({}),
1347        );
1348
1349        manager.capture_decision(decision1).await.unwrap();
1350        manager.capture_decision(decision2).await.unwrap();
1351
1352        let replayed = manager.replay_decisions_for_context(&context).await;
1353        assert_eq!(replayed.len(), 2);
1354    }
1355
1356    #[tokio::test]
1357    async fn test_decision_count() {
1358        let manager = LearningManager::new(RuleScope::Session);
1359
1360        assert_eq!(manager.decision_count().await, 0);
1361
1362        let context = DecisionContext {
1363            project_path: PathBuf::from("/project"),
1364            file_path: PathBuf::from("/project/src/main.rs"),
1365            line_number: 10,
1366            agent_type: "test_agent".to_string(),
1367        };
1368
1369        let decision = Decision::new(
1370            context,
1371            "test_type".to_string(),
1372            serde_json::json!({}),
1373            serde_json::json!({}),
1374        );
1375
1376        manager.capture_decision(decision).await.unwrap();
1377        assert_eq!(manager.decision_count().await, 1);
1378    }
1379
1380    #[tokio::test]
1381    async fn test_get_decision_statistics() {
1382        let manager = LearningManager::new(RuleScope::Session);
1383
1384        let context = DecisionContext {
1385            project_path: PathBuf::from("/project"),
1386            file_path: PathBuf::from("/project/src/main.rs"),
1387            line_number: 10,
1388            agent_type: "agent1".to_string(),
1389        };
1390
1391        let decision1 = Decision::new(
1392            context.clone(),
1393            "type_a".to_string(),
1394            serde_json::json!({}),
1395            serde_json::json!({}),
1396        );
1397
1398        let decision2 = Decision::new(
1399            context.clone(),
1400            "type_b".to_string(),
1401            serde_json::json!({}),
1402            serde_json::json!({}),
1403        );
1404
1405        let decision3 = Decision::new(
1406            context,
1407            "type_a".to_string(),
1408            serde_json::json!({}),
1409            serde_json::json!({}),
1410        );
1411
1412        manager.capture_decision(decision1).await.unwrap();
1413        manager.capture_decision(decision2).await.unwrap();
1414        manager.capture_decision(decision3).await.unwrap();
1415
1416        let stats = manager.get_decision_statistics().await;
1417
1418        assert_eq!(stats.total_decisions, 3);
1419        assert_eq!(stats.decision_types.get("type_a"), Some(&2));
1420        assert_eq!(stats.decision_types.get("type_b"), Some(&1));
1421        assert_eq!(stats.agent_types.get("agent1"), Some(&3));
1422    }
1423
1424    #[tokio::test]
1425    async fn test_extract_patterns() {
1426        let manager = LearningManager::new(RuleScope::Session);
1427
1428        let context = DecisionContext {
1429            project_path: PathBuf::from("/project"),
1430            file_path: PathBuf::from("/project/src/main.rs"),
1431            line_number: 10,
1432            agent_type: "test_agent".to_string(),
1433        };
1434
1435        let decision1 = Decision::new(
1436            context.clone(),
1437            "code_generation".to_string(),
1438            serde_json::json!({"input": "test"}),
1439            serde_json::json!({"output": "result"}),
1440        );
1441
1442        let decision2 = Decision::new(
1443            context,
1444            "code_generation".to_string(),
1445            serde_json::json!({"input": "test"}),
1446            serde_json::json!({"output": "result"}),
1447        );
1448
1449        manager.capture_decision(decision1).await.unwrap();
1450        manager.capture_decision(decision2).await.unwrap();
1451
1452        let patterns = manager.extract_patterns().await.unwrap();
1453        assert_eq!(patterns.len(), 1);
1454        assert_eq!(patterns[0].pattern_type, "code_generation");
1455    }
1456
1457    #[tokio::test]
1458    async fn test_capture_and_store_patterns() {
1459        let manager = LearningManager::new(RuleScope::Session);
1460
1461        let context = DecisionContext {
1462            project_path: PathBuf::from("/project"),
1463            file_path: PathBuf::from("/project/src/main.rs"),
1464            line_number: 10,
1465            agent_type: "test_agent".to_string(),
1466        };
1467
1468        let decision1 = Decision::new(
1469            context.clone(),
1470            "code_generation".to_string(),
1471            serde_json::json!({"input": "test"}),
1472            serde_json::json!({"output": "result"}),
1473        );
1474
1475        let decision2 = Decision::new(
1476            context,
1477            "code_generation".to_string(),
1478            serde_json::json!({"input": "test"}),
1479            serde_json::json!({"output": "result"}),
1480        );
1481
1482        manager.capture_decision(decision1).await.unwrap();
1483        manager.capture_decision(decision2).await.unwrap();
1484
1485        let pattern_ids = manager.capture_and_store_patterns().await.unwrap();
1486        assert_eq!(pattern_ids.len(), 1);
1487
1488        let patterns = manager.get_patterns().await;
1489        assert_eq!(patterns.len(), 1);
1490    }
1491
1492    #[tokio::test]
1493    async fn test_validate_pattern() {
1494        let manager = LearningManager::new(RuleScope::Session);
1495
1496        let context = DecisionContext {
1497            project_path: PathBuf::from("/project"),
1498            file_path: PathBuf::from("/project/src/main.rs"),
1499            line_number: 10,
1500            agent_type: "test_agent".to_string(),
1501        };
1502
1503        let decision1 = Decision::new(
1504            context.clone(),
1505            "code_generation".to_string(),
1506            serde_json::json!({"input": "test"}),
1507            serde_json::json!({"output": "result"}),
1508        );
1509
1510        let decision2 = Decision::new(
1511            context,
1512            "code_generation".to_string(),
1513            serde_json::json!({"input": "test"}),
1514            serde_json::json!({"output": "result"}),
1515        );
1516
1517        manager.capture_decision(decision1).await.unwrap();
1518        manager.capture_decision(decision2).await.unwrap();
1519
1520        let patterns = manager.extract_patterns().await.unwrap();
1521        assert_eq!(patterns.len(), 1);
1522
1523        let validation_score = manager.validate_pattern(&patterns[0]).await.unwrap();
1524        assert!(validation_score >= 0.0);
1525        assert!(validation_score <= 1.0);
1526    }
1527
1528    #[tokio::test]
1529    async fn test_update_pattern_confidence() {
1530        let manager = LearningManager::new(RuleScope::Session);
1531
1532        let context = DecisionContext {
1533            project_path: PathBuf::from("/project"),
1534            file_path: PathBuf::from("/project/src/main.rs"),
1535            line_number: 10,
1536            agent_type: "test_agent".to_string(),
1537        };
1538
1539        let decision1 = Decision::new(
1540            context.clone(),
1541            "code_generation".to_string(),
1542            serde_json::json!({"input": "test"}),
1543            serde_json::json!({"output": "result"}),
1544        );
1545
1546        let decision2 = Decision::new(
1547            context,
1548            "code_generation".to_string(),
1549            serde_json::json!({"input": "test"}),
1550            serde_json::json!({"output": "result"}),
1551        );
1552
1553        manager.capture_decision(decision1).await.unwrap();
1554        manager.capture_decision(decision2).await.unwrap();
1555
1556        let patterns = manager.extract_patterns().await.unwrap();
1557        assert!(!patterns.is_empty(), "Should extract at least one pattern");
1558
1559        let pattern_id = patterns[0].id.clone();
1560
1561        // Store the pattern first
1562        manager.store_pattern(patterns[0].clone()).await.unwrap();
1563
1564        let result = manager.update_pattern_confidence(&pattern_id, 0.9).await;
1565        assert!(result.is_ok());
1566
1567        let updated_pattern = manager.get_pattern(&pattern_id).await.unwrap();
1568        assert!(updated_pattern.confidence > 0.0);
1569    }
1570
1571    #[tokio::test]
1572    async fn test_get_patterns_by_confidence() {
1573        let manager = LearningManager::new(RuleScope::Session);
1574
1575        let mut pattern1 = LearnedPattern::new(
1576            "code_generation".to_string(),
1577            "Pattern 1".to_string(),
1578        );
1579        pattern1.confidence = 0.8;
1580
1581        let mut pattern2 = LearnedPattern::new(
1582            "refactoring".to_string(),
1583            "Pattern 2".to_string(),
1584        );
1585        pattern2.confidence = 0.3;
1586
1587        manager.store_pattern(pattern1).await.unwrap();
1588        manager.store_pattern(pattern2).await.unwrap();
1589
1590        let high_confidence = manager.get_patterns_by_confidence(0.5).await;
1591        assert_eq!(high_confidence.len(), 1);
1592        assert!(high_confidence[0].confidence >= 0.5);
1593    }
1594
1595    #[tokio::test]
1596    async fn test_get_patterns_by_confidence_sorted() {
1597        let manager = LearningManager::new(RuleScope::Session);
1598
1599        let mut pattern1 = LearnedPattern::new(
1600            "code_generation".to_string(),
1601            "Pattern 1".to_string(),
1602        );
1603        pattern1.confidence = 0.5;
1604
1605        let mut pattern2 = LearnedPattern::new(
1606            "refactoring".to_string(),
1607            "Pattern 2".to_string(),
1608        );
1609        pattern2.confidence = 0.9;
1610
1611        let mut pattern3 = LearnedPattern::new(
1612            "analysis".to_string(),
1613            "Pattern 3".to_string(),
1614        );
1615        pattern3.confidence = 0.7;
1616
1617        manager.store_pattern(pattern1).await.unwrap();
1618        manager.store_pattern(pattern2).await.unwrap();
1619        manager.store_pattern(pattern3).await.unwrap();
1620
1621        let sorted = manager.get_patterns_by_confidence_sorted().await;
1622        assert_eq!(sorted.len(), 3);
1623        assert!(sorted[0].confidence >= sorted[1].confidence);
1624        assert!(sorted[1].confidence >= sorted[2].confidence);
1625    }
1626
1627    #[tokio::test]
1628    async fn test_get_patterns_by_occurrences() {
1629        let manager = LearningManager::new(RuleScope::Session);
1630
1631        let mut pattern1 = LearnedPattern::new(
1632            "code_generation".to_string(),
1633            "Pattern 1".to_string(),
1634        );
1635        pattern1.occurrences = 5;
1636
1637        let mut pattern2 = LearnedPattern::new(
1638            "refactoring".to_string(),
1639            "Pattern 2".to_string(),
1640        );
1641        pattern2.occurrences = 10;
1642
1643        let mut pattern3 = LearnedPattern::new(
1644            "analysis".to_string(),
1645            "Pattern 3".to_string(),
1646        );
1647        pattern3.occurrences = 3;
1648
1649        manager.store_pattern(pattern1).await.unwrap();
1650        manager.store_pattern(pattern2).await.unwrap();
1651        manager.store_pattern(pattern3).await.unwrap();
1652
1653        let sorted = manager.get_patterns_by_occurrences().await;
1654        assert_eq!(sorted.len(), 3);
1655        assert_eq!(sorted[0].occurrences, 10);
1656        assert_eq!(sorted[1].occurrences, 5);
1657        assert_eq!(sorted[2].occurrences, 3);
1658    }
1659
1660    #[tokio::test]
1661    async fn test_pattern_count() {
1662        let manager = LearningManager::new(RuleScope::Session);
1663
1664        assert_eq!(manager.pattern_count().await, 0);
1665
1666        let pattern1 = LearnedPattern::new(
1667            "code_generation".to_string(),
1668            "Pattern 1".to_string(),
1669        );
1670
1671        let pattern2 = LearnedPattern::new(
1672            "refactoring".to_string(),
1673            "Pattern 2".to_string(),
1674        );
1675
1676        manager.store_pattern(pattern1).await.unwrap();
1677        manager.store_pattern(pattern2).await.unwrap();
1678
1679        assert_eq!(manager.pattern_count().await, 2);
1680    }
1681
1682    #[tokio::test]
1683    async fn test_clear_patterns() {
1684        let manager = LearningManager::new(RuleScope::Session);
1685
1686        let pattern = LearnedPattern::new(
1687            "code_generation".to_string(),
1688            "Pattern".to_string(),
1689        );
1690
1691        manager.store_pattern(pattern).await.unwrap();
1692        assert_eq!(manager.pattern_count().await, 1);
1693
1694        manager.clear_patterns().await;
1695        assert_eq!(manager.pattern_count().await, 0);
1696    }
1697
1698    #[tokio::test]
1699    async fn test_request_rule_promotion() {
1700        let manager = LearningManager::new(RuleScope::Session);
1701
1702        let rule = Rule::new(
1703            RuleScope::Project,
1704            "pattern".to_string(),
1705            "action".to_string(),
1706            crate::models::RuleSource::Learned,
1707        );
1708
1709        let result = manager.request_rule_promotion(rule).await;
1710        assert!(result.is_ok());
1711
1712        let review = result.unwrap();
1713        assert_eq!(manager.pending_promotion_count().await, 1);
1714    }
1715
1716    #[tokio::test]
1717    async fn test_get_pending_promotions() {
1718        let manager = LearningManager::new(RuleScope::Session);
1719
1720        let rule1 = Rule::new(
1721            RuleScope::Project,
1722            "pattern1".to_string(),
1723            "action1".to_string(),
1724            crate::models::RuleSource::Learned,
1725        );
1726
1727        let rule2 = Rule::new(
1728            RuleScope::Project,
1729            "pattern2".to_string(),
1730            "action2".to_string(),
1731            crate::models::RuleSource::Learned,
1732        );
1733
1734        manager.request_rule_promotion(rule1).await.unwrap();
1735        manager.request_rule_promotion(rule2).await.unwrap();
1736
1737        let pending = manager.get_pending_promotions().await;
1738        assert_eq!(pending.len(), 2);
1739    }
1740
1741    #[tokio::test]
1742    async fn test_approve_promotion() {
1743        let manager = LearningManager::new(RuleScope::Session);
1744
1745        let rule = Rule::new(
1746            RuleScope::Project,
1747            "pattern".to_string(),
1748            "action".to_string(),
1749            crate::models::RuleSource::Learned,
1750        );
1751
1752        let rule_id = rule.id.clone();
1753        manager.request_rule_promotion(rule).await.unwrap();
1754
1755        let result = manager.approve_promotion(&rule_id, Some("Looks good".to_string())).await;
1756        assert!(result.is_ok());
1757
1758        let promoted_rule = result.unwrap();
1759        assert_eq!(promoted_rule.scope, RuleScope::Global);
1760        assert_eq!(promoted_rule.source, crate::models::RuleSource::Promoted);
1761
1762        assert_eq!(manager.pending_promotion_count().await, 0);
1763    }
1764
1765    #[tokio::test]
1766    async fn test_reject_promotion() {
1767        let manager = LearningManager::new(RuleScope::Session);
1768
1769        let rule = Rule::new(
1770            RuleScope::Project,
1771            "pattern".to_string(),
1772            "action".to_string(),
1773            crate::models::RuleSource::Learned,
1774        );
1775
1776        let rule_id = rule.id.clone();
1777        manager.request_rule_promotion(rule).await.unwrap();
1778
1779        let result = manager.reject_promotion(&rule_id, Some("Not ready".to_string())).await;
1780        assert!(result.is_ok());
1781
1782        assert_eq!(manager.pending_promotion_count().await, 0);
1783    }
1784
1785    #[tokio::test]
1786    async fn test_promotion_history() {
1787        let manager = LearningManager::new(RuleScope::Session);
1788
1789        let rule = Rule::new(
1790            RuleScope::Project,
1791            "pattern".to_string(),
1792            "action".to_string(),
1793            crate::models::RuleSource::Learned,
1794        );
1795
1796        let rule_id = rule.id.clone();
1797        manager.request_rule_promotion(rule).await.unwrap();
1798        manager.approve_promotion(&rule_id, None).await.unwrap();
1799
1800        let history = manager.get_promotion_history().await;
1801        assert_eq!(history.len(), 1);
1802        assert!(history[0].approved);
1803
1804        let rule_history = manager.get_promotion_history_for_rule(&rule_id).await;
1805        assert_eq!(rule_history.len(), 1);
1806    }
1807
1808    #[tokio::test]
1809    async fn test_get_approved_promotions() {
1810        let manager = LearningManager::new(RuleScope::Session);
1811
1812        let rule1 = Rule::new(
1813            RuleScope::Project,
1814            "pattern1".to_string(),
1815            "action1".to_string(),
1816            crate::models::RuleSource::Learned,
1817        );
1818
1819        let rule2 = Rule::new(
1820            RuleScope::Project,
1821            "pattern2".to_string(),
1822            "action2".to_string(),
1823            crate::models::RuleSource::Learned,
1824        );
1825
1826        let rule1_id = rule1.id.clone();
1827        let rule2_id = rule2.id.clone();
1828
1829        manager.request_rule_promotion(rule1).await.unwrap();
1830        manager.request_rule_promotion(rule2).await.unwrap();
1831
1832        manager.approve_promotion(&rule1_id, None).await.unwrap();
1833        manager.reject_promotion(&rule2_id, None).await.unwrap();
1834
1835        let approved = manager.get_approved_promotions().await;
1836        assert_eq!(approved.len(), 1);
1837        assert!(approved[0].approved);
1838
1839        let rejected = manager.get_rejected_promotions().await;
1840        assert_eq!(rejected.len(), 1);
1841        assert!(!rejected[0].approved);
1842    }
1843
1844    #[tokio::test]
1845    async fn test_clear_pending_promotions() {
1846        let manager = LearningManager::new(RuleScope::Session);
1847
1848        let rule = Rule::new(
1849            RuleScope::Project,
1850            "pattern".to_string(),
1851            "action".to_string(),
1852            crate::models::RuleSource::Learned,
1853        );
1854
1855        manager.request_rule_promotion(rule).await.unwrap();
1856        assert_eq!(manager.pending_promotion_count().await, 1);
1857
1858        manager.clear_pending_promotions().await;
1859        assert_eq!(manager.pending_promotion_count().await, 0);
1860    }
1861
1862    #[tokio::test]
1863    async fn test_clear_promotion_history() {
1864        let manager = LearningManager::new(RuleScope::Session);
1865
1866        let rule = Rule::new(
1867            RuleScope::Project,
1868            "pattern".to_string(),
1869            "action".to_string(),
1870            crate::models::RuleSource::Learned,
1871        );
1872
1873        let rule_id = rule.id.clone();
1874        manager.request_rule_promotion(rule).await.unwrap();
1875        manager.approve_promotion(&rule_id, None).await.unwrap();
1876
1877        assert_eq!(manager.get_promotion_history().await.len(), 1);
1878
1879        manager.clear_promotion_history().await;
1880        assert_eq!(manager.get_promotion_history().await.len(), 0);
1881    }
1882}