How the Decay Math Formula and Retention Scoring Work in ai-memory
The decay math formula combines exponential time decay with logarithmic access reinforcement to calculate retention scores that determine which episodic pages get evicted from ai-memory.
The akitaonrails/ai-memory repository implements a mathematically-grounded retention model to manage the lifecycle of episodic memory pages. At the heart of this system lies the decay math formula defined in crates/ai-memory-store/src/decay.rs, which computes retention scores by weighing page age against access patterns, user feedback, and optional actor breadth metrics.
Core Decay Parameters
The DecayParams struct in crates/ai-memory-store/src/decay.rs defines the tunable constants that govern the retention curve. These parameters allow operators to adjust the memory system's forgetfulness without altering the underlying code.
| Parameter | Default | Mathematical Role |
|---|---|---|
lambda |
0.02 | Controls exponential decay on age since updated_at (approximately 35-day half-life) |
sigma |
0.6 | Sets the magnitude of the access-reinforcement boost |
mu |
0.04 | Governs exponential decay on days since last access (recent hits matter more) |
salience_default |
1.0 | Baseline salience for pages without explicit feedback |
cold_threshold |
0.20 | Score floor below which pages become eviction candidates |
hard_delete_after_days |
180 | Tombstone survival period before permanent removal |
Source: DecayParams definition
The Retention Score Formula
The public API entry point retention_score delegates to retention_score_with_breadth with a breadth weight of zero, preserving backwards compatibility with the original historic formula.
pub fn retention_score(
params: &DecayParams,
age_days: f64,
access_count: u32,
days_since_access: Option<f64>,
salience: Option<f64>,
) -> f64 {
retention_score_with_breadth(
params,
age_days,
access_count,
days_since_access,
salience,
0,
0.0,
)
}
Source: retention_score implementation
Mathematical Components
The retention score calculation combines three distinct mathematical components:
Time Decay Term
salience * exp(-λ * age_days)
Older pages decay exponentially based on the lambda parameter, while higher salience values lift the entire curve upward.
Access Reinforcement Term
σ * ln(1 + access_count) * exp(-μ * days_since_access) * breadth
This term applies a logarithmic scaling to access frequency (ln(1 + access_count)) multiplied by its own exponential decay based on recency. The sigma parameter scales the boost magnitude.
Breadth Multiplier (Optional)
1 + breadth_weight * ln(1 + distinct_actors - 1)
When breadth_weight is non-zero, the formula accounts for social reinforcement by scaling the access term based on the count of distinct actors who accessed the page. With breadth_weight = 0, this term collapses to 1.
Source: retention_score_with_breadth core math
Salience Adjustments via Feedback
User feedback directly manipulates the salience variable before the retention calculation. The salience_after_feedback function in crates/ai-memory-store/src/decay.rs clamps adjustments within bounded limits to prevent single actors from permanently locking or instantly destroying pages.
pub fn salience_after_feedback(
params: &DecayParams,
current: Option<f64>,
kind: ai_memory_core::FeedbackKind,
) -> f64 {
let current = current.unwrap_or(params.salience_default);
let next = match kind {
K::Helpful => current + SALIENCE_STEP,
K::NotHelpful => current - SALIENCE_STEP,
K::Stale | K::Wrong => SALIENCE_MIN,
};
next.clamp(SALIENCE_MIN, SALIENCE_MAX)
}
Source: salience_after_feedback
- Helpful feedback increases salience by
SALIENCE_STEP(0.25), capped atSALIENCE_MAX(2.0) - NotHelpful decreases salience by 0.25, with a floor of
SALIENCE_MIN(0.25) - Stale or Wrong feedback immediately floors salience to 0.25
These bounds ensure that the periodic retention sweep—not instantaneous feedback—governs long-term page eviction.
The Eviction Decision Flow
During the periodic forget sweep (ai_memory_store::Reader::decay_candidates), the system evaluates each page using the decay math formula:
- Calculate raw retention score using current metadata
- Compare against
cold_threshold(default 0.20) - Check
PageMetadata::pinnedstatus (pinned pages survive regardless of score) - Candidates below threshold enter soft-delete → tombstone → hard-delete pipeline after
hard_delete_after_days
Sources:
- Candidate extraction:
decay_candidates - Soft-delete logic:
soft_delete_for_decay_if_latest
Practical Implementation Examples
Computing a Basic Retention Score
use ai_memory_store::decay::{DecayParams, retention_score};
fn main() {
let params = DecayParams::default();
let age_days = 45.0;
let access_count = 12;
let days_since_access = Some(3.0);
let salience = None; // uses salience_default (1.0)
let score = retention_score(
¶ms,
age_days,
access_count,
days_since_access,
salience,
);
println!("Retention score = {:.4}", score);
}
Applying Feedback and Recomputing
use ai_memory_store::decay::{salience_after_feedback, retention_score};
use ai_memory_core::FeedbackKind;
fn main() {
let params = DecayParams::default();
// User marks page as Helpful
let new_salience = salience_after_feedback(
¶ms,
None,
FeedbackKind::Helpful,
);
let score = retention_score(
¶ms,
10.0, // age_days
5, // access_count
Some(1.0), // days_since_access
Some(new_salience),
);
println!("Score after helpful feedback = {:.4}", score);
}
Incorporating Multi-Actor Breadth
use ai_memory_store::decay::{DecayParams, retention_score_with_breadth};
fn main() {
let params = DecayParams::default();
let score = retention_score_with_breadth(
¶ms,
30.0, // age_days
20, // access_count
Some(2.0), // days_since_access
None, // default salience
5, // distinct_actors
0.5, // breadth_weight
);
println!("Score with actor breadth = {:.4}", score);
}
Summary
- The decay math formula lives in
crates/ai-memory-store/src/decay.rsand combines exponential time decay with logarithmic access reinforcement - Retention scoring weighs three factors: salience-adjusted age decay, recency-weighted access count, and optional social breadth
- The
cold_thresholdparameter (default 0.20) determines eviction eligibility, while pinned pages bypass deletion regardless of score - User feedback adjusts salience within bounded limits (0.25 to 2.0) to prevent permanent locking or instant destruction of pages
- Evicted pages enter a tombstone state for 180 days (
hard_delete_after_days) before permanent removal
Frequently Asked Questions
What is the default half-life for page decay in ai-memory?
With the default lambda value of 0.02, pages experience approximately a 35-day half-life through pure time decay. This means a page with default salience (1.0) and no access reinforcement will see its time-decay component halve roughly every 35 days according to the exponential decay formula exp(-0.02 * age_days).
How does feedback affect the retention score calculation?
Feedback modifies the salience variable before the retention formula executes. Helpful feedback increments salience by 0.25 up to a maximum of 2.0, while NotHelpful decrements by 0.25 down to a minimum of 0.25. Stale or Wrong feedback immediately floors salience to 0.25. Because salience multiplies the time-decay term, higher values effectively raise the entire retention curve, extending page lifetime.
What happens when a page's retention score drops below the cold threshold?
When retention_score returns a value below cold_threshold (default 0.20) and the page is not pinned, it becomes a candidate for the forget sweep. The system initiates a soft-delete via soft_delete_for_decay_if_latest, creating a tombstone that persists for hard_delete_after_days (180 days by default) before hard deletion and permanent removal from the ancestry chain.
Can the decay parameters be tuned without modifying source code?
Yes, the DecayParams struct exposes all mathematical constants—including lambda, sigma, mu, and cold_threshold—as configuration parameters. According to the source in crates/ai-memory-mcp/src/server.rs, these values are exposed via the MCP admin API, allowing runtime adjustment of the retention model's sensitivity without recompiling the ai-memory store.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →