PRIVACY.md makes two unqualified deletion claims to users:
- line 43: "The
forget tool deletes individual memories."
- line 90: "
forget — delete a specific memory."
Verified behaviour on main at 65395fb (2026-08-06) does not support those claims without qualification.
What forget actually does
mcp_server/handlers/forget.py:115 — a single call:
deleted = store.delete_memory(memory_id)
mcp_server/infrastructure/pg_store.py:995-996:
def delete_memory(self, memory_id: int) -> bool:
cur = self._execute("DELETE FROM memories WHERE id = %s", (memory_id,))
forget.py contains no artifact, wiki, or embedding handling (grep for artifact|wiki|embedding returns only the store constructor at line 75).
What survives
1. The raw full text, on disk, forever. core/gist_extraction.py stores a gist in the memory row and puts the full raw output in a content-addressed artifact — infrastructure/artifact_store.py, at ~/.claude/methodology/artifacts/<yyyy-mm>/<sha256[:16]>.md. Grepping artifact_store.py for unlink|remove|delete returns nothing: no code path in the module deletes an artifact. So forgetting a gist-and-pointer memory removes the pointer and leaves the complete original content readable on the filesystem.
2. Wiki claims, deliberately. infrastructure/pg_schema.py:221:
memory_id INTEGER REFERENCES memories(id) ON DELETE SET NULL,
wiki.claim_events rows derived from a memory survive forget with the back-pointer nulled. The claim text — which can carry the same content — persists and stays searchable, now unattributable.
For contrast, pg_schema.py:196-197 does cascade memory_entities, so the gap is specific rather than total; entity links are handled, durable content is not.
Why this matters more than a normal bug
The survey at arXiv 2604.16548 calls this the frontier case, stating "cross-substrate deletion is the frontier" and "forgetting is the strongest test of mnemonic sovereignty," with the forget-phase attack class being "residual toxins persisting after deletion attempts." Independently of any attacker, this is a published privacy policy that describes behaviour the code does not implement — the user-facing controls section of PRIVACY.md is what a user relies on to exercise deletion.
Ask
Either make deletion cross-substrate, or correct PRIVACY.md — the two must agree. Cross-substrate is the right answer for a control the policy advertises.
forget deletes the memory row, its artifact(s), and its derived wiki claims — or explicitly reports what it could not delete, in the tool result.
- Decide the
ON DELETE SET NULL semantics on wiki.claim_events.memory_id deliberately: if an orphaned claim is intended (it may be, for wiki integrity), then PRIVACY.md must say so and forget must tell the user at call time.
- Artifacts need a reachable lifecycle regardless of this issue — a store that only ever grows and is never pruned is also a §13 C2 resource-lifecycle gap.
Acceptance criteria
- A test stores an oversized memory (forcing the gist+artifact path), forgets it, and asserts the artifact file is gone from disk — not merely that the row is gone.
- A test covers a memory with a derived wiki claim and asserts the chosen behaviour explicitly, whichever way it is decided.
- Partial-failure behaviour defined and tested (§13 A5): artifact unlink fails → what state remains, and what signal is emitted (asserted, §13 F1).
- Both backends (§12.3).
- PRIVACY.md and
docs/mcp-tools.md updated in the same PR to match the shipped behaviour (§13 H4). If any content is intentionally retained after forget, PRIVACY.md says so in the "Your controls" section.
- Zero surviving non-equivalent mutants on changed files (§12).
Relates to #365 (poisoning — remediation requires working deletion), #360.
PRIVACY.md makes two unqualified deletion claims to users:
forgettool deletes individual memories."forget— delete a specific memory."Verified behaviour on
mainat 65395fb (2026-08-06) does not support those claims without qualification.What forget actually does
mcp_server/handlers/forget.py:115— a single call:mcp_server/infrastructure/pg_store.py:995-996:forget.pycontains no artifact, wiki, or embedding handling (grep forartifact|wiki|embeddingreturns only the store constructor at line 75).What survives
1. The raw full text, on disk, forever.
core/gist_extraction.pystores a gist in the memory row and puts the full raw output in a content-addressed artifact —infrastructure/artifact_store.py, at~/.claude/methodology/artifacts/<yyyy-mm>/<sha256[:16]>.md. Greppingartifact_store.pyforunlink|remove|deletereturns nothing: no code path in the module deletes an artifact. So forgetting a gist-and-pointer memory removes the pointer and leaves the complete original content readable on the filesystem.2. Wiki claims, deliberately.
infrastructure/pg_schema.py:221:wiki.claim_eventsrows derived from a memory surviveforgetwith the back-pointer nulled. The claim text — which can carry the same content — persists and stays searchable, now unattributable.For contrast,
pg_schema.py:196-197does cascadememory_entities, so the gap is specific rather than total; entity links are handled, durable content is not.Why this matters more than a normal bug
The survey at arXiv 2604.16548 calls this the frontier case, stating "cross-substrate deletion is the frontier" and "forgetting is the strongest test of mnemonic sovereignty," with the forget-phase attack class being "residual toxins persisting after deletion attempts." Independently of any attacker, this is a published privacy policy that describes behaviour the code does not implement — the user-facing controls section of PRIVACY.md is what a user relies on to exercise deletion.
Ask
Either make deletion cross-substrate, or correct PRIVACY.md — the two must agree. Cross-substrate is the right answer for a control the policy advertises.
forgetdeletes the memory row, its artifact(s), and its derived wiki claims — or explicitly reports what it could not delete, in the tool result.ON DELETE SET NULLsemantics onwiki.claim_events.memory_iddeliberately: if an orphaned claim is intended (it may be, for wiki integrity), then PRIVACY.md must say so andforgetmust tell the user at call time.Acceptance criteria
docs/mcp-tools.mdupdated in the same PR to match the shipped behaviour (§13 H4). If any content is intentionally retained afterforget, PRIVACY.md says so in the "Your controls" section.Relates to #365 (poisoning — remediation requires working deletion), #360.