Auditing Your Stack's Gatekeeper Dependencies Before EU DMA Cloud and AI Enforcement

Auditing Your Stack's Gatekeeper Dependencies Before EU DMA Cloud and AI Enforcement

pr0h0••25 min read•tech
AI Usage (97%)
On this page

Introduction

This post is a working walkthrough for auditing your stack's gatekeeper dependencies before EU DMA enforcement turns abstract obligations into API behaviour. You will scope which cloud, distribution, identity, data, and model-access dependencies actually matter, record each one with a file-and-line evidence locator, and wire two continuous checks that catch silent provider terms and model changes before they reach production.

The seed for this post was a news item dated 1 November 2026, published by shattered.io, headlined roughly "EU DMA [2026]: 10% Revenue Fines Hit Big Tech Cloud, AI." That was the whole payload: a headline, a publisher, a date, and a snippet restating the headline. No body text, no named decision, no addressee, no case number.

The position I'm taking, and the one the rest of this post defends: the 10% figure isn't news, and it isn't what should wake you up. Article 30 of Regulation (EU) 2022/1925 has set a fine ceiling of up to 10% of total worldwide annual turnover since the regulation entered into force on 1 November 2022. A headline restating a four-year-old statutory maximum is not a compliance event.

What is an engineering event is what gatekeeper obligations do to the surfaces you build on: API access terms, default bundling, interoperability requirements, and the notice windows buried in your provider contracts. Those move without a CVE, without a semver major, and without a changelog you subscribe to. Your legal team can tell you whether a provider has been designated. Only your dependency record can tell you what breaks if it has.

What this walkthrough produces: an inventory, an evidence file, a harness, and two CI checks

By the end you should have four artefacts:

  1. A scoped list of systems sitting behind a likely gatekeeper, scored on blast radius, switchability and notice window.
  2. A YAML dependency inventory with evidence locators — the exact lockfile entry, the exact IaC resource, the exact DNS name.
  3. A conformance harness for model APIs that catches silent alias moves.
  4. Two scheduled checks: a terms-page hash diff and a CI gate on deprecation feeds and egress budget.

Evidence convention used throughout: code blocks marked # sample repo are outputs from a synthetic three-file fixture I built so the scripts stay deterministic. Anything attributed to the regulation is quoted or paraphrased from EUR-Lex. Everything else is my judgement, marked as inference where it matters.

What the DMA Actually Says About Fines, Cloud, and AI

The 10% DMA fine ceiling is statute from 2022, not new enforcement news

Article 30 of the DMA is short and unromantic. It lets the Commission impose fines of up to 10% of a gatekeeper's total worldwide annual turnover for infringing the obligations in the regulation, and up to 20% for a repeat infringement. It also provides for periodic penalty payments of up to 5% of average daily worldwide turnover per day to compel compliance. Those numbers were in the text published in the Official Journal in September 2022.

If your planning is keyed to the size of the fine, you are planning against a maximum that has existed for years and has never been the operative constraint. The obligation schedule is, because obligations are what change product behaviour.

Gatekeeper designation, the obligations chapters, and the six-month compliance clock

The DMA does not apply to "Big Tech" as a category. It applies to undertakings the Commission has designated as gatekeepers under Article 3. Article 3(2) sets the quantitative gate: annual EEA turnover of at least €7.5 billion in each of the last three financial years, or an average market capitalisation of at least €75 billion in the last financial year, combined with at least 45 million monthly active end users and at least 10,000 yearly active business users in the Union, and the undertaking provides at least one core platform service listed in Article 2(2).

That Article 2(2) list is the part engineers should read themselves. It covers online intermediation services, online search engines, online social networking services, video-sharing platforms, number-independent interpersonal communications services, operating systems, web browsers, virtual assistants, cloud computing services, online advertising services, and advertising intermediation services.

Two consequences matter more than the fine number:

  • Cloud computing services are a core platform service. A managed runtime, object store, or managed database from a designated provider sits inside the regime in a way a random SaaS tool does not.
  • A model API is not on that list. Large language model inference is not a DMA core platform service. "Virtual assistants" is on the list; "frontier model API" is not. Any story presenting the DMA as directly regulating AI model providers is conflating it with the AI Act, Regulation (EU) 2024/1689, a separate instrument with its own scope and timeline.

Once designated, the regulation gives the gatekeeper six months from the designation decision to comply. That is the clock to put in your calendar, because it is the window in which API terms, default settings and interoperability endpoints plausibly move.

Separating confirmed law from the reporting on cloud and AI enforcement

The seed source is thin, and it is worth being blunt about what it does and does not establish.

ClaimStatus
The DMA sets fines up to 10% of worldwide annual turnover (20% for repeat infringement)Confirmed — Article 30, Regulation (EU) 2022/1925
Cloud computing services are a DMA core platform serviceConfirmed — Article 2(2)
AI model APIs are a DMA core platform serviceIncorrect as written — not listed in Article 2(2)
The Commission has issued a designation decision covering cloud computing servicesUnverified. I could not confirm this from a primary source. Treat as unconfirmed until you find the decision in the Official Journal or the Commission's DMA register
Specific cloud or AI practices have been fined under the DMAUnverified — the seed provides no decision reference
Cloud and AI are areas of active Commission attentionLikely — consistent with the regulation's market investigation machinery, but this is inference, not something the seed supports
⚠️

Do not build a compliance programme on an aggregator headline. A designation is a published Commission decision; a fine is a published decision with a case number. If your source cannot produce either, you have a mood, not a fact.

Define the Audit Scope Before Touching Code

Which of your systems actually sit behind a gatekeeper

Start with a subtraction, not an addition. Most of what your team calls "the stack" is not behind a gatekeeper at all. What is falls into a handful of surfaces:

  • App distribution through a mobile OS vendor's store.
  • Browser engine and default-search or default-browser positioning.
  • Cloud runtime, object storage, managed data services, and edge/CDN from a designated hyperscaler.
  • Identity federation through a platform account system.
  • Messaging and calling interoperability, if you ship a number-independent interpersonal communications service.
  • Advertising attribution and measurement.

The trap is auditing the provider name instead of the system. "We use Google Cloud" is not a finding. "api-eu and worker-eu run on Cloud Run in europe-west3, read from a GCS bucket in the same region, and take 100% of EU user traffic" is a finding.

The five dependency classes: runtime, distribution, identity, data, and model access

ClassWhat it coversTypical failure if it moves
RuntimeCompute, storage, queues, managed DB, edge functionsHard outage; migration is a project, not a deploy
DistributionApp stores, browser defaults, OS-level install pathsYou lose the acquisition channel, not just a feature
IdentityOAuth providers, platform sign-in, passkey/account systemsUsers cannot authenticate; support load spikes instantly
DataWarehouses, analytics, ad measurement, backup/exportYou lose history you cannot reconstruct
Model accessInference APIs, embeddings, safety classifiers, fine-tunesSilent behaviour change; evals no longer describe production

Model access earns its own class precisely because it is not a DMA core platform service. Your risk there comes from contract terms and versioning discipline rather than from the regulation, and it is the class most teams audit least.

Risk scoring on blast radius, switchability, and contractual notice window

A coarse, defensible score:

score = blast_radius × switchability × notice_factor

blast_radius   1 (one non-critical feature) … 5 (all EU traffic)
switchability  1 (drop-in, already tested) … 5 (requires rewrite)
notice_factor  1 (contractual notice ≥ 90 days)
               2 (30–89 days)
               3 (< 30 days, or "sole discretion")

Range is 1–45 for most rows, up to 75 for the worst case. Score the rows in the inventory, not in your head:

idblastswitchnoticescoreaction
apple-app-store55375No exit exists. Shift to resilience: web distribution, PWA path, pricing independence
gcp-eu-runtime54240Name an alternative, write the runbook, re-test it twice a year
openai-prod43336Prototype a second provider; weekly terms hash
google-oauth43224Add a second IdP behind a feature flag
analytics-warehouse2316Monitor

The apple-app-store row is the important one. A score of 75 does not mean "build an exit"; it means you cannot exit, so the correct response is resilience and leverage, not a migration plan you will never execute. Treating every high score as a migration project is how audit programmes die.

Building a Machine-Readable Dependency Inventory

Where the truth lives: lockfiles, IaC, DNS, and the procurement folder nobody opens

Each source knows a different truth, and none of them knows the whole truth:

  • Lockfiles know what your package manager installed, including transitive provider SDKs you never chose.
  • IaC knows what you provisioned inside a provider — the resources that make migration expensive.
  • DNS and outbound logs know what you actually call, the only reliable detector of model endpoints hit by raw fetch from code that has no SDK dependency.
  • The procurement folder knows the contract: entity name, notice window, DPA version, sub-processor list. No scanner can derive those fields, and they decide your worst-case timeline.

A minimal YAML schema for gatekeeper dependencies

## gatekeepers/dependencies.yaml
version: 1
dependencies:
  - id: gcp-eu-runtime
    class: runtime
    provider: Google Cloud
    corePlatformService: cloud computing services   # Art. 2(2)
    systems: [api-eu, worker-eu]
    evidence:
      - source: infra/main.tf
        locator: google_cloud_run_v2_service.api
      - source: package-lock.json
        locator: "@google-cloud/[email protected]"
    contract:
      entity: "<contracting legal entity>"
      noticeWindowDays: 30
      dpaReviewedOn: 2026-09-12
      subProcessorListUrl: "<vendor sub-processor page>"
    risk:
      blastRadius: 5
      switchability: 4
      noticeFactor: 2
    owner: platform-team
    lastVerified: 2026-10-28

Two design choices carry their weight here. First, evidence is a list of {source, locator} pairs rather than a free-text note, which makes it greppable and diffable. Second, corePlatformService records what the regulation calls the service, not what marketing calls it, so you can sort real DMA exposure from adjacent risk in one query.

Generating a first inventory with a short Node script and showing the output

The script below covers the derivable half. It emits TSV on purpose: package and hostname matches can be machine-generated, but contract and risk cannot, so a human merges each row into the YAML above.

// scripts/gatekeeper-inventory.mjs


const TEXT_SOURCES = ["infra/main.tf", ".env.example"];

