You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(verif): consolidation cadence uses ingested_at instead of wall-clock created_at
Production-relevant bug surfaced by LoCoMo smoke (tasks/e1-v3-locomo-smoke-finding.md):
backfilled memories with backdated created_at (e.g. a 2023 conversation
imported in 2026 wall-clock) trigger immediate gist/tag compression on
the first consolidation pass because (now - created_at) >> 7-day gist
gate. The intended semantics is "memory has had time to be revisited
in MY system" — elapsed since ingest, not elapsed since the original
event.
Changes:
- pg_schema.py: add memories.ingested_at TIMESTAMPTZ NOT NULL DEFAULT
NOW() in MEMORIES_DDL (fresh DBs) plus an idempotent migration block
that ALTERs existing tables and backfills ingested_at = created_at
for legacy rows. Comment kept semicolon-free (df14e16, 9f94bd3).
- pg_store.py: row normalizer surfaces ingested_at as ISO string. INSERT
inherits DEFAULT NOW() automatically.
- compression.py: cadence gate reads ingested_at (fallback to created_at
for in-memory dicts that never round-tripped through PG).
- decay_cycle.py: ACT-R lifetime L is ingest-relative; _hours_since_access
fallback chain now last_accessed -> ingested_at -> created_at.
- write_post_store.py, write_gate.py: synaptic-tagging window and
temporal-novelty signal both ask "in MY system" — also use ingested_at.
- Tests: regression in test_compression.py (backdated created_at + fresh
ingested_at must stay level 0), in test_decay_cycle.py (ACT-R does not
collapse on backfill), and a schema-shape test test_pg_ingested_at.py
asserting the column declaration, migration guard, backfill statement,
and semicolon-free comments.
Audit: synaptic_*, microglial_pruning, cascade_* contain no wall-clock
cadence reads (none of them use datetime.now() / created_at). The
PL/pgSQL effective_heat() and recall_memories() functions correctly use
heat_base_set_at / last_accessed (last_accessed -> created_at fallback
is for retrieval recency ranking, which IS event-time semantics — not
cadence — and is left unchanged). replay_execution.py and sleep_compute.py
sort by created_at for narrative/temporal ordering — correct, unchanged.
Verification:
- Full suite: 2656 passed.
- LoCoMo smoke (--with-consolidation, --limit 1): MRR 0.866 (matches
baseline non-consolidation MRR exactly; pre-fix this collapsed to
0.222 because immediate compression destroyed retrievable content).
Sources: Anderson & Lebiere (1998) ACT-R Eq. 4.4 — lifetime L is
elapsed time in the learner's system since acquisition, not elapsed
time since the original-source event. Tse et al. (2007) and McClelland
et al. (1995) describe consolidation timescales relative to acquisition
in the system, not relative to the original-event date.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
0 commit comments