Skip to content

fix(ENG-EXPERT-STREAM): the CUDA blocker is a missing vt::MatmulBTAlphaBeta, and the Gemma-4 device-expert upload now refuses before it happens (#1126, #1205, #1197, #1218) - #1200

Merged
localai-bot merged 15 commits into
mainfrom
row/ENG-EXPERT-STREAM-1126
Aug 18, 2026

Conversation

@localai-bot

@localai-bot localai-bot commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

FOLLOWING_AGENTS_PROTOCOL

#1126 says adding CudaBackend::DeviceMemoryInfo would let Gemma4MoE's
device-expert LRU stop refusing on CUDA and wake a slower third path. Reading the
chain to establish that claim found something else: it would wake a throw, in
the middle of a decode step. vt::MatmulBTAlphaBeta has no CUDA implementation at
all, and that is what step 1 is actually blocked on. That is #1205, and it was
recorded nowhere.

What lands

The hazard is guarded, before the upload rather than after it.
EnsureGemma4Fp8ExpertOnDevice returns false at
src/vllm/model_executor/models/gemma4_moe.cpp:571 when
vt::HasMatmulBTAlphaBeta(d.q) is false, so the caller takes the host fallback
already sitting in the else at :1515-1521EnsureGemma4Fp8ExpertCached plus
ExpertGeGLUHost, slower and two extra BF16 roundings per expert — and the step
answers instead of throwing. The upload's own try/catch (...) at :585-607
never covered the compute, so without this the exception left the decode step
rather than degrading.

The predicate is not a device-name test and not a build-macro test.
vt::MatmulBTAlphaBeta dispatches on HasMatmulBTAlphaBeta itself
(src/vt/fused_ops.cpp:102-109, dispatch at :117), so the two cannot disagree:
false there means the very next line throws, and writing a CUDA arm wakes the
device path in one edit with nothing to change at the call site.

The refusal names the right absence for each caller. "ROCm-only in this build"
named neither the device that asked nor where an implementation would go, so a
caller on CUDA could not tell a missing kernel from a missing build flag. The two
messages now are:

vt::MatmulBTAlphaBeta: no implementation for device 'cuda'; no 'cuda' kernel has
been written and the only arm in the tree is 'rocm'
(src/vt/rocm/rocm_matmul_hipblaslt.hip); see issue #1205.

vt::MatmulBTAlphaBeta: the 'rocm' arm (src/vt/rocm/rocm_matmul_hipblaslt.hip) is
compiled out of this build; reconfigure with -DVLLM_CPP_HIP to enable it.

The second is for a kROCM queue, which reaches the same line in a build configured
without -DVLLM_CPP_HIP. For that caller the kernel exists and the flag is
missing; telling them to write a kernel the tree already has would send them to fix
the wrong thing. The old message got that one case right and the first draft of
this change broke it.

Say plainly what the message gate pins: a contract in a unit test, not observable
behaviour.
With the guard in place the throw is unreachable off ROCm in any
shipped configuration, so no production run prints either string. What
tests/vt/test_gemma4_rocm_fp8_seams.cpp fixes is what a CUDA implementation has
to satisfy when someone writes one. That limitation is recorded under ## Owed
rather than left for a reader to discover.

Four records are corrected, and one of them was the reason for this branch. The
comment on vt::Backend::DeviceMemoryInfo claimed "(ROCm/CUDA)" in both places
that carried it. #1126's own closing plan, step 3, would source a load-time
budget verdict from a live contention-dependent probe; it is narrowed here to
total only, probed once at platform registration, rather than rejected outright.
#1197 and #1205 are filed with their chains traced.

How it is proven

tests/vllm/models/test_gemma4_moe_device_arm_guard.cpp enters through
vllm::RunGemma4Moe — the layer entry
src/vllm/model_executor/models/gemma4.cpp:634 calls — with a real
Gemma4MoeLayerWeights, the real router, the real device-expert LRU and the real
fallback. Nothing in it constructs the LRU, the Dev or vt::MatmulBTAlphaBeta by
hand.

It decorates the registered CPU backend so vt::Backend::DeviceMemoryInfo
answers, and changes nothing else. That is the whole point: the hazard is latent on
every machine that can run this suite, because MakeRoom refuses unless that probe
answers and only ROCm overrides it. On a stock build the memory probe refuses the
upload and the guard never binds, so deleting the guard would be invisible — an
unmoved-mutation trap, not a proof. #1126 step 1 IS the change that makes the
probe answer on a device with no MatmulBTAlphaBeta arm, so the test puts the tree
in exactly that state. Both directions of the probe are asserted before anything is
concluded, so an instrument that failed to arm cannot report the guard proven by a
run that never reached it.

Mutations on the merged tree. Each was applied, asserted applied by sha256 and
git diff --stat, rebuilt (a mutation that does not build is INVALID, not a pass),
run with its exit code captured directly rather than through a pipe, then restored
and re-asserted by sha256. Every one compiled.

# Mutation seams guard
M1 Restore the pre-PR "ROCm-only in this build" message RED rc 1, 4 cases / 1 failed green
M2 Delete the refusal outright (return;) RED rc 1, 4 cases / 2 failed green
M3 Delete the production call site gemma4_moe.cpp:90 green green
M4 Force HasMatmulBTAlphaBeta to true green RED rc 1
M5 Delete the guard green RED rc 1
M6 Delete the kROCM build-flag branch RED rc 1, 4 cases / 1 failed green
M7 Delete the guard and gemma4_moe.cpp:90 green RED rc 1

M5 is the reachability proof, and its failure text is the evidence: the guard test
goes red with vt::MatmulBTAlphaBeta: no implementation for device 'cpu' thrown
out of vllm::RunGemma4Moe. M4 shows the guard consults the predicate on the
executed path rather than passing for some incidental reason. M7 shows :90 is not
the only production route into the refusal — with :90 gone the chain still
reaches it through ExpertGeGLUTopKFusedGelu.

M3 is reported as it came out, because it is the finding that started this
repair.
Deleting gemma4_moe.cpp:90 leaves both suites green. For the guard test
that is correct and expected: with the guard in place the layer never reaches :90
at all, which is the point of the guard. For the seams suite it is the honest
consequence of what that suite is — a unit contract on a message that no correct
program reaches. A refusal a correct program never reaches has no production path
by construction, so no mutation can make one appear; the alternative would be
leaving the hazard unguarded so the string could be observed. That is stated under
## Owed rather than presented as reach.

Green after restore: test_gemma4_rocm_fp8_seams 4 cases / 37 assertions rc 0,
test_gemma4_moe_device_arm_guard 1 case / 11 assertions rc 0. Both source files
back to their exact pre-mutation sha256.

Full gate on the merged tree: cmake --build build -j 8 rc 0, 0 ENOSPC,
0 errors; ctest --test-dir build -j 4 523/523 passed, 0 failed, rc 0, with the two
pre-existing checkpoint-gated skips (test_modelopt_mixed_precision_checkpoint,
test_voxtral_e2e). An earlier merge in this sequence changed
cmake/CompilerWarnings.cmake, so that round was a clean rebuild from an empty
build/ rather than an incremental one, and it was also 523/523 rc 0.

scripts/check-symbol-anchors.py, which arrived on main during this work and
gates exactly the failure mode this row keeps producing, is green over these
records: 618 citations, in-repo checked 93, fresh 93, stale 0.

test_cpu_x86_llamacpp_floor failed once during this session under box load and
printed its own precondition: NO_QUIET_WINDOW after 30s (busy=110% builders=0 load=42.82 50.24 77.96) on a 20-core host — the load-dependent red of #618. It
is isolated rather than dismissed: the three files it reads have identical blob
SHAs
on this branch and on origin/main
(scripts/cpu-x86-llamacpp-floor.sh bd7a5192…,
docs/bench-evidence/cpu-x86-llamacpp-20260811.md 94f8509c…,
tests/scripts/test_cpu_x86_llamacpp_floor.py 358927d1…), so this branch cannot
move it, and it passed on the quieter reruns.

What is owed

#1218EnsureGemma4Fp8NativeOnDevice (gemma4_moe.cpp:611) has the same shape
and no guard, and it is the default arm: VT_GEMMA4_FP8_NATIVE returns true
when unset (:969-974), so #1126 step 1 wakes it before it wakes the guarded one.
Filed and not fixed here, and not for effort: the BF16 guard keys on ONE predicate
that is the same condition its own dispatch uses, which is what makes it honest,
whereas the twin depends on three different ops and needs a predicate per op.
Reusing HasMatmulBTAlphaBeta there would be a guard naming the wrong arm — the
exact defect this branch's review corrected in a refusal message.

#1205 — the CUDA MatmulBTAlphaBeta itself. A beta-accumulating BT GEMM on
cuBLASLt is a kernel with its own correctness gate, no per-expert FP8 Gemma-4
checkpoint is pinned anywhere in docs/USAGE.md to exercise it on, and the host
that found this has neither a ROCm nor a CUDA device.

#1197 — the device LRU's slot cap sits ahead of its eviction loop, so
VT_GEMMA4_EXPERT_EVICT=1 goes inert after 24 admissions. Filed and not fixed: the
one-line repair wakes more hipFree under load, which the surrounding comments
record as a permanent kfd_wait hang, and deciding that needs the dual-RDNA4 box.

Anchors

This row has now produced three stale-anchor defects, and the third was not caused
by its own diff. The audit therefore states its scope and uses two instruments.

The first repair covered the four ## Owed rows in this cluster: 53 examined, 53
exact, 0 stale. It never included a GitHub issue body, which is exactly how
#1205's body came to be eleven lines stale at 7beada17c. This repair re-derived
every anchor in those four rows, in the two new ## Owed rows, in the #1197,
#1205 and #1218 index rows and in the #1205 and #1218 issue bodies:
168 endpoints across nine rows resolved for range, 0 out of range, plus 69
load-bearing anchors asserted against the substring the prose claims lives at that
line, 0 stale
.

The second instrument is what earned its place. Merging origin/main moved
RocmBackend::DeviceMemoryInfo from :338-345 to :358-365, and the range-only
check reported OK because the old lines still existed — a checker that only asks
"does this line exist" passes exactly the failure it was written to find.

Several bare :NNN anchors also inherited the wrong file after a mid-sentence
mention of a different one; gemma4.cpp:634 in particular resolved to the 123-line
tool parser, where it is out of range. Those are spelled out in full.

Three .agents/issue-index.md rows are appended: #1197, #1205 and #1218. All
three were added by this branch and have not merged, so editing them while the pull
request is open cannot duplicate anything. Two index defects were caught by the
gates rather than by review and are repaired: the anchor sweep edited the MERGED
#1126 row, which is restored byte-for-byte from origin/main and deliberately
keeps its pre-move anchor because a duplicated row is worse than one stale number;
and a union merge left two byte-identical #1193 rows, one of which is removed.
The file now removes and edits nothing that main has, adds exactly three rows,
and contains no duplicate.

Closes nothing. #1126, #1197, #1205 and #1218 all stay open with their
remaining work stated above.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]

