Deleting a memory teaches the model nothing. Palinode forgets by retraction — and we measured why. #91
Paul-Kyle
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
When you tell an assistant "please forget that I collect sneakers," the
obvious implementation is deletion: find the memory, remove it. We built the
measurement before the feature, and the measurement says the obvious
implementation is the worst one available.
Erasure destroys the very evidence the model needs in order to honor the
erasure. In our paired pre-build check, removing every trace of a
"forgotten" preference didn't just fail to help — it scored worse than doing
nothing at all: every row the untouched baseline got right, full removal
broke, and it fixed none (n=18, and the effect had a mechanism we could read
directly in the transcripts). With no visible "the user asked me to forget
this," the model happily re-personalized on residual mentions of the
preference — a stray restatement in an old message — or simply pivoted to the
user's other preferences. Silent deletion is not forgetting; it is amnesia
with confidence.
What worked is what Palinode's architecture already believed in: retraction
with a paper trail. Archive the memories that carry the preference so recall
stops surfacing them — but keep the forget request itself retrievable as a
retraction record. When the model can see "the user asked me to forget this,"
it can treat the preference as radioactive instead of merely absent. In the
transcripts, that is literally what it does: it excludes candidate responses
"built upon the very memories you asked me to disregard."
That is the finding we want other memory-system builders to take even if they
never run Palinode: forgetting is a provenance problem. The record of the
retraction is not bureaucratic overhead — it is the load-bearing part.
What shipped
With
consolidation.forget.enabled: true, an explicit first-person forgetrequest in saved content — "please forget that I…", "could you forget my…" —
is detected at save time. The memories carrying the named preference are
resolved via the store's own hybrid search and archived: flipped to
status: archived, which the default recall path already excludes, with fullgit history retained. The request itself is saved normally and stays
retrievable; every archived memory carries
superseded_byprovenance pointingback at it, readable via
palinode trace. Nothing is deleted, and the wholetransaction is a reversible status flip.
Archival applies when the resolved memory is about the preference. When it
merely mentions the preference inside otherwise-unrelated content, the
operation narrows to mention-level retraction — exactly the sentences
carrying the preference are struck in place, and the rest of the memory stays
live. The design notes explain why that distinction exists; we learned it on
our own store.
The evidence, sized honestly
Three paired comparisons on the forgetting axis of the public PersonaMem-v2
benchmark — the one axis of that benchmark we found usable after gating it
(we have reported the benchmark's option-length artifact upstream; the
correct answer on this axis is the response that does not use the
forgotten preference):
archival with a visible retraction record fixed 3 rows and broke none;
full removal fixed none and broke every row it could break.
store build, cluster-bootstrapped): compliance 23.9% → 35.2%, +0.114
(95% CI [+0.026, +0.207], p = 0.017) on a 26B local backbone.
Disclosure: that net is 15 rows fixed, 5 rows broken. Archiving real
context under imperfect resolution sometimes costs an answer; the trade is
favorable and reversible, but it is a trade, not a free lunch.
p = 0.002), six rows changed and all six in the retraction record's favor —
though that model is much weaker at the task overall and both of its arms
sit near the floor; it is a different-family check, not a stronger-backbone
one. What it establishes is that the mechanism is not a quirk of one model.
Honest caveat, because we report our floors: on this benchmark slice a
trivial pick-the-shortest-option heuristic outscores every model
configuration, ours included — that is part of what we reported upstream.
The paired lifts are the claim; no absolute number here is.
Design notes
conservative: explicit, first-person request forms only. Assistant echoes
("I'll forget that you…"), negations ("don't forget…"), and self-reports
("I always forget my keys") do not fire. Paraphrase detection ("stop
bringing that up") is a planned extension, but is deliberately absent
from this release.
come from hybrid search, gated by shared content words with the stated
preference and capped per request — a false positive mutates a real
memory, so the guards are strict, and the retained retraction record is
the safety net for restatements resolution misses. The 15/5 record above
is what that trade looks like measured, not asserted.
mismatch. Our first real-store forget request named a person who existed
only as passing mentions inside dense project snapshots. Whole-file
archival resolved correctly and still did the wrong thing: forgetting one
person briefly removed a project closeout and an incident log from recall
(reversibly — the status flip and git history got both back). The fix
routes by coverage: a memory mostly about the preference archives whole;
a memory that merely mentions it gets mention-level retraction —
exactly the mentioning sentences struck in place with a visible
~~strikethrough~~ [RETRACTED <date>]marker, everything else live. Thestruck text stays retrievable as its own micro-tombstone: the same
provenance-first shape, at the grain the request actually had. What
striking cannot reach cleanly (headings, tables, code blocks, living
documents) is reported loudly as unforgotten rather than silently skipped
or archived whole. We re-ran the original request after the rebuild: it
struck exactly its mention sentences and nothing else. One provenance
note, so you can weight the claims: the paired benchmark numbers above
measured the archive path; the mention-level strike path is newer,
verified on our live store, and not yet benchmark-measured.
recall, the on-demand archive operation, supersession provenance, and the
audit history are all pre-existing Palinode machinery; this feature is the
missing write-time trigger, not new archival semantics.
Availability
Available now in Palinode v0.11.0, and running on our own store —
where the requests in this post's examples were run for real, on real
memories, before we wrote it up. Off by default — enable with:
Knobs:
min_shared_words(resolution precision gate, default 1),max_targets(archival cap per request, default 2), andmin_target_coverage(granularity floor routing whole-file archival vsmention-level retraction, default 0.05;
0.0restores unconditionalwhole-file archival).
All reactions