Skip to main content

do_memory_core/patterns/
mod.rs

1//! # Pattern Validation and Effectiveness Tracking
2//!
3//! This module provides tools for validating pattern extraction quality
4//! and tracking pattern effectiveness over time.
5//!
6//! ## Components
7//!
8//! - `affinity`: DyMoE routing-drift protection with pattern affinity classification
9//! - `changepoint`: Changepoint detection for pattern metric monitoring
10//! - `clustering`: Pattern clustering and deduplication
11//! - `dbscan`: DBSCAN-based anomaly detection for episodes
12//! - `effectiveness`: Pattern usage and success tracking
13//! - `extractors`: Hybrid pattern extraction system with specialized extractors
14//! - `optimized_validator`: Enhanced pattern validation
15//! - `validation`: Pattern accuracy metrics (precision, recall, F1)
16
17pub mod affinity;
18pub mod changepoint;
19pub mod clustering;
20pub mod dbscan;
21pub mod effectiveness;
22pub mod extractors;
23pub mod heuristic;
24pub mod optimized_validator;
25pub mod similarity;
26#[cfg(test)]
27mod tests;
28pub mod types;
29pub mod validation;
30
31pub use affinity::{
32    DEFAULT_AFFINITY_THRESHOLD, DEFAULT_MIN_SUCCESS_RATE, EpisodeAssignmentGuard,
33    PatternAffinityClassifier, RejectionReason, RelativeAffinity,
34};
35
36pub use changepoint::{
37    ChangeDirection, ChangeType, Changepoint, ChangepointConfig, ChangepointDetector,
38    SegmentComparison, SegmentComparisonConfig, SegmentStats,
39};
40pub use clustering::{ClusterCentroid, ClusteringConfig, EpisodeCluster, PatternClusterer};
41pub use dbscan::{
42    Anomaly, AnomalyReason, DBSCANAnomalyDetector, DBSCANClusterResult, DBSCANConfig, DBSCANStats,
43    FeatureWeights,
44};
45pub use effectiveness::{EffectivenessTracker, OverallStats, PatternUsage, UsageStats};
46pub use extractors::{
47    ContextPatternExtractor, DecisionPointExtractor, ErrorRecoveryExtractor,
48    HybridPatternExtractor, PatternExtractor, ToolSequenceExtractor,
49};
50pub use heuristic::Heuristic;
51pub use optimized_validator::{
52    EnhancedPatternApplicator, OptimizedPatternValidator, RiskAssessment,
53};
54pub use types::{Pattern, PatternEffectiveness};
55pub use validation::{PatternMetrics, PatternValidator, ValidationConfig};
56
57use crate::types::TaskContext;
58
59impl Pattern {
60    /// Check if this pattern is relevant to a given context
61    #[must_use]
62    pub fn is_relevant_to(&self, query_context: &TaskContext) -> bool {
63        if let Some(pattern_context) = self.context() {
64            // Match on domain
65            if pattern_context.domain == query_context.domain {
66                return true;
67            }
68
69            // Match on language
70            if pattern_context.language == query_context.language
71                && pattern_context.language.is_some()
72            {
73                return true;
74            }
75
76            // Match on tags
77            let common_tags: Vec<_> = pattern_context
78                .tags
79                .iter()
80                .filter(|t| query_context.tags.contains(t))
81                .collect();
82
83            if !common_tags.is_empty() {
84                return true;
85            }
86        }
87
88        false
89    }
90
91    /// Get a similarity key for pattern deduplication
92    /// Patterns with identical keys are considered duplicates
93    #[must_use]
94    pub fn similarity_key(&self) -> String {
95        match self {
96            Pattern::ToolSequence { tools, context, .. } => {
97                format!("tool_seq:{}:{}", tools.join(","), context.domain)
98            }
99            Pattern::DecisionPoint {
100                condition,
101                action,
102                context,
103                ..
104            } => {
105                format!("decision:{}:{}:{}", condition, action, context.domain)
106            }
107            Pattern::ErrorRecovery {
108                error_type,
109                recovery_steps,
110                context,
111                ..
112            } => {
113                format!(
114                    "error_recovery:{}:{}:{}",
115                    error_type,
116                    recovery_steps.join(","),
117                    context.domain
118                )
119            }
120            Pattern::ContextPattern {
121                context_features,
122                recommended_approach,
123                ..
124            } => {
125                format!(
126                    "context:{}:{}",
127                    context_features.join(","),
128                    recommended_approach
129                )
130            }
131        }
132    }
133
134    /// Calculate similarity score between this pattern and another (0.0 to 1.0)
135    /// Uses edit distance for sequences and context matching
136    #[must_use]
137    pub fn similarity_score(&self, other: &Self) -> f32 {
138        // Different pattern types have zero similarity
139        if std::mem::discriminant(self) != std::mem::discriminant(other) {
140            return 0.0;
141        }
142
143        match (self, other) {
144            (
145                Pattern::ToolSequence {
146                    tools: tools1,
147                    context: ctx1,
148                    ..
149                },
150                Pattern::ToolSequence {
151                    tools: tools2,
152                    context: ctx2,
153                    ..
154                },
155            ) => similarity::tool_sequence_similarity(tools1, ctx1, tools2, ctx2),
156            (
157                Pattern::DecisionPoint {
158                    condition: cond1,
159                    action: act1,
160                    context: ctx1,
161                    ..
162                },
163                Pattern::DecisionPoint {
164                    condition: cond2,
165                    action: act2,
166                    context: ctx2,
167                    ..
168                },
169            ) => similarity::decision_point_similarity(cond1, act1, ctx1, cond2, act2, ctx2),
170            (
171                Pattern::ErrorRecovery {
172                    error_type: err1,
173                    recovery_steps: steps1,
174                    context: ctx1,
175                    ..
176                },
177                Pattern::ErrorRecovery {
178                    error_type: err2,
179                    recovery_steps: steps2,
180                    context: ctx2,
181                    ..
182                },
183            ) => similarity::error_recovery_similarity(err1, steps1, ctx1, err2, steps2, ctx2),
184            (
185                Pattern::ContextPattern {
186                    context_features: feat1,
187                    recommended_approach: rec1,
188                    ..
189                },
190                Pattern::ContextPattern {
191                    context_features: feat2,
192                    recommended_approach: rec2,
193                    ..
194                },
195            ) => similarity::context_pattern_similarity(feat1, rec1, feat2, rec2),
196            _ => 0.0,
197        }
198    }
199
200    /// Calculate confidence score for this pattern
201    /// Confidence = `success_rate` * `sqrt(sample_size)`
202    #[must_use]
203    pub fn confidence(&self) -> f32 {
204        let success_rate = self.success_rate();
205        let sample_size = self.sample_size() as f32;
206
207        if sample_size == 0.0 {
208            return 0.0;
209        }
210
211        success_rate * sample_size.sqrt()
212    }
213
214    /// Merge this pattern with another similar pattern
215    /// Combines evidence and updates statistics
216    pub fn merge_with(&mut self, other: &Self) {
217        // Can only merge patterns of the same type
218        if std::mem::discriminant(self) != std::mem::discriminant(other) {
219            return;
220        }
221
222        match (self, other) {
223            (
224                Pattern::ToolSequence {
225                    success_rate: sr1,
226                    occurrence_count: oc1,
227                    avg_latency: lat1,
228                    ..
229                },
230                Pattern::ToolSequence {
231                    success_rate: sr2,
232                    occurrence_count: oc2,
233                    avg_latency: lat2,
234                    ..
235                },
236            ) => types::merge_tool_sequence(sr1, oc1, lat1, *sr2, *oc2, lat2),
237            (
238                Pattern::DecisionPoint {
239                    outcome_stats: stats1,
240                    ..
241                },
242                Pattern::DecisionPoint {
243                    outcome_stats: stats2,
244                    ..
245                },
246            ) => types::merge_decision_point(stats1, stats2),
247            (
248                Pattern::ErrorRecovery {
249                    success_rate: sr1, ..
250                },
251                Pattern::ErrorRecovery {
252                    success_rate: sr2, ..
253                },
254            ) => types::merge_error_recovery(sr1, *sr2),
255            (
256                Pattern::ContextPattern {
257                    evidence: ev1,
258                    success_rate: sr1,
259                    ..
260                },
261                Pattern::ContextPattern {
262                    evidence: ev2,
263                    success_rate: sr2,
264                    ..
265                },
266            ) => types::merge_context_pattern(ev1, sr1, ev2, *sr2),
267            _ => {}
268        }
269    }
270}