…t a one-line port, and #1126's own step 3 would be a defect (#1126, #1197)

`CudaBackend` still does not override `vt::Backend::DeviceMemoryInfo`, and this
change deliberately does not add it. What it fixes is the record that says how
to close #1126, because as filed that record would produce a defect.

## What was already true, and what was not

#1126 was filed against a seam comment reading "ROCm/CUDA override with
hipMemGetInfo/cudaMemGetInfo". That comment no longer exists. #1132 corrected it
in both places that carried it, `include/vt/backend.h:78-93` and
`gemma4_moe.cpp:440-448`, and recorded the gap under `## Owed` in
`expert-streaming.md`. Every anchor either of them cites was re-verified exact
against `fd64c76ee`: `rocm_backend.hip:338-345`, `gemma4_moe.cpp:440-448`,
`gemma4_moe.cpp:506`, `backend.h:78-93`, `platforms/cuda.cpp:71` and
`platforms/rocm.cpp:74`. Six examined, six correct.

So the comment half of this issue is done, and the honest question left is
whether to build the capability. The answer here is no, and the reason is not
the one the issue gives.

## What Gemma4 does today on CUDA

`Gemma4MoE` is the seam's only consumer. `FreeBytes` returns false on an absent
probe, `MakeRoom` refuses on unknown (`gemma4_moe.cpp:506`), so the device-expert
LRU admits nothing on every CUDA device and every routed expert takes
`ExpertGeGLUHost` instead (`gemma4_moe.cpp:49-74`, reached at `:1493-1499`), for
the life of the process, and nothing reports it.

