Chapter 5 of 6 · 10 min read
A region setting is a claim; the paths are the evidence
On this page
The auditor had been sent by a German insurer and had ninety minutes. The architect shared a screen, opened the provider console, and pointed at a field reading eu-central-1, then opened the storage account and showed the bucket location as Frankfurt, then produced the signed data processing agreement — the DPA, the contract that sets out what a supplier may do with personal data on the customer's behalf — with its annexe of standard contractual clauses, the pre-approved wording abbreviated SCCs that makes a transfer of EU personal data to a country outside the EU lawful. The auditor wrote nothing down and asked a different question: "How would you know if a prompt had been processed outside the EU last Tuesday?"
That question is the whole of the difference between configuration and evidence. A setting is an instruction to a system about how it should behave, made at some point in the past by someone who was thinking about that system. Evidence is an observation of what the system did, over an interval, produced by a mechanism that would have looked different if the answer had been different. The console screen showed an instruction. It could not have distinguished a month in which every request stayed in Frankfurt from a month in which 3% of them did not, and the auditor's job is to care about exactly that gap.
Everything that can carry the payload, and what would prove it
The inventory from the previous chapter answers "where does the content go". Residency asks a narrower and harder question of each destination: in which jurisdiction was the content, or anything derived from it, at rest or in processing. The list is longer than the set of things anyone configured, because several entries are managed by defaults inside vendor SDKs.
| Path | Failure mode | Evidence that settles it |
|---|---|---|
| DNS and edge routing | anycast terminates TLS outside the region | resolver logs + edge PoP in response headers |
| Model provider endpoint | a "global" endpoint routes by capacity | endpoint host in request logs; provider's regional endpoint contract |
| Cross-region inference | managed routing spills to a sibling region | provider inference-profile config + per-request region attribute |
| Response and trace storage | trace SaaS cluster is US-hosted | vendor's region attestation + destination IP geolocation |
| Telemetry export | OTLP collector default endpoint | egress log by destination, joined to IP geolocation |
| Error reporting | project created in the vendor's US org | vendor project settings + a deliberate test exception |
| Asynchronous jobs | nightly embedding job runs in us-east-1 | job scheduler region + the job's own egress log |
| Backups and DR replicas | cross-region replication for durability | bucket replication rules + inventory report |
| Support and admin access | an SRE in Denver opens an EU trace | access log with actor location, and an export policy |
| Failover | EU errors route to US | the routing rule as code, plus a count of activations |
Two pieces of vocabulary in the first row are worth expanding, because the row is the one people skip. Anycast is the routing arrangement in which a single IP address is announced from many locations at once so that the nearest point of presence — a PoP, one of the vendor's edge sites — answers, and the nearest PoP to a Frankfurt user is usually inside the EU without anything guaranteeing that it will be. Whichever PoP answers is where the TLS session terminates, which means the plaintext of the request existed there.
Two of those rows fail more often than the rest, and both fail for the same structural reason: they are configured by a library default in a file nobody associates with data residency. Telemetry export is one. An OTLP endpoint is a URL in an environment variable, set once during the initial instrumentation work by an engineer who was thinking about span propagation, and the vendor's default ingest host resolves to their primary cluster, which is usually American. Error reporting is the other: the project was created during onboarding by whoever needed a DSN that afternoon — the data source name, which is the client-side key telling the SDK which vendor project to report into — and the organisation region was a dropdown on the signup form.
Asynchronous work is the third and it is the one that produces the ugliest surprises, because the payload arrives there hours later and through a different code path. A nightly job that rebuilds embeddings, a weekly job that scores production samples against an evaluation rubric, a report generator that renders transcripts into PDFs — each of these reads customer content from a store and runs wherever the scheduler put it, and none of them go through the request-path routing that everyone reasoned about.
The provider endpoint row deserves a note of its own, because the defaults have moved in a direction that surprises people who set this up two years ago. Managed inference services now offer routing that spans regions on purpose: a cross-region inference profile spreads load across a geography to improve availability under bursty demand, and a "global" endpoint is explicitly a promise about capacity rather than about location. Both are the correct default for most workloads and the wrong default for a residency commitment, and both are selected by the model identifier you paste into a config file rather than by anything labelled as a region setting. Checking that row means reading the profile definition, not the console page that shows which region your account is in.
An SRE reading a trace is a transfer
The word "processing" in a residency clause covers more than inference. If your storage is in Frankfurt and an on-call engineer in Denver opens the trace viewer at three in the morning, the content has been transferred to the United States, on a laptop, by a person, and the fact that the bytes at rest never moved is not the test being applied. This is the row of the table that has no configuration to point at, and it is where a residency programme meets the ordinary structure of a follow-the-sun rota.
There are three workable answers and they are not equivalent. Restricting the reading population geographically is the cleanest and costs you your night coverage. Restricting what is readable — which is the first chapter's raw window with a region condition on it, so that structural fields are globally readable and text is not — keeps the rota intact and covers most on-call work. Recording the access with the actor's location and treating each one as a documented transfer under the relevant safeguards is the answer when the first two are impractical, and it requires that your trace store's access log actually captures who and from where, which many do not by default. Whichever you pick, the auditor will ask for the log, so the log has to exist before the question.
The failover is the question, so answer it first
Most EU-pinned architectures have a path that leaves the EU, and it is nearly always the fallback that fires when the primary provider returns errors. It exists because availability requirements were written by one group and residency requirements by another, and the routing code satisfies both on the days they do not conflict.
# router.yaml — the rule that makes the residency claim conditional
routes:
- name: primary
provider: anthropic
endpoint: https://api.anthropic.com # EU inference profile
region: eu-central-1
- name: fallback
provider: anthropic
endpoint: https://api.anthropic.com
region: us-east-1
trigger:
status_in: [500, 502, 503, 529]
after_attempts: 2
residency_class: out_of_geo # added after the audit
on_activate:
- emit_metric: residency.egress_out_of_geo
- annotate_span: {region_actual: us-east-1, residency_exception: true}The two dashed outcomes are the shape of the honest answer. The fallback moved a bounded, countable set of requests out of the region; the telemetry default moved every request's span attributes out of the region, continuously, for as long as it has been misconfigured. The one everybody discloses nervously is the smaller of the two.
Confronted with the fallback, the instinct is to avoid raising it and hope the auditor's list does not include it. That is a poor trade even on self-interested grounds, because an auditor who finds an undisclosed out-of-geo path after you have presented a residency claim will re-open everything you said, and because the disclosure itself is manageable when you bring numbers. At this company the honest version was: the fallback activated on 41 requests across nine months, all inside two provider incidents on 4 October and 19 January, totalling 6.2 seconds of out-of-geo processing; those requests were transmitted under the standard contractual clauses in the DPA annexe; the payloads were not persisted in the US region because the account is under zero retention; the trace records for them were written to the EU store with residency_exception: true and are queryable; and the affected customers were notified within the contractual window. That is a paragraph an auditor can accept or reject on its merits, and it is only writable if the metric and the span annotation existed before the incidents.
The alternative posture is to remove the exception rather than to document it, which is a product decision rather than an engineering one. The three options are worth setting against each other honestly, because the right answer differs by customer.
| Option | Availability effect | Residency claim | Where it fits |
|---|---|---|---|
| Fail closed: return 503 | outage during provider incidents | unconditional, provable | regulated customers with a written EU-only clause |
| Fail over in-geo (second EU region or second EU-hosted provider) | preserved, at the cost of a second integration | unconditional within the geography | the default worth building toward |
| Fail over out-of-geo with disclosure | preserved | conditional, requires SCCs and notification | acceptable only if the contract says so |
A per-tenant setting resolves the conflict rather than a global one. Tenants with an EU-only clause fail closed; everyone else fails over. The routing layer reads the class from the tenant record, and the tenant record becomes the thing an auditor can inspect for their own account rather than for your architecture in general.
Producing evidence continuously rather than at audit time
The mechanism that answers "how would you know" is a probe that runs on a schedule and produces a record with the same shape as the claim. Send a request from an EU vantage point carrying a unique token, then search for that token everywhere content could land — the trace store, the telemetry vendor's API, the error reporter, the object store, the warehouse — and record the region each hit was found in.
def residency_probe() -> dict:
token = f"RESIDENCY-{uuid.uuid4().hex}"
resp = assistant.turn(user_message=f"summarise: {token}", tenant="probe_eu")
hits = []
for store in (trace_store, otel_vendor, error_vendor, object_store, warehouse):
for hit in store.search(token, window="15m"):
hits.append({"store": store.name, "region": hit.region,
"path": hit.path})
out_of_geo = [h for h in hits if not h["region"].startswith("eu-")]
record = {"ts": now_iso(), "token": token,
"request_region": resp.headers.get("x-region"),
"hits": hits, "out_of_geo": out_of_geo}
evidence_log.append(record) # append-only, versioned bucket
if out_of_geo:
page_oncall("residency probe found content outside EU", record)
return recordThe set of things to hand an auditor follows from that record rather than from a document written for the occasion. Four artefacts do most of the work. A register listing every store and destination with its region, its owner and the date each was last verified, generated from the same allowlist the inventory uses rather than maintained by hand. The probe log, showing continuous observation over the period under review. The exception record, listing every activation of an out-of-geo path with timestamps, request counts and the customers affected. And the routing configuration in version control, where the commit history shows when each rule changed and who approved it. Those four are checkable against each other, which is the property that distinguishes evidence from assertion — an auditor can pick a date from the exception record and find the corresponding gap in the probe log.
Run hourly, that produces about 6,500 dated observations a year, each naming every store that held the content and the region it held it in. When the auditor asks about last Tuesday, the answer is a query. The probe is also the only mechanism on this list that catches a regression introduced by someone else — a vendor migrating a cluster, a Terraform module bumping a default, a new SDK version adding an exporter — because it observes outcomes rather than asserting on configuration you wrote.
Where region pinning stops helping
Keeping data inside a geography is not the same as keeping it outside a foreign government's reach. A US-headquartered provider operating an EU region remains subject to US legal process under the CLOUD Act, the 2018 statute that lets US authorities compel a provider within their jurisdiction to produce data it controls wherever in the world that data is stored. Residency, which is a question about where the bytes sit, and sovereignty, which is a question about whose law can reach them, are argued as separate requirements for that reason, and it is why some customers ask for an EU-controlled provider rather than an EU region. Telling a customer that data stays in Frankfurt is true and does not answer the question they may actually be asking.
Pinning also does nothing about volume. Every copy identified so far is still a copy, correctly located, and a correctly located copy is one you still have to find when the person it belongs to asks you to delete it. That request arrives with a legal clock on it, and the systems holding those copies do not all have a delete operation.
Data retention and privacy in logs — read the current version at https://daviddominguez.dev/learn/en/data-retention-and-privacy-in-logs/a-region-setting-is-a-claim-the-paths-are-the-evidence