Found by independent review of PR #967, which was self-reviewed and merged with --admin. Live on main today. Row ENG-EXPERT-STREAM, issue #912.
The defect
IsCudaKeepQuantSupported (src/vt/cuda/cuda_quant_dot.cu:1600-1601) now returns true for kIQ1_S and kIQ1_XXXS. Three dispatch switches consume that predicate; #967 extended only the dense one.
MatmulBTQuantGroupedKernelCuda (:1948-1957) uses the predicate at :1916 to SKIP its CPU fallback (:1917-1921), then dispatches through a switch (w) that has no case for either new dtype and no default:. It quantizes the activation, launches nothing, and returns. CheckCuda(cudaGetLastError()) at :1958 sees no error because there was no launch. The output tensor is never written.
Before #967 these dtypes returned false and took the CPU fallback: correct, just slow. #967 converted correct-but-slow into silently wrong, which is the exact inversion of its stated purpose.
Measured (GB10, reviewer probe, poisoned output buffer)
| case |
device out[0] |
CPU oracle out[0] |
nmse vs CPU |
iq1_s |
-12345 (poison, untouched) |
-2.18233 |
4.58e6 |
iq1_xxxs |
-12345 (poison, untouched) |
-4.11988 |
9.96e6 |
iq2_s (control, has a case) |
matches |
|
pass |
Why it is reachable by default
qwen3_5_gguf_weights.cpp:62 accepts any KeepQuantDType, which now includes ggml 19 and 66 -> qwen3_5.cpp:6091 -> :5186 KqGrouped -> vt::MatmulBTQuantGrouped (ops.cpp:214) -> the broken switch. VT_QWEN35_GROUPED_MOE defaults ON.
#985 ("loads and generates") ran on --device cpu, so nothing has exercised the CUDA arm end to end yet. The defect is waiting at exactly the next step of this row.
Why it compiled silently
cmake/CompilerWarnings.cmake:28 gives CUDA only -Werror=all-warnings and no -Wall, so the host pass never runs -Wswitch. A missing enum case in a switch without a default is therefore not an error here.
F2 (HIGH): the same omission in the fused MoE SwiGLU seam
MoeGateUpSwiGLUGroupedCuda (:2117-2126) guards with the same predicate at :2092-2096 and previously threw a NAMED error. #967 made the guard pass while the switch still matches nothing, so a loud refusal became silence. Latent for IQ1 today (reachable via cuda_deepseek_v4.cu:2082 / vt::MergedGemm), but any keep-quant MoE arch binding the shared seam inherits it.
F3 (HIGH): the CUDA grouped dispatch has no test at all
grep -rl MatmulBTQuantGrouped tests/ finds two files, neither with any kCUDA reference. The whole grouped dispatch is ungated on device, which is why F1 and F2 landed green.
F5 (MEDIUM): device grid tables are unsealed, and 13% of one is untested
cuda_quant_iq_tables.cuh:41-43 claims "the digests the CPU tests re-derive cover these bytes too". They do not: the tests digest the HOST symbols vt::cpu::kIq1sGrid / kIq1xxxsGrid; nothing reads vt::cuda::d_iq1s_grid. The header at :4 also claims a runtime memcmp test against the CPU tables that does not exist.
Replaying the gate's fixed-seed generator: 266 of 2048 d_iq1s_grid entries (13.0%) are never addressed by any test shape. Drifting entry 0 is caught; drifting entry 3 is GREEN, 150032/150032.
Remediation
- Add the two
LaunchGroupedGemm<> cases (the templates are generic in W; DotSuperblock/FinalFactor already specialize, so no new kernel code) and a default: that THROWS naming the dtype, in both grouped switches.
- Extend the CUDA gate to the grouped seam over the same case table.
- Add the
cudaMemcpyFromSymbol + memcmp seal the header already claims, and fix both comments.
- Consider giving CUDA
-Wswitch so the compiler catches the next one.
Owning row: ENG-EXPERT-STREAM.
Found by independent review of PR #967, which was self-reviewed and merged with
--admin. Live onmaintoday. RowENG-EXPERT-STREAM, issue #912.The defect
IsCudaKeepQuantSupported(src/vt/cuda/cuda_quant_dot.cu:1600-1601) now returnstrueforkIQ1_SandkIQ1_XXXS. Three dispatch switches consume that predicate; #967 extended only the dense one.MatmulBTQuantGroupedKernelCuda(:1948-1957) uses the predicate at:1916to SKIP its CPU fallback (:1917-1921), then dispatches through aswitch (w)that has no case for either new dtype and nodefault:. It quantizes the activation, launches nothing, and returns.CheckCuda(cudaGetLastError())at:1958sees no error because there was no launch. The output tensor is never written.Before #967 these dtypes returned
falseand took the CPU fallback: correct, just slow. #967 converted correct-but-slow into silently wrong, which is the exact inversion of its stated purpose.Measured (GB10, reviewer probe, poisoned output buffer)
iq1_siq1_xxxsiq2_s(control, has a case)Why it is reachable by default
qwen3_5_gguf_weights.cpp:62accepts anyKeepQuantDType, which now includes ggml 19 and 66 ->qwen3_5.cpp:6091->:5186KqGrouped->vt::MatmulBTQuantGrouped(ops.cpp:214) -> the broken switch.VT_QWEN35_GROUPED_MOEdefaults ON.#985 ("loads and generates") ran on
--device cpu, so nothing has exercised the CUDA arm end to end yet. The defect is waiting at exactly the next step of this row.Why it compiled silently
cmake/CompilerWarnings.cmake:28gives CUDA only-Werror=all-warningsand no-Wall, so the host pass never runs-Wswitch. A missing enum case in a switch without a default is therefore not an error here.F2 (HIGH): the same omission in the fused MoE SwiGLU seam
MoeGateUpSwiGLUGroupedCuda(:2117-2126) guards with the same predicate at:2092-2096and previously threw a NAMED error. #967 made the guard pass while the switch still matches nothing, so a loud refusal became silence. Latent for IQ1 today (reachable viacuda_deepseek_v4.cu:2082/vt::MergedGemm), but any keep-quant MoE arch binding the shared seam inherits it.F3 (HIGH): the CUDA grouped dispatch has no test at all
grep -rl MatmulBTQuantGrouped tests/finds two files, neither with anykCUDAreference. The whole grouped dispatch is ungated on device, which is why F1 and F2 landed green.F5 (MEDIUM): device grid tables are unsealed, and 13% of one is untested
cuda_quant_iq_tables.cuh:41-43claims "the digests the CPU tests re-derive cover these bytes too". They do not: the tests digest the HOST symbolsvt::cpu::kIq1sGrid/kIq1xxxsGrid; nothing readsvt::cuda::d_iq1s_grid. The header at:4also claims a runtimememcmptest against the CPU tables that does not exist.Replaying the gate's fixed-seed generator: 266 of 2048
d_iq1s_gridentries (13.0%) are never addressed by any test shape. Drifting entry 0 is caught; drifting entry 3 is GREEN, 150032/150032.Remediation
LaunchGroupedGemm<>cases (the templates are generic inW;DotSuperblock/FinalFactoralready specialize, so no new kernel code) and adefault:that THROWS naming the dtype, in both grouped switches.cudaMemcpyFromSymbol+memcmpseal the header already claims, and fix both comments.-Wswitchso the compiler catches the next one.Owning row:
ENG-EXPERT-STREAM.