Skip to content

feat(#810 A2-R): NemotronH's dense weights reach the device, and the attention block that reads them is model-local (#517) - #950

Merged
localai-bot merged 8 commits into
mainfrom
row/MODEL-NEMOTRON-H-ABI-A2A
Aug 16, 2026
Merged

feat(#810 A2-R): NemotronH's dense weights reach the device, and the attention block that reads them is model-local (#517)#950
localai-bot merged 8 commits into
mainfrom
row/MODEL-NEMOTRON-H-ABI-A2A

Conversation

@localai-bot

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

Copy link
Copy Markdown
Collaborator

Implements A2-R of .agents/specs/nemotron-h-abi-e2e.md, issue #810, parent row #517.

A2 was scoped as one unit and came back as a campaign. This is the first landable piece: the weights the device can actually execute move onto the tree's shared residency seam, and the 6 GQA attention layers compute there.

⚠ The unit names, because the obvious ones collide

The spec's §1 "permitted split" (lines 236-241) already defines an A2a and an A2b, and they are not this campaign's units. The spec's A2a is the paged unit — the one that narrows the G-SAFE interlock. An earlier revision of this PR also called itself A2a, so a reader grepping A2a landed here and expected the interlock to have moved. It has not. A2b is taken twice over: the spec's batching unit, and Laguna's unrelated "Brick A2b" (src/vt/cuda/cuda_laguna.cu:368).

name what it is interlock
A2-R THIS unit. Dense weights on the shared OwnedTensor seam; embeddings, 52 norms + norm_f and the 6 GQA blocks on the device untouched
A2-Q the NVFP4 / FP8 device arms (nemotron_h.cpp:1023) untouched
A2-P the spec's A2a — single-request paged decode narrows it to num_reqs > 1
A2-B the spec's A2b — batching drops the num_reqs clause

The rename is in the tree, not only here: the three TEST_CASE names, all 36 former Greek references across the model sources, the CMakeLists.txt source entry, both doc rows, and this PR's title. The mapping is recorded at tests/vllm/models/test_nemotron_h_forward.cpp §8 so it is greppable.

src/vllm/model_executor/models/nemotron_h_registry.cpp is the one deliberate exception. It still says A2b, in the spec's own sense, and the file is byte-identical to main: it carries the G-SAFE interlock, and an empty diff on it is evidence a reviewer reads directly. Touching it to fix a comment would cost that.

What runs where, and why the line falls there

DEVICE the embedding lookup, all 52 layer norms + norm_f, the 6 GQA attention blocks. The residual stream is device-resident for the whole forward.
HOST the 23 Mamba2 blocks, the 23 MoE blocks, lm_head.

The line is drawn by the memory format the checkpoint ships, not by taste. The released checkpoint is MIXED_PRECISION and only 216 of its tensors are plain bf16 (gated: test_nemotron_h_loader.cpp:254). Everything put on the device comes from that population; everything left on the host does not:

  • The 23 Mamba2 blocks are entered through mixer.in_proj, FP8 W8A8. The block is not splittablein_proj produces the fused zxbcdt that both the conv and the scan consume — so it moves as a unit, after the shared FP8 W8A8 linear seam is extracted out of qwen3_5.cpp (ResidentFp8:1456, MatmulFp8CutlassD:1495). That is The FP8 W8A8 linear path is not a shared seam: residency and GEMM entry points live inside qwen3_5.cpp, so a second model cannot reach them without hand-rolling a parallel path #940, deliberately not done here: its own gate is Qwen3.5 byte-identity, which does not belong in a NemotronH row.
  • The 5934 expert projections and lm_head are NVFP4 W4A16 g16: 30.19e9 parameters, 15.8 GiB packed, 56.2 GiB dequantized to bf16. There is no device NVFP4→bf16 dequant kernel in vt at all (the only standalone device dequant is vt::DequantFp8ChannelBf16, fused_ops.h:31, ROCm-only and per-channel FP8), so a "bf16 everywhere" device forward means a host dequant plus a 56.2 GiB upload. Both gate hosts are unified-memory, so that is a reboot, not an OOM. nemotron_h_loader.h:36-46 rejected the same design for the load.

What this does NOT prove

46 of 52 layers still compute on the host. lm_head still computes on the host. Nothing here is paged, nothing batches, and no throughput number is recorded or implied — this arm is slower than the host reference, because each host layer costs one download plus one upload. That bounce is scaffold, not architecture; every later unit deletes one pair of it.

Nothing production-facing reaches the new code. NemotronHDeviceForward and NemotronHAttnBlockHostIO are called only from test_nemotron_h_forward; ForwardNemotronHForCausalLM still routes to the host NemotronHForward. That is disclosed rather than hidden, and it is A2-P that must wire the device arm through ModelRegistry::Forward or the arm stays dead. Owed, named, and tracked on #810.

G-SAFE is fully intact

All three clauses at nemotron_h_registry.cpp:161-170attn_kv.empty(), gdn_state.empty(), num_reqs <= 1 — are untouched. The branch does not modify that file at all. This arm is non-paged and single-request, so it creates none of the capability the interlock guards and therefore does not narrow it.

Not dense_attn::AttnBlock (#941)

The spec's §2 names it as this model's seam. That is wrong, and routing there would reintroduce the exact defect #810 removed from the runner — a shared function reading HF-config fields this architecture does not ship. Three measured reasons:

  1. It takes Qwen3DenseAttnWeights (dense_attn_block.h:335), not this model's separate q/k/v/o.
  2. It reads cfg.rms_norm_eps. This config ships layer_norm_epsilon and norm_eps and no rms_norm_eps, which hf_config.cpp:551 defaults to 0.0 — a silent eps=0 normalization.
  3. Its default path calls vt::RopeNeox unconditionally (:496) against kNemotronHAttentionHasNoRope.

NemotronHAttnBlock follows the tree's model-local idiom (granite.cpp:84, gemma.cpp:42, glm4.cpp:80, none allowlisted) and documents its six deltas.

Not a d_dev on NemotronHOwned

That was the smaller diff and it is the parallel path AGENTS.md forbids. Dense weights move to the shared OwnedTensor and upload through dense_attn::ResidentWeight. NemotronHOwned survives for the quantized weights, precisely because OwnedTensor carries no form, no group scale and no input_scale — converting a quantized weight to it would discard the memory format the checkpoint ships.

Review repairs (findings on f77dbac3f)

Four of the seven findings were one defect wearing different clothes: an assertion that cannot fail reads exactly like one that passes.

F1 — the "armed margin" observed nothing, and used the wrong dtype's number

DevRelFor(dt) * 5 < kRopeSeparation compared two compile-time constants, so it measured nothing about the running system. And 2.11e-2 was the f32 arm's separation. Measured live, per dtype, on this fixture (Thor sm_110):

arm a rotation moves this block by band ratio
f32 2.10893e-2 1e-5 2109x
bf16 1.97151e-2 4e-3 4.93x

So the stored constant was ~6% too large for bf16 — and once the real number is read, the invented * 5 factor reds a bf16 arm that is in fact correctly armed. Lowering 5 to 2 to get green would be widening a scope to turn a gate green, which is the one thing AGENTS.md forbids outright.

The proxy is gone. The case builds the rotated counterfactual from the same per-dtype fixture (RefAttentionRotated, which carries its own q_moved instrument) and asserts the property: run the rotated answer through the same ExpectCloseRel arithmetic that accepted the real one, and require it to come out rejected. No stored twin, no safety factor, measured per dtype per run. The host no-RoPE case shares the helper, deleting 40 lines of inlined attention core.

F2 — the residency case gated a test-local copy, and nk had no reader at all

The fixture builds its OwnedTensors with the test's own OwnT, not with production CopyDenseOwned. It can prove the device arm consumes the type; it can never see the loader mis-produce it. Both halves are now closed against the real checkpoint.

host_bytes was printed and read by nothing. Truncating every production payload to half moved it 470 MiB with the forward suite 16/16 green and 3/3 oracle goldens still MATCHING — a shrunk std::vector keeps its buffer, so View() reads the same values back and only the accounting moved. Both totals are now asserted exactly, against the content-pinned revision.

CHECK(rep.host_bytes == rep.source_bytes) is deliberately NOT in the file, because it is false. The review proposed it on the strength of the printed line host bytes: 18013 MiB, source 18013 MiB, but MiB resolution hides the difference: measured exactly, they differ by 15324 bytes, so that assertion would have redded on correct code. What is asserted instead is both exact totals and the identity that explains the gap, so the number is accounted for rather than tolerated.

bytes
6039 f32 scalars READ but never stored as payload (5935 NVFP4 weight_scale_2 + 46×2 FP8 + 12 fp8-KV) −24156
the 69 f32-by-contract SSM widenings (23 × 3 × 64 heads × 2 B) +8832
host_bytes − source_bytes −15324

nk had no consumer on this path, exactly as the review found: View() does not propagate it and both arms called vt::MatmulBT unconditionally. Rather than delete the intent, it now has a real reader in the tree's own idiom (qwen3_5.cpp:3353, :3611, :7638): the two functions that call MatmulBTnemotron_h.cpp:317 (host) and nemotron_h_device.cpp:261 (device) — refuse a weight whose recorded orientation is not the [out, in] one MatmulBT reads. The tautological fixture assertions are deleted.

F3 — the GB10 leg is RUN, not owed: the bands transfer unchanged

The review asked for this to be documented as owed, because dgx's gpu.lock was held. It came free, so the leg was run instead, and F3 is closed by measurement rather than by a note.

The concern was specific and correct: the bands were calibrated against Thor's fallback kernels, with fa2 and cutlass-* reporting DISABLED for [110]. On GB10 the same device arm runs FA2 + CUTLASS GEMMs against the same CPU host reference, and the f32 band 1e-5 sat only 4.4x above Thor's measured 2.29e-6. A different attention kernel could plausibly have eaten that.

It did not. The separation is identical to Thor's, to six figures.

Thor sm_110 (fallback) GB10 sm_121a (FA2 + CUTLASS)
f32 device-vs-host separation 2.29122e-06 2.29122e-06
bf16 device-vs-host separation 0 (bit-exact) 0 (bit-exact)
f32 band DevRelFor 1e-5 unchanged, 4.4x headroom
bf16 band DevRelFor 4e-3 unchanged
rope separation f32 / bf16 2.10893e-2 / 1.97151e-2 identical

The rope separations matching exactly is expected and is a property of the repair: the counterfactual is built from the fixture in double precision on the host, so it is host-independent by construction. The device-vs-host separations matching is the actual finding — this arm's ops (vt::Attention, MatmulBT, RmsNorm, Embedding, FusedChain) land on the same answer through both kernel families.

The build is the non-degraded one, which is what makes the result admissible. A degraded build here would answer the Thor question twice rather than the GB10 question once, so the script voids rather than fails on any missing fast path. Configure at 121a:

-- CUDA target architectures: 121a
--   CUDA feature fp4-mma: ENABLED for [121a]
--   CUDA feature cutlass-nvfp4: ENABLED for [121a]
--   CUDA feature cutlass-fp8: ENABLED for [121a]
--   CUDA feature marlin-nvfp4: ENABLED for [121a]
--   CUDA feature fa2: ENABLED for [121a]
-- CUTLASS found at /cutlass; enabling sm120a NVFP4 cutlass GEMM
-- Triton AOT: ... <- sm_121a as vt_aot_sm_121a_gdn_deltah_h48_default
VOID_FLAG=0

cutlass-fp8: ENABLED, so the result stands. BUILD_EXIT=0, compile_errors: 0, enospc_hits: 0, -j 4, 3.0 TB free. Binaries a330e72f… / 68eb1e88….

suite, GB10 sm_121a cases assertions status
test_nemotron_h_forward 16 / 16 5716 SUCCESS
test_nemotron_h_scaffold 14 / 14 38302 SUCCESS
test_nemotron_h_loader (real checkpoint) 2 / 2 53 SUCCESS, 3/3 oracle goldens MATCH

host bytes exact: 18888922112, source bytes exact: 18888937436byte-for-byte the Thor values, which is the evidence that the two new exact literals are properties of the pinned checkpoint plus the loader and not of a host.

Two honest caveats on this leg. local-ai-worker was not parked: there is no systemd unit by that name on dgx in its current state, so systemctl stop was a no-op and the ./local-ai worker process ran throughout. That is inert for this measurement — every number here is a numerical separation, not a timing — and it would have voided a throughput result, which this row does not record. Free memory during the run was 114 GiB of 119, so there was no pressure. The gpu.lock was held for the whole run via flock and is released.

F5 — "both arms share one reader" is not literally true

nemotron_h.cpp:56 and nemotron_h_device.cpp:126 are two file-local function-local statics with byte-identical predicates, latching independently. Nothing straddles today and the duplication is the tree's idiom (qwen3_5.cpp:1699), but the comment claimed impossibility. It now says what is true: a convention, not an impossibility, and hoisting the predicate is a tree-wide change rather than this row's.

F7 — one dead device allocation per layer per step

DBuf mixer_out(d, adt, {T, H}) was allocated and then move-assigned over on both branches. The mixer output now goes straight into carry, which is the only thing that reads it; the previous carry block returns to the pool at exactly the same statement as before, so the lifetimes are unchanged. No speed claim is made or implied.

Gate

Thor (sm_110), FRESH build directory, real checkpoint

Both gate hosts were exercised — Thor below, GB10 in F3 above. Spec §5.4 requires both, and Thor is the portable/fallback path rather than a second CUDA host.

COMPILE_EXIT=0   compile_errors: 0   warnings: 0   enospc_hits: 0
suite cases assertions status
test_nemotron_h_forward 16 / 16 5716 SUCCESS
test_nemotron_h_scaffold 14 / 14 38302 SUCCESS
test_nemotron_h_loader (real 20.1 GiB checkpoint) 2 / 2 53 SUCCESS, 3/3 oracle goldens MATCH

Baseline binaries: test_nemotron_h_forward 34a49eaf…, test_nemotron_h_loader 4cfeb7e9…. Device confirmed in-container (NVIDIA Thor), no skip message emitted. Per case, each with a non-zero case count:

case cases assertions
device-consumed weights are in the shared residency type 1 5408
device attention block matches the host reference block for block 1 34
hybrid device forward matches the host reference token for token 1 20

The gate was re-run at the pushed head, not only at the head the mutations used. The final commit is comment-only, and the rebuilt binaries hash to 34a49eaf… / 4cfeb7e9…byte-identical to the baseline — so the whole mutation table below is valid at the merged head rather than at a superseded one.

Resolved checkpoint directory recorded as evidence: /w/ckpt/nemotron-3.5-lightning-30b-nvfp4, VT_NEMOTRON35_SNAPSHOT unset. host bytes exact: 18888922112, source bytes exact: 18888937436. Thor disk 338 GiB free before and after.

Mutations

Each applied alone to a scratch copy with anchor uniqueness (count == 1) asserted on every edit, rebuilt, run, then restored — and every restore rebuilds back to the baseline binary sha, which is the control that proves the tree came back byte-for-byte.

# mutation compile mutated sha result
M2 the device block applies the NeoX rotation this architecture does not have 0, 0 errors fwd b8394994… RED BOTH DTYPES. attention case 34 assertions / 5 failed (3 at f32, 2 at bf16); hybrid 20 / 4 failed. bf16 device-vs-host separation 0.0200768 against band 0.004
M3 revert to the old RelFor bands with both new guards disabled, plus M2 0, 0 errors fwd 4a42e062… RED f32 ONLY in the attention case: 34 / 2 failed, both f32; bf16 GREEN. The historical hole, reproduced
M3B widen the bands back to RelFor, no product mutation at all 0, 0 errors fwd 0c30f4e1… RED bf16 ONLY: 34 / 2 failed, both bf16; f32 GREEN. The new guard alone closes the hole, on correct code
M4 the loader records the wrong nk for all four attention projections 0, 0 errors fwd e22fb03f…, loader ea0f360b… forward 16/16 GREEN (the synthetic fixture is blind, as the review said); loader 2 cases / 1 FAILED, THREW weight 'mixer.q_proj' is not in the [out, in] torch-Linear orientation vt::MatmulBT consumes
M5 production CopyDenseOwned truncates every payload to half 0, 0 errors fwd 5f113cce…, loader 3771a85f… forward 16/16 GREEN and 3/3 goldens still MATCH; loader 53 / 2 failed on host_bytes == 18888922112 (read 18396080000) and on the composition identity
M3, first attempt COMPILE_EXIT=1, 1 error (unused variable 'atol') fwd b8394994…identical to M2's, i.e. unchanged VOID, not a result. Reported rather than counted: it would have read as a pass

Two traps caught by the harness rather than by luck, both worth recording:

  • A mutation that fails to build reads as a passing test. The first M3 attempt did not compile, and the binary it ran was M2's. Printing COMPILE_EXIT, the error count and the sha beside every result is what caught it.
  • shutil.copy2 preserves mtime, and ninja keys on mtime. A restored file older than its object silently keeps the previous mutation's object in the binary — the first M3B run reported a rotated device arm on unmutated source. Fixed by stamping mtime on restore, and the restore-to-baseline-sha control now makes that class of error impossible to miss.

M4 and M5 are both caught only by the checkpoint-gated loader suite, because they are defects in how the loader produces a weight and no synthetic fixture runs that code. That is stated plainly rather than presented as CI coverage.

Full gate

ctest on the local x86_64 development arm, whole suite: 485 / 485 passed, 0 failed (2 skipped: test_modelopt_mixed_precision_checkpoint, test_voxtral_e2e), 488.96 s.

scripts/agent-preflight.sh: 1 gate failed — test_cpu_x86_llamacpp_floor — and it is not this change's, which was verified rather than assumed. The failure is NO_QUIET_WINDOW … exit 4, the harness refusing to measure, not a floor violation, on a box at load average 157 from this session's own 973-target build. Re-run at load average 15 on the same tree: Ran 10 tests in 49.154s / OK, exit 0. So it is a load artefact, and the local gate is green on a quiet box. This diff touches no CPU and no llama.cpp path. The inherited baseline was RE-MEASURED on this head rather than subtracted from a list. That matters, because it shrank: 4880c5715 — picked up by the pinned merge above — landed #904's LTX-2.5 device use-after-free, and sanitize-cpu is now GREEN on both legs (address,undefined 41m17s, thread 44m45s). It is therefore no longer inherited, and a red there would have been mine. The seven #873 gates are likewise green, repaired by #878, and are not subtracted.

That leaves exactly one inherited red on CI: windows-msvc-cpu and windows-msvc-vulkan (#584), which have no main baseline and so are red on every PR. Verified rather than assumed to be inherited — both were already failing on the reviewed head f77dbac3f (gh api .../commits/f77dbac3f.../check-runswindows-msvc-cpu failure, windows-msvc-vulkan failure), and the failing step is Build and execute the native Windows CPU focused gate. Everything else on the PR passes, including cuda-fat-build (1h20m35s), build-test-cpu, build-test-cpu-arm64, build-test-vulkan, device-leakage, pr-size, agent-record, documentation-checkpoint and commit-protocol-tag.

origin/main was merged at the pinned SHA 4880c5715 per #841. Three files overlap — CMakeLists.txt, docs/FEATURES.md, docs/USAGE.md — and all three are keyed; git diff 4880c5715 after the merge is exactly this row's own edits and nothing else, so every other key came from the target byte-for-byte. The merge also caught the one file the rename had missed (CMakeLists.txt:882).

Docs: FEATURES.md and USAGE.md updated (both owed and both demanded by check-doc-checkpoint). No lifecycle change, so no STATUS/BENCHMARKS/NOW write is owed.

One trap this PR hit, recorded rather than worked around

commit-protocol-tag reported this body as missing Following-Agents-Protocol and AI-Assisted while it carried both, correctly, in a well-formed final paragraph. The cause was two bare --- markdown horizontal rules: squash_merge_commit_message = PR_BODY makes this body the landed commit message, and git interpret-trailers treats a bare --- as the end of a commit message, so everything below it — trailer block included — is never parsed. Measured both directions on the stored body: --parse returned nothing; sed 's/^---*$/***/' returned all three trailers. The checker was right and the body was wrong. Written up in .agents/style/commits.md so the next author is told which character did it. A table's |---|---| is unaffected — the line is not bare.

Follow-ups filed and referenced, not folded in: #940 (extract the shared FP8 W8A8 linear seam), #941 (the spec's §2 dense_attn::AttnBlock naming is wrong).

FOLLOWING_AGENTS_PROTOCOL

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

mudler added 5 commits August 15, 2026 18:26
…ttention block that reads them is model-local (#517)

A2 was scoped as one unit and came back as a campaign. This is A2a, the first
landable piece: the weights the device can actually execute move onto the
tree's shared residency seam, and the 6 GQA attention layers compute there.

WHY THE LINE FALLS WHERE IT DOES. The released checkpoint is MIXED_PRECISION
and only 216 of its tensors are plain bf16 (gated: test_nemotron_h_loader.cpp
:254). Everything this change puts on the device comes from that population.
Everything it leaves on the host does not:

  * the 23 Mamba2 blocks are entered through `mixer.in_proj`, FP8 W8A8. The
    block is NOT splittable -- in_proj produces the fused zxbcdt the conv and
    the scan both consume -- so it moves as a unit, after the shared FP8 W8A8
    linear seam is extracted out of qwen3_5.cpp (ResidentFp8:1456,
    MatmulFp8CutlassD:1495). That is #940 and is deliberately not done here:
    its own gate is Qwen3.5 byte-identity, which does not belong in this row.
  * the 5934 expert projections and lm_head are NVFP4 W4A16 g16 -- 30.19e9
    parameters, 15.8 GiB packed and 56.2 GiB dequantized to bf16. There is no
    device NVFP4->bf16 dequant kernel in vt at all, so a "bf16 everywhere"
    device forward means a host dequant plus a 56.2 GiB upload. Both gate hosts
    are unified-memory, so that is a reboot rather than an OOM.
    nemotron_h_loader.h:36-46 rejected the same design for the load.

So 46 of 52 layers still compute on the host, lm_head still computes on the
host, and each host layer costs one download plus one upload. That bounce is
scaffold, not architecture, and every later unit deletes one pair of it. NO
SPEED CLAIM IS MADE OR IMPLIED.

NOT dense_attn::AttnBlock (#941). The spec's section 2 names it as this model's
seam and that is wrong: it takes Qwen3DenseAttnWeights, it reads
`cfg.rms_norm_eps` -- which this config does not ship, so hf_config.cpp:551
defaults it to 0.0 -- and its default path calls vt::RopeNeox unconditionally
against kNemotronHAttentionHasNoRope. Routing there would reintroduce the exact
defect #810 just removed from the runner. NemotronHAttnBlock follows the
tree's model-local idiom (granite.cpp:84, gemma.cpp:42, glm4.cpp:80) and
documents its six deltas.

NOT a d_dev on NemotronHOwned. That was the smaller diff and it is the parallel
path AGENTS.md forbids. The dense weights move to the shared OwnedTensor and
upload through dense_attn::ResidentWeight. NemotronHOwned survives for the
quantized weights precisely because OwnedTensor carries no form, no group scale
and no input_scale, so converting a quantized weight to it would discard the
memory format the checkpoint ships.

G-SAFE IS FULLY INTACT. All three clauses at nemotron_h_registry.cpp:161-170 --
`attn_kv.empty()`, `gdn_state.empty()`, `num_reqs <= 1` -- are untouched. This
arm is non-paged and single-request, so it creates none of the capability the
interlock guards and therefore does not narrow it.

THE GATE IS NUMERIC, NOT TOKEN-ONLY. A too-wide dtype and a wrongly-applied
rotation are both invisible to tokens, so the device attention block is
compared against the host reference element by element through ExpectCloseRel
(which self-certifies by requiring the band to reject an all-zeros answer), and
the no-RoPE property is proven by SEPARATION against a rotated reference with
the rotation instrument checked first. Both arms now route the residual
add+RMSNorm through vt::FusedChain, so they compose the identical op sequence
and differ only in which backend runs it -- check-fusion-consistency caught
that the first draft did not, which would have made the equivalence claim a
comparison of two different compositions.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
Merged at a PINNED SHA rather than the moving ref: this checkout is shared and
origin/main advances under a long-running row, so a diff against the REF would
accuse this branch of dropping files it never touched.

Overlap is docs/FEATURES.md and docs/USAGE.md only, both KEYED tables. The
NemotronH row is the only key this branch edits; every other key is taken from
the target wholesale.

Also picks up bc6433d (#878), the repair for the #873 checker regression that
this row measured as its inherited red baseline.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
…on, and bf16 is the checkpoint's dtype

MEASURED coverage hole, found by running the mutation rather than by reasoning
about it. M2 (apply the RoPE this architecture does not have) reded f32 and
stayed GREEN at bf16:

  rope separation .................. 2.11e-2   (Thor sm_110, measured)
  RelFor(kBF16) .................... 3.0e-2    (band -- ABOVE the separation)

So the bf16 arm accepted a fully rope'd answer, and bf16 is the released
checkpoint's own model dtype. A mutation that stays green is a coverage hole,
not a pass.

The band was wrong because it was the WRONG BAND. RelFor is calibrated for a
forward against an independent f64 reference and has to absorb the whole
accumulated error of the port. Device-vs-host is far tighter: identical vt:: op
sequence, identical dtype, only the backend differs. Measured on Thor with the
band driven to 1e-9:

  f32   worst element slack 2.42e-08, whole-output separation 2.29e-06
  bf16  passes at 1e-9 outright -- the bf16 store absorbs the f32-level
        difference entirely

DevRelFor is therefore f32 1e-5 (~4x over the measured separation) and bf16
4e-3 (about one bf16 ULP, the smallest band that cannot flake on another GPU's
reduction order). Both sit far below 2.11e-2.

And the margin is now ASSERTED rather than remembered: the case checks
`DevRelFor(dt) * 5 < kRopeSeparation`, so a future widening of the band fails
THERE instead of silently disarming the no-RoPE property.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
… watched a test-local copy, and `nk` had no reader at all

Review findings on f77dbac. Four of the seven were the same defect wearing
different clothes: an assertion that cannot fail reads exactly like one that
passes.

F1 -- THE MARGIN WAS TWO COMPILE-TIME CONSTANTS, AND THE WRONG DTYPE'S NUMBER.
`DevRelFor(dt) * 5 < kRopeSeparation` compared a constant with a constant, so it
observed nothing about the running system, and `2.11e-2` was the f32 arm's
separation. Measured live, per dtype, on this fixture:

  f32   a rotation moves this block by 2.10893e-2   band 1e-5     ratio 2109x
  bf16  a rotation moves this block by 1.97151e-2   band 4e-3     ratio 4.93x

So the stored constant was ~6% too large for the bf16 arm, and the invented `*5`
factor REDS a bf16 arm that is in fact correctly armed. Lowering 5 to 2 to get
green would be widening a scope to turn a gate green.

The proxy is gone. The case now builds the rotated counterfactual from the same
per-dtype fixture (`RefAttentionRotated`, which carries its own instrument) and
asserts the PROPERTY: run the rotated answer through the SAME `ExpectCloseRel`
arithmetic that accepted the real one, and require it to come out REJECTED. No
stored twin, no safety factor, measured per dtype per run. The host no-RoPE case
shares the helper, which deletes 40 lines of inlined attention core.

M3B proves the repair is what closes the hole, with NO product mutation at all:
widen the band back to `RelFor` and the guard reds at bf16 ONLY (2 assertions),
while f32 stays green. That is the historical hole, isolated.

F2 -- THE RESIDENCY CASE GATED `OwnT`, NOT `CopyDenseOwned`. The fixture builds
its OwnedTensors with the test's own helper, so it can prove the device arm
CONSUMES the type and can never see the loader mis-PRODUCE it. Two consequences,
both now closed against the real checkpoint:

  * `host_bytes` was printed and read by nothing. Truncating every production
    payload to half moved it 470 MiB with 16/16 green and 3/3 oracle goldens
    still MATCHING -- a shrunk std::vector keeps its buffer, so only the
    accounting moved. Both totals are now asserted EXACTLY, and the 15324-byte
    gap between them is accounted for rather than tolerated: -24156 for 6039
    f32 scalars read but never stored as payload, +8832 for the 69 f32-by-
    contract SSM widenings. `host_bytes == source_bytes` would have been wrong.
  * `nk` had NO READER on this path. `View()` does not propagate it and both
    arms called `vt::MatmulBT` unconditionally, so `CHECK(aw.q_proj.nk)` recorded
    an intent. It has a consumer now, in the tree's own idiom (qwen3_5.cpp:3353,
    :3611, :7638): the two functions that CALL MatmulBT refuse a weight whose
    recorded orientation is not the [out, in] one MatmulBT reads. The tautological
    fixture assertions are deleted.

F4 -- THE NAMES COLLIDED ON THE GREPPABLE SURFACES. The spec's `A2a` is the PAGED
unit, the one that NARROWS the interlock; this one does not narrow it. `A2b` is
taken twice (the spec's batching unit and Laguna's "Brick A2b",
cuda_laguna.cu:368). Renamed throughout -- test case names, the 35 Greek
references, the docs rows and the PR title -- to A2-R residency / A2-Q quantized
/ A2-P paged / A2-B batching, with the mapping recorded in-tree where a reader
greps rather than only in a PR body.

F5 the "can never straddle" claim is softened to what is true: two file-local
statics with identical predicates, a convention rather than an impossibility.
F7 removes one dead device allocation per layer per step; no speed claim.

`nemotron_h_registry.cpp` is STILL BYTE-IDENTICAL TO MAIN, deliberately, including
its `A2b` spelling: that file carries the G-SAFE interlock and its empty diff is
itself evidence a reviewer reads.

Gate on Thor (sm_110, fa2/cutlass DISABLED for [110] -- this host's documented
profile): test_nemotron_h_forward 16/16, 5716 assertions, SUCCESS;
test_nemotron_h_scaffold 14/14, 38302; test_nemotron_h_loader against the real
20.1 GiB checkpoint 2/2, 53 assertions, 3/3 oracle goldens MATCH. Every mutation
carries compile exit, error count and a binary sha distinct from baseline, and
every restore rebuilds back to the baseline sha byte-for-byte. One mutation
attempt did not build (`unused variable 'atol'`) and is reported VOID rather
than counted -- its binary sha was the previous mutation's, unchanged.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
Pinned SHA, per #841: `origin/main` moves under a shared checkout, so a diff
taken against the moving ref accuses this branch of dropping files it never
touched. Merged at an immutable SHA and verified against it.

Three files overlap -- CMakeLists.txt, docs/FEATURES.md, docs/USAGE.md -- and
all three are keyed. `git diff 4880c57 -- <those three>` after the merge is
exactly this row's own edits and NOTHING else: the one NemotronH row in each
doc table, and the one source entry in the CMake list. Every other key came
from the target byte-for-byte.

The merge also caught the one file the A2-R rename had missed. CMakeLists.txt
:882 still spelled the unit `A2α`, so a grep for the new name would have found
the tests and the model sources but not the build entry that names the file
they gate. Renamed here rather than left for the next reader.

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 feat(#810 A2α): NemotronH's dense weights reach the device, and the attention block that reads them is model-local (#517) feat(#810 A2-R): NemotronH's dense weights reach the device, and the attention block that reads them is model-local (#517) Aug 15, 2026
mudler added 2 commits August 15, 2026 20:42
…laced

Comment only, no assertion changes. The block header said the property is proven
"by much more than the band above", which was true of the `* 5` ratio and is not
true of what replaced it: the check is now that the band REJECTS the rotated
answer outright, with no margin factor. A reader who trusted the old sentence
would go looking for a ratio that is deliberately gone.

test_nemotron_h_forward rebuilt and re-run: 16/16, SUCCESS.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
… the parser's view

Found by hitting it on this row's own pull request. `commit-protocol-tag`
reported #950 as missing `Following-Agents-Protocol` and `AI-Assisted` while the
body carried both, correctly, in a well-formed final paragraph.

The cause is not the trailer block. The repository sets
`squash_merge_commit_message = PR_BODY`, so the body IS the landed commit
message, and `git interpret-trailers` treats a bare `---` as the end of a commit
message -- everything after it is a patch, and is not parsed. Two markdown
horizontal rules in the body therefore hid the trailer block completely.

Measured, both directions, on the body as stored by GitHub:

  git interpret-trailers --parse < body        -> nothing
  sed 's/^---*$/***/' body | interpret-trailers -> all three trailers

A markdown table's `|---|---|` separator is unaffected: the line is not bare.

Recorded in the commit and pull request guide rather than in a checker, because
the checker is already CORRECT -- it refused a body whose trailers the parser
genuinely cannot see, which is exactly what the landed commit would carry. The
gap was that nothing told the author which character did it.

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 16, 2026
…W6's own variable shadow (#965, #672)

`windows-msvc-cpu` and `windows-msvc-vulkan` fail on every open pull request:

  server_main.cpp(1315,55): error C2220: the following warning is treated as an error
  server_main.cpp(1315,55): warning C4456: declaration of 'loaded' hides
                            previous local declaration

That is W6's own speech-attach block declaring `loaded` inside the scope of the
text engine's `loaded` at `:1025`. It is the ONLY warning in the job, it has
been on `main` since W6 landed, and it is fixed here by renaming the inner
declaration. Nothing is suppressed and no detector is weakened.

WHAT FOUND IT WAS THE MATCHED-ARM CHECK, NOT THE LABEL, and that is the part
worth recording. Both jobs are habitually red and habitually attributed to #645
— which is the `M_PI` portability regression in three LTX2 sources: different
file, different detector, different failure. A second cause sitting behind a
known-red name is invisible for exactly as long as nobody reads the log.

Three unrelated open pull requests that touch no speech surface — #956, #950 and
#939 — fail with the identical C4456, which is what separates "pre-existing"
from "mine". `main` carries no baseline because `windows-msvc-*` are PR-only
(#584), so the failure presents to each author in turn as a red their own diff
caused.

Verified after the rename: 7 of 7 server ctest cases pass, `test_openai_api_server`
is 62 cases / 733 assertions, and `vllm-server --speech-model <dir>` with no
`--model` starts and serves for real:

  server: speech/music-only model (family=minimax-music3, 44100 Hz,
          text-only synthesis, family DETECTED); serving /v1/audio/speech
  server: listening on http://0.0.0.0:18923 (model 'minimax-music3')

Issue: #965

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 16, 2026
…the first, and it came from main (#968, #672)

With #965's `C4456 'loaded' shadow` removed, `windows-msvc-cpu` and
`windows-msvc-vulkan` failed again on this row's pull request — and on a
different cause:

  include\vector(1461,29): error C2220: the following warning is treated as an error
  include\vector(1461,29): warning C4244: '=': conversion from 'const double'
                           to 'float', possible loss of data

raised from `src/vllm/multimodal/ltx2_video.cpp:203,214`, the two narrowing
`positions.assign` calls that `c7cb59fbb` (#964, LTX25-TOKEN-APPEND) landed on
`main` while this row was in flight. `StreamState::positions` and
`Ltx2LatentState::positions` differ in element type; GCC and Clang narrow
silently, MSVC diagnoses and the build treats it as an error.

NOT FIXED HERE, deliberately. #964's own comment at `ltx2_video.cpp:129-132`
reasons that "double -> float -> double reproduces the bits", so the narrowing
is intentional and a silencing `static_cast` would be a claim about that
reasoning rather than a formatting repair. It belongs to the lane that owns the
round trip. Filed as #968 with the evidence rather than papered over.

THE MATCHED ARM SPLITS EXACTLY ON THE MERGE BASE, which is what makes it
inherited rather than mine. Grepping each `windows-msvc-cpu` job log for the
warning: #966 and #951, both on `c7cb59fbb`, hit it twice each; #967, #956,
#950, #939 and #938, all based before it, do not hit it at all. This row's diff
touches zero LTX2 files.

THE FINDING WORTH CARRYING is not either warning. It is that TWO INDEPENDENT
CAUSES WERE STACKED BEHIND ONE HABITUALLY-RED JOB NAME, and the first hid the
second — and that neither was #645, the `M_PI` regression both jobs are usually
attributed to. A known-red list tells you a job is often red. It never tells you
that today's red is the same one. Only reading the log does.

Issue: #968

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
Six commits of `main` since the branch's pinned merge of 4880c57. Verified
before committing rather than after:

  .agents/issue-index.md   origin/main is a strict PREFIX of the result, so the
                           auto-merge appended rather than interleaving. That is
                           the one check an interleave fails, and this record has
                           produced clean-but-wrong merges repeatedly today.
  docs/FEATURES.md         every row this branch does not own is byte-identical
  docs/USAGE.md            to origin/main. Only the NemotronH row differs.

The three gated files that carried the fresh review's PASS -- the forward test,
nemotron_h_device.cpp and nemotron_h.cpp -- are untouched by this merge.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
localai-bot added a commit that referenced this pull request Aug 16, 2026
… heard, and the five keys upstream refuses that we dropped (#672, #953, #965) (#966)

feat(MODEL-MUSIC-MUSIC3): a music-only server, an example that can be
heard, and the five keys upstream refuses that we dropped (#672, #953)

Developer directive: parity on what upstream supports — "we want to be a
good
reference" — usage docs for MiniMax-Music3, and in those docs the
weights. Then,
mid-flight: "we should allow to load only the music model" and "we need
to have
an e2e test working".

FOLLOWING_AGENTS_PROTOCOL

## The upstream surface, enumerated rather than summarized

SGLang-Omni `748a0b43` `models/minimax_music3/` and diffusers `c6da9936`
`modular_pipelines/minimax_music3/`, read field by field and recorded
with
`file:line` in spec §10.1 so the next reader re-derives nothing.

**Closed here:** the music-only server, the missing example, and five
refusals.
**Owed and named:** the non-`wav` response formats, request batching and
`/v1/audio/speech/batch`, the 32 kHz delivery resample.
**Permanently refused rather than owed:** streaming — neither upstream
arm has
it (`supports_streaming_vocoder=False`).
**One place we are ahead of both arms:** `guidance_scale` is a real
per-request
control here, where diffusers freezes it at 1.7 into the guider
component
(`denoise.py:180`) and SGLang exposes it only as a serve-time knob.

## `--model` is optional when `--speech-model` is given

Serving a 28.5 GB music model also forced loading an unrelated text
model, and
on this box the smallest text checkpoint is 35B — so the recipe this
project
documented was effectively unrunnable. Upstream's own is `sgl-omni serve
--model
MiniMaxAI/MiniMax-Music3`, no text tower anywhere.

    vllm-server --speech-model /path/to/minimax-music3

Third instance of a shape already in `server_main.cpp`: a pooling
checkpoint
serves `/v1/embeddings` alone, a Parakeet checkpoint serves
`/v1/audio/transcriptions` alone. It mirrors vLLM's task-conditional
registration (`api_server.py:255-265`).

**Additive, and proved rather than argued.** The only case whose verdict
changes
is BOTH flags absent, which was an error and remains one with a message
naming
both options. The route table is gated in both directions over a real
socket,
because a handler-dispatch test cannot see route registration at all.

## The example the music family did not have

`examples/minimax_music3_gen` — a thin client of `include/vllm.h` and
nothing
else, like `parakeet-transcribe` and `vllm-cli`. Hearing this model
previously
needed a running server plus a `curl`, or a C ABI caller nobody had
written.

## Five keys upstream refuses by name were SILENT here (#953)

`temperature`, `top_p`, `top_k`, `repetition_penalty` — refused upstream
at
`request_builders.py:14-19,109-114`, because this model's autoregressive
stage
has ONE sampler, a fixed top-50 draw (`encoders.py:48,94-103`). And
`max_new_tokens`, upstream's LENGTH spelling in 25 Hz frames rather than
seconds
(`request_builders.py:56-68`), so a 250-frame request silently became
the
family's 60 s default. That is the #925 class exactly, in the same file
that
already carries #925's refusal one paragraph above. Fixed in flow.

## The e2e gate no longer reports a skip wearing a pass

It read 5 cases / 5 passed with **`assertions: 0`** whenever the
checkpoint was
absent — the same shape that fooled this project on
`test_qwen3_paged_engine`.
Split into a checkpoint-free half that runs unconditionally in CI
(request
contract, both ceilings, the speech-only route table over a real socket
with a
stub synthesizer) and the env-gated half, whose HTTP case now drives the
real
engine over a real socket against the music-only server shape. A
coverage-report
case prints which arms ran, every run.

The full arm was run: `POST /v1/audio/speech -> 200 audio/wav, 12332
bytes in
518 s wall`, 2 AR frames -> 6 latent frames -> 3072 samples/channel,
6144 int16
samples all non-zero, 0 clipped, 2818 of 3072 positions differing
between L and
R, and `/v1/completions` + `/v1/chat/completions` both 404 from the
route table.
`checkpoint_arms_run=5`.

| arm | cases | assertions |
|---|---|---|
| `test_minimax_music3_e2e_real`, no env vars | 9 | 37 (was 5 / **0**) |
| `test_minimax_music3_e2e_real`, checkpoint only | 9 | 86 |
| `test_minimax_music3_e2e_real`, checkpoint + `VLLM_CPP_MUSIC3_DIT=1` |
9 | **582** |
| `test_speech_api` | 6 | 67 |
| `test_openai_api_server` | 62 | 733 |
| `test_openai_conformance` | 23 | 252 |
| `test_minimax_h3` (unchanged) | 79 | 57395 |
| server flag ctest cases | 7 passed | |

## The weights are documented (porting-a-model.md §2.1)

`docs/USAGE.md` gains component-by-component tables: the diffusers arm
at
`MiniMaxAI/MiniMax-Music3`@`fbdf52fbaaca799592917417eb05f1899f1255ec`,
**28.5 GB
resident** (28 517 617 303 B, measured) out of a 57.4 GB repository and
why they
differ; the native `.pth` arm we refuse and SGLang-Omni serves; the one
implemented GGUF Q4_K artifact with its sha256; and the fourteen
third-party
quantized repositories in five formats, each marked refused. The
revision is
verified rather than copied —
`condition_encoder/diffusion_pytorch_model.safetensors`
on disk hashes to that revision's own LFS record.

## A sample a human can hear

2.0 s of 44100 Hz stereo from this engine in 3286 s of wall clock: RMS
0.03169,
peak 0.97437 with 0 clipped samples, 84 073 of 88 064 positions
differing
between left and right. **Its samples are compared to nothing** — §5
withdrew
the token gate — so it shows the pipeline runs, not that the music is
right. It
is not committed: `check-pr-size.py` classifies every path and none
takes a
`.wav` outside `tests/`, where a file compared to nothing would sit
beside the
goldens and imply it was one.

## The four asks, answered directly

**1. Music-only server.** `vllm-server --speech-model <dir>` with NO
`--model`
starts and serves, observed live rather than inferred:

    server: speech/music-only model (family=minimax-music3, 44100 Hz,
text-only synthesis, family DETECTED); serving /v1/audio/speech
    server: listening on http://0.0.0.0:18923 (model 'minimax-music3')

`--model` alone and `--model` + `--speech-model` are **byte-identical in
behaviour**. The whole change is one new early branch, `if
(args.model_dir.empty())`,
which loads the speech engine and `return 0`s before reaching a single
line of
the existing path; nothing downstream of it was touched. The only case
whose
verdict changes is BOTH flags absent, which was an error and remains
one.
Server suites: **7 of 7** ctest cases (4 pre-existing + 3 new — neither
flag is
still an error and now names both options; `--speech-model` alone
reaches the
speech LOAD; `--speech-family` alone still demands a checkpoint),
`test_openai_api_server` **62 cases / 733 assertions** (+1 case / +24
assertions,
the speech-only route table over a real socket),
`test_openai_conformance`
**23 / 252** unchanged.

**2. e2e, three arms.** What a bare CI run executes unconditionally: the
request
contract on the exact body the real case posts, the near-miss and
sampling
refusals, the duration arithmetic including both ceilings, and the
speech-only
route table over a real socket with a stub synthesizer. What stays
env-gated:
everything needing the 28.5 GB checkpoint, plus the two 2.4B-DiT arms
behind
`VLLM_CPP_MUSIC3_DIT`.

| arm | cases | assertions | checkpoint arms run |
|---|---|---|---|
| no env vars (what CI runs) | 9 | **37** | 0 — was 5 cases / **0
assertions** |
| `VLLM_CPP_MUSIC3_CHECKPOINT` | 9 | **86** | 3 |
| + `VLLM_CPP_MUSIC3_DIT=1` | 9 | **582** | 5 |

**3. The five keys.** All five were **accepted and silently dropped**;
all five
are **now refused by name**.

| key | upstream anchor | why it cannot be honoured |
|---|---|---|
| `temperature` | `request_builders.py:14-19,109-114` | the AR stage's
only sampler is a fixed top-50 draw, `encoders.py:48,94-103` |
| `top_p` | same | no nucleus branch exists |
| `top_k` | same | `_AR_SAMPLING_TOP_K` is a module constant of 50 |
| `repetition_penalty` | same | no penalty is applied anywhere in the
loop |
| `max_new_tokens` | `request_builders.py:56-68`, `constants.py:4-5` |
upstream's LENGTH, in 25 Hz frames not seconds; the refusal names
`audio_duration` and the /25 conversion |

**4. The weights table** (`docs/USAGE.md`, "MiniMax-Music3: the exact
weights").
It carries: repo **and** revision —
`MiniMaxAI/MiniMax-Music3`@`fbdf52fbaaca799592917417eb05f1899f1255ec`,
verified
rather than copied, since
`condition_encoder/diffusion_pytorch_model.safetensors`
on disk hashes to `83179c5e…a202c2a4d`, that revision's own LFS record;
the
Q4_K artifact's sha256 `4c5d41b2…c70cbdd0` at revision `c36aaeed…` with
its exact
byte count; **28.5 GB resident (28 517 617 303 B, measured) versus 57.4
GB
repository**, with the reason they differ; the refused native `.pth` arm
(`qwen_7B/`, `flowmatching_vae.pth`, `dav.pth`) and that SGLang-Omni
serves it;
and all fourteen community quant repositories across five formats, each
marked
refused and each marked **third-party** rather than first-party. This is
the
first application of `.agents/porting-a-model.md` §2.1 (landing as
#951).

## Two reds stacked behind one habitually-red job name

`windows-msvc-cpu`/`windows-msvc-vulkan` are usually attributed to #645
(`M_PI`
in three LTX2 sources). **Neither of the two causes here was #645**, and
the
first hid the second.

**#965, fixed in flow.** `C4456: declaration of 'loaded' hides previous
local
declaration` at `server_main.cpp:1315` — W6's own speech-attach block
declaring
`loaded` inside the text engine's `loaded`. The only warning in the job,
on
`main` since W6 landed. Matched arm: #956, #950 and #939, none touching
the
speech surface, fail identically. Renamed; nothing suppressed.

**#968, filed and NOT fixed here.** With the shadow gone the same jobs
failed
again on `C4244: conversion from 'const double' to 'float'`, raised
inside
MSVC's `<vector>` from `ltx2_video.cpp:203,214` — two narrowing
`positions.assign` calls that `c7cb59fbb` (#964) landed on `main` while
this row
was in flight. **This branch touches zero LTX2 files.** The matched arm
splits
exactly on the merge base: #966 and #951 (on `c7cb59fbb`) hit it,
#967/#956/
#950/#939/#938 (before it) do not. It is deliberately left to the
LTX-2.5 lane —
#964's own comment reasons that "double -> float -> double reproduces
the bits",
so a silencing cast is a claim about that reasoning rather than a
formatting fix.

**The finding, which outlives both:** a known-red list tells you a job
is often
red. It never tells you that today's red is the same one. Only reading
the log
does — and here it took two readings, because removing the first cause
is what
made the second visible.

<!-- kept for the record -->
### The first of the two, in detail (#965)

`windows-msvc-cpu`/`windows-msvc-vulkan` failed here, and they are
**not** #645
(`M_PI` in three LTX2 sources). They were W6's own
`C4456: declaration of 'loaded' hides previous local declaration` at
`server_main.cpp:1315` — the only warning in the job, on `main` since W6
landed.
The matched-arm check is what separated it from my diff: #956, #950 and
#939, all
touching no speech surface, fail identically. `main` has no baseline
because
`windows-msvc-*` are PR-only (#584), so it presents to each author in
turn as
their own red. Filed and fixed in flow by renaming the inner
declaration; nothing
suppressed.

## Mutations

Four run, four fire: sampling refusal neutered (5 assertions red),
`max_new_tokens` refusal neutered (2 red), `--model` made mandatory
again
(2 ctest cases red), generate routes registered unconditionally (3 cases
/
6 assertions red in the api-server suite, 1 / 2 in the e2e suite).
Sources
restored and verified sha256-identical.

Supersedes #954 (untrailered merge commits) and #963 (a
`server_main.cpp` commit
that owed `docs/USAGE.md` under the per-commit documentation
checkpoint). Same
tree, linear history, every commit green on `check-doc-checkpoint`,
`check-commit-trailers` and `check-commit-style` locally before pushing.
Every
source file is byte-identical to the one built and gated.

Issue: #672

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

---------

Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
@localai-bot
localai-bot merged commit 598226e into main Aug 16, 2026
26 of 28 checks passed
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