That function's name misleads and it is worth being exact, because the first
reading here was wrong: it does not compute on the host. It re-copies the
expert's BF16 bytes host-to-device into a scratch buffer (`:59-60`), runs the
same `vt::MatmulBT` / `GeluAndMul` pair on the device, and drains the queue once
per expert (`:73`). So what the dead LRU costs is bandwidth and a per-expert
`Synchronize`, not a wrong answer — the issue's "falls back to host H2D on every
expert" is the accurate description. The refuse-on-unknown polarity at that call
site is right, so the defect is the missing probe rather than the consumer.

## Why the override is not built here

Four things came out of re-reading it, and each raises the price.

1. **There is nothing to run it on.** The LRU needs `ex.is_fp8`, which only
   `LoadMoeFp8PerExpert` sets (`gemma4_weights.cpp:210-215`) from a per-expert
   `F8_E4M3` export. No such Gemma-4 checkpoint is pinned anywhere in
   `docs/USAGE.md`: all 32 lines there matching `gemma` case-insensitively were swept, and every
   checkpoint among them is the LTX-2.5 text tower
   (`gemma4-12b-with-proj*.safetensors`), not a per-expert FP8 MoE decoder. The
   woken path cannot be exercised, here or elsewhere, until one is.
2. **The CUDA consumers are not the ones the ROCm arm measured.**
   `ExpertGeGLUDeviceAccum` (`gemma4_moe.cpp:76-93`) is generic `vt::MatmulBT` /
   `GeluAndMul` / `MatmulBTAlphaBeta` and would run. But
   `RunGemma4FusedTopkExpertGeGLU` (`:1599`), `ExpertGeGLUDeviceBatched` (`:240`),
   `PeerCopyGemma4Fp8ExpertSlice` and `RunGemma4Fp8TopKOnExpertDevice` are
   HIP-only, and a non-HIP build links stubs that return `false`. The override
   would admit experts to VRAM and then route them through the serial per-expert
   fallback: a third path, measured by nobody. Nor is the swap token-neutral by
   construction — the resident arm accumulates with `vt::MatmulBTAlphaBeta`
   (`:90`) where the fallback writes its output outright (`:70`), so the two sum
   the top-k experts in a different order.
