lean_ctx/core/
homeostasis.rs1#[derive(Debug, Clone, Copy, PartialEq)]
16pub enum PressureLevel {
17 Nominal, Elevated, High, Critical, Emergency, }
23
24impl PressureLevel {
25 pub fn from_utilization(util: f64) -> Self {
26 if util >= 0.95 {
27 Self::Emergency
28 } else if util >= 0.90 {
29 Self::Critical
30 } else if util >= 0.80 {
31 Self::High
32 } else if util >= 0.70 {
33 Self::Elevated
34 } else {
35 Self::Nominal
36 }
37 }
38}
39
40#[derive(Debug, Clone, PartialEq)]
42pub enum HomeostasisAction {
43 None,
45 TrimOutputs,
47 EvictProbationary { target_tokens: usize },
49 UnloadIndices,
51 EvictProtected { target_tokens: usize },
53 EmergencyDrop,
55}
56
57pub struct HomeostasisController {
59 last_level: PressureLevel,
61 consecutive_at_level: u32,
63 budget_tokens: usize,
65 last_action_effective: bool,
67}
68
69impl HomeostasisController {
70 pub fn new(budget_tokens: usize) -> Self {
71 Self {
72 last_level: PressureLevel::Nominal,
73 consecutive_at_level: 0,
74 budget_tokens,
75 last_action_effective: true,
76 }
77 }
78
79 pub fn evaluate(&mut self, current_tokens: usize) -> HomeostasisAction {
82 let util = if self.budget_tokens == 0 {
83 0.0
84 } else {
85 current_tokens as f64 / self.budget_tokens as f64
86 };
87
88 let level = PressureLevel::from_utilization(util);
89
90 if level as u8 >= self.last_level as u8 && level != PressureLevel::Nominal {
92 self.consecutive_at_level += 1;
93 } else {
94 self.consecutive_at_level = 0;
95 self.last_action_effective = true;
96 }
97
98 self.last_level = level;
99
100 let escalate = !self.last_action_effective && self.consecutive_at_level > 2;
102
103 match level {
104 PressureLevel::Nominal => HomeostasisAction::None,
105 PressureLevel::Elevated => {
106 if escalate {
107 HomeostasisAction::EvictProbationary {
108 target_tokens: self.target_free(0.60),
109 }
110 } else {
111 HomeostasisAction::TrimOutputs
112 }
113 }
114 PressureLevel::High => HomeostasisAction::EvictProbationary {
115 target_tokens: self.target_free(0.70),
116 },
117 PressureLevel::Critical => {
118 if escalate {
119 HomeostasisAction::EvictProtected {
120 target_tokens: self.target_free(0.75),
121 }
122 } else {
123 HomeostasisAction::UnloadIndices
124 }
125 }
126 PressureLevel::Emergency => HomeostasisAction::EmergencyDrop,
127 }
128 }
129
130 pub fn report_outcome(&mut self, pressure_reduced: bool) {
132 self.last_action_effective = pressure_reduced;
133 }
134
135 fn target_free(&self, target_util: f64) -> usize {
137 (self.budget_tokens as f64 * target_util) as usize
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn nominal_pressure_no_action() {
147 let mut ctrl = HomeostasisController::new(100_000);
148 let action = ctrl.evaluate(50_000); assert_eq!(action, HomeostasisAction::None);
150 }
151
152 #[test]
153 fn elevated_pressure_trims_outputs() {
154 let mut ctrl = HomeostasisController::new(100_000);
155 let action = ctrl.evaluate(72_000); assert_eq!(action, HomeostasisAction::TrimOutputs);
157 }
158
159 #[test]
160 fn high_pressure_evicts_probationary() {
161 let mut ctrl = HomeostasisController::new(100_000);
162 let action = ctrl.evaluate(85_000); assert!(matches!(
164 action,
165 HomeostasisAction::EvictProbationary { .. }
166 ));
167 }
168
169 #[test]
170 fn critical_pressure_unloads_indices() {
171 let mut ctrl = HomeostasisController::new(100_000);
172 let action = ctrl.evaluate(92_000); assert_eq!(action, HomeostasisAction::UnloadIndices);
174 }
175
176 #[test]
177 fn emergency_drops_everything() {
178 let mut ctrl = HomeostasisController::new(100_000);
179 let action = ctrl.evaluate(96_000); assert_eq!(action, HomeostasisAction::EmergencyDrop);
181 }
182
183 #[test]
184 fn escalation_on_ineffective_action() {
185 let mut ctrl = HomeostasisController::new(100_000);
186
187 ctrl.evaluate(92_000);
189 ctrl.report_outcome(false);
190 ctrl.evaluate(92_000);
191 ctrl.report_outcome(false);
192 ctrl.evaluate(92_000);
193 ctrl.report_outcome(false);
194 let action = ctrl.evaluate(92_000);
195
196 assert!(matches!(action, HomeostasisAction::EvictProtected { .. }));
198 }
199
200 #[test]
201 fn recovery_resets_escalation() {
202 let mut ctrl = HomeostasisController::new(100_000);
203
204 ctrl.evaluate(92_000);
206 ctrl.report_outcome(false);
207 ctrl.evaluate(92_000);
208
209 let action = ctrl.evaluate(50_000);
211 assert_eq!(action, HomeostasisAction::None);
212
213 let action = ctrl.evaluate(72_000);
215 assert_eq!(action, HomeostasisAction::TrimOutputs);
216 }
217}