feat(memory): thread_id + supersede action + upsert resurrection fix#379
Merged
Conversation
Thread-identity slice 1a (mega-monkey plan 73daa28f v5). The memory face
of resolution-as-fan-out: every read path already filters
superseded_by IS NULL — this PR makes that column actually populated.
- v44 migration: memories.thread_id (indexed, nullable) +
supersede_reason audit column; index in the migration block per the
v42 boot-order rule
- memory(action="supersede", thread_id|key, reason): idempotent
tombstone — superseded_by = own id (self-pointer = tombstone without
successor), scope-gated (callers only close facts they can see),
removes memory:{key} graph edges like forget does
- FIX upsert resurrection: same-key store no longer resets
superseded_by = NULL — a routine cron re-store on a superseded key
silently un-superseded it. Supersession is preserved; thread_id only
updates when explicitly provided; graph edges stay removed
- store accepts thread_id; store response flags still_superseded
Tests: 10 new in memorySupersede.test.ts incl. the release gate
(cron re-store cannot resurrect).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e manifest The supersede addition pushed the memory tool rawDescription to 489 chars (cap 360) and staled the embedding manifest descriptionHash — the 4 full-matrix CI failures on #379. Trimmed to 355 keeping the required "Returns"/"Does not" rewrite-completeness phrases; manifest regenerated. tool-routing contract suite 41/41. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Plan
mega-monkey plan 73daa28f (thread-identity-resolution-loop), implementation plan v5 — slice 1a, the memory face. Council ×2 verdict: ship this face FIRST because every read path already filters
superseded_by IS NULL(schema.ts:392; memory.ts get/search/list; brief.ts; entityHistory.ts) — the face closes the instant the column is populated.What
memories.thread_id(indexed, nullable — correlation id minted by the engine threads registry) +supersede_reasonaudit column. Index lives in the migration block per the v42 boot-order rule.memory(action:"supersede", thread_id|key, reason): idempotent tombstone.superseded_by = own id(self-pointer = tombstone-without-successor); already-superseded rows counted, not errored. Scope-gated: callers only close facts they can see (global + own agent scope) — never another agent's private facts. Removesmemory:{key}graph edges (mirrors forget) so stale edges don't outlive the fact.memory.ts:250): same-key store no longer resetssuperseded_by = NULL. Previously a routine cron re-store on a superseded key silently un-superseded it — the exact "resolved items resurface" bug class. Supersession preserved;thread_idonly updates when explicitly provided; graph edges not resurrected; store response flagsstill_superseded.storeacceptsthread_id.No new read-filter work — that would duplicate the existing
superseded_byfilter.Pairs with
velvetmonkey/mega-monkey#105 (threads registry + resolution ledger + engine-side applier calling this supersede action). Either side deploys independently: engine supersede pushes stay
pendingand drain once this lands.Tests
10 new in
memorySupersede.test.ts, including the release gate: superseded fact never resurfaces in get/search/list after supersede, including after a same-key cron re-store. tsc clean.🤖 Generated with Claude Code