rill_ml/drift/
strategy.rs1use crate::drift::action::DriftAction;
9use crate::drift::detector::DriftLevel;
10
11pub trait DriftStrategy {
18 fn decide(&self, level: DriftLevel, samples_seen: u64) -> DriftAction;
20}
21
22#[derive(Debug, Clone)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub struct StaticStrategy {
44 pub warning_action: DriftAction,
46 pub drift_action: DriftAction,
48}
49
50impl StaticStrategy {
51 pub const fn new(warning_action: DriftAction, drift_action: DriftAction) -> Self {
53 Self {
54 warning_action,
55 drift_action,
56 }
57 }
58}
59
60impl Default for StaticStrategy {
61 fn default() -> Self {
62 Self {
64 warning_action: DriftAction::NotifyOnly,
65 drift_action: DriftAction::NotifyOnly,
66 }
67 }
68}
69
70impl DriftStrategy for StaticStrategy {
71 fn decide(&self, level: DriftLevel, _samples_seen: u64) -> DriftAction {
72 match level {
73 DriftLevel::None => DriftAction::NotifyOnly,
74 DriftLevel::Warning => self.warning_action,
75 DriftLevel::Drift => self.drift_action,
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn default_strategy_is_notify_only() {
86 let s = StaticStrategy::default();
87 assert_eq!(s.decide(DriftLevel::None, 0), DriftAction::NotifyOnly);
88 assert_eq!(s.decide(DriftLevel::Warning, 10), DriftAction::NotifyOnly);
89 assert_eq!(s.decide(DriftLevel::Drift, 100), DriftAction::NotifyOnly);
90 }
91
92 #[test]
93 fn custom_strategy() {
94 let s = StaticStrategy::new(DriftAction::ReduceConfidence, DriftAction::ResetModel);
95 assert_eq!(s.decide(DriftLevel::None, 50), DriftAction::NotifyOnly);
96 assert_eq!(
97 s.decide(DriftLevel::Warning, 50),
98 DriftAction::ReduceConfidence
99 );
100 assert_eq!(s.decide(DriftLevel::Drift, 50), DriftAction::ResetModel);
101 }
102
103 #[test]
104 fn samples_seen_does_not_affect_static_strategy() {
105 let s = StaticStrategy::new(DriftAction::NotifyOnly, DriftAction::ResetModel);
106 assert_eq!(
108 s.decide(DriftLevel::Drift, 1),
109 s.decide(DriftLevel::Drift, 1000)
110 );
111 }
112
113 #[cfg(feature = "serde")]
114 #[test]
115 fn serde_roundtrip() {
116 let s = StaticStrategy::new(DriftAction::ReduceConfidence, DriftAction::ResetModel);
117 let json = serde_json::to_string(&s).unwrap();
118 let restored: StaticStrategy = serde_json::from_str(&json).unwrap();
119 assert_eq!(restored.warning_action, DriftAction::ReduceConfidence);
120 assert_eq!(restored.drift_action, DriftAction::ResetModel);
121 }
122}