Phase 4 operator platform

Per-org allow/deny model policies (Postgres + LRU+TTL cache + Redis pub/sub), OrgAwareRegistry gate in ProviderRoutingMiddleware, agent default_model fill, and management CRUD.

Milestone 4.C.2 — Per-Org Model Routing Configuration

Status: Completed
Goal: Track C — Multi-Provider Adapters & Resilience
Phase: 4 — Operator Platform & Multi-Provider
Estimated effort: 2 days
Track: Track C — Multi-Provider Adapters & Resilience


Why This Milestone Exists

Exit criteria requires model-based routing configuration per org — allowlists/denylists and default-model overrides (e.g. enterprise restricted to Anthropic for compliance). Platform registry remains the source of which models exist; org policy is a veto gate before Registry.For.


Non-Goals

  • Generic rules engine / DSL
  • Per-user model routing
  • Azure OpenAI or Bedrock adapters
  • Auth service changes
  • fallback_chain (4.C.4)
  • Strict provider allowlist (#790)

Shipped surface

LayerWhat landed
ADRADR-0075
SchemaMigration 000029_org_model_policies (RLS; no fallback_chain)
Domainpackages/modelpolicy — store, evaluate, LRU+TTL, publisher/subscriber, OrgAwareRegistry
ProxyChat parse allows empty model; ProviderRoutingMiddleware + bootstrap subscriber
Errors403 MODEL_NOT_ALLOWED; unknown after allow still 501 PROVIDER_NOT_CONFIGURED
APIOrg-scoped model-policies CRUD + model_policy_updates:{org_id} publish-on-write

Precedence

  1. Request model (trimmed) if non-empty
  2. Else agent default_model from proxy Postgres
  3. Else 400 model required
  4. Org policy first-match (priority ASC, filepath.Match); no match → allow
  5. Registry.For(candidate) → attach provider or 501

Channels

  • model_policy_updates:{org_id} / model_policy_updates:*
  • Payload: {"v":1,"org_id":"<uuid>"}

Success signals

  • Deny → ErrModelNotAllowedForOrg → 403 MODEL_NOT_ALLOWED (middleware unit + registry tests)
  • Cache hit avoids second loader call; TTL expiry + pub/sub invalidate ≤1s (miniredis)
  • TestRouting_OrgPolicy_* against real Postgres (//go:build integration)
  • Unit foreign-org path checks → 404 on all verbs (test_unit_model_policies_*_foreign_org_404; live API+RLS ISO is a follow-up)
  • Minimal middleware + constructor wiring (not “zero middleware changes”)

Prerequisites

  • M4.C.1 Anthropic adapter merged (two providers useful for routing demos)
  • M4.A.3 agents default_model column available for empty-model fill
Edit on GitHub

Last updated on