#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct RegionWriteCounters {
pub memories_since_last_cycle: u32,
pub edges_since_last_cycle: u32,
pub seconds_since_last_cycle: u64,
}
#[derive(Clone, Copy, Debug)]
pub struct DreamsTrigger {
pub memory_threshold: u32,
pub edge_threshold: u32,
pub age_floor_days: u32,
pub min_interval_hours: u32,
}
impl Default for DreamsTrigger {
fn default() -> Self {
Self {
memory_threshold: 1000,
edge_threshold: 5000,
age_floor_days: 30,
min_interval_hours: 6,
}
}
}
impl DreamsTrigger {
pub fn should_fire(&self, c: &RegionWriteCounters) -> bool {
let min_interval = (self.min_interval_hours as u64) * 3600;
if c.seconds_since_last_cycle < min_interval {
return false;
}
c.memories_since_last_cycle >= self.memory_threshold
|| c.edges_since_last_cycle >= self.edge_threshold
|| c.seconds_since_last_cycle >= (self.age_floor_days as u64) * 86400
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fires_on_memory_threshold_after_interval() {
let t = DreamsTrigger::default();
let c = RegionWriteCounters {
memories_since_last_cycle: 1000,
edges_since_last_cycle: 0,
seconds_since_last_cycle: 7 * 3600,
};
assert!(t.should_fire(&c));
}
#[test]
fn rate_limited_below_min_interval() {
let t = DreamsTrigger::default();
let c = RegionWriteCounters {
memories_since_last_cycle: 5000,
edges_since_last_cycle: 5000,
seconds_since_last_cycle: 3600,
};
assert!(!t.should_fire(&c), "R-MT17 rate limit");
}
#[test]
fn age_floor_fires_on_stale_region() {
let t = DreamsTrigger::default();
let c = RegionWriteCounters {
memories_since_last_cycle: 0,
edges_since_last_cycle: 0,
seconds_since_last_cycle: 31 * 86400,
};
assert!(t.should_fire(&c));
}
}