Repository navigation
Conversation
totalreclaw_forget tombstoned the fact, but auto-extraction kept reading text that restated it (the original turn, the forget turn, an answer built from Hermes' session search, the session summary). The dedup context lists active facts only, so the write path never knew the user had deleted it, and the fact was stored again. - core: new forget_guard module. match_forgotten (exact / subset / superset / anchor; lexical plus cosine, so value swaps still store) and is_forget_request (deletion notes). PyO3 + WASM bindings, shared fixture tests/parity/fixtures/forget-guard-v1.json. - python: ForgetLedger, an encrypted per-account file of facts the user forgot (vault key, never plaintext, nothing on-chain). A user-asked forget snapshots the fact first and records it. Every auto-extracted write and the session Crystal drop restatements and deletion notes. An explicit remember clears the entry; mirrored Hermes memory writes can't; internal tombstones don't record. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bd3G1BkVMFSXkcdAQ7nFax
This branch has not been deployed
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.
Refs graphprotocol/totalreclaw-internal#605, graphprotocol/totalreclaw-internal#640.
Summary
A fact the user asks to forget now stays forgotten. Before,
totalreclaw_forgettombstoned it, and a later auto-extraction stored it again.Root cause
Auto-extraction keeps reading text that restates the forgotten fact:
session_searchover the old transcript (rc3 S5);The write path has no record of the deletion. Line numbers are on
main. The dedup context comes fromclient.recall(...)over active facts only (python/src/totalreclaw/agent/lifecycle.py:122).totalreclaw_forget(hermes/tools.py:323) callsclient.forget(client.py:1120), which only writes a tombstone. So the restatement looks new, passes the near-duplicate check (lifecycle.py:401), and_auto_extract_innerstores it (lifecycle.py:373-441). A note about the deletion ("User previously identified as vegetarian and asked for that record to be removed", internal 640) is stored the same way.Fix
Write-time, client-side, no on-chain change.
rust/totalreclaw-core/src/forget_guard.rs), pure logic shared by all clients:match_forgotten(text, embedding, entries):exact(normalized text equal),subset(adds no content word, cos >= 0.70),superset(keeps every content word, cos >= 0.80),anchor(2+ and at least half of the forgotten text's capitalized or numeric words, cos >= 0.80).is_forget_request(text): notes about a deletion. It needs a request verb before "to forget", or a memory/record target. "Tends to forget appointments" and "wants to delete their Facebook account" pass.match_forgotten/is_forget_request, WASMmatchForgotten/isForgetRequest. Shared fixturetests/parity/fixtures/forget-guard-v1.json(21 match, 14 request, 11 token/anchor cases).ForgetLedger(forget_guard.py):~/.totalreclaw/forgotten-<eoa>.enc, XChaCha20-Poly1305 under the vault key, mode 0600, capped at 500. Plaintext lives only in process memory.client.forget(fact_id, suppress_reextraction=True)decrypts the fact first (operations.fetch_fact_plaintext) and records it once the tombstone lands. Onlytotalreclaw_forgetpassesTrue. UPDATE tombstones, re-crystallization and the USER.md mirror's replace don't._auto_extract_innerdrops ADD/UPDATE candidates that restate a ledger entry or are deletion notes. This covers turn,on_pre_compress, session end and the pending drain.session_debriefdrops matching Crystal sentences and items. If no narrative is left, no Crystal is stored.totalreclaw_rememberclears the matching entry, so the user can bring a fact back. Mirrored Hermes memory writes (_from_mirror) can't bring it back.Tests
python/tests/test_forget_sticks_605.py: reproduction with a realTotalReclawclient, a mocked relay and chain write, and the real Hermes tools. Onmain, the 605, 640, Crystal, mirror and UPDATE cases fail; with the fix all 7 pass.python/tests/test_forget_guard.py: fixture parity (Python port, and the core binding when present), ledger encryption, wrong key, cap and release,fetch_fact_plaintext, andclient.forgetwiring.cargo test(core): 717 passed, including 9forget_guardtests.tests/parity/forget-guard-parity.test.ts: WASM, 36 passed. Added as a CI step.check-pyfunction-parity.py,check-phrase-safety.shandcheck-docs.share green.anchor(cos 0.905). The rc2 "outdated" note matches assubset(0.739). Porto, vegan, green and "brother Rui" all store.Known limits
supersetcan over-suppress. "User's sister is vegetarian" is dropped once "User is vegetarian" was forgotten (cos 0.884).Overlap
_auto_extract_inner, in a block after the contradiction try/except. This PR adds its check inside the per-fact loop, so any conflict should be small.Needs the same fix (not in this PR)
storeExtractedFacts(skill/plugin/index.ts:1551) and the forget tool path (skill/plugin/memory/).mcp/src/tools/forget.ts, and the batch write path inmcp/src/index.ts(around lines 848 and 2218).matchForgotten/isForgetRequestonce core 2.7.0 ships.No version bump, no RC, no publish.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Bd3G1BkVMFSXkcdAQ7nFax