
What the AI crawlers actually fetched from this site in one week
SAGARIS5 min
BlogEngineering
You deleted the contact row. The model had already stored what it concluded from their emails as separate records with their own identity.

Someone writes in and asks to be forgotten. You open the CRM, find the contact, and delete it. The row is gone. The audit log records the deletion. You reply confirming it.
Meanwhile, an AI assistant read a year of that person's emails. From them it concluded that they were the economic buyer on a deal, that their budget cycle ends in March, that they were frustrated on a call in June, and that they mentioned a competitor by name. Those conclusions are not fields on the contact record. They are separate records with their own identity, their own provenance and their own lifecycle, and deleting the contact row touches none of them.
Ask the assistant a question next week and it will answer using facts about a person you told was erased. Everything you said in your confirmation email was true about the row and false about the system.
For most of the last decade, "delete the customer's data" meant "delete the records the customer gave us". That worked because systems mostly stored what they were told. A CRM holds fields a human typed. Delete the fields, delete the data.
A system with a memory layer stores something different: what it concluded. Those conclusions are derived records. They are about the person but they were not supplied by the person, they do not live under the person's primary key, and in a well-built store they deliberately survive the thing they were derived from, because the whole point of the memory is to outlast the source.
That is where "we deleted your data" quietly becomes false. Not through bad faith. Through the deletion being aimed at the wrong table.
The specific hazard gets sharper if your memory layer is bitemporal, which SAGARIS's is: every stored claim records both when the fact was true in the world and when the system came to believe it, so you can ask what was believed on any past date.
A store like that is engineered so history cannot be lost. Contradictions supersede rather than overwrite. Intervals close rather than disappear. That is what you want for a forecast you need to explain, and exactly wrong for an erasure request.
The tempting implementation is to close the fact's validity interval. Stamp an end date; SQL:2011 has dedicated syntax for it, FOR PORTION OF. The record now reads as no longer true, the current view is clean, and every dashboard agrees the person is gone.
The comment sitting directly above the deletion code refuses that, and states why in one sentence: a valid-time-scoped delete closes an interval and is a logical delete; it leaves the fact readable at earlier instants and is not Article 17 erasure.
Read that as a user rather than as an engineer. It means anyone who asks the system what it believed last March still gets the answer. The person was not deleted. They were moved into the past tense.
The claim store interface carries the requirement in its own contract, in language that leaves no room for a compromise implementation: both erasure operations are hard deletes, with no status flag, no logical delete, and no tombstoned-but-readable history.
The Postgres implementation is a literal DELETE against the claims table, with a predicate that is deliberately not narrowed by any temporal clause. Each claim's full lifecycle history lives in the same row it belongs to, so removing the row destroys the history with it. There is no append-only commit log holding a second copy, which is a design constraint chosen for precisely this moment rather than discovered at it.
Two erasure shapes exist as separate methods rather than one parameterised call, because they are different operations. Workspace erasure is offboarding: a customer leaves and everything goes. Subject erasure is harder: one person exercises their right while the workspace stays fully operational for everybody else.
And subject erasure has to find more than you would guess. Three kinds of record carry a data subject, and the classifier names all three:
- claims about the person, including every merged identity alias they resolve to; - claims about somebody else that name the person as an object, such as a claim that a particular deal's champion is this contact; - claims extracted from the person's own messages, even where the claim itself is about a third party.
The third is the one teams miss. A note the system derived about a competitor's pricing, extracted from an email that person wrote, is still derived from their data. Deleting only the claims whose subject field matches them leaves a trail somebody can walk backwards.
Deleting is the easy half. The half worth writing about is what happens next.
After the delete, the adapter goes back and checks. It re-reads on both time axes at six instants: the Unix epoch, the exact moment the erased claims were recorded, two intermediate dates, the present, and the far-future bound of 9999-12-31. It runs those probes for every alias in the subject's identity set. Only if every probe comes back empty does it issue a receipt.
If any probe still surfaces the subject, it throws a dedicated erasure-incomplete error, and that error carries the count of residual claims and the list of probes that still resurrect the person. It does not issue a partial receipt. It does not issue a receipt with a caveat. It refuses.
That refusal is the whole argument of this article, so it is worth stating in commercial terms. A deletion certificate is worth exactly as much as the check performed before it was signed. Most of them are signed because a delete statement returned without error. This one is signed because the system went looking for the person afterwards and could not find them at any point in time it knows how to ask about.
A smaller detail in the same function tells you what kind of engineering produced it. The obvious way to make three write steps safe is a transaction, but the executor here draws a pooled connection per statement, so a begin and commit issued through it would land on different connections and wrap nothing. Rather than write a transaction that only looks atomic, the code orders the statements so every partial failure is safe and converges on retry: resurrection guard first, then delete, then clear dangling pointers, then verify. If anything fails midway, writes for that subject are already blocked and a retry finishes the job.
The resurrection guard stores hashes only. The comment is one line: the table never holds a plaintext id. That is the difference between a deletion record and a shadow copy of the thing you just deleted. Anything that names the person in order to prove you stopped holding data about them has failed on its own terms. The receipt follows the same rule, digested with the same canonical hash the customer-facing certificate uses.
Not every storage engine can do this. An engine whose entire value proposition is an immutable ledger cannot destroy a fact, because destroying facts is the one thing it promises never to do.
So the contract has a clause for that case, and the clause is the strongest honesty mechanism in the codebase. An engine that cannot truly delete must throw a dedicated erasure-not-supported error from both methods, with a real stated reason. And the shared conformance suite has a mode for those engines that is explicitly not a skip: it asserts that both methods throw and that the reason is non-empty. Declining loudly is a recorded conformance outcome. Passing quietly is not available.
Two of the four adapters run in that mode. Both are prototypes used only for evaluation, and neither is ever constructed at runtime; the production factory returns the Postgres store and nothing else. But the point is not which engines decline. The point is that the codebase makes an engine's inability to delete a visible, tested, permanent fact rather than a footnote in a design document that nobody reads before signing a data processing agreement.
That is the pattern worth stealing whatever you are building. Compliance claims that live in a policy document drift silently. Compliance claims expressed as code either hold or fail a build. A PDF cannot refuse to be signed. A contract test can.
Three things this article does not say.
It does not say SAGARIS is certified, attested or compliant with anything. GDPR Article 17 is the obligation being engineered against, not a badge. There is no SOC 2 report and no ISO certification, and the trust page says so.
It does not say the memory layer is currently full. The claim store and the erasure route are shipped and ungated. The extraction that would populate the store from email, transcripts and enrichment is not generally available yet. Pretending otherwise would be the exact failure this article is against.
And it does not say this is finished. It says that when the request arrives, the system either produces a verified receipt or refuses to produce one, and that refusing is the feature.
The question to ask any vendor whose product has a memory: not "can you delete my data", which everyone answers yes to, but "what does your system check after the delete, and what happens when that check fails?"
Thirty minutes, your own data, no setup.
SAGARIS opens fully in October 2026. Join the waitlist and we will be in touch before launch.