Short answer: Rewrite one canonical live memory so today is clear and yesterday stays briefly readable, instead of blind delete or double winners.
Engram rewrites can fold prior state into the update and drop duplicate extracts. Full prior text can live in cold storage or an external versions table for audits. Keep history in the live object short; load full trails only when the user asks about the past. Cap chained flips and compress older ones toward summarization.
Supersession is what you do after a contradiction is clear. You replace the live fact with the newer value, and you keep enough history that the agent still understands what changed. Blind delete removes the trail. Blind append leaves two winners. Good supersession rewrites one canonical memory so today is obvious and yesterday is still readable. Weaviate Engram’s transform path is built for that pattern. A rewrite can fold prior role into a promotion update, then drop the duplicate extract so search does not return two job titles.
This chapter explains how much history to keep in the live object, how Engram rewrite and delete actions cooperate, when to archive full prior text outside the retrieval path, and how an application can force a careful supersession when leftovers remain. The through-line is simple. Current advice must be unambiguous. Past state must remain recoverable without competing in ordinary hybrid search.
Why is “delete the old row” not the same as superseding with history?
Once detection flags a conflict, delete feels clean. It often is too clean. Hard deletion permanently removes the memory by id. That is right for privacy wipeouts and for true junk. It is wrong when later questions need the trail. “What adhesive did we use before the switch?” needs history. “Did the user always prefer dark mode?” needs history. If you only delete, those answers become guesses.
Append-only updates fail the other way. The new fact sits beside the old one. Both retrieve. The agent cites both and invents a compromise. Research on temporal validity shows that retiring the stale value from active retrieval, while retaining it for as-of or audit queries, is the durable pattern. Engram’s rewrite-plus-delete transform is the practical version of that idea for conversational personalization. One object carries current truth plus a short past clause. The redundant new extract is deleted so it never becomes a second live row.
Think of three layers. Live Engram content answers “what is true now, with a brief used-to-be.” Cold archive stores full prior wording if compliance needs it. Conversation logs remain the raw evidence. Supersession manages the live layer. It does not replace archival policy.
How does Engram rewrite a memory so the past stays in the text?
After you accept that history belongs in the canonical object, look at the write path. Engram extracts a new fact, retrieves related memories, then decides actions per memory. In the classic promotion case, the older “works as a machine learning engineer” memory is rewritten to “used to work as a machine learning engineer, but has now been promoted to CEO.” The new extract is deleted. Unrelated facts, such as working from home, stay untouched.
That single rewrite is the supersession. The agent later searches for role and gets one memory. The current title is clear. The prior title is still in the sentence for context. How much history to keep is a configuration concern. Topic descriptions and transform instructions control whether Engram keeps a short clause, a dated chain, or almost no past at all. Prefer short history for preferences that flip often. Prefer a dated clause when the change itself matters for advice.
Bounded topics strengthen the pattern. When a topic allows only one memory per scope, updates rewrite in place instead of spawning siblings. Conversation summaries follow the same idea. Each add refreshes one summary memory for the conversation id. The live object stays singular. History lives inside the rewritten text, not as a pile of near-duplicates.
When should history live outside the live Engram object?
Rewrite-with-clause covers most product needs. Some domains need more. Regulated workflows may require immutable prior versions. Long technical migrations may need exact old API names for as-of debugging. In those cases, copy the full prior content to cold storage before you delete or before transform collapses it. Then let Engram hold only the current fact, optionally with a one-line “superseded on DATE” note.
Bi-temporal designs separate valid time from recorded time. They close the old interval instead of erasing the row. Engram’s public manage API is create, search, get, and delete oriented. You can still approximate the ledger in your app. Keep an external versions table keyed by memory subject. On supersession, write the outgoing text there, then send a correction into Engram so transform rewrites the live memory. Ordinary search stays current. Audits read the versions table.
Do not put the entire ledger into every prompt. History in the live memory should be short enough to help without drowning the current instruction. Full history belongs in tools the agent calls only when the user asks about the past.
What does a careful application-side supersession look like?
Imagine a bookbinding shop agent on bookbinding-press-desk-3. The preferred adhesive changed from PVA to hide glue for leather spines. A contradiction scan found both strings. You want one live memory that states the current glue and briefly records the prior choice.
import os
from datetime import datetime, timezone
from engram import EngramClient, HybridRetrieval
client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])
binder = "binder-rosa-nguyen"
press = {"press_id": "bookbinding-press-desk-3"}
archive = [] # stand-in for cold storage
def supersede_with_history(old_content: str, new_fact: str) -> str:
stamp = datetime.now(timezone.utc).date().isoformat()
return (
f"{new_fact} "
f"(Previously, until {stamp}: {old_content.rstrip('.')}.)"
)
def apply_supersession():
hits = client.memories.search(
"preferred adhesive leather spines",
user_id=binder,
group="personalization",
properties=press,
retrieval_config=HybridRetrieval(limit=10),
)
older = next((m for m in hits if "pva" in m.content.lower()), None)
newer = next((m for m in hits if "hide glue" in m.content.lower()), None)
if not older or not newer:
# Prefer letting Engram transform merge via a correction add.
run = client.memories.add(
"For bookbinding-press-desk-3 leather spines, preferred adhesive is hide glue, not PVA.",
user_id=binder,
group="personalization",
properties=press,
)
client.runs.wait(run.run_id)
return "delegated-to-transform"
archive.append({"id": older.id, "content": older.content, "at": older.updated_at})
merged = supersede_with_history(
older.content,
"On bookbinding-press-desk-3, preferred adhesive for leather spines is hide glue.",
)
# Write the merged canonical fact; transform should reconcile siblings.
run = client.memories.add(
merged,
user_id=binder,
group="personalization",
properties=press,
)
client.runs.wait(run.run_id)
# Remove leftover absolute old/new rows if they still retrieve separately.
for m in client.memories.search(
"preferred adhesive leather spines",
user_id=binder,
group="personalization",
properties=press,
retrieval_config=HybridRetrieval(limit=10),
):
text = m.content.lower()
if m.content.strip() == merged.strip():
continue
if "pva" in text or (
"hide glue" in text and "previously" not in text and "until" not in text
):
client.memories.delete(m.id, user_id=binder, group="personalization")
kept = client.memories.search(
"preferred adhesive leather spines",
user_id=binder,
group="personalization",
properties=press,
retrieval_config=HybridRetrieval(limit=5),
)
return [m.content for m in kept]
print(apply_supersession())
print("archived_versions", len(archive))
Prefer the first branch in production. Send a clear correction and let Engram rewrite. Use the merge-and-delete path when you must repair a store that already holds siblings. Always archive before delete when the prior wording may be audited.
How much history should the agent see at answer time?
Supersession shapes storage. Prompting shapes use. For routine help, inject the live memory as written. The short previous clause is usually enough. For “what did we use last year” questions, search cold archive or ask for an explicit history tool. Do not retrieve every superseded sibling into the context window. That recreates the conflict you just resolved.
Tune transform instructions so rewrites stay readable. “Used to X, now Y” beats a paragraph of changelog prose. Cap chained history after a few flips. Compress older flips into “changed several times; currently Y.” That is already a step toward summarization as compression, which is the next maintenance lever when even well-superseded stores grow too large.
Our next chapter, How does summarization compress memory?, shows how to shrink long trails into compact memories without throwing away the decisions that still matter.