Skip to content

fix(memory): anchor staleness to last_verified, not file mtime#150

Open
huytg2610 wants to merge 1 commit into
SafeRL-Lab:mainfrom
huytg2610:fix/memory-staleness
Open

fix(memory): anchor staleness to last_verified, not file mtime#150
huytg2610 wants to merge 1 commit into
SafeRL-Lab:mainfrom
huytg2610:fix/memory-staleness

Conversation

@huytg2610

Copy link
Copy Markdown

Problem

MemorySearch rewrites the memory file to update last_used_at, which bumps
the file's mtime. Both the recency score in _memory_search and the
stale-memory warning in memory_freshness_text were derived from that mtime,
so a single read of a stale, never-re-verified memory reset its recency to
~1.0 and suppressed its "verify against current code" warning — the
"stale-but-confident" failure the design (paper §4.2) warns against. The
most-retrieved memories, the ones most likely to be acted on, became immune
to the staleness penalty.

Repro (before this PR)

A memory 60 days old, never re-verified:

  • warning before a read: SHOWN
  • warning after ONE read: (gone) ← bug

Fix

  • New last_verified frontmatter field; defaults to created at save time.
  • Staleness/recency now computed from verified_epoch (last_verified →
    created → mtime fallback for legacy files), never from raw mtime.
  • touch_last_used preserves mtime and never touches last_verified — a read
    can't look like a write.
  • New MemoryVerify tool / mark_verified() is the only thing that
    refreshes the clock, called after the agent re-checks the claim against the
    environment. This is integral to the fix, not a separate feature: removing
    the broken implicit refresh (read = fresh) requires providing the correct
    explicit one, otherwise a still-valid old memory would be stuck stale.

After the fix, the same scenario keeps the warning after a read, and only
MemoryVerify clears it.

Tests

tests/test_memory_staleness.py (7 tests) encodes the bug as a regression
(fails on the old design, passes here): retrieval doesn't reset staleness,
mtime is preserved, explicit verification refreshes, verification-anchored
ranking, and legacy-file fallback. Existing test_memory.py stays green.

Retrieval rewrote the memory file (last_used_at), bumping mtime; both the
recency score and the stale-memory warning were derived from mtime, so a
single read reset a stale memory's recency to ~1.0 and suppressed its
verify-against-code warning. Anchor staleness to a last_verified date
(fallback created, then mtime for legacy files), refresh it only via the
new MemoryVerify tool / mark_verified(), and preserve mtime in
touch_last_used. Adds a regression test. Realizes the paper's 'make trust
a runtime decision' for memory (§4.2).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant