use super::{BudgetPressure, SignalBudget};
#[derive(Debug, Clone)]
pub enum PolicyAction {
Allow,
SoftWarn(String),
AutoTrim { keep_lines: usize },
Reject(String),
}
pub struct BudgetPolicy {
pub hard_cap: usize,
pub warn_at_pct: f64,
pub trim_at_pct: f64,
}
impl BudgetPolicy {
pub fn default_policy() -> Self {
Self {
hard_cap: 8_000,
warn_at_pct: 0.65,
trim_at_pct: 0.85,
}
}
pub fn evaluate(&self, budget: &SignalBudget, incoming_tokens: usize) -> PolicyAction {
let projected = budget.used + incoming_tokens;
let projected_pct = projected as f64 / self.hard_cap as f64;
if projected > self.hard_cap {
return PolicyAction::Reject(format!(
"budget overflow: {projected} > {}",
self.hard_cap
));
}
match budget.pressure() {
BudgetPressure::Overflow | BudgetPressure::Critical => {
let keep = (self.hard_cap.saturating_sub(budget.used)) / 4;
PolicyAction::AutoTrim {
keep_lines: keep.max(5),
}
}
BudgetPressure::Elevated => {
PolicyAction::SoftWarn(format!("context at {:.0}% capacity", projected_pct * 100.0))
}
BudgetPressure::Calm => PolicyAction::Allow,
}
}
}