Skip to content

Pillar 2 — Sovereign Model

The thesis. Build a sovereign model on the proprietary data of the Data Trust. The in-region inference switch on open weights is already built and tested behind the same provider seam: when it is enabled, the data and the query never leave the jurisdiction. The production default remains frontier quality until the evals reach parity; fine-tuning and distillation come later, when the corpus justifies them. Facts live in RAG with deterministic citations; the weights only learn behavior. We never bake facts into the model, because it would break the provenance moat.

It is the second pillar of the cycle: it consumes the trust's corpus (1 → 2) and feeds both governance (2 → 3) and Frontier Intelligence (2 → 4).

Note on the three-pillar frame

In grant materials the initiative is presented as three pillars: the Data Trust (1), the Sovereign Model (2) and the Governance Engine, which groups democratic governance (3) with the decision layer of pillar 4. The platform canon remains the four-pillar cycle; the canonical mapping lives in state/FOUR_PILLARS.md.

Sovereignty is a provider toggle, not a rewrite

The chat agent loop is written against the Anthropic Messages API (system + cache_control + tool_use). Provider resolution lives in a single place — server/chat/provider.ts — and selects by first match:

  1. SOVEREIGN_INFERENCE_URL + SOVEREIGN_INFERENCE_KEY set → routes to a self-hosted / in-region open-weights endpoint that speaks the Messages API. This is sovereign mode.
  2. OPENROUTER_API_KEY set → routes via OpenRouter (native Anthropic endpoint).
  3. ANTHROPIC_API_KEY set → calls api.anthropic.com directly.
  4. None → unconfigured (the chat emits the not_configured event).

That list picks the primary provider; since the chat robustness wave, providerChain() additionally builds an ordered failover chain: the primary first and every other configured provider behind it, as transparent backup. With a single key the behavior is identical; with two or more, a downed primary fails over mid-request without intervention — and the provider badge is re-announced if the switch happens mid-response. Model ids are re-resolved per provider (the namespaces differ: anthropic/claude-sonnet-4.6 on OpenRouter vs. claude-sonnet-4-6 direct), and the CHAT_MODEL / CHAT_FOLLOWUP_MODEL overrides apply only to the primary. The not_configured event is emitted when the chain is empty — not on the mere absence of one key: a sovereign key without its URL is diagnosed honestly.

Mid-request failover (server/chat/handler.ts) obeys four invariants:

InvariantWhy
Fires only on Anthropic.APIErrorA self-inflicted abort (tab closed, wall-clock budget exhausted) never triggers a provider switch.
Only if the round has emitted no visible text (roundText empty)Once tokens are on screen, a second provider re-streaming would duplicate the visible text. Narration from earlier rounds was already cleared on the client (reset_text).
Retries the same round (round -= 1)A failover does not consume tool-recovery budget.
Re-emits the provider eventThe badge always names the host that actually answered — and follow-up suggestions also run on the surviving provider, in its model namespace.

Per-provider model id re-resolution

Each ChatProvider in the chain carries its own native ids — reusing the OpenRouter slug against api.anthropic.com would 404, which is why failover re-resolves the model along with the client:

ProviderAnswer modelFollow-ups model
sovereignSOVEREIGN_INFERENCE_MODEL (default local-model)the same served model
openrouteranthropic/claude-sonnet-4.6anthropic/claude-haiku-4.5
anthropicclaude-sonnet-4-6claude-haiku-4-5

CHAT_MODEL / CHAT_FOLLOWUP_MODEL override only the primary entry of the chain: a cross-override would drag the wrong namespace onto a backup.

SDK client hardening (CLIENT_OPTS)

Every Anthropic client the seam constructs — sovereign, OpenRouter or direct — is created with { timeout: 20_000, maxRetries: 2 } instead of the SDK defaults (10-minute timeout):

  • timeout: 20s bounds only connection + time-to-first-byte, not token generation: the SDK disarms the timer as soon as the response headers arrive, before a single token flows. That is why this timeout can never abort a legitimate long streaming response — its only job is to make a dead or hung upstream surface fast as APIConnectionTimeoutError so providerChain() fails over, instead of the 10-minute default degenerating into an opaque Vercel FUNCTION_INVOCATION_TIMEOUT with the SSE stream silently truncated. The real bound on stream duration is the handler's wall-clock budget + the function's maxDuration.
  • maxRetries: 2 retries only transient failures: the SDK retries 408/409/429/5xx but not 400/401/402/403 — so an authentication or exhausted-credits failure on the primary fails over instantly, with no sleeping between retries, while a transient blip self-heals on the same provider.
  • The short post-answer calls (follow-ups with Haiku, non-streaming) additionally carry their own stricter bound at the call site (server/chat/followups.ts, Promise.race with a deadline), because for a non-streaming call the SDK timeout still covers only up to the headers and may not see a stalled body read — and those calls must never delay the terminal done event.

