Skip to content

Decay is usage recency; importance must be earned

Status: accepted (2026-07-06), implemented

The hybrid/semantic scoring gives 40% of its budget to decay + importance, but in practice decay measured write-age (no retrieval path ever bumped last_accessed_at) and importance was a constant 0.5 (no production caller of reinforce(), no importance field on MemoryCreate). Decision: (1) retrieval bumps last_accessed_at/access_count in batch for memories actually kept in assembled evidence, so decay means usage recency; (2) episodic memories decay on event time (valid_from, per ADR 0001), not access time — for events, "when it happened" is the recency that matters; (3) importance stays only if it is fed by a real signal (e.g. policy-critical facts boosted at write); otherwise its weight goes to zero. Rejected alternative: decay-as-write-age ("memories fade unless explicitly reinforced") — it silently punishes exactly the long-term memories the product exists to keep, and no benchmark exercises it because benchmark ingestion is always fresh.

Implementation notes (2026-07-06)

Producers wired: Engram.record_usage() batch-bumps last_accessed_at/access_count and recall() calls it for the memories kept in its evidence block; episodic rows with caller-supplied event time (valid_from <> created_at) decay on valid_from in all three scoring paths; policy-critical facts (metadata["critical"], stamped by MemoryPolicy.apply_metadata) are written with importance 0.8 vs the 0.5 default. Because a real importance producer now exists, the importance weight stays in the formula (the zero-weight branch of this decision was not needed).

Threshold re-validation outcome: near_duplicate_threshold (0.95) compares raw embedding cosine similarity in _find_near_duplicate, not the combined score — unaffected by the scoring changes, no adjustment needed. All min_score floors default to 0.0 at the client seam, so the re-scored combined values (lower for stale episodic events, higher for critical facts, keyword term now pure per ADR 0007) filter nothing unexpectedly.