Enforce a sovereignty floor
A step-by-step setup for a regulated workload — workspace Reach policy, a dedicated router, tests that prove refusal, and the request log as evidence.
The requirement usually reads: inference for this workload must not be subject to third-country disclosure, and you must show it per request. That is two jobs: stop the traffic, then prove it stopped.
The layers
| Layer | Where | Applies to |
|---|---|---|
| Workspace floor, region, ZDR, no training | Your workspace → Govern → Key policies → Reach | Every request, routed or pinned |
| Blocked provider countries | Your workspace → Connect → Routers (default router settings) | The workspace |
| Blocked Inference Providers | Your workspace → Govern → Key policies → Reach | Every request on every surface; a pinned or named request is refused with provider_blocked |
| Router floor, region, ZDR, no training, allowed models | Your workspace → Connect → Routers → a named router | Requests to that router |
X-Stav-Sovereignty-Level + request log | Response, Your workspace → Monitor → Request log | Every request |
Settings only tighten. A router can never loosen the workspace.
Step 1 — Pick the level
| Requirement | Floor |
|---|---|
| Inference on EU/EEA soil | L1 |
| Plus certified EU/EEA operation | L2 |
| No third-country control of the operator | L3 |
| Full sovereignty | L4 |
Most regulated work lands on L3. See Sovereignty. Check Your workspace → Connect → Inference Providers for what is available at that level before you commit to it in a contract.
Step 2 — Set the workspace boundary
In Your workspace → Govern → Key policies → Reach:
- Sovereignty floor: your level.
- Compute region: EU only, or EU + EEA, if inference must run there.
- Zero data retention only: on if the provider must keep nothing. This narrows the pool to endpoints with confirmed ZDR.
- No training on our data: leave on (the default).
- Blocked Inference Providers: add any company that must never serve you. Routed requests go around it; a pinned request is refused.
In Your workspace → Connect → Routers, default router settings, add any country you cannot accept to Blocked provider countries.
This applies to pinned models too. A pinned model with no endpoint at the floor gets 403 model_below_sovereignty_floor.
Step 3 — Give the workload its own router
Create a router in Your workspace → Connect → Routers:
- Floor, region, ZDR, no training: same or stricter than the workspace.
- Allowed models: the few you have qualified.
Call it by address:
resp = client.chat.completions.create(
model="@acme/regulated",
messages=[{"role": "user", "content": case_text}],
)
Changing the qualified models is now a change in Your workspace, not a release.
Step 4 — Test both directions
Positive — the level is what you expect:
raw = client.chat.completions.with_raw_response.create(
model="@acme/regulated",
messages=[{"role": "user", "content": "ping"}],
)
assert raw.headers.get("X-Stav-Sovereignty-Level") in ("L3", "L4")
Negative — the policy refuses. On a scratch router, set the floor to L4 with an allowed-models list nothing at L4 satisfies:
import openai
try:
client.chat.completions.create(
model="@acme/floor-test",
messages=[{"role": "user", "content": "ping"}],
)
raise AssertionError("expected the floor to refuse")
except openai.NotFoundError as e:
assert e.body["error"]["code"] == "no_eligible_models"
A blocked provider refuses the same way. Pin an endpoint on it:
try:
client.chat.completions.create(
model="mistral/mistral-large/azure", # an endpoint on a provider you blocked
messages=[{"role": "user", "content": "ping"}],
)
raise AssertionError("expected the provider block to refuse")
except openai.PermissionDeniedError as e:
assert e.body["error"]["code"] == "provider_blocked"
Keep the positive assertion in production code. Policy is read behind a short cache. If that read fails, Stav refuses the request with 503 policy_unavailable. The floor, region and ZDR requirements are never dropped to let a request through (the request fails closed). The header is the per-request proof. Treat a missing header, L0 or UNCLASSIFIED as a failure.
Step 5 — Produce the evidence
Each request log row in Your workspace → Monitor → Request log records the model, Inference Provider, sovereignty level, compute country and region, ZDR and training facts, tokens and cost. The facts are stamped when the request runs, so later catalogue edits do not rewrite history. Refusals are logged too, naming the rule, e.g. Blocked by workspace policy: sovereignty floor L3.
Use one API key per workload, so filtering by key filters by workload.
Limits
- Not a DPA. Region, ZDR and training are the provider's statements with a source on file. Keep your own DPA and sub-processor list.
- An unknown fact keeps an endpoint out. An endpoint whose facts are unsourced is not used, so fewer models may qualify. If a model is missing, check its endpoints on the model page.
- Levels are Stav's dated assessment, not a regulatory recognition.