3. **The headroom test does not mean the same thing on the CUDA device this
   project gates on.** `MakeRoom` admits iff `free_b >= need + 1.5 GiB`
   (`gemma4_moe.cpp:514`), a constant tuned on discrete dual R9700s where free
   VRAM is distinct from host RAM. On a GB10 it is not. #1123 measured that
   `cudaMemGetInfo`'s `total` there is exactly `/proc/meminfo MemTotal` times
   1024, which is why it reached for that instrument where `nvidia-smi` answers
   `[N/A]`; `free` is therefore reported over the same unified pool, and the host
   BF16 expert cache the device upload exists to relieve is drawn from that pool
   too. The admission test would double-count, on a box whose unified-memory OOM
   takes the host down with it. The `free` half of that is an inference from the
   measured `total` rather than a second measurement, and it wants confirming on
   the device before any override lands.
4. **The gap is isolated, not a pattern.** Comparing overrides one by one across
   `src/vt/cuda/cuda_backend.cu` and `src/vt/rocm/rocm_backend.hip`,
   `DeviceMemoryInfo` is the only optional `vt::Backend` seam ROCm answers and
   CUDA does not.

A dead path with a truthful comment beats a live path nobody has exercised, and
points 2 and 3 say the live path would not even be the one the lab throughput
note was taken on.

## Which answer to "how much device memory" is authoritative

The tree holds two, and they are not duplication.

- `vt::Backend::DeviceMemoryInfo(free, total)` is a **live** probe that moves
  with contention. Authoritative for a **runtime admission** decision — can this
  allocation succeed right now — and for nothing else.
- `vllm::platforms::ResidencyPolicy::device_memory_total_bytes` is a **total**
  probed once at platform registration, `0 == UNKNOWN`. Authoritative for a
  **load-time budget** verdict, which has to be reproducible and independent of
  whatever else the box is doing.

This makes #1126's own closing plan wrong at step 3, which proposes that the
#1123 fit check "can then read the budget from the backend seam". Collapsing the
second onto the first would make the same checkpoint load or be refused depending
on the page cache, which is the property `total`-not-`free` was chosen to avoid.
What #1126 owes is its steps 1 and 2 **together**, the override and the Gemma4
measurement; never step 1 alone, and never step 3. Both seams already carry the
division in prose (`backend.h:90-93`, `platforms/interface.h:61-69`); it is
restated in `## Owed` because that is the record a reader of the issue acts on.

## A second defect, filed in flow

Reading `MakeRoom` line by line turned up #1197. The slot cap is tested before
the eviction loop (`gemma4_moe.cpp:498` against `:499-500`) and `EvictOne`
(`:457`) is the only thing that shrinks `slots`, so after 24 admissions
`VT_GEMMA4_EXPERT_EVICT=1` is a no-op for the life of the process and the cache
degrades permanently to fill-only. It binds only when the slot cap is reached
before the byte budget. Filed and not fixed, for the same reason as above rather
than for effort: the one-line repair wakes more `hipFree` under load, which the
surrounding comments call a permanent `kfd_wait` hang, so the current ordering
may be deliberate. It is owned by `ENG-EXPERT-STREAM` and listed under `## Owed`.

