Repository navigation
gpu: size mixed expert scratch from selected resident forms - #783
Conversation
Preserve selected-program stack admission and resident-form scratch accounting alongside current tier, reserve-only card, footprint and seat owners. Load mixed-wrapper fixtures by selected part formats and retain gate/up mismatch refusal without rejecting admitted Solar Q6_K downs.
There was a problem hiding this comment.
Verdict: MUST_FIX: no behavior bug found, but the diff adds two copies of one fact, one redundant parameter, a second owner of the down forms, and drops a test pin without a dated reason.
Must fix
1. STACK_ROLES is defined twice
card_experts.rs:61 and leg_tier.rs:57 hold the same pair of refusal texts, differing by one word ("card" and "tier"). Two copies in one diff are a finding. Fix: one pub(crate) const STACK_ROLES beside GATE_UP in card_leg.rs, imported by both files; delete the two local constants.
2. Fill::run re-implements Card::selected_scratch
placement.rs:3112 builds down_acts, the scratch closure and bound by hand. placement.rs:282 already folds the same "forms of the down tensors of layers with counts > 0" into leg.bytes(forms) and returns (bound, selected). One rule in two places will drift. This is also why Fill::run rose from complexity 9 to 18. Fix: delete down_acts, scratch and bound, and use
let scratch = |counts: &[u64]| Ok::<_, PlacementError>(card.selected_scratch(self.model, counts)?.map_or(0, |(_, s)| s));
let bound = card.selected_scratch(self.model, &[])?.map_or(0, |(b, _)| b);(counts.get(l) already treats a missing layer as 0). Planning runs at load, so the extra tensor scan costs nothing at decode.
3. LegStack::of keeps a planes parameter that is now redundant
card_leg.rs:524. Three callers now pass arms.x as both runs and planes. The fourth, Relu2Stacks::of, passes |_| false, and card_sel32_runs(NVFP4) is already false. Fix: drop the parameter and test runs(GgmlType::NVFP4) in the Nvfp4Stack arm. Then update the four call sites.
4. MiniMax keeps its own down-forms owner, and a panic wrapper has one user
minimaxm3/place.rs:152 leg_downs does the same job as the new accepts::leg_down_forms, which GLM and Solar use in this diff. It differs: it ignores the gate·up arm, g == u and the pair rule, and it falls back to Q8Act. A Blocks32 down under an unadmitted gate type therefore widens the bound. Also, tier_batch (line 138) is the only caller of the panicking workstation::tier_leg_batch_bytes_of. Fix: accepts::leg_down_forms(Program::MiniMaxM3Body, &inputs.model), return Result<TierBatchBytes, PlacementError> like GLM and Solar, call try_tier_leg_batch_bytes_of, and delete leg_downs and the panic wrapper.
5. Test pin dropped without a dated reason
solar2/place.rs:321. The old assert_eq!(inputs.prompt_reserve, reserve, "describe keeps the figure") is gone, and the test now assigns inputs.prompt_reserve = reserve itself. Mutant: describe passes 1 instead of PROMPT_ROWS, or the wrong model. No assertion turns red, because the other checks read inputs.prompt_reserve back. The n_l.sum() == 0 clause ("no room is left for an expert") was also weakened to violations().is_empty(). The doc comment above the test still states that clause. Fix: right after describe, before the type edits, add
assert_eq!(inputs.prompt_reserve, prompt_reserve_bytes(&inputs.hp, &inputs.spec, &inputs.model, PROMPT_ROWS).expect("reserve"));and restore the no-expert assertion, or give it a dated PIN(2026-10-26): reason and update the doc comment.
Non-blocking
⚠ Selected-reserve branch of check_tier_reserves has no test: batch.rs:1145. Mutant: Some(c) => *b, which is the old bound. The placement test pins card_reserve, and the new hw_ test never calls check_tier_reserves. Only a model-load gate would turn red, and the PR body names none. Name the gate you ran, or add a case that checks a mixed-down tier against plan.card_reserve.
⚠ Two owners of the staging and host formulas: workstation.rs:607 counted rewrites tier_batch_staging_bytes and tier_batch_host_bytes in checked form. A change to one leaves the other stale. Keep one formula.
⚠ flint-attach.md:88: the new section records history ("The 2026-10-26 cutover removes…"). State only what is true now.
Checked
- Duplicates: about 14 new items checked. Hits are items 1, 2 and 4, and the staging formula ⚠. dryer pairs: the two 1.00 pairs (
glm5nextandmimo2tier.rs,minimaxm3andsolar2tier.rs) share the oldwidthsshape, and the diff adds only theprogramline to each. The 0.90 pair is two test fixtures. None is a finding on its own. - Complexity:
Fill::run9→18 is a branch added to an existing function (item 2).check_tier_reserves12→16 is one nested match. The other flagged functions grew by 1 each (harmless). - Silent failure: 6 sites followed (
card_reserveNone,selected_reserve_bytes,TierLegScratch::bytes,try_leg_bytes, node reserve,leg_armslookup). Each returns a named error. - Tests: the new
hw_test and the overflow tests would fail if the form union, the padding or the overflow edge were mutated. Item 5 is the exception. - Gates: no band or pin moved. The removed
TierLegrefusal and its test follow the deleted feature. - Performance: load-time only; no decode-path change.
- Escape catalog: no match.
Notes
- The PR body lists no
nvidia-smiline, and nojust gate-*commands with output. GPU evidence is marked false.
Card check: needs-gpu. This pull request changes crates/gpu-deepseek41/src/body.rs, crates/gpu-gates/src/bin/gate_glm5next_nodes.rs, crates/gpu-gates/src/bin/gate_glm5next_twocard.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)
There was a problem hiding this comment.
Verdict: MUST_FIX: the new commits fix the empty-tier mismatch, but the five must-fix items of the last review are all still open.
Since the last review (head 3071a9f): the new commits touch only the empty-tier test, tier_leg_batch_bytes, the MiMo and placement tests, and the doc. None of the earlier items was addressed.
- 1
STACK_ROLEStwice: still open, card_experts.rs:61 and leg_tier.rs:57. - 2
Fill::runre-implementsCard::selected_scratch: still open, placement.rs:3112 (down_actsis still there). - 3
LegStack::ofplanesparameter: still open, card_leg.rs:524. - 4 MiniMax
leg_downsand the panic wrapper: still open, minimaxm3/place.rs:152. The panic wrappertier_leg_batch_bytes_of(workstation.rs:583) now has two callers: MiniMaxtier_batchand, since the new commits,tier_leg_batch_bytes(workstation.rs:568); the latter can calltry_tier_leg_batch_bytes_of(..).expect(..)itself. - 5 Solar test pin dropped: still open, solar2/place.rs:410 still assigns
inputs.prompt_reserve = reserveand never asserts whatdescribeproduced. - ⚠
check_tier_reservesselected branch has no test: still open. The newhw_case does not call it. - ⚠ Two owners of the staging and host formulas: still open, workstation.rs:611.
- ⚠ Doc history: still open, and the new commits add more (see below).
Must fix
1 to 5. The earlier items stand as written in the last review
Each fix is in the last review and is mechanical. Items 1, 2 and 4 each remove more elements than they add. Item 2 also brings Fill::run (complexity 9 to 18) back under control. Doing them now is cheaper than after the next change to the form union.
Non-blocking
⚠ tier_leg_batch_bytes now panics where it returned a value: workstation.rs:561 calls the checked path and expects. qwen35moe/place.rs:1503 still maps an unrouted spec to (0, 0), and try_leg_bytes refuses n_used == 0 and ff == 0. A two-card gate run (qwen3moe_place.rs:275) on a dense Qwen3.6 file would panic instead of returning a plan error. Fix direction: make leg_tier_batch return Result through try_tier_leg_batch_bytes_of, as GLM and Solar do, and drop the (0, 0) fallback.
⚠ New doc text records history and bare numbers: flint-attach.md:98 ("failed before the fix", "Follow-up review found", "Historical exact-source proof"). "reserve24868 versus 20692" and "GPU library418 passed" carry no conditions (geometry, card, model). State what is true now and put the history in the commit message.
Checked
- Duplicates: about 4 new items checked in the new commits (the empty-tier test block, the
tier_leg_batch_bytesdelegation, the three-row test table). No new duplicate. dryer pairs: same three as before, none a finding. - Complexity: nothing new beyond the earlier
Fill::run(item 2). The other flagged functions grow by 1. - Silent failure: 2 sites followed (
tier_leg_batch_bytesexpect,leg_tier_batch(0, 0)). The first is a named panic, see the ⚠. - Tests: the empty-tier assertion in
card_experts.rscomparesblock_bytes()withleg_bytes(.., DownForms::NONE). Mutant "LegTieralways allocates the Q8Act buffer" turns it red. The planner test's new[Q5_K; 2]row pinstier_leg_batch_bytesagainst the selected scratch. Mutant "the wrapper passesNONE" turnsoneandtwored. The removed MiMo assertion compared two calls to the same function after this change, so no pin is lost. - Gates: no band or pin moved.
- Performance: load and planning only; no decode-path change.
- Escape catalog: no match.
Notes
- The PR body has no
nvidia-smiline and nojust gate-*commands with output, only a summary table. GPU evidence is marked false. - dryer and crapper ran (see
diagnostics.md).
Card check: needs-gpu. This pull request changes crates/gpu-deepseek41/src/body.rs, crates/gpu-gates/src/bin/gate_glm5next_nodes.rs, crates/gpu-gates/src/bin/gate_glm5next_twocard.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)
There was a problem hiding this comment.
Verdict: CLEAN: the new commit changes only flint-attach.md; it adds no code and no behavior bug.
Since the last review (head c26025b): the diff holds one doc edit. The earlier items sit in code this commit does not change (STACK_ROLES, Fill::run, LegStack::of, MiniMax leg_downs, the Solar test, check_tier_reserves, tier_leg_batch_bytes, the staging formulas). They are not raised again on a re-review.
Non-blocking
⚠ New doc lines carry history and operations notes: flint-attach.md:113 ("The repair at … then executed", "returned to review-ready only after", "Later documentation-only commits", a request id, "credential cleanup unconfirmed", "GPU1 remained active"). "24.18s" and "model557 … placement202" carry no card, model or command. Keep what is true now: the checks the consumer runs and the geometry; move the rest to the commit message.
Checked
- Duplicates: the new commit adds no code. dryer pairs read earlier; none is a finding.
- Complexity: no function changed in this commit.
- Silent failure: no new site in this commit.
- Tests: no test changed.
- Gates: no band or pin moved.
- Escape catalog: no match.
Notes
- The PR body has a summary table but no
nvidia-smiline and nojust gate-*commands with output. GPU evidence is marked false. - dryer and crapper ran.
Card check: needs-gpu. This pull request changes crates/gpu-deepseek41/src/body.rs, crates/gpu-gates/src/bin/gate_glm5next_nodes.rs, crates/gpu-gates/src/bin/gate_glm5next_twocard.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)
There was a problem hiding this comment.
Verdict: CLEAN: the new commits (Qwen descriptor repair and the upstream merge) hold no behavior bug and no proven duplicate; two non-blocking items remain.
Since the last review (head 4d841c9): the earlier ⚠ on flint-attach.md history is still open and the new text adds more of it (see the first item below). No earlier must-fix existed. This review covers the repair 462213ca and the merge only.
Non-blocking
⚠ Doc carries history and run logs: flint-attach.md:124 to :152. "Historical exact-source proof at ", "subsequently merges pinned upstream", and test counts ("model557", "placement202", "24.18s") without card, model or command. docs/ is not covered by tools/check-comments.sh. Keep what is true now (what the consumer checks, the geometry); move hashes, counts and timings to the commit message or the PR body.
⚠ A skipped layer index: if let Some(forms) = down_forms.get_mut(l) at placement.rs:3150 skips a tensor whose layer is past model.layers; the old down_acts[l] panicked. A skipped tensor would leave its down form out of the selected scratch sum. I found no input that reaches it (layers and tensors come from one descriptor). A named error would keep it that way.
Checked
- Duplicates: 14 new items checked (the Qwen wrappers,
routed_down_acts,selected_leg_scratch,leg_down_formscallers, the checked staging and host formulas). dryer: 3 pairs read. glm5next/mimo2 and minimaxm3/solar2 are traitwidthsbodies that differ inProgram; minimaxm3/solar2place.rsdiffer in model constants. None is a finding. - Complexity:
Fill::run9 → 18 is a new owner (per-layer form cache) in an existing function; its pieces are already helpers (routed_down_acts,selected_leg_scratch), so no split is needed.check_tier_reserves12 → 16 is not in the new commits. The gate bin functions grew by 1 (a?). - Silent failure: 6 sites followed (
tier_batchandleg_tier_batchnow returnResult; every caller incrates/propagates with?orexpectin tests; the dense Qwen3.6 tier request is a namedMetadatarefusal). One skip, above. - Tests:
qwen3_bp_plan(2 failed before, 3 pass after, per the PR body) protectsleg_down_formsuse inleg_tier_batch; mutant "bound to Q8Act only" turns the Q8_0 case red. The dense-header test asserts the refusal key; mutant "return zero geometry" turns it red. The Solar test now sets byte granules and asserts the one-byte boundary and emptyn_l; mutant "reserve off by one" turnsshortred. - Gates: no band, tolerance or lint level moved. Pins in the diff (
PIN(2026-10-26),PIN(2026-10-27)) belong to upstream hunks from the merge. - Escape catalog: no match (no shell changes in this PR's files).
Notes
- The PR body carries an
nvidia-smiline, thetools/gate.sh --gpucommand and its output onc143c98d. GPU evidence is true. - The incremental
diff.patchalso holds upstream files from the merge (metal, glm5next, nemotron). They are not this PR's changes and were not reviewed. - dryer and crapper ran.
Card check: gpu-evidence. This pull request changes crates/gpu-deepseek41/src/body.rs, crates/gpu-gates/src/bin/gate_glm5next_nodes.rs, crates/gpu-gates/src/bin/gate_glm5next_twocard.rs … and carries a gate run on the author's card, which counts as verified.
🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)
# Conflicts: # docs/research/flint-attach.md
…overflow test names its panic Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Verdict: CLEAN: the new head is an ordinary merge of main; it holds no behavior bug, and the merge does not touch any item this PR changes.
Since the last review (head c143c98): no earlier must-fix existed.
⚠ Doc history in flint-attach.md: still open, flint-attach.md:147 to :179 (hashes, test counts and timings). The author acknowledged it and left it. The new lines at 8 to 29 come from main (#781), not from this PR.
⚠ Skipped layer index at placement.rs (down_forms.get_mut(l)): still open, answered by the author (no reachable input). The merge does not touch it.
Checked
- Scope:
diff.patchsincec143c98holds only main's files (handoff.rs,parts.rs,chain/ffn/batch.rs, Metal docs,model-tax.tsv, ptx-shapes,unsafe-ratchet.txt) and theflint-attach.mdconflict. They are not this PR's changes and were not reviewed as such. - Merge interaction: Grep of
handoff.rs,parts.rsandbatch.rsfinds no use ofLegStack::of,tier_batch,leg_tier_batchorSTACK_ROLES. This PR does not change those files. No semantic conflict found. flint-attach.md: no conflict markers; the headings are in order and hold both main's six-slot text and this PR's selected-scratch text.- Duplicates: 0 new items in the merge-resolution lines. dryer pairs are the same three as before and sit in lines the new head does not add.
- Complexity: crapper's list is the same functions as before; no new growth since
c143c98. - Silent failure: no
unwrap_or,.ok(),let _ =or_ => {}in the diff lines. - Tests and gates: no test or gate changed in the merge. The
PIN(2026-10-26)andPIN(2026-10-27)lines belong to main's hunks and carry a date and a reason. - Escape catalog: no match (no shell changes).
Notes
- The PR body carries an
nvidia-smiline and atools/gate.sh --gpurun with output onc143c98, not on this head. It says so itself. The merge adds no file this PR changes, so the evidence is still the PR's own run. - dryer and crapper ran.
Card check: gpu-evidence. This pull request changes crates/gpu-deepseek41/src/body.rs, crates/gpu-gates/src/bin/gate_glm5next_nodes.rs, crates/gpu-gates/src/bin/gate_glm5next_twocard.rs … and carries a gate run on the author's card, which counts as verified.
🔨 Shingler, bloomery's review bot: approves a clean pull request and requests changes on a must-fix (how it works)
# Conflicts: # docs/research/flint-attach.md
|
Thank you. I merged main (now with #781 and #782) into this branch and added one maintainer commit, so it can land in 0.3.10:
Your newer head already fixed the Qwen3 tier leg forms, so I kept yours. Box: |
…m/Burntgogi/bloomery into land783 # Conflicts: # docs/research/flint-attach.md
There was a problem hiding this comment.
Verdict: CLEAN: I built no failure path that the code does not block, and the duplication and element checks found nothing that must change before merge.
Non-blocking
⚠ Second admission scan: accepts.rs:537 leg_down_forms re-decides which layers the rule admits. RoutedRule::layer_runs (placement.rs:2290) owns that decision. The copy passes pair(.., false); the tier plan passes tier = true. It skips an unnamed part with continue; the rule refuses it by name. No program has a pair today, so nothing breaks now. Direction: group tensor indices per layer once and call layer_runs(stacks, model, true).
⚠ Permanent doc carries run history: flint-attach.md:197 to line 233 list commit hashes, pass counts and timings (24.18s, model557) for other sources, and the timings name no card. History belongs in the commit message. Direction: keep the contract paragraphs above line 197 and drop the rest.
⚠ Program is named twice per family: CardFamily.program (card_experts.rs:72) and LegWidths.program (leg_tier.rs:472) in mimo2, minimaxm3 and solar2. accepts::program_of(arch) exists.
Also 2 minor: fixed.checked_sub(bound) failing (placement.rs:3168, Fill::run; also line 308) is reported as bytes_past_u64, a wrong message; the ### Six-slot heading in the doc follows text with no blank line.
Checked
- Duplicates: 14 new items checked. The hits are the ones above. The glm5next/mimo2 and minimaxm3/solar2
widthspairs are per-model shape facts. - Complexity:
Fill::run9→18 is branch growth for the tier-leg cache, with one owner (selected_leg_scratch).check_tier_reserves12→16 adds one branch. - Silent failure: 7 sites followed. Each skips only layers or tensors the rule keeps on the host. A form outside the descriptor errors by name in
TierLegScratch::bytes. - Tests: three planted mutants (drop
scratch(n), drop+ bound, drop thechunk == 0check) each turn a test red. - Gates: no band, tolerance or lint level moved. The two removed tests are replaced; the doc gives a dated reason.
- Hot path: load-time sizing and
check_tier_reservesonly. No per-token term. - Escape catalog: C1 to C4 are shell patterns. The diff has no shell.
Notes
I did not use the PR body's approvals or CI claims. Its GPU run is for c143c98d; the head is 338ee5d (a merge), so GPU evidence is absent for this head.
Card check: needs-gpu. This pull request changes crates/gpu-deepseek41/src/body.rs, crates/gpu-gates/src/bin/gate_glm5next_nodes.rs, crates/gpu-gates/src/bin/gate_glm5next_twocard.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)
Current head: main reconciled; renewed review approved
Current 9e7ab5a is an ordinary merge of main 4e05b5f (#781). The only merge conflict was
docs/research/flint-attach.md; both the landed six-slot handoff contract/provisional pin provenance and this PR's selected-scratch contract were retained. No functional conflict resolution or precision change was made. The actual existing Qwen planner integration suite ran on this merge: 3 passed, 0 failed, 0 ignored, 0 filtered (cargo test -p bloomery-model --test qwen3_bp_plan -- --nocapture). The renewed bot review of this exact head is APPROVED/CLEAN (2026-10-27T07:40:01Z); lint succeeded and T0 completed successfully. The prior c143 GPU run below is not GPU execution of this new merge. The old c143 approval is not the basis for this new-head approval.Historical source-scoped evidence through c143 (not current head)
Historical c143 status at its review
Current component c143c98 contains repair 462213c and an ordinary merge of pinned upstream 0df4076. The merge was required by an observed conflict blocking CI, not an unrelated new contribution. The sole conflict was the
LegStack::ofcomment; its no-planes API and upstream Q5_0 packed-layout dispatch are retained.Review repairs retained
STACK_ROLESowner.LegStack::ofno longer takes redundantplanes; all callers migrated.Additional reachable Qwen defect, now fixed
The old geometry-only Qwen wrappers bounded candidate scratch to Q8Act while admitting Q8_0/Q5_1/IQ4_NL downs requiring Q8Blocks32. An over-budget candidate could therefore abort a valid plan before remaining on the host. Both wrappers now take
PlanInputsand useaccepts::leg_down_formsover the actual admitted model. All production and integration-test callers were migrated; no compatibility shim or alternate admission list remains. This component intentionally has no input_scales bool.Actual existing
cargo test -p bloomery-model --test qwen3_bp_plan -- --nocapturereproduced 2 failed/1 passed before, then 3 passed/0 failed after, with the existing placement expectations unchanged. A separate actual native consumer at the budget boundary produced:The throwaway consumer was removed after preserving its source and observed output; this is metadata/planner execution, not CUDA.
On both exact code sources 462213c and c143c98: formatting check, the discovered model unit/integration targets’ non-ignored cases (
cargo test -p bloomery-model --tests), and workspace all-target Clippy with the existing feature union exited0. No warning/ratchet, band, tolerance, precision or tie policy was changed.Card/CI scope
The recorded exact 462213c mixed/empty-tier GPU0 consumer has now completed: 1passed,0failed/ignored,432filtered,24.06s, step and terminal exit0. The worker then advanced to separately pinned integrated695 checks. This462 result is not relabeled as c143. Current c143 compile-only preparation completed0 and preserved the original462 source and executable (archived executable SHA e391d261fcd38a0749043846f3f175a9b10d5039e3abb50f782745480cf6f6c6). It was followed by a separate actual current-c143 GPU run, reported below. GPU1 is not stopped.
Historical 7e37ef9 on RTX3090 cc8.6: mixed/empty1/0/0,427filtered,23.98s; its dense-header frontend1/0/0,6filtered was metadata-only. Historical c38d603 and fd2a64b T0/lint passed, and c38 versus cb8 canonical4bins/8carriers/1657identical, non-JIT rows equal. These are not new c143 GPU, CI or JIT results.
Current c143 now has actual affected GPU proof, T0 37/37 and lint success plus clean independent static review. The fresh current-head bot review has now APPROVED/CLEAN,must_fix0,warn2; maintainer merge remains before closure. Older CHANGES_REQUESTED/approval states are not represented as current approval. No ROCm, whole-model FlInt acceptance, physical cc12.1 or performance claim.
Current c143 native accounting: 581passed,0failed,125ignored,0filtered across the reported test targets. Ignored real-model/fixture cases were not executed; no all-model runtime coverage is inferred.
Current c143 independent full static re-review: no findings; the earlier Qwen descriptor defect is resolved. This is separate from public GitHub approval.
Current untouched-main-compatible owning card evidence
Exact source c143c98, actual GPU0 inventory:
Actual command (existing pinned Rust1.99.1 / oxide9df9e7ce + backend31ab6a1d3f58 / LLVM21.1.8):
Current-source case and terminal both exit0. Both start/collection credential cleanups are confirmed; GPU1 remains active/healthok. This used the same existing repository local GPU lock as the integrated worker, so CPU builds can overlap but actual card execution is serialized; no bound was raised. It is not a relabeling of462's24.06s, nor a new full418-case library run.
Current PR-check40448380273 on c143 completed T0 37/37,red0 and lint success. Current full static re-review has no findings. No source change is needed to return this component to review.
Current public review disposition
The new review of exact c143c98 is APPROVED/CLEAN,must_fix0,warn2 (run40450776053). Both nonblocking notes are acknowledged, not called fixed: permanent-doc history remains, and an out-of-range layer-index skip had no reachable input identified by the reviewer. No new generic validation or unrelated cleanup is added to move this verified/approved head; a maintainer can merge or explicitly request either change. Earlier CHANGES_REQUESTED states are not the current verdict.