test(MODEL-MM-QWEN4-EXP): the CUDA router tie-break is stable, and the geometry that proves it had never been run - #2595
Merged
Conversation
…EALISES the tie-break it declares Wave MOEDIV (#2552) measured that 32.9% of this model's routing boundaries are exact bf16 ties and concluded, from a source read of both arms, that the flips are tie-break order rather than a defect. A source read establishes the INTENDED tie-break. It does not establish that a parallel argmax realises it. The standing adversarial sweep in tests/vt/test_ops_moe_grouped.cpp sweeps E in {32,64,128,256}, and MoeRouterWarpValuesPerThread admits none of E=512, so the block kernel at the geometry qwen4_exp actually routes has never been executed by a test. Its tie patterns also keep the tied set inside a contiguous prefix, which at kBlock=256 sits in warp 0 and never asks the cross-warp comparison to break a tie. This section states the hypothesis so it can fail, the closed-form expectation that gates the semantics rather than arm-vs-arm agreement, the determinism arms, the counted property that stops a case reading green while measuring nothing, and the five upstream anchors at the parity pin that show vLLM DEFINES this tie-break in both of its kernels and registers E=512 as a topkGating width. FOLLOWING_AGENTS_PROTOCOL Refs: #2586 Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code]
…the router at the geometry qwen4_exp routes Wave MOEDIV (#2552) concluded from a source read that the CPU and CUDA routers break an exact tie the same way. This adds the executable form of that claim, at E=512 k=10 -- the geometry the model routes and the one no case in this tree has ever run, because MoeRouterWarpValuesPerThread excludes E=512 from the warp kernel and the standing adversarial sweep in test_ops_moe_grouped.cpp stops at E=256. Each row has a CLOSED-FORM correct answer: h strict winners, then a tied set S whose members carry one bf16 bit pattern, then a low floor, so the top-k is the h winners followed by the k-h LOWEST INDICES OF S. That is upstream's own rule (topk_softmax_kernels.cu:536-537, :515-517, :465 @ vLLM 5559679229), so this gates the semantics and cannot pass by both arms being wrong the same way. Indices are compared with == and the selection as a sorted set; there is no tolerance in the file, because a discrete selection has bimodal error. Six tie PATTERNS decide which level of the reduction has to break the tie. Pattern 5 is the one that needs E > 256: it puts BOTH slots of the same threads in S, so the per-thread strided scan alone decides between expert t and t+256. At E <= 256 a thread holds one expert and that compare cannot be reached, which is why no existing case discriminates it. Counted property: tied_seen counts rows whose boundary carries the SAME bf16 bit pattern on both sides, read off the LOGITS rather than any kernel, and is CHECKed against the row count -- a builder that stopped producing ties cannot read green. CPU arm on this box: assertions 488 | 488 passed | 0 failed, rc=0. Red-first: flipping the CPU kernel's strict `>` to `>=` (cpu_ops.cpp MoeRouterTopKKernel, one site, N=1) turned 90 of the selection assertions red while the counted property stayed intact; restored byte-for-byte and green again. The CUDA arms need nvcc and a device and are measured in a lease. FOLLOWING_AGENTS_PROTOCOL Refs: #2586 Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code]
…try that proves it had never been run
Thor measured wave TIEBREAK's question and the answer is no defect: at E=512
k=10 on bit-identical logits with an exact bf16 tie at the boundary, the
dispatched CUDA kernel returns the closed-form correct selection, agrees
byte-for-byte with the serial GPU oracle and the CPU reference, repeats over 32
launches and is invariant across 257 batch positions. 4 cases, 4652 assertions,
0 failed, rc=0. MOEDIV's conclusion stands and the session goal's three
disagreeing token ids do not move, because nothing moved them.
The wave still found something. Flipping the block kernel's per-thread strided
scan to highest-index-wins is caught by 104 of the new assertions and by ZERO
assertions of the standing sweep, whose counts are byte-identical before and
after. The failures land only at E in {512, 1024} and only on the two patterns
that put two tied experts on one thread; E=256 contributes zero, because that
compare does not exist below E > kBlock.
Two negatives are recorded rather than dropped. The mutant stayed perfectly
deterministic, so repeatability alone would have called it clean. And the
corroborating orin lease registered no CUDA backend, skipped every device case,
and read 488/488 GREEN with the broken tie-break compiled in -- distinguishable
from Thor's real result only by the assertion COUNT.
FOLLOWING_AGENTS_PROTOCOL
Refs: #2586
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
…ms it could falsify Sixteen commits, none of them touching the router. The wave's two load-bearing statements are re-read against the merged tree rather than assumed: the standing sweep in tests/vt/test_ops_moe_grouped.cpp still stops at E=256, and MoeRouterWarpValuesPerThread still returns 0 for E=512, so the block kernel is still the path qwen4_exp routes and the coverage gap the mutation quantified is still the gap. FOLLOWING_AGENTS_PROTOCOL Refs: #2586 Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code]
…s this tree cannot run The section carried `ctest -R 'vt_ops'` and `build/tests/vt_tests -ts='*moe*'`. This tree builds ONE binary per suite, has no `vt_tests` aggregate and no `vt_ops` ctest label, so both commands would have selected nothing and reported success for it. `ctest --test-dir build -R moe` on a tree with only one suite built exits 8 with `Unable to find executable` on 32 of 33 entries, which is the same class of answer: a gate that names something absent is not a gate. Replaced with the build-then-run pair that was actually used, and with the instruction the Outcome paid for: read the ASSERTION COUNT beside every rc. On a CPU-only build the three device cases skip and the suite reads 488 at rc 0 instead of a device run's 4652, and the orin lease in the Outcome read exactly that number GREEN with a broken tie-break compiled in. Local rcs at this head, one binary at a time: test_moe_router_tie_stability rc=0 488 | 488 passed | 0 failed test_ops_moe rc=0 69 | 69 passed | 0 failed test_ops_moe_grouped rc=0 3 | 3 passed | 0 failed test_moe_router_warp_map rc=0 4597 | 4597 passed | 0 failed FOLLOWING_AGENTS_PROTOCOL Refs: #2586 Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code]
…d head, because the merge touched a file the binary links The wave's numbers were taken at 64617b1. The merge with origin/main then brought in src/vt/cuda/cuda_exl3.cu, which links into the same binary, and this row has already had a merge falsify prose inside its own pull request. So the counts were taken again rather than reasoned about. Second thor:gpu0 lease at d52bc83, job 186b67e9-4e48-43fb-9424-65735964083c, BUILD rc=0 objects=586, 41 *.cu.o: baseline 4652/0 rc=0, mutant 4652/104 rc=1, restored 4652/0 rc=0, and the standing suites unmoved at 1907/1906/1 and 33451/0 under both. The mutant's failures land 12/12 at E=512 patterns 3 and 5, 12/12 at E=1024, and ZERO at E=256, exactly as before. Only this commit lands after that run and it edits two documents, so the binary those numbers came from is the binary the branch ships. FOLLOWING_AGENTS_PROTOCOL Refs: #2586 Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code]
…d it is measured here The pull-request body said flipping the CPU router's strict `>` to `>=` turned "90 selection assertions" red. That number does not reproduce and it never could: the file has SIX tie patterns, and 90 is 5 x 3 x 3 x 2, a stale figure from a five-pattern draft. `squash_merge_commit_message = PR_BODY` here, so the body becomes the commit message on `main`, and a wrong measured number in it is an unrepairable falsehood in the history. Re-measured on the authoring host, CPU-only build at this branch head, one site (`src/vt/cpu/cpu_ops.cpp:2985`, `grep -c` = 1): baseline `1 case | 488 | 0 failed | rc 0`, mutant `1 case | 488 | 380 passed | 108 failed | rc 1`, restored `488/488`. All 108 failures are `CHECK( ids == r.expect )` and none is a counted property, so the row builder is proved still to have built ties. 108 is the whole selection population rather than a subset: `h < k` is `REQUIRE`d, so each of the 54 rows selects at least one tied member, and `>=` mis-selects on every row in both dtypes. Three further repairs, none of them a redesign of the wave. The `## Outcome` said a sweep that stops at 256 is "blind to it", which invites a broader reading than the mutations support. The fresh review inverted the other two reduction levels: the warp `__shfl_down_sync` argmax reds 313 assertions of the standing sweep and the cross-warp pass reds 199. Only the per-thread strided compare reds zero there. The sentence now names that one defect class and says the sweep is adequate for the levels that exist at E <= 256. The Gates instruction taught the assertion count alone, and the assertion count separates only two of three states: a CPU-only build reads `1 case | 488`, a device-less CUDA build reads `4 cases | 488`, and a real device run reads `4 cases | 4652`. Both 488s are rc 0. The case count is the other half of the discriminator and the section now carries both. `test_moe_router_tie_stability.cpp:43` put upstream's `:465` sentence in quotation marks as `[0,1,...,k-1]`; upstream writes `[0,1,2,...,k-1]`. Two gaps the review found are RECORDED and not fixed, each with an issue and a `## Owed` entry, because neither belongs in a test-only change. The permissive `HasCuda()` skip that lets a device-less CUDA build read green is a tree-wide shape across 14 files (#2603). Half the device sweep is a duplicate above E = 256, because `MoeRouterWarpValuesPerThread` returns 0 there and both `VT_MOE_ROUTER_WARP` arms dispatch the same block kernel, so coverage at the geometry `qwen4_exp` routes is half what the doubled counts imply (#2604). The counts stay honest; only their reading changes. No product code changed. FOLLOWING_AGENTS_PROTOCOL Following-Agents-Protocol: true AI-Assisted: true Assisted-by: AGENT:claude-opus-5 [claude-code]
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.
test(MODEL-MM-QWEN4-EXP): the CUDA router tie-break is stable, and the geometry that proves it had never been run
Wave MOEDIV (#2552) measured that 32.9% of this model's routing boundaries are
exact bf16 ties, and concluded that the CPU/CUDA expert flips are tie-break
order rather than a defect. It verified that conclusion BY SOURCE READ of both
kernels. A source read establishes the INTENDED tie-break; it does not establish
that a parallel argmax realises it. This wave tests the part a source read
cannot reach.
The answer
The CUDA top-k realises the lowest-index tie-break it declares. On
bit-identical logits whose top-k boundary is an EXACT bf16 tie, at E = 512
k = 10 -- the geometry
qwen4_exproutes -- the dispatched kernel returns theclosed-form correct selection, agrees byte-for-byte with the serial GPU oracle
and with the CPU reference, repeats identically over 32 launches, and gives the
same answer for a row run alone and as each of 257 rows of a batch.
Measured on
thor:gpu0(job5f50e5f7-c730-463f-93cc-3293835ed007, podrc-worker-n8smh, NVIDIA Thor, driver 595.78, cc 11.0, nvcccuda_13.0.r13.0,sm_110):CMAKE rc=0,BUILD rc=0 objects=586, 41*.cu.o,libcudart.so.13and
libcublasLt.so.13in the test binary's ownldd, andtest_moe_router_tie_stabilityreading 4 cases | 4652 assertions | 0 failed |rc=0.
So MOEDIV's reading stands, the remaining CPU-vs-CUDA token divergence stays
attributed to arithmetic, and the session goal's three disagreeing ids do not
move -- because nothing moved them. No product code changed. No fix was made,
because none was needed.
What the wave found anyway
The tree could not have answered this question before.
MoeRouterWarpValuesPerThreadreturns 0 for E = 512, so
qwen4_exproutes throughMoeRouterTopKKernel<Tin,false>at 2 experts per thread, and the standing adversarial sweep in
tests/vt/test_ops_moe_grouped.cppstops at E = 256 -- where a thread holds ONEexpert and the per-thread strided compare can never see a tie at all.
Flipping that compare to highest-index-wins (
cuda_moe.cu, ONE site, assertedn == 1,MUT BUILD rc=0 objects=1) is caught by 104 of the new assertionsand by ZERO assertions of the standing sweep, whose counts are byte-identical
before and after:
test_ops_moe_groupedread1907 | 1906 passed | 1 failedboth times, that one failure being the pre-existing #962 Marlin NVFP4 block-size
disagreement on this arch, and
test_ops_moeread33451 | 33451both times.Restoring returned 4652/4652.
par == r.expectfailures under the mutationZero at E = 256 is the finding: the compare the mutation breaks does not exist
below
E > kBlock.Two negatives kept rather than dropped
The mutant stayed perfectly deterministic. All 279 repeat comparisons and
2313 batch-position comparisons passed with the wrong tie-break compiled in. A
repeatability check alone would have called it clean, so determinism is recorded
as necessary and never sufficient.
A corroborating
orin:gpu0lease registered no CUDA backend, skipped everydevice case, and read 488/488 GREEN with the broken tie-break in the binary.
The assertion count is what distinguishes it from Thor -- 488 against 4652 --
but the assertion count ALONE separates only two of three states, because a
CPU-only build reads 488 as well. The CASE count is the other half:
#ifdef'd outEvery table here therefore carries both counts and never a status line, and the
spec's Gates section now teaches both.
How it is asserted
Every row has a closed-form correct answer --
hstrict winners, then a tied setS sharing one bf16 bit pattern, then a low floor -- so the top-k is the h winners
followed by the k-h LOWEST INDICES OF S. That is upstream's own rule at the
parity pin
5559679229, not a local convention:csrc/libtorch_stable/moe/topk_softmax_kernels.cu:536-537("We want lowerindices to "win" in every thread so we break ties this way"),
:515-517("only updated if > (not >=)"),
:707-708(case 512: LAUNCH_TOPK(512, ...),so E = 512 is a registered
topkGatingwidth upstream),:186,222,225(
cub::ArgMaxin the fallback) and:465. The gate therefore measures thesemantics and cannot pass by both arms being wrong the same way.
Indices are compared with
==and the selection as an ordered vector; there isno tolerance anywhere in the file, because a discrete selection has bimodal
error. The counted property is
tied_seen-- rows whose boundary carries thesame bf16 bit pattern on both sides, read off the LOGITS rather than any kernel
-- CHECKed equal to the row count, so a builder that stopped producing ties
cannot read green.
Red-first on the CPU half, on the dev box, CPU-only build at this branch head:
flipping the greedy argmax's strict
>to>=at ONE site --src/vt/cpu/cpu_ops.cpp:2985,grep -c= 1 -- turns every selectionassertion in the CPU case red. Baseline
1 case | 488 | 0 failed | rc 0; mutant1 case | 488 | 380 passed | 108 failed | rc 1, all 108 of themCHECK( ids == r.expect )and none of them the counted property; restored488/488. 108 is the whole population and not a subset:h < kisREQUIREd,so each of the 54 rows selects at least one member of the tied set, and
>=mis-selects on every row in both dtypes --
54 x 2 = 108.(An earlier revision of this body said 90. That figure came from a
five-pattern draft of the file --
5 x 3 x 3 x 2-- and the shipped file hassix patterns. It was re-measured rather than carried forward, because
squash_merge_commit_message = PR_BODYmakes this text the commit message and awrong measured number in it cannot be repaired afterwards.)
Owed
Two gaps the fresh review found are RECORDED here rather than fixed, each
with an issue and a
## Owedentry in the row's spec, because neither belongsin a test-only change.
HasCuda()skip lets a device-less CUDA build read green. That is theorin:gpu0row above, and it is a tree-wide shape:grep -rl 'no CUDA backend registered; skipping' tests/finds 14 files, 13 ofthem not this one. The tree already carries the idiom that refuses instead
(
tests/parity/test_qwen27n_fp8_tower_paged_engine.cpp:149readsVT_REQUIRE_27N_FP8_GATEand turns absence into a FAILURE), so adopting it isa row of its own.
sweep is a duplicate above E = 256.
MoeRouterWarpValuesPerThreadreturns 0for every E outside
{32,64,128,256}andLaunchRouterWarp(
cuda_moe.cu:564) returnsfalseonvpt == 0, so at E = 512 and E = 1024--
qwen4_exp's own geometry -- bothVT_MOE_ROUTER_WARParms dispatch thesame block kernel. The counts stay honest, because every assertion really
executes; but 36 of the 72 rows at E > 256 are byte-identical repeats, the
12per cell above is2 arms x 3 h x 2 dtypesof which 6 are a secondcount of one disagreement, and COVERAGE at E > 256 is half what the doubled
figures imply. Only E = 256 compares two structures.
The gate against vLLM itself stays owed for the reason the row's
spec already records under
## Owed: it needs an artifact vLLM can load, andvLLM's GGUF support is an out-of-tree plugin while every safetensors arm of this
model exceeds the largest fleet box. This change says our two arms agree with
each other AND with upstream's stated rule; it does not run upstream's kernel on
upstream's weights.
Evidence:
docs/bench-evidence/qwen4exp-moe-tiebreak-stability-20260902.md.Spec:
.agents/specs/qwen4-exp-flash-next.md"## Wave TIEBREAK".Closes #2586
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]