Repository navigation
Let a discovered candidate be adjusted without restating it - #270
Merged
Merged
Conversation
CatalogDiscovery's javadoc says it exists "so that using the router does not begin with writing out every model's price, latency and per-task quality by hand -- figures a caller has no way to know and would have to invent." It delivers that only if a caller can then change one thing about what it returned. ModelCandidate is a record of thirteen components with no derivation, so adding a single capability to a discovered candidate meant rebuilding it component by component and keeping that copy in step by hand. That costs more than declaring the model from scratch, which makes not discovering the rational choice -- and the invented figures then drift from the artifacts. The walkthrough in the deep-dive article declared qwen3-0.6b with a 32,768-token context window where its GGUF says 40,960, having never asked. toBuilder() returns a builder initialised from every component. addCapabilities(String...) adds names to the ones already set, which is the operation a discovered candidate needs: the catalog reports what the model is (chat) while an application routes on names only it defines (liveness, grounding), and replacing would mean restating the catalog's own answer to keep it. Capabilities carry over from toBuilder as an explicit choice. On a fresh builder tags() seeds capabilities; on a derived one that would silently discard what the application had just added, so the flag is set and a test pins it. Seven tests, each checked against a deliberately broken implementation. One fixture had to be changed: it held contextWindow at 8192, which is also the builder's default, so dropping that copy could not fail it. It now uses a real 131,072 and two tests catch the mutant.
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.
Why
CatalogDiscovery's javadoc states its purpose: it exists "so that using the router does not begin with writing out every model's price, latency and per-task quality by hand — figures a caller has no way to know and would have to invent." It delivers on that only if a caller can then change one thing about what it returned.ModelCandidateis a record of thirteen components with no derivation. Adding a single capability to a discovered candidate meant rebuilding it component by component and keeping that copy in step by hand — which costs more than declaring the model from scratch. So not discovering was the rational choice, and the invented figures drifted from the artifacts: the deep-dive walkthrough declared qwen3-0.6b with a 32,768-token context window where its GGUF says 40,960, having never asked.Probed against the released 0.1.60 catalog, discovery already returns for SmolLM2:
Of the seven builder calls that walkthrough wrote for that model, four were already there, one was half there, and only per-task
qualitygenuinely was not.What
ModelCandidate.toBuilder()— a builder initialised from every component.ModelCandidate.Builder.addCapabilities(String...)— adds rather than replaces, which is the operation a discovered candidate needs: the catalog reports what the model is (chat), an application routes on names only it defines (liveness,grounding).Both additive and non-breaking.
Capabilities carry over from
toBuilderas an explicit choice: on a fresh buildertags()seedscapabilities, and on a derived one that would silently discard what the application just added.Evidence
CandidateDerivationTest, each checked against a deliberately broken implementation.contextWindowat 8192, which is also the builder's default, so dropping that copy could not fail it. It now uses a real 131,072 and two tests catch the mutant.build complianceCheck verifyDependencyPolicy verifyReleaseMetadata: 2,721 tests, 0 failures, 0 errors.:docs:generateSiteis excluded — it fails in any git worktree, independent of this change.