feat(routing): canonicalize model names before [[models]] lookup#307
Merged
Destynova2 merged 1 commit intofix/preset-mod-include-strfrom Apr 28, 2026
Merged
Conversation
Users frequently send small variations of provider model IDs (date
suffixes like `claude-3-5-sonnet-20241022`, `-latest` aliases, dotted
versions like `gemini-2.5-flash`, mixed casing, or the older Anthropic
`claude-{N}-{M}-{family}` ordering). Without canonicalization those all
miss the configured `[[models]]` entry and fall through to the
auto-mapper's catch-all default — bypassing the user's intended
fallback chain.
Add `routing::classify::model_name::canonicalize_model_name` and call
it as step 0 of `Router::route`, before any background / auto-map /
prompt-rule / lookup logic. The function is idempotent and returns
`Cow::Borrowed` for already-canonical inputs (steady state in
production), so configs that use the canonical IDs (`claude-sonnet-4-5`,
`gpt-4o`, `gemini-3-pro`, …) pay zero allocations.
Coverage: 25-row matrix across Anthropic 3.x/4.x, OpenAI (gpt-4o /
gpt-5 / gpt-5.2), DeepSeek, Gemini, and Grok families plus a proptest
that exhaustively checks idempotence over arbitrary alphanumeric
strings. All 130 existing routing tests still pass.
4 tasks
Destynova2
pushed a commit
that referenced
this pull request
Apr 28, 2026
ADR hygiene pass identified two zombie statuses where designs were marked `done` but production code does not match the design yet. Reverts both to `accepted` with inline status notes recording the correction: - ADR-0013 — storage refactor on atomic files + JSONL: redb persistence (`GrobStore` in `src/storage/mod.rs`) is still the live code path; `~/.grob/spend/*.jsonl` has not yet been written. A-7 deferred. - ADR-0015 — indirect prompt injection coverage: A-6 implementation deferred; framework design final but no production code merges yet. Adds four new ADRs as `status: proposed`, formalising decisions that have been operating informally: - ADR-0023 — Preset Naming and Composition Strategy. Adds the `[meta] tier` taxonomy (base/audience-specific/experimental), kebab-case naming convention, the rule that presets do not nest, and the `grob preset info` shippability gate. Compliance overlays are a separate `kind = "overlay"` concept. - ADR-0024 — Preset-as-Compliance-Template. Treats compliance presets as packaged decisions bundling topology + policies + ADR-0022 `[endpoints.compliance]` metadata + `[meta] compliance_reviewed` attestation. Customer overlays may tighten but never loosen; documents the certification-renewal lifecycle. - ADR-0025 — RPC Mutation Transactionality and In-Flight Visibility. Resolves issue #228: in-flight requests see pre-mutation snapshots, persistence is atomic with the in-memory swap (rollback on disk-write failure), per-namespace mutex permits parallel writes, every mutation emits an `AuditEvent::RpcMutation` with before/after hashes. - ADR-0026 — Model Name Canonicalization Policy. Records the fixed rule set landed in PR #307 (lowercase, strip `-latest`, strip 8-digit date suffix, dot-to-dash version on a known-prefix gate, Anthropic family-version reorder), the idempotence guarantee, the operator escape hatches (per-endpoint `actual_model` mapping or table patch), and the 2-minor-release deprecation window for renamed models. CHANGELOG `[Unreleased]` records the additions under a `Documentation` heading. No code changes — doc only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
routing::classify::model_name::canonicalize_model_nameand call it as step 0 ofRouter::route, so cosmetic variations of provider model IDs collapse to a single canonical key before any subsequent step (background regex, auto-map, prompt rules,[[models]]lookup).Cow::Borrowed), so configs that use the canonical IDs (gpt-4o,claude-sonnet-4-5, …) pay nothing.default_non_clauderow now carries the canonicalizedgpt-5-2instead ofgpt-5.2.Rules (in order)
-latest.-YYYYMMDD(exactly 8 digits — guardsgpt-5-2).<digit>.<digit>to<digit>-<digit>, gated on a known family prefix (claude-,gpt-,gemini-,grok-,deepseek-) so unrelated IDs likeglm-4.6survive untouched.claude-{N}-{M}-{family}→claude-{family}-{N}-{M}so olderclaude-3-5-sonnetand modernclaude-sonnet-4-5spellings collapse into one key (matching the spelling used inpresets/*.toml).Why this base branch
Based on
fix/preset-mod-include-str(PR #304) becausemaindoes not currently build (referencedpresets/{medium,local,cheap,fast}.tomlfiles were deleted butinclude_str!calls remain). Will rebase tomainautomatically once #304 lands.Test plan
model_name.rsexercises Anthropic 3.x/4.x, OpenAI (gpt-4o,gpt-5,gpt-5-2,gpt-5.2), DeepSeek, Gemini, Grok families.0.0.0checked in).test_auto_map_skips_explicit_virtual_modelandtest_no_auto_map_non_matching—glm-4.6is unaffected by rule 4 thanks to the family-prefix gate).cargo fmt --check,cargo clippy --all-targets -- -D warnings, andcargo nextest runall green locally.