Complexity Routing

What you'll accomplish: Configure the routing gateway's three cost/capability tiers, understand how PII policy and explicit provider intent interact with size-based classification, and read the Local/Cloud pool composition the dashboard uses.

There is no [routing] section with simple_model/medium_model/complex_model fields. The real mechanism is the routing gateway (crates/platform/hoziron-core/src/routing/gateway.rs + tier.rs), configured under [routing_gateway] (ADR-053/054).

The three tiers

A request classifies into exactly one of three tiers, purely by size — this classification never dispatches by itself, it only selects which of the gateway's three ranked preference lists resolves the request:

TierPurposeBoot requirement
localTrivial enough to need nothing beyond a Local model — hard-walled, Local-sovereignty-onlypreference required (non-empty) whenever the inventory has a non-empty Local pool
economyNeeds Cloud/general capability, but a cheap/fast model suffices — disabled by defaultNot boot-required; opt-in
standardThe catch-all: everything elsepreference required (non-empty) whenever the inventory has any provider at all
[routing_gateway.local]
max_chars   = 500     # default; size-based `local` classification
max_tools   = 0        # default: any tools present → too complex for size-based local
preference  = [{ provider = "ollama.west", model = "llama3.2" }]

[routing_gateway.economy]
max_chars  = 2000      # default 0 = disabled; a request never lands in `economy`
max_tools  = 2          # unless you widen these thresholds
preference = [{ provider = "ollama.west", model = "llama3.2" }, { provider = "big.licence", model = "claude-sonnet-4-5-20260929" }]

[routing_gateway.standard]
preference = [{ provider = "big.licence", model = "claude-sonnet-4-5-20260929" }]
  • local and economy may freely mix Local- and Cloud-sovereignty providers in their preference list except local, whose list is hard-walled to Local-sovereignty providers only (a Cloud entry there is a boot error) — because local's preference list is shared infrastructure consulted by every path that routes to Local (size classification, a PII-policy force, or an explicit ForceLocal intent), not just the size tier.
  • economy/standard may mix Local and Cloud (Pool::Mixed) — a request reaching either tier has already cleared PII policy as Cloud-eligible, so ranking a self-hosted model there is never a compliance regression.
  • Widening economy's thresholds without also setting its preference silently opts into declaration-order-over-the-combined-pool — set preference explicitly once you enable a tier.

Classification rules

// routing/tier.rs
  • A workflow type in always_standard_workflows, or the presence of attachments, always forces Standard regardless of size.
  • Otherwise: within local's thresholds → Local; else within economy's thresholds → Economy; else Standard.
  • Classification is pure size/shape — it has no notion of PII policy or explicit provider intent by itself. Two independent gates evaluate on top of it inside gateway.rs::route():
  • A local_only PII type detected in the payload forces local routing immediately — checked first, before size classification is even consulted for that decision. See PII Engine § LLM dimension. This is the single source of the force-local verdict — there is no separate provider-pattern rule engine layered on top.
  • An explicit RequestedProvider::ForceLocal intent (an agent hard-requiring the Local tier) also routes through the same hard-walled Local pool.
  • Both bypass size classification for routing purposes — the fact that a message happened to be short or long never overrides a local_only PII hit or an explicit force-local request.

Live availability (circuit breakers)

Ranked preference resolution filters out providers whose circuit is currently open (Issue #448) — the same CircuitBreakerRegistry the platform records dispatch success/failure into. Without this wired (rare — only in isolated test setups), every pool member is treated as available.

Gateway pools (dashboard / operator visibility)

curl http://localhost:4200/gateway/pools -H "Authorization: Bearer hzk_..."

Returns the Local/Cloud pool composition sourced from the same ADR-053 inventory the gateway itself dispatches against — each entry's declared driver disposition, resolved sovereignty reason (native-local / attested-local / defaulted-cloud / cloud), live auth status, live circuit-breaker reachability, and resolvable models:

{
  "local": [
    {
      "id": "ollama.west",
      "driver": "ollama",
      "disposition": "AlwaysLocal",
      "sovereignty_reason": "native-local",
      "auth_status": "NotRequired",
      "reachable": true,
      "models": ["llama3.2", "qwen2.5"]
    }
  ],
  "cloud": [
    {
      "id": "big.licence",
      "driver": "anthropic",
      "disposition": "AlwaysCloud",
      "sovereignty_reason": "cloud",
      "auth_status": "Configured",
      "reachable": true,
      "models": ["claude-sonnet-4-5-20260929"]
    }
  ]
}

GET /gateway/pools requires config:read — the same role bar (Admin/Operator/Developer/Viewer/Auditor) as reading the rest of the routing config.

Next steps


Related: