Repository navigation
feat(swe-router): route on a six-question rubric (0.2.0) - #33
Merged
Merged
Conversation
The vended skill was still 0.1.x: it asked the assistant's model to judge a quality floor and a complexity tier in prose, then took the cheapest model clearing that floor at that tier. Measuring that version against its own evidence showed the judgment, not the arithmetic, was the weak part -- three identical passes agreed on the floor for only 14 of 21 tasks. The two pages that document that run are the motivation for this change, so they stay, with a note saying they score the previous router. 0.2.0 replaces the prose judgment with six scored questions. Four set a difficulty bucket (easy, moderate, hard, very_hard) and two set the required quality, each 0-2 against written criteria in rubric.md. routing-policy.json holds the thresholds, so an organisation can retune what a bucket demands without touching route.py. The router then takes the cheapest permitted model whose benchmark score IN THAT BUCKET clears the bar, and skips a model that failed a benchmark task there rather than trusting its mean. - vend/swe-router/: route.py (both schema majors; --rubric needs 2), SKILL.md, README.md, allowed-models.txt, model-aliases.json, models.json (schema 2.0, with score_by_difficulty/completion_by_difficulty columns), and two new files -- rubric.md (the questions) and routing-policy.json (the thresholds). - install.sh: installs seven files instead of five, preserves BOTH policy files on upgrade (overwriting routing-policy.json would silently replace an organisation's quality bar), and refuses to install without python3 3.8+ rather than leaving a skill that fails the first time it fires. - benchmarks/scripts/: swe_router_rubric.py (new; the shared bucket/quality arithmetic, so the skill, the generator and the evaluator cannot drift), build_vended_models.py (builds the difficulty columns from a rubric pass), run-swe-router-headless.py (--mode rubric alongside the kept --mode floor), eval_swe_router.py. - Tests: test_swe_router_rubric.py (new) plus the route/generator/headless suites. 549 tests pass, 19 more than before. Three deviations from the upstream version of these files, all to avoid shipping something broken here: 1. models.json is committed as a vended artifact rather than regenerated. The generator reads docs/metrics/pareto-frontier-omp-swe3.json and the per-task run artifacts, neither of which is committed in this repository, so it cannot run here. Same as the 0.1.x file. 2. The skip guards this repo added in 56560da are re-applied to test_build_vended_models.py. Upstream commits the frontier data and so has no guards; without them, CommittedArtifactTest and the real-data tier test fail here for want of input. They still run wherever the data is present. 3. Five links to docs that do not exist here are dropped rather than left dangling (swe-router-how-it-works, swe-router-rubric-design and -evaluation, results-cli-cli-v1). Those pages carry un-abstracted model names and have not been ported. The prose that stood on its own is kept, and the one-off repo issue link became a bare ref, matching convention. Verified end to end: a rubric scoring all zeros buckets easy, floor 60, and recommends claude-haiku-5-5 at $0.14/task; all twos buckets very_hard, floor 80, and recommends claude-opus-5-5 at $4.44. Low confidence keeps the developer on their model instead of guessing. install.sh installs all seven files from a ref, a re-run keeps an edited allowed-models.txt and routing-policy.json, and the installed copy routes on its own and honours the local allow-list. ruff, ruff format, mypy and bandit (0 issues) clean. The one failing test, test_judge_common.test_lowercase_preferred_on_collision, fails on main too: it assumes a case-sensitive filesystem.
All three describe shipped behaviour inaccurately, and all three were introduced or missed by the two migration PRs, so they are cheaper to fix on this branch than as a follow-up against main. - README.md:121 still described the 0.1.x router -- a quality floor plus a tier table -- two paragraphs below the line 69 rewrite that describes the rubric. A reader got two incompatible accounts of the same skill. The row's link also pointed at .claude/skills/swe-router/SKILL.md, which is a symlink (mode 120000) and so does not resolve on github.com; it now points at vend/swe-router/SKILL.md, the real file. - docs/repository-structure.md:28 itemised the skill as the five-file 0.1.x layout. Added rubric.md and routing-policy.json, the two new files. - docs/strands-setup.md promised derived Claude pricing: "the table covers the Claude models from Haiku 4.5 to the Claude 5 family". It does not, and that is deliberate -- an Anthropic model reports its cost through the agent, so the table carries only the GPT models. Strands is not a pass-through agent though: it reports usage and no cost, so a Claude model under --agent strands records total_cost_usd null, which a live Bedrock run confirmed. The paragraph now says that and points at the token counts instead. Prose only; the price table is intentional and untouched. 549 tests, no new failures, no dangling links in the changed files.
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
The vended skill was still 0.1.x. It asked the assistant's model to judge a quality floor and a complexity tier in prose, then took the cheapest model clearing that floor at that tier.
Measuring that version against its own evidence showed the judgment, not the arithmetic, was the weak part:
docs/swe-router-evaluation.mdand-judged.mddocument that run, so they stay. This PR adds a note to each saying they score the previous router — the instability they document is what motivated the change.What 0.2.0 does
Six scored questions replace the prose judgment. Four set a difficulty bucket (
easy,moderate,hard,very_hard); two set the required quality. Each is 0–2 against written criteria in the newrubric.md, androuting-policy.jsonholds the thresholds, so an organisation can retune what a bucket demands without touchingroute.py.The router then takes the cheapest permitted model whose benchmark score in that bucket clears the bar — and skips a model that failed a benchmark task in that bucket rather than trusting its mean.
vend/swe-router/route.py(accepts both schema majors;--rubricrequires 2),SKILL.md,README.md,allowed-models.txt,model-aliases.json,models.json→ schema 2.0 withscore_by_difficulty/completion_by_difficultyrubric.md(the questions) androuting-policy.json(the thresholds)install.shpython33.8+benchmarks/scripts/swe_router_rubric.py(new — shared bucket/quality arithmetic),build_vended_models.py,run-swe-router-headless.py(--mode rubric, keeping--mode floorfor one release),eval_swe_router.pytest_swe_router_rubric.py(new) plus the route/generator/headless suitesswe_router_rubric.pyexists so the skill, the generator and the evaluator share one implementation of the bucket arithmetic and cannot drift apart.Three deviations from upstream's version of these files
Each avoids shipping something broken here:
models.jsonis committed as a vended artifact, not regenerated. The generator readsdocs/metrics/pareto-frontier-omp-swe3.jsonand the per-task run artifacts, neither committed in this repo, so it cannot run here. Same situation as the 0.1.x file.56560daare re-applied totest_build_vended_models.py. Upstream commits the frontier data and so has no guards; without themCommittedArtifactTestand the real-data tier test fail here for want of input. They still run wherever the data is present.swe-router-how-it-works.md,swe-router-rubric-design.md,-evaluation.md,results-cli-cli-v1.md. Those pages carry un-abstracted model names and haven't been ported. Prose that stood on its own is kept, and a repo issue link became a bareissue #221ref, matching the convention used in 28 places already.Verification
Routing behaviour, exercised directly:
easyclaude-haiku-5-5@ $0.14/taskvery_hardclaude-opus-5-5@ $4.44/task--confidence lowvery_hardA 32x cost spread across the range, which is the point of routing. Low confidence declining to answer is deliberate: the policy keeps the developer put rather than guessing.
Installer, against this branch:
Kept your existing routing-policy.json allowed-models.txtand both edits survive.main(whererubric.mddoesn't exist yet) it 404s, writes nothing, and says so — verified.allowed-models.txt.Checks: 549 tests pass (19 more than before),
ruff,ruff format,mypy,bandit(0 issues at every severity), no dangling relative links in any changed markdown.test_judge_common.test_lowercase_preferred_on_collisionfails — it fails onmaintoo, assuming a case-sensitive filesystem. Untouched here.Follow-ups
vend/swe-router/README.mdcarries the explanation inline.benchmarks/README.md's routing-evaluation section still documents the--mode floorworkflow end to end; this PR documents--mode rubricahead of it, but the older walk-through is now of historical interest only.