fix(router): match routing-memory scores on canonical model identity - #547
Merged
Conversation
`rank` stored each score key in the spelling its policy used, and `knn._score` matched `qualities` keys against candidate selectors by exact string. That holds for one policy. It breaks as soon as a user has two learned policies that spell one model differently: normalization picks a single spelling, so the other policy's lookup misses, the candidate scores nothing, and the strong model wins unopposed at confidence 1.0 while `/status` reports the pool warm. The only signal is a log line. Store the canonical `instance:model` instead, and canonicalize the pool and each neighbor's stored keys in `_score`, so spelling cannot decide whether a candidate matches anywhere. Canonicalizing on read also picks up records written before this change, and aliases resolve through the same path. A record holding two spellings of one model (which `rank` refuses) keeps the first, so the collision resolves the same way on every request. Fixes #541
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (6)
WalkthroughRouting-memory validation and kNN scoring now canonicalize model selectors to ChangesRouting-memory canonicalization
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Description
rankstored each score key in the spelling its policy used, andknn._scorematchedqualitieskeys against candidate selectors by exact string. That holds for one policy, but a user with two learned policies that spell one model differently gets a single stored spelling, so the other policy's lookup misses: the candidate scores nothing, the strong model wins unopposed at confidence 1.0, and/statusreports the pool warm. The only signal is a log line.Store the canonical
instance:modelinstead, and canonicalize the pool and each neighbor's stored keys in_score, so spelling cannot decide whether a candidate matches anywhere. Canonicalizing on read also picks up records written before this change, so no migration is needed, and aliases resolve through the same path. A record holding two spellings of one model (whichrankrefuses) keeps the first, so the collision resolves the same way on every request.PR Type
Relevant issues
Fixes #541
Checklist
tests/unit,tests/integration).make lint,make typecheck,make test).uv run python scripts/generate_openapi.py).Tests: a unit test where a record keyed in the other spelling still scores its candidate, and an integration test where a second policy naming the same pool as
provider/modelroutes on examples taught through theinstance:modelpolicy. Both fail onmain. Full suite: 2617 passed, 10 skipped.AI Usage
AI Model/Tool used:
Claude Opus 5 via Claude Code.
Any additional AI details you'd like to share:
Implemented from the issue write-up via back-and-forth with @njbrake; the reasoning and decisions are his.
Summary
instance:modelidentities.Validation