Skip to main content

codemem_engine/consolidation/
decay.rs

1use super::ConsolidationResult;
2use crate::CodememEngine;
3use codemem_core::CodememError;
4use serde_json::json;
5
6impl CodememEngine {
7    /// Consolidate decay: power-law decay that rewards access frequency.
8    pub fn consolidate_decay(
9        &self,
10        threshold_days: Option<i64>,
11    ) -> Result<ConsolidationResult, CodememError> {
12        let threshold_days = threshold_days.unwrap_or(30);
13        let now = chrono::Utc::now();
14        let threshold_ts = (now - chrono::Duration::days(threshold_days)).timestamp();
15
16        let stale = self.storage.get_stale_memories_for_decay(threshold_ts)?;
17
18        if stale.is_empty() {
19            if let Err(e) = self.storage.insert_consolidation_log("decay", 0) {
20                tracing::warn!("Failed to log decay consolidation: {e}");
21            }
22            return Ok(ConsolidationResult {
23                cycle: "decay".to_string(),
24                affected: 0,
25                details: json!({
26                    "threshold_days": threshold_days,
27                }),
28            });
29        }
30
31        // Compute power-law decay: importance * 0.9^(days_since/30) * (1 + log2(max(access_count,1)) * 0.1)
32        let now_ts = now.timestamp();
33        let updates: Vec<(String, f64)> = stale
34            .iter()
35            .map(|(id, importance, access_count, last_accessed_at)| {
36                let days_since = (now_ts - last_accessed_at) as f64 / 86400.0;
37                let time_decay = 0.9_f64.powf(days_since / 30.0);
38                let access_boost = 1.0 + ((*access_count).max(1) as f64).log2() * 0.1;
39                let new_importance = (importance * time_decay * access_boost).clamp(0.0, 1.0);
40                (id.clone(), new_importance)
41            })
42            .collect();
43
44        let affected = self.storage.batch_update_importance(&updates)?;
45
46        if let Err(e) = self.storage.insert_consolidation_log("decay", affected) {
47            tracing::warn!("Failed to log decay consolidation: {e}");
48        }
49
50        Ok(ConsolidationResult {
51            cycle: "decay".to_string(),
52            affected,
53            details: json!({
54                "threshold_days": threshold_days,
55                "algorithm": "power_law",
56            }),
57        })
58    }
59}