decision
ADR-0002: Model routing single source of truth
ADR-0002 (Accepted, 2026-05-08): Model routing single source of truth.
Status: Accepted
Date: 2026-05-08
Deciders: Seth (Lead Architect), Blair (CEO sign-off pending)
Context
SPEC §8.4: “Free-tier server-side enforcement of model routing. Never
accidentally route a Free user to Sonnet.” Without a single source of
truth, model choices drift across call sites and the invariant becomes
discipline-dependent.
Decision
The TIERS dict in src/memberintel/entitlement/tiers.py is the only
place a tier-to-model mapping exists. Modifications go through PR review.
No client input, no admin override path, no env-flag bypass.
CI guard rules enforce two boundaries:
import anthropicis allowed only insrc/memberintel/llm/..model_idis read only insrc/memberintel/llm/.
A future SDK upgrade or routing change requires editing tiers.py plus
the corresponding test in tests/unit/test_tiers.py plus a re-run of
the tier-routing-safety eval. No other code path changes.
Consequences
Positive:
- Routing changes are visible in PR diffs.
- Eval coverage is direct and obvious.
- New operations (added in future slices) inherit the same enforcement.
Negative / costs:
- Adding a new operation requires touching three files (operations.py, tiers.py, the eval).
Mitigations:
- The three-file change is intentional friction; it’s the discipline the SPEC requires.
Alternatives considered
- Per-feature config files (e.g., chat config, site_analysis config) — rejected because invariants enforced across operations would split.
- Database-backed routing table — rejected for V1; introduces runtime config drift and DB migration on routing changes. Revisit in V2 if dynamic routing is needed.