Chapter 6 of 7 · 10 min read
Sending to a provider is irrevocable, so the send is the control
On this page
The erasure request arrives through the support queue and is escalated within an hour, because it names a specific customer, cites Article 17 — the GDPR's right to erasure, which entitles a person to have their personal data deleted and gives you a month to do it — and starts a thirty-day clock. Customer 88214 wants everything relating to them deleted. The engineer assigned to it does the sensible first thing and writes down every system a support transcript touches, intending to turn each row into a query.
The first eleven rows go well. Primary Postgres is a delete from tickets where customer_id = ..., executing in under a second. The read replica follows it. The nightly warehouse load needs a partition rewrite rather than a delete, which is two hours of Spark. The object store holding original attachments is a prefix delete. The error tracker has a per-event deletion API. The observability backend has no per-record deletion at all, only a ninety-day retention window and an index-level drop, so the answer there is "it expires on 12 September and we can prove that". Each of those rows resolves into an action with an owner and a duration.
The twelfth row is the model provider, and there is nothing to write in the query column. The transcript went out in a prompt eleven times over four months. There is no delete from to issue, no API to call that answers to your credentials over their storage, and no way to verify what was done. Whatever happens next happens because a contract says it should, on a timeline the contract sets, subject to whatever the contract excludes.
The two halves of a data map
The distinction the eleven rows share and the twelfth breaks is control. For a system you operate, deletion is a fact you can establish: you issue the statement, you check the row count, you re-query and get nothing back, and if you need evidence for an auditor you can produce it from your own logs. For a system operated by someone else and reached over an API, deletion is a request whose fulfilment you infer from their assurance. That is the same difference an engineer already knows between a DELETE against their own table and a DELETE /v1/records/88214 against a partner's service, except that here the partner also holds copies you did not know were made.
Writing the map with that distinction as an explicit column is what turns it from an inventory into a decision document.
| Stage | System | Recall mechanism | Latency to recall | Residual after recall |
|---|---|---|---|---|
| Ingest | Postgres tickets | SQL delete | < 1 s | PITR WAL retains 14 days |
| Ingest | Read replica | Replicated delete | < 5 s | None |
| Store | S3 attachments | Prefix delete | Minutes | Versioned objects until lifecycle expiry |
| Store | Nightly snapshots | None until expiry | 35 days | Full copy in every snapshot taken |
| Analytics | Warehouse partitions | Partition rewrite | ~2 h | Time-travel window, 7 days |
| Observability | Span backend | Retention expiry only | Up to 90 days | None after expiry |
| Errors | Error tracker | Per-event delete API | Minutes | Aggregated fingerprints, no raw text |
| Serving | Semantic cache | Key delete or flush | Seconds | None |
| Serving | Vector index | See next chapter | — | — |
| Egress | Model provider | Contractual request only | Their terms | Abuse-review copies, per carve-out |
| Egress | Provider, if training-eligible | None | — | Model weights |
Two entries in the residual column need reading carefully, because they are the ones that look like nothing. The PITR WAL on the Postgres row is the write-ahead log the database keeps for point-in-time recovery — a record of every change, retained so the cluster can be rewound to any moment in the last fourteen days, which means a deleted row remains reconstructible for a fortnight after the delete succeeds. The versioned objects on the S3 row are the same idea in a different system: a delete writes a marker and the previous version stays until a lifecycle rule removes it.
The bottom two rows are the ones a sign-off is actually about. Everything above them is work with a completion date. Everything at or below them is a statement about somebody else's systems that you are relaying on trust, and the honest formulation is that once a transcript reaches an external model provider, its retention is governed by that provider's terms, abuse-review copies and derived artefacts can outlive any deletion request you file, and the decision to send therefore has to be treated as irreversible at the moment it is made.
What the provider row actually says
Most major API providers now state that inputs and outputs to their standard API endpoints are not used to train their models by default, which removes the worst case for the last row of the table in the ordinary configuration. Retention is a separate question from training, and the common shape is a retention window of around 30 days for abuse and misuse monitoring, held so that automated systems and, on escalation, human reviewers can investigate policy violations. Several providers offer zero-data-retention arrangements for enterprise contracts, which drop the at-rest copy after the response is returned.
Three details in that paragraph decide whether it helps you.
Zero retention is usually not zero processing. The request is still decrypted, still passes through inference infrastructure, and is often still evaluated by classifiers in memory; what changes is that no durable copy is written. That is a real and large improvement and it is not the same claim as "the data never existed on their side".
The abuse-monitoring carve-out is typically excluded from deletion commitments, and it is the exclusion that matters most for an erasure request. A prompt flagged by a safety classifier and escalated to human review can be retained on a different timeline than ordinary traffic, sometimes considerably longer, because it has become evidence in an investigation. This is the part of the exposure you genuinely cannot undo, and the way you find out is to ask for it in writing rather than to read the marketing page: request the data processing addendum, the current sub-processor list, the per-category retention periods, and a direct answer to the question of whether the deletion mechanism covers abuse-monitoring and human-reviewed copies. Record the answers with the date and the person who gave them, because that record is the artefact your incident response will rely on in a year.
Training eligibility, where it exists, is categorically worse than retention. A transcript incorporated into training data does not sit in a row that can be deleted; it has been mixed into weight updates, and removing its influence after the fact is the subject of an active research literature on machine unlearning that currently offers approximations rather than guarantees, at retraining-scale cost. If a pipeline uses an endpoint or a tier where inputs are training-eligible — some consumer surfaces, some free tiers, some fine-tuning flows — that fact belongs at the top of the map rather than in a footnote.
Making the send the enforcement point
If the send is irrevocable then the strongest control has to sit immediately before it, and it has to be a control that can refuse. That is what the block action from chapter 2 exists for, and it generalises into an egress gate that consults the policy rather than the detector's confidence alone.
def may_send(doc: Document, dest: Destination) -> Decision:
findings = detector.scan(doc.text)
tiers = {POLICY[f.entity]["tier"] for f in findings}
if 1 in tiers and not dest.zero_retention:
return Decision.BLOCK("tier-1 entity present, destination retains")
if dest.training_eligible:
return Decision.BLOCK("destination may train on inputs")
if doc.tenant_region == "EU" and dest.region != "EU":
return Decision.BLOCK("no transfer mechanism for this tenant")
return Decision.SEND(redact(doc, POLICY))Blocking rather than redacting on a tier-1 hit looks excessive until you consider what a hit means about the document. A detector that found one national identity number in a transcript has told you the transcript is the kind of document in which such numbers appear, and its recall on the second occurrence is the same 0.71 it had on the first. Refusing the document and routing it to a human is a decision about the document's class, and it is available to you precisely because the detector's positive findings are more trustworthy than its negative ones.
The destination attributes in that function — zero_retention, training_eligible, region — are not things a client library reports. They come from the contract, and they change when the contract changes, which means they belong in configuration that is reviewed with the same seriousness as the policy file and dated the same way. A team that hard-codes zero_retention=True because it was true when the integration was written will not notice when the account is migrated to a different plan.
What refusing costs at 41,000 transcripts a day
A gate that can refuse is only a control if the refusals are survivable, and that is an arithmetic question with the traffic numbers in front of you. The support platform sends 41,200 transcripts a day through may_send, and the first fortnight of running it in shadow mode gave this breakdown.
| Tier | Entities | Share of documents | Action | Documents/day |
|---|---|---|---|---|
| 1 | national ID, payment card, health condition | 0.9% | block, route to human | 371 |
| 2 | email, phone, postal address | 34% | redact and send | 14,000 |
| 3 | personal name alone | 62% | send | 25,500 |
Three hundred and seventy-one documents a day arriving in a review queue is 4.1 hours of work at the median 40 seconds a reviewer took to judge one, and the tail is worse because the cases that need a second opinion took six minutes. One person can absorb that, and one person cannot absorb it after the traffic triples, which is the point at which somebody proposes an exemption list keyed on the sending team and the gate quietly stops applying to the busiest pipeline.
The move that made the queue sustainable was not a policy change. Sampling 200 blocked documents showed 108 of them were the same false positive: the platform's own ticket references have the form NL-8842-1993, which the national identity number pattern matched on every occurrence, so a system-generated string was blocking documents that contained no personal data at all. Anchoring that pattern to reject the platform's reference format took the block rate from 0.9% to 0.35%, or 144 documents a day, and left the policy exactly as written. The other lever with no policy cost is upstream: structured fields such as the account email and the billing address are already columns, so removing them from the prompt template and passing an opaque customer key instead means the detector never has to find them in prose. Both of those reduce the number of decisions the gate has to make. Loosening the tiers reduces the number of decisions it is allowed to make, and the two are easy to confuse in a meeting about queue depth.
What this framing gets wrong if you overextend it
Treating the send as irrevocable is a statement about recall, not a claim that the provider is a hostile party or that any send is a breach. A transfer under a data processing agreement to a processor — a party that handles personal data only on your instructions and for your purposes, which is what a model provider is in the ordinary API configuration — with contractual retention limits is a normal, lawful arrangement, and the irrevocability is a property it shares with every third-party processor you already use, including the payment gateway and the email service. What makes the model provider salient is the volume of free text going to it and the fact that free text carries entities you did not choose to send.
It also does not mean the downstream controls stop mattering. A zero-retention endpoint shortens the window in which a mistake is recoverable from months to seconds, which is not the same as making the send reversible and is worth a great deal. Nor does the irrevocability of the send excuse the internal rows of the map: an erasure request that leaves the transcript in a warehouse partition and a set of nightly snapshots has failed for reasons that have nothing to do with the provider, and those failures are the ones a regulator can most easily demonstrate.
One row of the map was deferred, and it is the row where a single transcript stops being a single object. A chunk of that transcript sits in a vector index, and its embedding, its stored text, its cached retrieval results, and whatever evaluation set someone sampled it into are all separate copies with separate lifecycles. The next chapter works out what removal has to cover once a document has been multiplied that way.
PII detection and redaction in AI pipelines — read the current version at https://daviddominguez.dev/learn/en/pii-detection-and-redaction-in-ai-pipelines/sending-to-a-provider-is-irrevocable-so-the-send-is-the-control