Append or Supersede? What to Do When New Information Contradicts Agent Memory
Most agent memory systems only know how to add. The moment a fact changes, the store holds both versions and the retriever picks whichever one scores higher — which is why a scheduling agent keeps booking a room that was decommissioned last month.
A scheduling agent learned in March that the team's standup runs at 9:30 in the Oak room. In June the standup moved to 9:00 and Oak was turned into storage. Both facts are now in memory. Nothing crashed, nothing errored, and the agent will happily book Oak at 9:30 for the rest of the year — because the retriever has no notion of which memory is later, only which one is closer to the query.
This is the failure that separates a memory store from a memory system. Writing is easy. Deciding what an old entry means once a new one contradicts it is the whole problem.
🔍 Why "just add it" quietly breaks
Almost every memory implementation starts as append-only: embed the observation, write the row, move on. That works until two rows disagree, and then three things go wrong at once.
- Retrieval is similarity-ranked, not time-ranked. A richly-worded old note often out-scores a terse new one. "Standup is at 9:30 in the Oak room, chaired by Priya" beats "standup moved to 9:00."
- Both can surface together. The agent sees the contradiction inside one context window and resolves it by vibes — usually by whichever appeared first.
- The contradiction compounds. Later notes reference the stale fact ("booked Oak again"), so the wrong version accumulates corroboration and looks more true over time.
The tell in production is an agent that is confidently, consistently wrong about one narrow thing while behaving perfectly everywhere else. That shape almost always means two live versions of one fact.
The three write modes
When a new observation arrives, exactly one of three things should happen to what's already stored.
Append — the new fact coexists with the old one. Use when the memory is an event: something that happened at a point in time and stays true forever. "Ran the migration on the staging DB" doesn't stop being true when you run it again.
Supersede — the new fact replaces a specific old one, and the old one stops being retrievable by default. Use when the memory is state: a current value that has exactly one correct answer at a time. Standup time. Preferred database. The customer's shipping address.
Amend — the new fact narrows or qualifies the old one without killing it. Use when both are partly right. "Deploys need approval" plus "except for docs-only changes" should end up as one merged memory, not two competing ones.
The mistake is treating all three as append because append is the only one the storage layer makes easy.
💡 The classification question that actually works
Before writing, ask one thing about the observation:
If someone asked this question a year from now, would the correct answer be the same?
- Same answer forever → event → append.
- Answer could change → state → check for an existing memory answering that same question, and supersede it.
That single question routes most writes correctly, and it's cheap enough to run as a small classification step on the write path rather than a design meeting.
Implementing supersede without a graph database
You don't need a temporal knowledge graph. You need a stable key and a status column.
# On every write, derive a subject key for state-type memories.
# "what is the standup time" -> subject="team.standup.time"
def write_memory(store, observation):
kind, subject = classify(observation) # "event" | "state", plus a key
if kind == "event":
store.insert(text=observation, kind="event", status="active")
return
prior = store.find_active(subject=subject)
if prior and not equivalent(prior.text, observation):
store.update(prior.id, status="superseded",
superseded_by=None, superseded_at=now())
store.insert(text=observation, kind="state",
subject=subject, status="active")
Three properties make this work:
- The subject key is the join. Two memories collide only if they answer the same question. Getting keys stable matters more than getting them elegant — a small controlled vocabulary beats free-form keys the model invents differently each time.
- Superseded rows are marked, not deleted. Default retrieval filters to
status = "active". History stays queryable for audits and for the "why did you think that?" question. - Equivalence is checked before superseding. Otherwise every re-observation of an unchanged fact churns a new row and the audit trail becomes noise.
Where it gets genuinely hard
Partial contradiction. "Standup moved to 9:00" doesn't say anything about the room. Superseding the whole prior memory silently discards the room. Either store state at one fact per row so the room is its own subject, or make supersede a merge that carries forward the unmentioned fields.
Trust ordering. Newer is not always righter. A user statement should outrank an agent's own inference; a system of record should outrank both. Attach a source tier to each memory and require the incoming one to be at least as trusted before it supersedes.
Scoped truth. "We deploy on Fridays" may be true for one team and false for another. If your subject key doesn't include the scope, two teams will overwrite each other forever. Namespace the key before you need to.
The retrieval side of the contract
Superseding is only half of it. The retriever has to honour the status filter, and this is where implementations leak: a summarisation job, an "export all memories" path, or a debugging tool reads the raw table without the filter, and stale facts walk back into context through a side door. Make status = "active" the default in the query layer, not something each caller remembers to add.
⚠️ One more leak: memories already summarised into a rolled-up digest. If a superseded fact was folded into last month's summary paragraph, marking the original row inactive doesn't touch the copy inside the digest. Summaries need re-derivation, or they need to be treated as events — a record of what was believed then, never as current state.
What to check tomorrow
Pull the last few hundred memory writes and count how many were state, not events. If your store treats all of them as append, that count is the number of contradictions waiting to surface. Then pick the one subject your agent gets wrong most often and give it a key. Correct memory is much less about remembering more and much more about being willing to retire what you already wrote down.