Repository navigation
gpu-gates: refuse stale recorded fixture budgets before planning - #606
Conversation
There was a problem hiding this comment.
Verdict: CLEAN: No merge-blocking behavior or quality defect survived review.
Non-blocking
⚠ Exercise regeneration advice through admission: crates/gpu-gates/src/tier.rs:1711 calls the formatter directly. Replacing its production call at tier.rs:973 with generic path-and-error formatting removes the regeneration advice without failing these assertions. Add an otherwise valid stale fixture case through header_budget and assert the returned advice. This catches a message-routing regression before gate users encounter it.
Checked
Duplicates: 8 new or moved definitions and the new error variant checked; no duplicate owner. The CLI table moved to the registry. Dryer reported 0 pairs; gpu-gates was checked manually.
Complexity: crapper flagged no changed function. The added branches select shared fixture policies during setup.
Silent failure: 5 branches/defaults followed. Missing budgets reach fixture-tier refusal; invalid values and planner failures return errors. Fixed-budget and variant exemptions are explicit. The test planner's None means an uncapped plan.
Tests: static mutation audit covered the admission call, positive-budget filter, variant guard, checked sum, registry comparison, mismatch comparison/type, regeneration branch, and reader calls. Their corresponding assertions reject removal, inversion, or wrapping mutants; the formatter-call mutant above survives. Changed fixture-budget tests require the typed mismatch. Tests were not executed.
Gates: no tolerance, threshold, budget pin, or gate clause moved or disappeared. The removed architecture-check exception belonged to the removed CLI imports.
Escape catalog: no C1–C4 pattern matched the changed code. No decode, prefill, kernel, or host-expert hot path changed.
Notes
GPU evidence is incomplete: the RTX 5090 gate runs refer to an earlier revision without its exact head hash. Supply both tested commit hashes with the commands and output to complete the evidence record.
Card check: needs-gpu. This pull request changes crates/gpu-gates/src/tier.rs and carries no gate run on a card (CONTRIBUTING's evidence list); a maintainer adds gpu-verified after one.
🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)
|
The review is done and the contribution check passed, so I'm merging this. |
GPU 게이트가 낡은 fixture의 기록된 budget을 받으면, 한참 뒤에 엉뚱한 expert 수 오류로 실패하던 것을 시작 단계에서 "budget이 낡았으니 fixture를 다시 만들라"는 이름 있는 오류로 거절하게 바꾸는 작업입니다.
Refs #594. 938167b fixed the stale
qwen38budget itself. This PR makes the next stale budget name its cause when a gate starts, instead of failing a later clause.What and why
A fixture file records the card budget its planner used when the file was written. When the planner later changes how many bytes a tensor takes on the card, the recorded budget no longer fits, and a gate that plans under it gets a different expert count than the file was built for.
gate-gpu-qwen4exp-mtphit this on aqwen38fixture. Its recorded budget planned 257 experts on two layers where the fixture expects 256, and the gate reported that as a failure in clause (d), far from the cause.gate-fixture-budgetandfixture verifyalready catch a stale budget throughfixture::check_budget, but a gate that plans under the header never called it. This PR makestier::header_budget, the function every gate reads the header budget through, call that checker for a fixture file. When the plan under the recorded budget gives a different expert count, the gate stops before planning with aBudgetMismatcherror. The message has the first shard path, the recorded budget, the planned and expected expert counts and the regeneration section ofdocs/contrib/local-check.md. Only that expert count mismatch is called stale. A zero budget, missing metadata or a planner refusal gets its own message with the path and no regeneration advice. A variant fixture (one that records a variant key) keeps the budget of its base and is only checked to be a positive number, so it is not planned again. A file without a fixture version keeps its old behavior.The family spec table moves from the
fixtureCLI intoFIXTURE_SPECSincrates/model/src/arch/registry.rs, andregistry::fixture_specis the one lookup both the CLI and the gates use. I also changed the draft reservation sum inbudget_leverstochecked_add, because an oversized budget overflowed it instead of failing with a name.docs/contrib/local-check.mdnow says that a budget can drift to too many experts as well as too few, and that the variants of a replaced base fixture are made again withjust fixture-requant FAMILY TAG.docs/contrib/new-model.md, theFixtureRowdocumentation,tools/refset-publish/sources.tsvandtools/refset-publish/README.tmplpoint at the new table, and thetools/check-arch.shentry for the old table is gone.The stale budget itself comes from the Qwen3.8 BF16 dense-weight accounting, which changed how many bytes the indexer projections take on the card. That planner change is correct, and 938167b moved the
qwen38fixture's recorded budget to match it. This PR adds no regeneration and moves no budget value. A fixture file whose recorded budget no longer matches the planner is refused by name at start.Release notes: Fixed: GPU gates refuse a fixture whose recorded card budget is stale at start-up, naming the file and the regeneration steps, instead of failing later on an expert count.
Code shape
fixture::check_budgetthroughheader_budget, the same checker thatfixture verifyandgate-fixture-budgetuse. No per-model check was added.tier.rsgained no per-model branch.header + extrasum can no longer overflow silently.cargo fmt --all -- --checkpasses on this head.Duplication found or removed (
path:line): the table of the seven family specs lived in the fixture CLI, where the gates could not read it. It now lives once incrates/model/src/arch/registry.rs, and the CLI reads it from there.Where gates read the header budget
header_budgetis the single reader, so a check there covers every caller. The direct callers areplan_levers(shared by the DeepSeek, Qwen and GLM gates), the Qwen4Exp MTP init, the GLM sharedinit_fileand the DeepSeek two-card run. The shell helperfixture_budgetintools/ref/ref-paths.shonly carries the value, so I left it alone.What I ran
The head of this PR is one commit on upstream
938167b2, and the before runs used upstream74240f50. The Qwen3.8 and V4.1 budget tests below ran on this head. The CPU tests ran on the same commit on upstream2d4c8131, with the commit unchanged (git range-diffreports=); the upstream commits in between change the Qwen3.8 card pins, two Qwen4Exp metadata tests andtools/model-tax.tsv, none of which these tests cover. The GPU gate runs and the 11 mutants ran on an earlier revision of this branch with the same gate calls and checker. Since then the change gained a separate error formatter,fixture_budget_error, with the regeneration test that covers it, a doc comment, one test message, the registry and documentation edits, and thetools/gate-paths.tsvrow for the Qwen3.6 fixture spec, which now derives its gates.Before the fix, the new admission test was written on the unfixed code and the overflow test with it. Both fail there. The admission test fails because the old reader never reaches the checker, and the overflow test fails with
attempt to add with overflow.On that commit, the 24
tiertests, the budget test in the model crate and the spec test pass,cargo fmt --all -- --checkpasses, and the registry tests pass.Eleven mutants replace each of the four callers'
header_budgetcall withNone, or break a lookup, the variant rule, the metadata case, the count comparison, the typed mismatch or the registry lookup. All 11 fail a test. A twelfth mutant removes the regeneration hint branch, and the newa_budget_mismatch_names_the_file_and_regeneration_steptest fails. These tests check that the calls are wired in and that the messages are right. They do not replace a full GPU run of the other models.GPU evidence
The GPU gate runs below ran on the earlier revision named in What I ran, on an RTX 5090 host with a
qwen38fixture. A diagnostic copy of the fixture, with its recorded budget set to the stale value from the report in #594, reproduced the failure on base. The same copy is refused at start-up on the head, with the same budget and the same counts.Stale fixture on base,
just gate-fixture-budget: the check reportsqwen38with budget 9490661376 planning[257, 257, 256, 256]experts a layer, not[256, 256, 256, 256].Stale fixture on the head,
just gate-gpu-qwen4exp-mtpwithBLOOMERY_TIER=fixture: the gate stops at once with exit 1 and the messagestale recorded fixture budget 9490661376, thenregenerate the fixture using docs/contrib/local-check.md.I regenerated
qwen38from its source headers withfixture fetch qwen38and checked it withjust gate-fixture-budget:On the regenerated fixture the budget is 9482272768 and the plan is
[256, 256, 256, 256].With the regenerated fixture and the matching MTP reference set (
<refset dir>is the directory that holds it):The gate ends with
clauses: 25 ran, 4 left to the real tierand exit 0.Clause (d) is among the 25:
draft resident 2779869184 (want 2779869184matches.The
q6kdownvariant fixture goes through the changed reader too.BLOOMERY_FIXTURE_VARIANT=q6kdown just gate-gpu-glm5next-nvtierends withclauses: 6 ran, 0 left to the real tierandevery clause passed.Two budget tests pass on this head on the RTX 5090 host, each
1 passed; 0 failed:hw_fixture_q38_budgetandhw_fixture_v41_budget. Each reads the header of its source model, builds a fixture header from it and runs the family planner over that header. They do not read an installed fixture and they are not CUDA kernel gates.hw_budget tests of the GLM-5.3, Qwen3.6 and Solar families were not run.What I ran into
This does not block the PR. A fixture written before a planner change to its card bytes fails the fixture-tier gates until it is written again; with this change the gate names the file and the regeneration step at start instead of failing a later clause.
Hardware
One Linux CPU host for the unit tests and mutants. One RTX 5090 host (driver 595.99.02, CUDA 13.2) for the fixture runs and the GPU gates.
AI help
AI 코딩 에이전트가 코드를 작성한 후 설명을 썼고, 테스트를 마쳤습니다. diff 리뷰와 PR 초안 리뷰는 제가 직접 했습니다.