The Copies You Forgot About
The first two problems with deletion are about meaning and reversibility: what the button does, and whether you can take it back. The third is quieter and harder to fix, because it isn’t a decision anyone made. It’s a decision nobody made, repeatedly, over several years.
A record enters your system once and leaves through a dozen doors. It gets written to the primary store. It gets picked up by the change stream and written to a search index. A nightly job rolls it into an analytics warehouse. A report generated last quarter embedded a snapshot of it. Someone exported a CSV. A notification email quoted three of its fields and sits in an inbox you don’t control. Your backups hold it at every point in the retention window. A third-party processor got a copy because that’s what integrations do.
Then a user clicks delete, and the primary row goes away.
The Inventory Nobody Has
The uncomfortable question isn’t “did we delete it” but “do we know where it went.” Most teams cannot answer the second question, not because they’re careless, but because no single change ever created the problem. Each copy was a reasonable feature at the time. The search index made things findable. The warehouse made reporting possible. The export made a customer happy on a Tuesday. Nobody sat down and designed a fan-out of nine destinations; it accumulated one useful decision at a time.
What that means practically is that deletion completeness is a property of your architecture, not your delete endpoint. You can write the cleanest tombstone logic in the world and still be wrong, because correctness here depends on a list you don’t maintain.
The fix is boring and unglamorous: maintain the list. Every place a record can come to rest gets written down, with an owner and a deletion path. Not as a diagram someone drew once — as a document that a new integration is expected to update, the same way a new endpoint is expected to have a test.
Derivatives Are Different From Copies
There’s a distinction worth drawing. A copy is the same data somewhere else — the search index, the replica, the backup. Those you can chase down mechanically, because the identifier travels with them.
A derivative is data computed from the record, and it usually doesn’t carry the identifier at all. The monthly total that included this transaction. The trained model that saw this row. The cached aggregate that says a customer has 47 items. When the record goes, the derivative is silently wrong, and no cleanup job will find it, because there’s nothing to match on.
Most teams solve this the pragmatic way: derivatives get recomputed on a schedule, so they self-heal within a window. That’s fine, as long as you know the window and say so. It stops being fine when someone treats a derivative as authoritative — when the cached count becomes the number you bill on, or the report from last quarter becomes the record of what happened. At that point a deletion leaves behind a number that disagrees with reality and has more institutional standing than reality does.
Backups Are the Honest Exception
Backups deserve to be called out, because they’re the one copy you probably shouldn’t purge, and the one people are most surprised about.
You cannot go back and surgically remove a record from a month of point-in-time backups without undermining the thing backups are for. Almost nobody tries. The standard practice is to let backups age out, and to have a documented, enforced rule that a restore re-applies the deletion log — so a record that was deleted stays deleted even if a restore briefly brings it back.
That rule is the whole game, and it’s the one most often missing. If a disaster restore quietly resurrects a thousand records that users asked to have removed, you have shipped a violation with a very good excuse attached. Write the re-apply step into the restore runbook, and test it during the restore drill you’re already supposed to be running.
What Honesty Looks Like
The end of this thread is the same place the beginning was: say what you actually do.
If deletion means the record is gone from the live system and ages out of backups within thirty days, say that. If a search index lags by an hour, say that. If exports a customer downloaded are theirs now and outside your reach, say that too — it’s true, and it’s better said in a help article than discovered during an incident.
The failure mode isn’t having copies. Every real system has copies. The failure mode is having a delete button that implies a completeness your architecture was never built to deliver, and finding out which parts were untrue at the worst possible moment — when someone is asking you, in writing, to prove it.