## Why this is a record-only change

The record is the work here: a filed gap whose closing plan is wrong in two ways,
and a newly filed defect. It does not restate what #1132 landed — points 1
through 4, the authority split and #1197 are all new. Leaving it out means the
next agent implements step 3 as written.

No code changed, so there is nothing to mutate and no behaviour to gate. The
gate run is the checker suite.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
…phaBeta`, not a slower third path, and the arm now refuses by name (#1126, #1205)

A fresh review returned FAIL on the record this repairs. The decision it argued
for was right and five of its six substantive claims survive. Its central
technical paragraph was wrong, and on a record-only change a wrong record is the
defect.

## The finding that inverts it

`vt::MatmulBTAlphaBeta` has NO CUDA implementation. `src/vt/fused_ops.cpp:102`
dispatches to `rocm::MatmulBTAlphaBetaRocm` (`rocm_matmul_hipblaslt.hip:516`)
under `#if defined(VLLM_CPP_HIP)` AND `q.device.type == kROCM`; every other
device falls through to a throw. There is no CUDA, Vulkan, Metal or CPU arm.

So the record's claim that `ExpertGeGLUDeviceAccum` "would run" on CUDA is
false. What the override wakes is: `EnsureGemma4Fp8ExpertOnDevice`
(`gemma4_moe.cpp:548-586`, no HIP guard) -> `lru.MakeRoom` at `:565` succeeding
once `FreeBytes` can answer -> `true` at `:575` -> the call site at `:1486` ->
`ExpertGeGLUDeviceAccum` at `:1487` -> `vt::MatmulBTAlphaBeta` at `:90` ->
throw. The `try`/`catch (...)` at `:563-585` wraps only the upload; the compute
at `:1487` is outside it, so the exception leaves the decode step rather than
degrading to the host fallback.

It is latent today only because the other route into that function, `same_dev`
(`:730-731`), needs `ex.gate_up_dev`, assigned nowhere but
`rocm_gemma4_experts.hip:207,226`. The resident arm is unreachable off ROCm, not
safe. That makes the missing CUDA arm the actual blocker for #1126 step 1,
recorded nowhere, and a stronger argument than any of the record's four. Filed
as #1205.

## Three further corrections

`ExpertGeGLUDeviceBatched` (`:240`) was named beside three genuine HIP-only
stubs. It is not one: it sits outside the file's only `#ifndef VLLM_CPP_HIP`
block (`:1574-1628`), has no HIP implementation and no header declaration, and
is unconditionally `return false` under its own lab note at `:237-239`. It is
disabled everywhere, ROCm included, so listing it inflated the ROCm/CUDA
asymmetry. The other three are correct and stay.

"The two arms sum the top-k experts in a different order" is false. Both run
inside the same `for (int i = 0; i < top_k; ++i)` at `:1431`. The real
difference is rounding and where the routing weight is applied: the resident arm
folds `ww` into the GEMM `alpha` and accumulates in the epilogue with `beta`
(`:1434`, `:1442`, `:90`), while the fallback writes the unweighted product to a
BF16 buffer (`:67`, `:70`) and applies `ww` afterwards with separate BF16
kernels (`MulScalar` at `:1524`, `MulScalar` plus `Add` at `:1526-1527`). Two
extra BF16 roundings per expert, weight applied post-rounding. Right
conclusion, wrong mechanism.

"Never step 3" overstated the case, in the spec and in the previous title.
#1126 step 3 proposes the fit check read the budget from the backend seam, and
that seam returns BOTH `free` and `total` (`include/vt/backend.h:94`). Reading
`total` is contention-independent and legitimate. The defensible statement, and
the one the row now asserts: step 3 may read only `total`, never `free`, and
must keep the value probed once at platform registration
(`include/vllm/platforms/interface.h:70-72`).

Two smaller ones. `DevExpertLru::Note` also calls `slots.clear()` at `:522`;
it is a device-index reset rather than an eviction, frees nothing, and is
unreachable in a single-device process, so the #1197 row now names it and the
next reader does not conclude the sweep missed it. And the H2D cost the row
states in the present tense is conditional: the device LRU is `ex.is_fp8`-gated
(`:969`, `:1484`), and by the row's own point (1) no per-expert FP8 Gemma-4
checkpoint is pinned, so on CUDA the fallback is never even asked for today.

## The code this uncovered