The sovereign branch is the pillar's sovereignty seam: it points the same Messages loop at an in-jurisdiction gateway (LiteLLM/vLLM behind a Messages shim, serving Llama, Qwen, DeepSeek or Mistral) so that the corpus and the query never leave the sovereign host. Only the baseURL changes — the agent loop, the tools and the grounding discipline are identical.

Why this matters

Data sovereignty is not achieved with a contractual promise of "we don't look at your data". It is achieved by making the data and the inference physically live inside the region's jurisdiction. Because the loop is identical across providers, switching to sovereign does not degrade the logic — it only changes where the compute happens.

The "sovereign mode" badge in the chat

The provider SSE event carries to the client the identity of the active chain entry (and is re-emitted if a failover switches providers mid-response); the interface shows a "sovereign mode" badge when sovereign: true. The user sees, on every answer, where the inference ran. The guarantee is visible, not a footnote.

The code deliberately separates two claims that are often conflated:

  • sovereign: true = the inference runs self-hosted, under the operator's control.
  • inRegion = the stronger geographic claim — "the data stays in the region" — and it is only asserted when SOVEREIGN_INFERENCE_REGION is declared. In-region residency is never inferred from the mere presence of an endpoint, because the seam could point at a host outside LATAM.

Environment variables of the sovereign seam

VariableWhat it controls
SOVEREIGN_INFERENCE_URL / _KEYEnable sovereign mode (Messages-compatible gateway).
SOVEREIGN_INFERENCE_MODELName of the served model (default local-model).
SOVEREIGN_INFERENCE_LABELBadge label (default Soberano).
SOVEREIGN_INFERENCE_REGIONDeclares the gateway's region; it is the only way to assert inRegion.
CHAT_MODEL / CHAT_FOLLOWUP_MODELModel overrides, bound to the primary provider.

The assistant uses two models: one for the grounded answer (default Sonnet) and a smaller one for the throwaway follow-up suggestions (default Haiku); a sovereign deployment reuses its single served model for both unless CHAT_FOLLOWUP_MODEL says otherwise.

The RAG-not-fine-tune rule: the provenance moat

The pillar's most important architecture decision: facts are never baked into the weights.

  • Facts live in RAG. Every figure the model cites comes from the corpus retrieved at query time, bound to a deterministic citation_id. The answer is grounded and verifiable against the primary source.
  • The weights only learn behavior. Fine-tuning, when it comes, teaches how to reason and answer — not what is true. A weight cannot cite its source; a retrieved passage can.

Baking facts into the weights would break the moat: a number generated from weights cannot be traced to a primary source, and two-click traceability is the whole platform's contract. That is why the default model (Sonnet on the direct/OpenRouter path) prioritizes grounding discipline — binding the correct citation_id to every figure and surfacing contradictions between sources — over raw fluency.

The phased path

PhaseWhat
NowIn-region inference switch built and tested (toggle + failover + tests); the production default remains frontier quality until the evals reach parity.
RoadmapIn-region inference on open weights as the production default, once the evals show parity.
RoadmapRegional adaptation pass: fine-tuning / distillation on the trust's corpus, gated: only when the evaluation harness (faithfulness / retrieval) proves the corpus justifies it.
RoadmapZK inference over encrypted records: answering queries without decrypting the underlying record, aligned with the ZK phase of the advanced provenance roadmap.

Fine-tuning is not a goal in itself. It is conditioned on the existing evaluation harness: until a fine-tuned open model matches the measured faithfulness and retrieval quality, frontier quality remains the default. We advance when the numbers allow it, not before.

The evaluation gates already exist as harnesses in the repository: scripts/chat-eval.ts (answer quality), scripts/chat-faithfulness.ts (attribution precision, CHAT_FAITH_MIN threshold, default 0.85) and scripts/eval-retrieval.ts (retrieval quality). The honest caveat: their results are not yet published as a public artifact; today they run as internal repository checks.

Why the moat is the corpus, not the base weights

Anyone can download Llama or Qwen. Base weights are a commodity. What is not a commodity is a verified-provenance, clean-license corpus spanning 25 countries — built by the Data Trust, impossible to scrape, and bound figure by figure to its source. The sovereign model is valuable not because its weights are secret, but because it is grounded in data no one else has and that it can cite deterministically.

This inverts the usual intuition about models: the defensible asset is not inside the model, it is in the corpus that grounds it and in the discipline that guarantees every answer traces back to it.

Verification

Everything above is verified against server/chat/provider.ts (provider selection, providerChain(), usingSovereign()) and the handler's failover tests (server/chat/handler-failover.test.ts). The grounding discipline and the evaluation harness are detailed on the assistant page and in methodology.

Related surfaces

  • The grounded assistant lives at /sala and across the platform.
  • The provider badge appears on every chat answer.
  • Sovereignty's physical leg: /soberania-computo — the Compute Sovereignty Index (ISC) ranks the 25 countries by their readiness to host sovereign compute, on 4 components with published weights (clean energy, connectivity, financing, scale) and the binding constraint per country; every input cited. Full treatment in Pillar 4.

Follow the cycle: this model's outputs serve democratic governance and Frontier Intelligence.

Every figure with its source — traceability is the contract.