fix(engine): stamp memory_units.updated_at on the writes that change a memory (#3490) - #3502
Open
nicoloboschi wants to merge 1 commit into
Open
fix(engine): stamp memory_units.updated_at on the writes that change a memory (#3490)#3502nicoloboschi wants to merge 1 commit into
nicoloboschi wants to merge 1 commit into
Conversation
…a memory (#3490) `updated_at` reads as "when this memory last changed" and consumers chase it (`WHERE updated_at > watermark`) for incremental export, cache invalidation and the mental-model staleness check. Several write paths never touched it, so the chase silently skipped their changes and reported itself finished: the document tag propagation, `set_memory_embedding`, `set_invalidation_reason` and the transfer importer's event_date / proof_count / source_memory_ids / created_at fixups. Those statements now stamp the column. Consolidation bookkeeping stays exempt, deliberately. `consolidated_at` and `consolidation_failed_at` are scheduler state, not the memory: stamping them would make every consolidation pass look like an edit to every fact it folded, re-flagging mental models stale and re-feeding unchanged facts to a delta refresh for no content change. `mark_consolidated` already documented that choice; the requeue sites that clear the markers inline now say so too. The contract is written down on META_UPDATED_AT in the memories interface, so a store that owns memories itself has the same rule to keep — and so the next write path added has something to check itself against.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3490.
memory_units.updated_atreads as "when this memory last changed", and consumers chase it (WHERE updated_at > watermark) for incremental export, cache invalidation and the mental-model staleness check. Several write paths never touched it, so the chase silently skipped their changes and reported itself finished.What now stamps the column
memory_engine.update_documentSET tags— a document's tags propagated to its memoriesmemories/pg/writes.set_memory_embeddingmemories/pg/writes.set_invalidation_reasontransfer/importer._restore_fact_lifecyclecreated_attransfer/importer._import_observationsevent_datetransfer/importer._link_observation_sourcesproof_count,source_memory_idsWhat deliberately does not
The un-consolidate paths and
mark_consolidated—consolidated_at/consolidation_failed_at. That exemption already existed and was documented inmark_consolidated; this PR keeps it and makes it explicit at the requeue sites that clear the markers inline, because it is load-bearing rather than an oversight:any_memory_updated_since(the mental-model staleness check) and the delta-refresh watermark both readupdated_at. Stamping bookkeeping would make every consolidation pass look like an edit to every fact it folded, re-flagging mental models stale and re-feeding unchanged facts to a delta refresh — an LLM-billed refresh for no content change.That is also why this went with option 2 from the issue (fix the call sites) rather than a
BEFORE UPDATEtrigger: a trigger cannot express the exemption, and the two readings of the column — "row last written" vs "memory last changed" — genuinely conflict here. To stop "the next one added is a new gap" being the whole cost of that choice, the contract is now written down onMETA_UPDATED_ATin the memories interface (so a store extension that owns memories has the same rule to keep), withmark_consolidatedpointing at it as the single exception.Not addressed, and unaddressable with a timestamp: hard deletes. A consumer that must catch those still needs a content fingerprint.
Tests
tests/test_memory_units_updated_at.pypins both halves — the paths that must stamp, and the bookkeeping ones that must not. The three "must stamp" cases fail onmainand pass here.Also ran:
test_observation_invalidation,test_document_tracking,test_document_transfer,test_memory_curation,test_admin_bank_transfer,test_admin_backup_restore,test_consolidation*,test_mental_models,test_mental_model_delta,test_memories_extension— all green.