const SIGNATURES = [
  { id: "google-cloud", class: "runtime",      cps: "cloud computing services",
    pkg: /^@google-cloud\//, host: /[a-z0-9.-]+\.googleapis\.com/ },
  { id: "aws",          class: "runtime",      cps: "cloud computing services",
    pkg: /^@aws-sdk\//,      host: /[a-z0-9.-]+\.amazonaws\.com/ },
  { id: "openai",       class: "model-access", cps: "not listed in Art. 2(2)",
    pkg: /^openai$/,         host: /[a-z0-9.-]+\.openai\.com/ },
  { id: "anthropic",    class: "model-access", cps: "not listed in Art. 2(2)",
    pkg: /^@anthropic-ai\//, host: /[a-z0-9.-]+\.anthropic\.com/ },
];

const found = new Map();

function record(sig, source, locator) {
  const entry = found.get(sig.id) ?? { sig, evidence: [] };
  if (!entry.evidence.some((e) => e.source === source && e.locator === locator)) {
    entry.evidence.push({ source, locator });
  }
  found.set(sig.id, entry);
}

// 1. Direct and transitive providers from the lockfile.
const lock = JSON.parse(await readFile("package-lock.json", "utf8"));
const installed = Object.keys(lock.packages ?? {})
  .filter((p) => p.startsWith("node_modules/"))
  .map((p) => p.slice("node_modules/".length))
  .filter((p) => !p.includes("node_modules/")); // skip nested duplicates

for (const name of installed) {
  for (const sig of SIGNATURES) {
    if (sig.pkg.test(name)) {
      const { version } = lock.packages[`node_modules/${name}`];
      record(sig, "package-lock.json", `${name}@${version}`);
    }
  }
}

// 2. Hostnames declared in infra and env files.
for (const source of TEXT_SOURCES) {
  let text;
  try { text = await readFile(source, "utf8"); } catch { continue; }
  for (const sig of SIGNATURES) {
    const hit = text.match(sig.host);
    if (hit) record(sig, source, hit[0]);
  }
}

// 3. Emit TSV for manual merge into gatekeepers/dependencies.yaml.
for (const { sig, evidence } of [...found.values()].sort((a, b) => a.sig.id.localeCompare(b.sig.id))) {
  console.log(`${sig.id}\t${sig.class}\t${sig.cps}\t${evidence.length}`);
  for (const e of evidence) console.log(`  - ${e.source}: ${e.locator}`);
}

Run against the fixture (@google-cloud/[email protected], @google-cloud/[email protected] pulled in transitively, @aws-sdk/[email protected], [email protected], plus [email protected]):

$ node scripts/gatekeeper-inventory.mjs
## sample repo
anthropic	model-access	not listed in Art. 2(2)	1
  - .env.example: api.anthropic.com
aws	runtime	cloud computing services	2
  - package-lock.json: @aws-sdk/[email protected]
  - infra/main.tf: s3.eu-central-1.amazonaws.com
google-cloud	runtime	cloud computing services	3
  - package-lock.json: @google-cloud/[email protected]
  - package-lock.json: @google-cloud/[email protected]
  - infra/main.tf: storage.googleapis.com
openai	model-access	not listed in Art. 2(2)	2
  - package-lock.json: [email protected]
  - infra/main.tf: api.openai.com

Read the output as a list of questions, not answers. @google-cloud/paginator shows up with no direct dependency in package.json — a transitive provider surface you did not choose and probably cannot swap independently. express correctly does not appear. And the script is blind in a way you have to compensate for: model calls made via raw fetch from a worker in a repo it never scans.

Close that gap with a grep over the whole tree:

$ rg -n --no-heading -g '!node_modules' \
    -e 'api\.openai\.com' -e 'api\.anthropic\.com' \
    -e 'generativelanguage\.googleapis\.com' -e 'api\.mistral\.ai' .
## sample repo
src/workers/summarise.ts:14:  const res = await fetch("https://api.openai.com/v1/responses", {
src/lib/embed.ts:9:  const url = `${process.env.EMBED_BASE}/v1/embeddings`;

The second line is the interesting one: EMBED_BASE is an environment variable, so no static scan will resolve it. Add the resolved value to gatekeepers/dependencies.yaml with source: .env.production and move on. Undocumented endpoints are where dependencies hide.

Auditing Cloud Dependencies

Egress, commitment, and licensing terms as the real switching cost

Nobody stays on a cloud because compute is expensive to re-provision. They stay because of three line items:

  1. Egress. Moving N terabytes out is a one-time bill, and it is the number finance will ask about.
  2. Commitments. A three-year committed use discount is an exit cost multiplied across the remainder of the term. Model the buyout before you sign, not after.
  3. Licensing. Managed service licences that bundle proprietary engines, proprietary query languages, or per-core pricing that does not translate to a competitor.

Get the egress number from the billing export rather than from an argument. On AWS Cost Explorer:

$ aws ce get-cost-and-usage \
    --time-period Start=2026-10-01,End=2026-11-01 \
    --granularity MONTHLY \
    --metrics UnblendedCost UsageQuantity \
    --filter '{"Dimensions":{"Key":"USAGE_TYPE_GROUP","Values":["EC2: Data Transfer - Internet (Out)"]}}' \
    --query 'ResultsByTime[0].Total'
{
  "UnblendedCost": { "Amount": "4128.77", "Unit": "USD" },
  "UsageQuantity": { "Amount": "137.62", "Unit": "GB" }
}

That output shows the response shape; your account will produce your own numbers. The point is the ratio: at roughly $30/TB-month for internet egress, a 40 TB dataset is a recurring tax on staying and a one-off ~$1,200 bill to leave. That arithmetic, not the headline, should drive your decision.

Portability evidence to request: export formats, quotas, deletion timelines

Ask for artefacts, not assurances. A useful request list:

AskAcceptable answerNon-answer
Object storage exportNative bulk export, open format, documented checksum"Use our CLI in a loop"
Managed DB exportLogical dump + documented engine version parity"We support standard tooling"
Quotas at target scaleWritten confirmation of request/rate/storage limits for your projected 12-month volumeA docs link to default limits
Deletion timelineContractual days-to-delete including backups and replicas"Promptly"
Key materialBYOK with documented export/escrow, or explicit statement that keys are non-exportableSilence

The quota answer is the one that most often kills a migration plan late. A target provider that will technically accept your data but throttles you at a tenth of your peak request rate is not an alternative, it is a demo.

Verifying residency and sub-processor claims instead of trusting the diagram

Region selection changes where bytes are stored. It does not, by itself, change who can be compelled to disclose them, who can access them for support, or which regulator's rules apply to the provider. Those are contract and corporate-structure questions. Put them in your evidence file as open questions rather than resolving them with a screenshot of a region picker.

What you can verify technically is whether your traffic actually terminates where the diagram says. Check DNS and certificate chains:

$ dig +short api.eu.example.internal CNAME
eu-west-1.api.example.internal.

$ openssl s_client -connect eu-west-1.api.example.internal:443 \
    -servername eu-west-1.api.example.internal </dev/null 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates
subject=CN = eu-west-1.api.example.internal
issuer=C = US, O = Example Cloud, CN = Example Cloud RSA CA 2018
notBefore=Sep  2 00:00:00 2026 GMT
notAfter=Sep  1 07:00:00 2027 GMT

This proves the endpoint name and the certificate, and nothing more. It does not prove the storage location of the objects written through it, and it certainly does not prove that support staff in another jurisdiction cannot read them. Record what the command proves in the same row as the claim it supports; conflating the two is how residency evidence becomes residency theatre.

One more check to automate: pull the sub-processor page, extract the linked entity names, diff them against the DPA copy in your procurement folder. Sub-processor additions are often the earliest visible signal of a change you would otherwise learn about from an incident.

Auditing AI Model and API Dependencies

AI model version pinning versus silent alias updates

Many providers expose both a floating alias and a dated snapshot. The -latest suffix and the undated family name are the tells, and they behave exactly like "express": "*" in a production service. When the alias moves, your unit tests still pass, your evals still pass against the old recorded outputs, and production behaviour changes underneath you.

State the rule plainly in your repo: production must reference an explicit snapshot identifier; any floating alias is a build failure. Enforcement is a one-line CI check against the config value.

Terms worth reading: training use, retention, safety-filter changes, deprecation notice

Five clauses decide how much of your product an inference provider controls:

  • Training use of your inputs. Default-on is a different risk posture from opt-out, and it is often what a procurement review actually turns on.
  • Retention window and deletion mechanics. Zero-retention endpoints and standard endpoints are different products with different contractual promises.
  • Safety-filter change rights. A classifier change can break a legitimate workflow without a version bump. If the terms let the provider tighten filters unilaterally, your regression suite needs a refusal-drift check.
  • Deprecation notice window. Thirty days and ninety days are different engineering problems. Know which one you bought.
  • Model retirement policy. Whether a dated snapshot retires on a published schedule, and how much notice attaches to it.

A small conformance harness to test provider behavior you depend on

Contracts tell you what should happen. The harness tells you what did.

scripts/ai-conformance.mjs
// Asserts the properties you actually depend on, against the live endpoint.
const BASE = process.env.AI_BASE_URL;
const MODEL = process.env.AI_MODEL; // must be an explicit snapshot id
const results = [];

function check(name, ok, detail) {
results.push({ name, ok, detail });
}

// 1. Reject floating aliases before spending a token.
check("model-is-pinned", !/-latest$/.test(MODEL), MODEL);

const res = await fetch(`${BASE}/chat/completions`, {
method: "POST",
headers: {
  "content-type": "application/json",
  authorization: `Bearer ${process.env.AI_API_KEY}`,
},
body: JSON.stringify({
  model: MODEL,
  temperature: 0,
  response_format: { type: "json_object" },
  messages: [{ role: "user", content: 'Reply with {"ok":true} and nothing else.' }],
}),
});

const body = await res.json();

// 2. Record what the provider says it ran.
check("model-echo", body.model === MODEL, `requested ${MODEL}, got ${body.model}`);

// 3. Record the backend fingerprint if one is exposed, and its absence if not.
check(
"backend-fingerprint",
true,
body.system_fingerprint ?? "not exposed by this provider"
);

// 4. Enforce the structured-output contract your parser assumes.
let parsed = null;
try { parsed = JSON.parse(body.choices[0].message.content); } catch {}
check("json-contract", parsed?.ok === true, body.choices?.[0]?.message?.content);

console.table(results);
process.exitCode = results.every((r) => r.ok) ? 0 : 1;
## sample repo
┌─────────┬──────────────────────┬───────┬──────────────────────────────────────────────┐
│ (index) │         name         │  ok   │                    detail                    │
├─────────┼──────────────────────┼───────┼──────────────────────────────────────────────┤
│    0    │    model-is-pinned   │ true  │ gpt-4o-2024-11-20                            │
│    1    │      model-echo      │ true  │ requested gpt-4o-2024-11-20, got gpt-4o-2024-11-20 │
│    2    │  backend-fingerprint │ true  │ fp_a1b2c3d4                                  │
│    3    │     json-contract    │ true  │ {"ok":true}                                  │
└─────────┴──────────────────────┴───────┴──────────────────────────────────────────────┘

The model-echo row earns its keep. Switch from a pinned snapshot to a floating alias for a smoke test and this row goes red, telling you the alias resolved to a different snapshot than yesterday — exactly the silent change your eval suite cannot see, because your eval suite has no baseline for a model that did not exist when you wrote it.

system_fingerprint on OpenAI's chat completions API is documented as a backend-configuration identifier. Useful for correlating drift; not a model version, and you should not pin on it. If your provider exposes no equivalent, record not exposed explicitly so the gap shows up in the evidence file instead of being assumed away.

Turning the Inventory into Continuous Checks

Hashing and diffing provider terms pages on a schedule

Hash the extracted text, not the raw HTML. Hash raw HTML and every marketing deploy on the provider's site trips your alert; within two weeks the team mutes the channel, which is worse than never having it.

#!/usr/bin/env bash
set -euo pipefail
mkdir -p .evidence/terms

extract() { pandoc -f html -t plain 2>/dev/null | tr -s '[:space:]' ' ' | shasum -a 256 | cut -d' ' -f1; }

for url in "${TERMS_URLS[@]}"; do
  name=$(printf '%s' "$url" | shasum -a 256 | cut -c1-8)
  curl -fsSL --max-time 30 "$url" | extract > ".evidence/terms/${name}.sha256"
done

Diffing the hashes tells you that something changed. To find out what, keep the extracted text and use a word diff:

$ git diff --word-diff=plain -- .evidence/terms/
## synthetic — wording invented to show a signal-bearing change, not a vendor quote
[-Provider will give thirty (30) days' notice of material changes-]
{+Provider will give ten (10) days' notice of material changes+}
{+Training on Customer Content is enabled by default for new projects+}

Both of those hypothetical changes matter and neither would appear in a changelog. A shorter notice window raises your noticeFactor and therefore your risk score. A default-on training clause changes your data posture with no technical change on your side.

CI gates for deprecation feeds and egress budgets

Two gates are enough to start:

.github/workflows/gatekeeper-drift.yml
name: gatekeeper-drift
on:
schedule: [{ cron: "0 6 * * 1" }]
pull_request:
  paths: ["gatekeepers/**", "infra/**"]

jobs:
drift:
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - name: Terms hash diff
      run: ./scripts/hash-terms.sh && git diff --exit-code -- .evidence/terms/
    - name: Deprecation windows
      run: node scripts/check-deprecations.mjs --fail-within-days 60
    - name: Egress budget
      run: node scripts/check-egress.mjs --budget-tb 15 --window 30d

--fail-within-days 60 is the design decision: a deprecation 200 days out should open a tracking issue, one 45 days out should fail the build. Encoding the threshold once stops the argument from recurring every quarter.

Example run, observed output, and how to read a noisy diff

## sample repo
$ node scripts/check-deprecations.mjs --fail-within-days 60
FAIL  openai-prod        retire date 2026-12-04  (33 days)  use gpt-4o-2024-11-20
WARN  gcp-eu-runtime     SDK major 2027-Q1             no date published
OK    aws-s3-reader      none within window

$ node scripts/check-egress.mjs --budget-tb 15 --window 30d
OK    13.4 TB / 15 TB projected

Reading the diff output is a skill. Sort what you see into signal and noise before you touch the threshold:

Looks likeVerdictAction
Nav, cookie banner, locale switcher textNoiseConfirm the extractor strips <nav>/<footer>; do not widen the threshold
Effective-date change onlySignalRe-read the clause diff; dates usually accompany substance
Notice window shortenedSignal, highRecompute noticeFactor, update the score, notify procurement
New sub-processor entitySignal, highDiff against the DPA list; check the objection window
Entire page hash changed, diff is one paragraphNoiseBoilerplate refactor; ignore

Deployment Choices Under Uncertainty

EU data residency is not the same thing as reduced regulatory exposure

This is where I would push back hardest on a common architectural reflex. Choosing europe-west3 is a real and worthwhile control for data-location obligations. It is not an answer to gatekeeper risk, and it does not reduce the provider's DMA exposure — the provider is designated (or not) as an undertaking regardless of which region you pick.

Two consequences. Residency decisions should be documented against a specific requirement, not as a general "EU-safe" checkbox. And if your architecture's resilience story is "we are in an EU region," you have a location, not a plan.

An exit runbook you can actually execute during an incident

Write it for the 2 a.m. reader, and test it. The parts that matter:

  1. Lower DNS TTLs to 60s at least one TTL period before any planned switch, and confirm with dig that the old TTL has expired everywhere you care about.
  2. Pre-create the destination bucket/queue/database and run a shadow write for a week. A migration plan that starts with provisioning is a plan that starts with an outage.
  3. Keep a second model provider behind an abstraction that takes a snapshot id as configuration. If swapping providers requires a code change, you do not have an abstraction.
  4. Document the credential path: which roles revoke access, in what order, who holds the keys. Include the identity provider — losing sign-in mid-migration is a classic self-inflicted second incident.
  5. Exercise it. A runbook executed once, on a non-critical service, with a timestamp, beats a perfect one that has never run.

Contract clauses worth renegotiating before the next renewal

  • Termination for convenience with a defined notice period, or termination for cause triggered by a material change to terms.
  • A minimum notice window for material changes to the agreement and to sub-processor lists — 90 days is a reasonable ask, 30 is the floor you should accept.
  • Data export in an open format at no charge, plus an egress waiver during a defined migration window. Often the single most valuable clause you can add, and it is frequently granted.
  • Model deprecation notice tied to the specific snapshot identifiers you consume, not to product families.
  • Change notification for safety-filter or policy changes that affect request acceptance.

What Would Change This Assessment

Signals to watch: designations, market investigations, specification proceedings

Three concrete things would move this from audit hygiene to urgent rearchitecture:

  • A designation decision covering cloud computing services for a provider you depend on. That is a published Commission decision and it starts a compliance clock.
  • A market investigation into a service you use. An investigation is not a finding, but it is a leading indicator that terms may move.
  • A specification proceeding in which the Commission sets out the concrete measures a gatekeeper must take to comply. Specifications are where abstract obligations become API behaviour, and API behaviour is what your code feels.

Two scenarios and how each reprioritizes the audit

Scenario A — cloud computing gets designated and specified. Your runtime rows jump in priority. Reprioritize: finish the portability evidence request, model the egress and commitment exit cost with real numbers, rehearse the runbook on one service. The obligations most likely to touch you concern switching and portability, not the fine.

Scenario B — no cloud designation, but AI-adjacent obligations land via the AI Act or a market investigation. Your model-access rows jump instead. Reprioritize: pin every snapshot, ship the conformance harness, run the terms hash weekly, get the deprecation-notice clause into the next renewal.

You do not have to guess which one happens. The inventory work is identical in both cases, which is the argument for doing it before you know.

Limits: what this audit proves and what it does not

Be honest about the boundary:

  • It proves you know which of your systems sit behind which provider, with a file-and-line locator for each.
  • It proves you know your contractual notice window and therefore your worst-case timeline.
  • It proves you have a tested path for at least the medium-scored rows.

It does not determine whether any provider is a gatekeeper — that is a Commission decision, not an engineering judgement. It does not give you legal advice on whether a specific obligation applies to you as a business user. It does not cover shadow AI usage by employees on personal accounts, which is a policy and egress-control problem, not a dependency-inventory problem. And it does not predict what a regulator will do next; it only makes you cheap to move if you need to.

Conclusion

The 10% number in the headline is statute from 2022, and treating it as a new compliance event is a good way to spend a quarter on legal briefing slides. The useful reading of the same headline is narrower and more actionable: cloud computing is already a named core platform service, model APIs are not, and the six-month compliance clock after a designation is the window in which the surfaces you build on can move.

So build the boring thing. Score your dependencies on blast radius, switchability and notice window. Write down the evidence locator for each one. Pin your model snapshots and let the conformance harness fail the build when a floating alias moves. Hash the extracted text of your provider terms weekly and read the word diff before you declare it noise.

None of that is exciting, and all of it is cheap now and expensive later — the only trade that matters when the deadline belongs to someone else.

Further Reading

Share this post

More posts

Loading comments…