`fused_ops.cpp` threw a bare "ROCm-only in this build" mid-decode for an
unimplemented arm. AGENTS.md requires an unimplemented arm to refuse with a
message that names the missing part, and that one named neither the device that
asked nor where an implementation would go, so a caller could not tell a missing
kernel from a missing build flag. It now names all three plus the issue.

`tests/vt/test_gemma4_rocm_fp8_seams.cpp` gates it on a posed CUDA queue and on
`kCPU`, `kVULKAN` and `kMETAL` — the refusal reads only `q.device.type`, so a
CPU build can pose as any device and no ROCm hardware is needed. This is an
in-flow gateable defect independent of #1126, and when someone writes the CUDA
implementation the same test is what it has to satisfy. It pins the
precondition without any checker that says do not fix it.

Red before green: the three message assertions and the three device-name
assertions failed against the old message. Mutation-proven twice, both
compiled, both applied, three cases each, tree restored byte-exact: restoring
the old message goes RED, and deleting the refusal outright goes RED.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
@localai-bot localai-bot changed the title record(ENG-EXPERT-STREAM): the CUDA DeviceMemoryInfo override is not a one-line port, and #1126's own step 3 would be a defect (#1126, #1197) fix(ENG-EXPERT-STREAM): the CUDA blocker is a missing vt::MatmulBTAlphaBeta, not a slower third path, and the arm now refuses by name (#1126, #1205, #1197) Aug 18, 2026
mudler added 2 commits August 18, 2026 08:39
`1f4878fdc` (SPEC-DSPARK-QWEN3-ROUTING) landed while this row's review repair was
in flight, so the preflight trailer and style gates skipped rather than reporting
on this tree. Only `.agents/issue-index.md` overlapped, and it union-merged; the
#1205 row this branch appends and the #1193 row main appends are both present and
neither was edited.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
… row at the right numbered point (#1205)

The `## Owed` rows now say the review repair re-audited every anchor the three
rows cite against the repaired tree, 53 examined and 53 exact, so a reader can
tell a re-verified anchor from a carried-over one. The #1205 row said "this
row's point (1)" for a point that lives in the `DeviceMemoryInfo` row above it.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
mudler added 9 commits August 18, 2026 09:51
…e it happens, and stop telling a ROCm caller the kernel is missing (#1126, #1205, #1197, #1218)

FOLLOWING_AGENTS_PROTOCOL

The review of #1200 returned FAIL on three findings and recommended a fourth
change. This is the repair, and the recommended change is the substance of it.

THE GUARD. #1205 named a cheaper and reachable fix that the first pass did not
take: refuse at the `gemma4_moe.cpp` call site BEFORE the upload rather than
throwing after it. `EnsureGemma4Fp8ExpertOnDevice` now returns false at
`gemma4_moe.cpp:571` when `vt::HasMatmulBTAlphaBeta(d.q)` is false, so the
caller takes the host fallback already sitting in the `else` at `:1515-1521`
and the decode step answers instead of throwing mid-decode. That matters more
than a better message: the reviewer's M3 deleted the production call site at
`gemma4_moe.cpp:90` and the old focused gate stayed fully green, because it
constructed a `vt::Queue` by hand and so measured the class rather than the
capability.

The predicate is not a device-name test and not a build-macro test.
`vt::MatmulBTAlphaBeta` dispatches on `HasMatmulBTAlphaBeta` itself
(`src/vt/fused_ops.cpp:102-109`, dispatch at `:117`), so the two cannot
disagree, and writing a CUDA arm wakes the device path with no edit at the
call site.

`tests/vllm/models/test_gemma4_moe_device_arm_guard.cpp` gates it through
`vllm::RunGemma4Moe` — the layer entry `gemma4.cpp:634` calls — with a real
`Gemma4MoeLayerWeights`, the real router, the real LRU and the real fallback.
It decorates the registered CPU backend so `vt::Backend::DeviceMemoryInfo`
ANSWERS, because that is the post-#1126 state and the only state in which the
guard binds at all: on a stock build `MakeRoom` refuses on the absent probe,
and deleting the guard would change nothing observable. Both directions of the
probe are asserted before anything is concluded, so an instrument that failed
to arm cannot report the guard proven by a run that never reached it. Deleting
the guard turns that test RED with the exact `no implementation for device
'cpu'` throw; forcing the predicate to `true` turns it RED too.

F1. The new refusal was wrong for the one case the old one got right. A kROCM
queue in a build without `-DVLLM_CPP_HIP` falls through the same `#if`, and the
message told it a kernel was missing and pointed it at a CUDA issue. It now
gets its own message naming the absent BUILD FLAG, and the seams test poses
kROCM alongside the four devices that made the old message look right. Say
plainly what that test pins: a contract in a unit test, not observable
behaviour. With the guard in place no production run off ROCm reaches either
string.

F2, F4, F6. #1205's issue body anchors matched `0acf2ca1d` and were eleven
lines stale at `7beada17c`; this change moves them again by twenty-two. Every
anchor in the cluster was re-derived against the final tree — 168 endpoints
across nine rows, none out of range. `fused_ops.cpp:102` was the signature and
the dispatch is at `:117`. The audit headline now states its SCOPE, because
"53 examined, 53 exact, 0 stale" covered four spec rows and never included an
issue body, which is exactly how the body went stale unnoticed. Several bare
`:NNN` anchors also inherited the wrong file after a mid-sentence mention of a
different one; those are spelled out.

#1218 is filed and deliberately NOT fixed here. `EnsureGemma4Fp8NativeOnDevice`
is the DEFAULT arm and carries the same shape, but it depends on three
different ops and needs a predicate per op; reusing `HasMatmulBTAlphaBeta`
there would be a guard naming the wrong arm, which is the exact defect this
review just corrected in a refusal message. It is owned by `ENG-EXPERT-STREAM`
and listed under `## Owed`.

Two `.agents/issue-index.md` rows are EDITED rather than appended. Both were
added by this branch and have not merged, so no other branch can hold a
different version of them, and the append-only rule protects merged rows
against a duplicating union merge.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
FOLLOWING_AGENTS_PROTOCOL

Bring the branch level with origin/main so the commit-trailer and commit-style
gates run instead of skipping. Only .agents/issue-index.md differs, and it
carries merge=union.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
…kend after main, and name gemma4.cpp in full (#1205)

FOLLOWING_AGENTS_PROTOCOL

`vt::RegisterBackend` documents that all registration completes before `main()`,
and the guard test calls it after. The contract buys the absence of
synchronization on the read path, and this binary is single-threaded across the
swap, so there is no concurrent reader to race — but a reviewer should not have
to derive that, and an undiscussed contract violation reads as one that was not
noticed.

`gemma4.cpp` is also spelled in full. Two files in this tree carry that name and
the shorter form resolved to the 123-line tool parser, where `:634` is out of
range — the same class of defect as a stale line number.

Comment-only: the diff contains no non-comment line.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
FOLLOWING_AGENTS_PROTOCOL

Bring the branch level with origin/main so the commit-trailer and commit-style
gates run instead of skipping; a skipped gate reported nothing about this tree.

`src/vt/rocm/rocm_backend.hip` moved on main and this row's records anchor
`DeviceMemoryInfo` there, so every anchor is re-derived against the merged tree
rather than assumed to have held.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
…merge moved, and check anchors semantically rather than only for range (#1205)

FOLLOWING_AGENTS_PROTOCOL

Merging origin/main moved `RocmBackend::DeviceMemoryInfo` from `:338-345` to
`:358-365`, and five citations across the spec and the issue index still pointed
at the old lines. That is this row's third stale-anchor defect, and the first one
caused by somebody else's diff rather than its own.

The range-only audit did not catch it. An anchor that is still IN RANGE can
point at the wrong line, and a checker that only asks "does this line exist"
reports OK for exactly the failure it was written to find. The audit is now
two instruments: 168 endpoints resolved for range, and 69 load-bearing anchors
asserted against the substring the prose claims lives there. The second one is
what found this.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
…-byte (#1205)

FOLLOWING_AGENTS_PROTOCOL

Re-deriving the moved `rocm_backend.hip` anchor was done with a blanket string
replace over `.agents/issue-index.md`, and it hit the `#1126` row as well as this
branch's own. That row is already on `main`. Editing a merged row is exactly what
the append-only rule forbids, because the union driver DUPLICATES an edited line
instead of merging it — the gate caught it, and it was right to.

The row is restored from `origin/main`, and the file now removes or edits nothing
that main has: it adds three rows, #1197, #1205 and #1218, all appended by this
branch. Those three are still editable because they have not merged, so no other
branch can hold a different version of them.

The merged `#1126` row keeps its pre-move anchor deliberately. One stale number
in an append-only log is a smaller problem than a duplicated row, and the spec's
`## Owed` entry carries the current anchor and says so.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
FOLLOWING_AGENTS_PROTOCOL

Level the branch with origin/main again so the trailer and style gates run
instead of skipping. This merge brings a compiler-warning change
(`cmake/CompilerWarnings.cmake`, the gcc 16 lane), so the tree is rebuilt and
re-gated rather than assumed to still compile: a clean merge is not a merge that
builds.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
…1205)

FOLLOWING_AGENTS_PROTOCOL

`.agents/issue-index.md` carried two byte-identical `#1193` rows after merging
origin/main, and `check-agent-record.py` refused: under `merge=union` a duplicate
is what two branches appending the same issue look like, so the checker cannot
tell that case from this one and is right to stop.

The two copies were compared before either was touched, and only then was the
stray one removed. The surviving row is the one whose position matches
origin/main's ordering (after `#1190`); the deleted one sat inside this branch's
own appended block, which is where the union driver placed it.

The file now removes and edits nothing that main has, adds exactly `#1197`,
`#1205` and `#1218`, and contains no duplicate row.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
FOLLOWING_AGENTS_PROTOCOL

Level the branch with origin/main so the trailer and style gates run against it
rather than skipping. This merge brings `scripts/check-symbol-anchors.py`, a gate
on exactly the failure this row has now produced three times, so it is run over
this branch's records rather than merely inherited.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
FOLLOWING_AGENTS_PROTOCOL

Level the branch with origin/main so the trailer and style gates keep reporting
rather than skipping. This merge carries #1234, which repairs the
`test_check_gate_commands` red this branch inherited: that gate failed here on
three files whose blob SHAs were identical to main's, so it was never this
change, and it is now fixed at the source rather than worked around.

No source file this row anchors is touched by the merge, and every anchor is
re-checked against the merged tree anyway.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5-1m [Claude Code]
@localai-bot localai-bot changed the title fix(ENG-EXPERT-STREAM): the CUDA blocker is a missing vt::MatmulBTAlphaBeta, not a slower third path, and the arm now refuses by name (#1126, #1205, #1197) fix(ENG-EXPERT-STREAM): the CUDA blocker is a missing vt::MatmulBTAlphaBeta, and the Gemma-4 device-expert upload now refuses before it happens (#1126, #1205, #1197, #1218) Aug 18, 2026
localai-bot pushed a commit that referenced this pull request Aug 18, 2026
`origin/main` advanced to 65d6cda while this branch's review repair was being
written: the gcc 16 build lane, the ROCm attention-backend selection, and
`vt::MatmulFp8BlockScaled`. Sixty-five files on the incoming side, mostly
additive.

Four files are edited on both sides — `CMakeLists.txt`, `tests/CMakeLists.txt`,
`include/vllm.h` and `.agents/issue-index.md` — and git reported no conflict in
any of them. `.agents/specs/expert-streaming.md` is the one to watch, because
open PR #1200 edits its `## Owed` table two rows above this branch's #1127 row;
#1200 has not landed yet, so this merge does not meet it. If it lands first, the
next merge takes the target-branch version of that file whole and re-applies the
one scoped row, as AGENTS.md requires for a keyed record — never the automatic
three-way result.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
localai-bot pushed a commit that referenced this pull request Aug 18, 2026
`origin/main` advanced to c20018f while the review repair's gate was running:
the CUDA-graph dedup device record, and `GATE-SYMBOL-ANCHORS`, which replaces
`file:line` citations with symbol citations and adds a checker for them.

Three files are edited on both sides. `tests/vllm/entrypoints/test_gguf_device_fit_reach.cpp`
takes an anchor rewrite at line 62 on the incoming side and this branch's "These
two / three cases" correction at line 321; git reported no conflict and the two
hunks are 250 lines apart. `docs/USAGE.md` and `.agents/issue-index.md` likewise
merge without a conflict. `.agents/specs/expert-streaming.md` is untouched on the
incoming side, so the #1127 `## Owed` row this branch edits still needs no manual
reconciliation; PR #1200, which edits that table two rows above, is still open.

The full gate is rerun on the merged tree rather than inherited from the
pre-merge run, because a clean merge is not a merge that builds.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
The base moved while the guard was under review and repair.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
@localai-bot
localai-bot merged commit c802dba into main Aug 18, 2026
1 check failed
@localai-bot
localai-bot deleted the row/ENG-EXPERT-STREAM-1126 branch August 18, 2026 14:32
localai-bot pushed a commit that referenced this pull request Aug 18, 2026
The base moved while W2 was under review and repair, and #1200 landed edits to
`.agents/specs/expert-streaming.md` two rows above this row's own entry.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]

# Conflicts:
#	.agents/specs/expert-streaming.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants