Skip to content

MODEL-NEMOTRON-H: the WEIGHT LOADER — the real checkpoint LOADS in its packed format (the model is NOT yet reachable from the ABI, see #810) - #752

Merged
localai-bot merged 9 commits into
mainfrom
row/MODEL-NEMOTRON-H-LOADER-LAND
Aug 15, 2026
Merged

MODEL-NEMOTRON-H: the WEIGHT LOADER — the real checkpoint LOADS in its packed format (the model is NOT yet reachable from the ABI, see #810)#752
localai-bot merged 9 commits into
mainfrom
row/MODEL-NEMOTRON-H-LOADER-LAND

Conversation

@localai-bot

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

Copy link
Copy Markdown
Collaborator

Important

This branch makes the WEIGHTS LOAD. It does NOT make the model reachable from the public ABI.
NemotronH does not run end to end through include/vllm.h — not on main, and not
with this branch merged. Both refuse at src/vllm/v1/worker/gpu/runner.cpp:525,
runner: Qwen3.5 MambaSpec shapes disagree with model config, a line this branch does
not touch. Established independently on the real 21 GiB checkpoint on GB10: the weights
load fine (17.7 GiB RSS) and then engine construction refuses. Tracked as #810.

So "the real checkpoint runs" below means the host reference forward runs on real
weights
. It must not be read as "the server runs it".

That single VT_CHECK is the only load-time blocker — neutering it alone made
vllm_engine_load succeed and reach the forward. That is not a fix.
ForwardNemotronHForCausalLM ignores attn_kv, gdn_state, gdn_meta and num_reqs,
so a server past that check emits silently wrong tokens from decode step 2 — exactly
what a 1-token golden arm cannot see. The refusal is currently the only thing making the
gap visible. #810 owns it; W6 owns the paged/device runner. Out of scope here.

Closes the blocker .agents/specs/nemotron-h-model.md §6b named as "still owed
after W4": nothing materialized the 18487 enumerated tensors, so every
checkpoint load left NemotronHHostWeights unmaterialized and the forward
refused by name. Issue #517; spec §6d is the authority on this brick.

RED first

Off the real 20.1 GiB checkpoint, resolved by CONTENT (#569) to
/mnt/nas_share/checkpoints/nemotron-3.5-lightning-30b-nvfp4 @ 29f2d174:

Status: FAILURE!, exit 1
THREW: NemotronHForCausalLM forward: host weights are not materialized
assertions: 3 | 3 passed | 0 failed     <- the case THREW; read Status:
peak RSS after "load": 29 MiB

The design decision, and why it is arithmetic

Every weight is held in the format the checkpoint SHIPS it in. Not tidiness:
the 5888 routed-expert projections alone are 29.4e9 parameters, 16.5 GB
packed against 58.7 GB at bf16
(both DECIMAL GB; 16.5 GB is 15.4 GiB, and the
review caught this written as GiB). A dequantize-at-load loader does not fit on any
box this project owns, and on a unified-memory box that is a reboot rather than a
failed load.

Measured host mirror 18013 MiB against 18013 MiB read out of the shards:
the mirror is the checkpoint, not a widened copy of it.

The consequence is recorded rather than hidden. The HOST reference forward
composes vt::MatmulBT and has no NVFP4 and no FP8 entry point, so it widens a
quantized operand transiently at the GEMM call site, through the shared
model_loader/nvfp4_dequant.h seam every other ModelOpt consumer here uses.
That arm is named in the header, named at the call site, and the quantized GEMMs
stay kMoeGroupedGemmNvfp4Marlin and the fp8-linear registration, which W6
selects. NemotronHOwned::View now REFUSES a non-dense weight by name, so a
packed buffer cannot be reinterpreted as the model dtype by a caller that did not
think about it.

The structural gate, as hard numbers

Gated structurally and not only by tokens, because a checkpoint read as uniform
NVFP4 stays numerically plausible and still matches tokens while moving the wrong
bytes.

Row Measured
enumerated / in model.safetensors.index.json 18487 / 18487
materialized + deferred 18217 + 270 = 18487
deferred BY NAME (MTP tower, W5) 270
NVFP4 W4A16 g16 5935 projections / 17805 tensors
FP8 W8A8 static 46 projections / 138 tensors
fp8 KV scales 12
unquantized bf16 / f32 on disk 216 / 46
the five scheme rows sum to materialized 18217 == 18217
widenings (bf16 on disk, f32 in memory) 69, and no more
host bytes 18,888,922,112 (17.59 GiB)
peak RSS 17.70 GiB after load, 18.38 GiB after a forward

{W4A16_NVFP4: 5935, FP8: 46} is exactly the histogram W1 measured over the
5981 quantized_layers entries, now confirmed against the TENSORS.

A finding worth the reviewer's attention: A_log, D and dt_bias ship
BF16 on disk and the forward requires them f32. Those 69 widenings are
upstream's own polarity (-torch.exp(self.A_log.float())) and are counted so
they cannot spread.

Evidence, NOT the W6 token gate

One forward per committed oracle prompt, argmax of the last position against the
golden's FIRST generated token: 3/3 (6993, 1032, 1349). W6 still owns the
token gate. This is here because it is the only check that can fail for a reason
the counts cannot see.

Mutation proof

Mutation Result
M1 mamba in_proj read as NVFP4 not FP8 refused by name, ships dtype F8_E4M3, not the U8 its scheme declares
M2 the 12 fp8-KV scales dropped refused by name, enumerated but no host slot claimed it
M3 A_log/D/dt_bias inherit the model dtype widened_tensors == 69 red, then wrong dtype for this arm
M4 NVFP4 nibble order flipped 0/3 goldens; 45 of 46 assertions STILL PASS
M5 weight_scale_2 read and then ignored 0/3 goldens; 45 of 46 assertions STILL PASS

M4 and M5 are the pair that keeps the golden arm honest: a loader gate built only
out of counts would have called both clean.

Not in scope, refused by name

The MTP head (W5, its 270 tensors deferred and named), the GGUF arm (W7, refused
at load), the e2e token gate (W6), and any speed claim.

Review repair (fresh review of 9bffa2b60)

A fresh reviewer confirmed every number above and returned 2 MEDIUM, 3 LOW, 2 NIT.
All seven repaired; none declined. Spec §6e is the authority.

# Finding Repair
F1 CopyDense read the mmap through reinterpret_cast<const uint16_t*>(t.data) / <const float*>(t.data). StTensor::data is 8 + <header len> + <sum of preceding sizes> — none required to be even, so the pointer may not be formed routed through vt::LoadUnaligned; the two bulk memcpys drop the typed pointer they never needed. Mirrors fc903b8dd (#674). nemotron_h_weights.cpp:468,477,490,499
F2 The View guard was correct but UNARMED: deleting it left the whole suite green, and with no CHECKPOINT_ROOT the loader test read Passed 0.00 sec with zero assertions (a) new offline suite test_nemotron_h_quantized_forms.cpp, registered unconditionally; (b) a named, counted skip with a closing accounting case
L1 LoadMamba did not branch on quantized, so a bf16 checkpoint refused with a dtype message for what is a declared scheme branches, as LoadExpert/LoadMlp and the enumeration do. The arm is reachable but ungated and docs/FEATURES.md deliberately does not claim it
L2 "consumes no golden" in two places, contradicted by the code corrected to what it does: one forward per prompt, argmax vs the golden's FIRST token
L3 The restoration proof named nemotron_h_loader.cpp, which does not exist 186ae4cea4d7… is a REAL sha — of the pre-rename TU at c4029deed; 08a65696d folded it into nemotron_h_weights.cpp as a documented pure move. Both identities now named, and it says plainly M1–M3 were not re-run after the move
N1 "16.5 GiB" is 16.5 GB (15.4 GiB); arithmetic written out
N2 "the dequant is counted by the loader's report" the report counts quantized weights, not dequant events

Gate at the pushed head c6255afa1, over origin/main @ ca01719e6

Arm Result
Release -Werror, clean full build from an empty tree BUILD_EXIT=0, 0 warning:, 0 error:, 0 No space left, 1395/1395
ctest -j4 471 of 471 PASSED, CTEST_EXIT=0, 111 s. Skipped: test_modelopt_mixed_precision_checkpoint, test_voxtral_e2e
the four Nemotron-H suites scaffold 12/12, forward 13/13, loader 2/2, quantized_forms 5/5
scripts/agent-preflight.sh All gates green
check-commit-style.py / check-commit-trailers.py OK: commit writing style / OK: commit trailer contract
disk 100G free / 77%, before and after

test_op_parity, red on main when this work was scoped (#755/#672), passes at
this base. test_cpu_x86_llamacpp_floor went red earlier in the session at load
average 91-130 and reproduced on the shared checkout at main, which is what
made it environmental rather than this branch's; it passes on the idle box.

F2 RED-before → green-after

The new suite catches M4/M5 — the pair that leaves every structural count correct
— in 0.01 s with no checkpoint, where before they needed the 20.1 GiB
checkpoint and three oracle prompts. Compile exit and binary sha printed beside
every result; all binaries differ, so no stale binary printed a green status.

Mutation BUILD_EXIT binary sha Result
baseline 0 7b7df3464fb2 5/5 cases, 134/134, Status: SUCCESS!
wrong nibble order (kHighFirst) 0 26bc2e92ed72 Status: FAILURE!96 of 96 elements differ; probe pair exactly swapped (16576 vs 16128); the GEMM-reach case moves too
weight_scale_2 ignored (1.0F) 0 702537076950 Status: FAILURE!84 of 96 differ, 36 assertions failed
View's VT_CHECK neutralized 0 0303eeaeff7d Status: FAILURE!
FP8 input_scale applied (must be carried) 0 630495efa1a9 Status: FAILURE!

The reference is derived independently from the upstream ModelOpt formula —
E2M1 table, fp8-e4m3 decoder and bf16 RNE round all written from their format
definitions, anchored by hand (0x38→1.0, nibble 0x7→6.0, bf16(1.5)=0x3FC0,
and the subnormal ladder). Every fixture is dyadic, so comparisons are on the
bf16 bit pattern and doctest::Approx's ~1.19e-5 floor never enters.

F2(b) the skip is no longer indistinguishable from a pass

With CHECKPOINT_ROOT unset: 2 cases / 7 assertions, Status: SUCCESS!, and
the log states checkpoint-gated cases: 0 ran, 1 skipped, of 1. Armed — restoring
the pre-repair silent early return gives Status: FAILURE!, 0 of 2 assertions
passed
(sha 13e7a4d46101, BUILD_EXIT 0).

#818 — a merge that was CLEAN and did not build

Merging origin/main made test_nemotron_h_scaffold RED though both parents
are green
. #784 rewrote its refusal subcase to call the real load_weights
(correct on main, where the loader ignores source.safetensors); §6d gives that
call a loader that refuses an empty source. Repaired here by splitting the subcase
— refuse-at-load and refuse-on-unmaterialized-weights — keeping #784's substance
(no StubModel, no downcast, no UB). Both halves mutation-armed.

No overlap with #815 / row/FIX-UNALIGNED-LOADERS-772

Checked, not assumed. That branch closes the same class at voxtral.cpp:51,344,
qwen3_vl.cpp:78, qwen3_5_mtp.cpp:71 and minimax_h3_vae_loader.cpp; its file
list contains no nemotron_h_* file, and git log -S'nemotron_h_weights' over
origin/main..origin/row/FIX-UNALIGNED-LOADERS-772 is empty. Structural, not luck:
#772's sweep was taken over main, and this site does not exist on main — it
arrives with this PR. Established with a positive control rather than a
silent grep: the same regex that is silent on the repaired nemotron_h_weights.cpp
fires on voxtral ×2 and qwen3_vl.cpp:78, exactly #815's set. Complementary;
whichever lands second re-resolves docs/FEATURES.md and tests/CMakeLists.txt
by key.

Not in scope, refused by name

The MTP head (W5, its 270 tensors deferred and named), the GGUF arm (W7, refused
at load), the e2e token gate (W6), the ABI reachability blocker (#810), and any
speed claim.

mudler added 3 commits August 14, 2026 12:38
…, in the formats it ships in (#517)

Closes the blocker §6b named as "still owed after W4": nothing materialized the
18487 enumerated tensors, so every checkpoint load left NemotronHHostWeights
unmaterialized and the forward refused by name. Spec §6d is the authority.

RED first, off the real 20.1 GiB checkpoint at the CONTENT-pinned revision
29f2d174 (#569): `Status: FAILURE!`, exit 1, THREW "host weights are not
materialized", peak RSS after "load" 29 MiB. Note the instrument trap in the
same output -- `assertions: 3 | 3 passed | 0 failed` beside a red gate, because
the case THREW.

EVERY WEIGHT IS HELD IN THE FORMAT THE CHECKPOINT SHIPS IT IN, and that is
arithmetic rather than taste: the 5888 routed-expert projections alone are
29.4e9 parameters, 16.5 GiB packed against 58.7 GB at bf16. A
dequantize-at-load loader does not fit on any box this project owns, and on a
unified-memory box that is a reboot rather than a failed load. Measured host
mirror 18013 MiB against 18013 MiB read out of the shards.

The host reference forward composes vt::MatmulBT and has no NVFP4 and no FP8
entry point, so it widens a quantized operand TRANSIENTLY at the GEMM call site
through the shared model_loader/nvfp4_dequant.h seam. That arm is DECLARED --
named in the header, named at the call site, counted by the load report -- and
the quantized GEMMs stay kMoeGroupedGemmNvfp4Marlin and the fp8-linear
registration, which W6 selects. NemotronHOwned::View now refuses a non-dense
weight by name, so a packed buffer cannot be reinterpreted as the model dtype.

Gated STRUCTURALLY, not only by tokens, because a checkpoint read as uniform
NVFP4 stays numerically plausible and still matches tokens while moving the
wrong bytes:

  enumerated / in the index      18487 / 18487
  materialized + deferred        18217 + 270 = 18487   (MTP tower -> W5, by name)
  NVFP4 W4A16 g16                5935 projections / 17805 tensors
  FP8 W8A8 static                46 projections / 138 tensors
  fp8 KV scales                  12
  unquantized bf16 / f32         216 / 46
  the five rows sum to           18217 == materialized
  widenings                      69, and no more
  host bytes                     18,888,922,112 (17.59 GiB)
  peak RSS                       17.70 GiB after load, 18.38 GiB after a forward

{W4A16_NVFP4: 5935, FP8: 46} is exactly the histogram W1 measured over the 5981
quantized_layers entries, now confirmed against the TENSORS. A finding worth
carrying: A_log, D and dt_bias ship BF16 on disk and the forward requires them
f32; those 69 widenings are upstream's own polarity and are counted so they
cannot spread.

EVIDENCE, not the W6 token gate: one forward per committed oracle prompt, argmax
of the last position against the golden's FIRST generated token -- 3/3 (6993,
1032, 1349) on x86_64 AND on Jetson Thor. W6 still owns the token gate.

Five mutations, each applied alone and restored with its SHA-256 re-verified:
uniform-NVFP4 and the dropped KV scales refuse by name; the un-widened SSM
scalars red the widening count and then the dtype; and the flipped nibble order
and the ignored weight_scale_2 each give 0/3 goldens while 45 of 46 assertions
STILL PASS -- a loader gate built only out of counts would have called both
clean.

The load lives in nemotron_h_weights.cpp, beside the enumeration it must agree
with tensor-for-tensor, which is where every other architecture puts its load
and which avoids a CMakeLists.txt edit that would have owed a docs/USAGE.md
change with nothing honest to write in it.

Reported, not repaired: test_op_parity is RED on this base for a reason owned by
MODEL-MUSIC-MUSIC3 (#672) -- RunGoldenPass does `m["op"]` on every manifest.json
under the goldens root and minimax_music3_oracle's has no `op` key. It landed at
34dc578, an ancestor of this base.

Squashed off origin/main so check-doc-checkpoint's PER-COMMIT rule is satisfied
trivially, the same call §5e made for W3; `git diff` against the merged branch
tree is EMPTY.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…it may not form, and NOTHING new ran in CI (#517)

FOLLOWING_AGENTS_PROTOCOL

Repairs the two MEDIUM findings, three LOWs and two NITs a fresh review returned
against PR #752 at `9bffa2b60`. The review CONFIRMED the substance -- 18217 of
18487 tensors materialized, 270 `mtp.*` deferred by name, host bytes
18,888,922,112 re-derived bit-exact from the 52 safetensors headers, 3/3
first-token agreement on x86_64 and Thor -- and every number it confirmed is
unchanged here.

F1. `CopyDense` read the safetensors mmap through
`reinterpret_cast<const uint16_t*>(t.data)` / `<const float*>(t.data)`.
`StTensor::data` is `8 + <JSON header length> + <sum of preceding sizes>` and NOT
ONE of those terms is required to be even, so forming either pointer is
undefined whether or not the access faults -- and the same file's scalar read
already used `memcpy`, so it was internally inconsistent. This is #627's class,
whose THIRD recurrence closed on main the same day at `fc903b8dd` (#674) after
main had been RED on `sanitize-cpu (address,undefined)` since #641; that repair
is mirrored exactly. Reads go through `vt::LoadUnaligned` (the seam #301 left
behind, eight sibling loaders already on it) and the two bulk `memcpy`s drop
their typed pointer, which they never needed. No sanitizer configuration
touched, no scope widened. It also makes docs/FEATURES.md:83 true again -- that
row already claims the `*_weights.cpp` loaders never form a typed pointer into
the mapping.

Anchors re-derived at HEAD and asserted unique (count == 1), because recorded
line numbers go stale within a PR. A standalone `-fsanitize=address,undefined
-fno-sanitize-recover=all` probe over an ODD address: the shipped cast exits 1
with `load of misaligned address 0x521000000101 ... requires 2 byte alignment`;
`vt::LoadUnaligned` exits 0 and matches the memcpy oracle exactly. The reviewer
measured this LATENT on this checkpoint (0 of 216 BF16, 0 of 6085 F32
misaligned) and that is recorded rather than used as a reason to leave it.

F2. The seams were unreachable without the 20.1 GiB checkpoint: deleting
`View`'s `VT_CHECK` left the live gate at 46/46 and both offline suites green,
and with no `CHECKPOINT_ROOT` the loader test recorded `Passed 0.00 sec` with
ZERO assertions -- indistinguishable from a real pass. The guard is not
decorative: without it `View` hands out a 128-element bf16 tensor over a 64-byte
NVFP4 buffer, 192 bytes OUT OF BOUNDS.

(a) `test_nemotron_h_quantized_forms.cpp`, a new OFFLINE gate needing no
checkpoint and registered unconditionally, asserts `View` refuses by name and
that `DenseBf16` reproduces a dequant derived INDEPENDENTLY from the upstream
formula -- E2M1 table, fp8-e4m3 decoder and bf16 RNE round all written from
their format definitions, anchored by hand (0x38->1.0, nibble 0x7->6.0,
bf16(1.5)=0x3FC0). Every fixture is dyadic so every expected value is EXACT in
bf16 and the comparison is on the BIT PATTERN, which keeps doctest::Approx's
1.19e-5 floor out of it entirely. The nibble order, the per-16 group scale and
the MULTIPLIED weight_scale_2 are each asserted, and a fifth case reaches the
file-private DenseFor/DenseCopy through NemotronHMlpMixer against a dense arm
built from the INDEPENDENT reference, so a dequant defect cannot cancel itself
out.

RED-before, compile exit status printed beside every result and the binary sha
with it (all four differ, so no stale binary): baseline 5 cases / 130
assertions SUCCESS; nibble order -> kHighFirst FAILURE, 96 of 96 elements
differ, probe pair exactly swapped; weight_scale_2 ignored FAILURE, 36
assertions; View guard neutralized FAILURE; FP8 input_scale applied FAILURE.
The first two are spec 6d's M4/M5 -- the pair a counts-only gate calls clean --
which previously needed the 20.1 GiB checkpoint and three oracle prompts and are
now caught in 0.01 s with no checkpoint.

(b) the checkpoint-gated skip is LOUD, NAMED and COUNTED, on the
`PendingRunnerOps()` idiom: a registry of gated cases, a recorded verdict each,
and a closing accounting case. With CHECKPOINT_ROOT unset it now reports 2 cases
/ 7 assertions and logs "checkpoint-gated cases: 0 ran, 1 skipped, of 1". Armed:
not recording the skip REDs 4 of 6 assertions, and restoring the pre-repair
silent return REDs 2 of 2.

L1: `LoadMamba` now branches on `quantized` like LoadExpert/LoadMlp and the
enumeration do, so a released bf16 NemotronH no longer refuses with a DTYPE
message for what is a declared scheme. `mamba_proj_bias` remains owed and is
named rather than left to be found. L2: the two "consumes no golden" scope
statements now say what the code does -- one forward per prompt, argmax of the
last position vs the golden's FIRST token; the 32-token decode stays W6's. L3:
`186ae4cea4d7...` turned out to be a REAL sha, of the pre-rename TU at
`c4029deed`; `08a65696d` then folded it into `nemotron_h_weights.cpp` as a
documented pure move. The table now names both identities and says plainly that
M1-M3 were not re-run after the move. N1: 16.5 GiB is 16.5 GB (15.4 GiB), fixed
in both headers and the spec with the arithmetic written out. N2: the report
counts quantized WEIGHTS, not dequant EVENTS.

Carried into the spec rather than fixed: the FP8 arm is weight-only on the host
path (input_scale carried, unapplied) so it is not a bit-mirror of vLLM's W8A8
static GEMM; and the golden arm's reach is 3 prompts x 1 token, at most 78 of
128 experts per layer, never the dense mlp, never the MTP tower.

Gate: Release -Werror clean build exit 0, 0 warnings, 0 ENOSPC (44G free, 90%);
new suite 5/5 130/130; loader with CHECKPOINT_ROOT unset 2/2 7/7;
-DVLLM_CPP_SANITIZE='address,undefined' build of the three Nemotron-H targets
clean, all three SUCCESS, no sanitizer finding. The live checkpoint gate is
deliberately NOT re-run here -- the operator runs it on GB10.

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

`origin/main` at 3edb3c0, 36 commits ahead of
this branch's fork point. Merged with an explicit message file rather than
`--no-edit`, which writes a trailer-less message that `check-commit-trailers`
does not exempt for merges.

TWO KEYED RECORDS moved on main and NEITHER was taken from the automatic
three-way merge (AGENTS.md Records). Both were re-resolved by key: main's
version checked out WHOLESALE, this row's scoped edit reapplied on top with the
anchor asserted unique, then the result verified against main.

  docs/FEATURES.md      -- differs from main by EXACTLY ONE line, the
                           `NemotronHForCausalLM` row. Every other row byte-for-byte
                           main's, including the rows main added since the fork.
  tests/CMakeLists.txt  -- differs from main by EXACTLY ONE additive hunk,
                           594a595,637: 43 lines added, 0 removed. main's 56 new
                           lines since the fork are untouched.

`.agents/roadmap_v1.md` also moved on main; this row does not edit it and the
merged file is byte-identical to main's.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
mudler added 6 commits August 14, 2026 22:00
… did not build the behaviour either side had

FOLLOWING_AGENTS_PROTOCOL

Found by RE-RUNNING the full gate after merging `origin/main`, not by reading the
diff -- `git merge` reported no conflict at all, because the two changes touch
different files.

#784 (`b1cd4d8f6`, part of #730) rewrote `test_nemotron_h_scaffold`'s refusal
subcase to call the REAL `reg.factory->load_weights(reg, config, source)` rather
than downcast a fabricated `struct StubModel : vllm::LoadedModel`. UBSan was
right about the stub, and the rewrite is correct ON MAIN, where
`LoadNemotronHForCausalLM` reads only `source.kind` and never touches
`source.safetensors`. §6d then gave NemotronH a loader that refuses an empty
source by name. Merged, #784's `ModelSource source; source.kind =
kSafetensors;` hits exactly that refusal and the subcase THREW before it ever
reached the forward:

    test_nemotron_h_scaffold.cpp:666: ERROR: test case THREW exception:
      Model architecture NemotronHForCausalLM: the safetensors source carries no shards

Neither parent is red. [[merge-tree-clean-is-not-builds]]. Repaired here because
here is where the two sides meet, by SPLITTING the subcase rather than deleting
either side's guarantee:

  - an empty safetensors source REFUSES AT LOAD, by name (`NemotronHForCausalLM`,
    `carries no shards`) -- the guarantee moved EARLIER and is asserted where it
    now lives, which is a stronger claim than the one it replaces;
  - the forward still refuses on unmaterialized weights, reached through the
    exported `vllm::NemotronHForward` on a default-constructed
    `NemotronHHostWeights`. That state is no longer reachable through the factory
    at all now that the loader exists, so it is asserted on a REAL
    `NemotronHHostWeights`. #784's substance is kept in full: no `StubModel`, no
    downcast onto an object that never was a `NemotronHLoadedModel`, no UB.

ARMED, not decorative; compile exit and binary sha printed beside each result
and the two binaries differ. Replacing the `carries no shards` refusal with
`return model;` -> BUILD_EXIT=0, sha `4e6cdbd93478`, `Status: FAILURE!`, 11 of 12
cases, 2 of 38289 assertions failed. Neutering `VT_CHECK(host.materialized, ...)`
to `VT_CHECK(true, ...)` -> BUILD_EXIT=0, sha `84179116c90c`, `Status: FAILURE!`,
11 of 12, 2 of 38289. Green after: 12/12 cases, 38289/38289, `Status: SUCCESS!`
-- the split adds four assertions to W4's 38285 and the CASE count stays 12.

Also in this commit, carried from the review repair: the new offline suite's
independent fp8-e4m3 reference had the SUBNORMAL exponent wrong (2^-7 for
2^-6). No fixture reached it, so nothing was mis-judged, but a reference that is
only right where it is exercised is not a reference. Fixed and anchored by hand
at 0x01/0x07/0x08, and armed -- restoring 2^-7 REDs 2 of 134 assertions at
BUILD_EXIT=0, sha `182816a73a4c`.

`docs/FEATURES.md` deliberately does NOT claim the unquantized bf16 mamba arm
L1 added: it is reachable and consistent with its own enumeration, but no
released bf16 NemotronH checkpoint is within reach and no synthetic one exists,
so it is argued rather than measured. An ungated branch is visible debt, not a
supported surface, and the spec says so.

Full gate at the merged head: clean Release `-Werror` build from an empty tree
BUILD_EXIT=0, 0 warnings, 0 errors, 0 ENOSPC; `ctest -j4` 468 of 469 (the one
failure being exactly this #818, repaired after that run); the four Nemotron-H
suites 12/12+13/13+2/2+5/5 all SUCCESS afterwards. `test_op_parity` PASSES at
this merge base -- main's own red (#755/#672) is gone.

Closes #818.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…e from the ABI (#810), and #815 does not overlap F1 (#517)

FOLLOWING_AGENTS_PROTOCOL

Record only. No executable line moves.

TWO facts a reader of §6d would otherwise get wrong.

1. #810. NemotronH does NOT run end to end through `include/vllm.h` -- not on
`main`, and not with this branch merged. Both refuse at
`src/vllm/v1/worker/gpu/runner.cpp:525`, `runner: Qwen3.5 MambaSpec shapes
disagree with model config`, a line this branch does not touch. Established
independently on the real 21 GiB checkpoint on GB10: the weights load fine
(17.7 GiB RSS) and then ENGINE CONSTRUCTION refuses. So "the real checkpoint
runs" means the HOST REFERENCE FORWARD runs on real weights, and the spec now
says that in those words so nobody reads it as "the server runs it".

That single `VT_CHECK` is the ONLY load-time blocker -- neutering it alone made
`vllm_engine_load` succeed and reach the forward. The spec records why that is
NOT a fix: `ForwardNemotronHForCausalLM` ignores `attn_kv`, `gdn_state`,
`gdn_meta` and `num_reqs`, so a server past that check emits silently wrong
tokens from decode step 2 -- precisely what a 1-token golden arm cannot see. The
refusal is the only thing currently making the gap visible. #810 owns it, W6
owns the paged/device runner, and it is explicitly out of scope here.

2. PR #815 / `row/FIX-UNALIGNED-LOADERS-772` closes the SAME CLASS as F1 and
does NOT overlap it. Checked, not assumed: its complete file list carries no
`nemotron_h_*` file, and `git log -S'nemotron_h_weights'` over
`origin/main..origin/row/FIX-UNALIGNED-LOADERS-772` is empty. The reason is
structural -- #772's sweep was taken over `main`, and this site does not exist
on `main`; it arrives with PR #752 itself. Established with a POSITIVE CONTROL
rather than from a silent grep: the same regex that is silent on the repaired
`nemotron_h_weights.cpp` FIRES on `voxtral.cpp:51`, `voxtral.cpp:344` and
`qwen3_vl.cpp:78`, which is exactly #815's set. The two are complementary;
whichever lands second re-resolves `docs/FEATURES.md` and `tests/CMakeLists.txt`
by key, the only two files both touch.

Anchors re-derived at HEAD with uniqueness asserted (count == 1) for all ten
sites this row edits, and the drift is why: F1's two anchors have moved
455 -> 468 and 473 -> 490 since the reviewed head `9bffa2b60`
([[recorded-line-anchors-go-stale-within-the-same-pr]]).

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

FOLLOWING_AGENTS_PROTOCOL

Merged an IMMUTABLE SHA, `c01e4be93ddcea6c7bf922cbcdc351808c9097ad`, not the
moving `origin/main` ref: one `.git` is shared by many sessions here and the ref
moves under you mid-merge ([[origin-main-moves-under-you-in-a-shared-checkout]]).
Five commits ahead of the previous merge base. Explicit `-F <message-file>`
rather than `--no-edit`, which writes a trailer-less message that
`check-commit-trailers` does not exempt for merges.

TWO KEYED RECORDS moved on main. `git merge` reported NO CONFLICT on either, and
that automatic three-way result was DISCARDED rather than accepted (AGENTS.md
Records). Both were re-resolved by key: main's version checked out WHOLESALE,
this row's scoped edit reapplied on top with the anchor asserted UNIQUE
(count == 1), then the result verified against main:

  docs/FEATURES.md      -- differs from main by EXACTLY ONE line, the
                           `NemotronHForCausalLM` row (`diff` reports `142c142`
                           and nothing else). Every other row byte-for-byte
                           main's, including rows main added since the fork.
  tests/CMakeLists.txt  -- differs from main by EXACTLY ONE additive hunk,
                           `594a595,637`: 43 lines added, ZERO removed. Verified
                           the two targets it registers appear exactly once each,
                           and that main's own `test_offload_config` addition at
                           :875 -- which taking this row's file wholesale would
                           have silently DELETED -- survives.

That last line is the reason the rule exists: the automatic merge happened to
get it right this time, but a wholesale take would have evicted a target added
by an unrelated PR, and nothing would have failed loudly.

`.agents/roadmap_v1.md` also moved on main; this row does not edit it and the
merged file is byte-identical to main's, asserted with `git diff --quiet`.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…470, clean build, all preflight gates green (#517)

FOLLOWING_AGENTS_PROTOCOL

Record only. No executable line moves.

Re-ran the row's gate MYSELF at `e3f2992af` over `origin/main` @ `c01e4be93`,
rather than carrying forward the numbers from the contended run earlier in this
session:

  Release -Werror, CLEAN full build from an empty tree
      BUILD_EXIT=0, 0 `warning:`, 0 `error:`, 0 `No space left`, 1393/1393
  full `ctest -j4`
      470 of 470 PASSED, CTEST_EXIT=0, 124 s
      skipped: test_modelopt_mixed_precision_checkpoint, test_voxtral_e2e
  scripts/agent-preflight.sh
      All gates green
  disk 103G free / 76-77% before and after

Two reds reported earlier in this session are now shown to be ENVIRONMENTAL, and
both are recorded rather than quietly dropped. `test_cpu_x86_llamacpp_floor` RED
at load average 91-130 with `NO_QUIET_WINDOW after 30s (busy=102% ...)`, and it
reproduced on the SHARED CHECKOUT at `main`, which is what made it base-inherited
rather than this row's ([[cpu-x86-floor-test-reds-under-box-load]]); it passes on
the idle box. `test_cpu_threadpool` likewise. `test_op_parity`, RED on `main`
when this task was scoped (#755/#672), PASSES at this merge base.

The earlier contended run is KEPT in the spec rather than replaced: 468 of 469
with `test_nemotron_h_scaffold` red is how #818 was found, and it was found by
RE-RUNNING the gate, not by reading the merge diff -- which reported no conflict
at all. A negative result is a result.

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

FOLLOWING_AGENTS_PROTOCOL

Second merge of this task, at an IMMUTABLE SHA again: `origin/main` moved under
me between the previous merge and the push, which is exactly what a shared
checkout does ([[origin-main-moves-under-you-in-a-shared-checkout]]). Six
commits, and two of them matter here.

**#815 LANDED** as `ca01719e6` -- the branch this task asked me to check for
overlap with F1. The verdict is now confirmed against `main` itself rather than
against a branch: `git show --name-only ca01719` lists NO `nemotron_h_*` file,
and `main`'s own `nemotron_h_weights.cpp` contains zero occurrences of
`CopyDense` and neither of F1's two casts. The site F1 repairs does not exist on
`main` at all; it arrives with THIS PR, which is why #772's sweep could not have
seen it. The two changes are complementary and together close the class: after
this merge, the regex that finds the defect fires nowhere in `src/`.

**A new commit-style checker landed** (`ddff09093`, POLICY-SINGLE-PR-AND-STYLE)
with `.agents/style/commits.md`, `.agents/style/prose.md` and
`scripts/check-commit-style.py`, and `scripts/agent-preflight.sh` changed with
it. That is a gate this branch had never been measured against, so the merge is
followed by a full re-gate rather than by a push.

BOTH KEYED RECORDS moved again, and #815 edited one of them. The automatic
three-way merge was CLEAN and was DISCARDED for both (AGENTS.md Records): main's
version taken WHOLESALE, this row's scoped edit reapplied with the anchor
asserted unique, then verified against main.

  docs/FEATURES.md      -- differs from main by EXACTLY ONE line, the
                           `NemotronHForCausalLM` row. #815's own edit to :83
                           ("no loader forms a typed pointer into the mapping.
                           Last three fixed by #772") survives untouched, which
                           is the point of resolving by key rather than by file.
  tests/CMakeLists.txt  -- differs from main by EXACTLY ONE additive hunk,
                           606a607,649: 43 added, ZERO removed. #815's new
                           `test_loader_unaligned_offsets` target survives.

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…e new style checker (#517)

FOLLOWING_AGENTS_PROTOCOL

`origin/main` moved again between the previous gate and the push, so the whole
gate ran again rather than the earlier numbers being carried forward. The move
mattered for a second reason: `ddff09093` landed
`scripts/check-commit-style.py`, a checker this branch had never been measured
against, and it changed `scripts/agent-preflight.sh` with it.

At the merged head over `origin/main` @ `ca01719e6`:

  Release -Werror, CLEAN full build from an empty tree
      BUILD_EXIT=0, 0 `warning:`, 0 `error:`, 0 `No space left`, 1395/1395
  full `ctest -j4`
      471 of 471 PASSED, CTEST_EXIT=0, 111 s
      skipped: test_modelopt_mixed_precision_checkpoint, test_voxtral_e2e
  the four Nemotron-H suites
      scaffold 12/12, forward 13/13, loader 2/2, quantized_forms 5/5
  scripts/check-commit-style.py --range ca01719..HEAD
      OK: commit writing style
  scripts/check-commit-trailers.py --range origin/main..HEAD
      OK: commit trailer contract
  disk 100G free / 77%

One instrument failure is recorded because it nearly became a false report. A
`tail` of the ctest log taken one minute before the run started read a
PRE-EXISTING file naming a foreign worktree
(`.claude/worktrees/agent-a956d471bf9a3b7d0/build-rel`) and ending in `Errors
while running CTest`. The scratchpad is shared, so a stale log looks exactly
like a fresh red ([[scratchpad-is-shared-across-sessions]]). It was discarded
after checking that the live log names this worktree in its own header, and the
result above comes only from the run that did.

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

Copy link
Copy Markdown
Collaborator Author

Review repair pushed at c6255afa1, over origin/main @ ca01719e6. All seven findings repaired, none declined. Spec §6e is the authority.

#772 / #815 overlap — no overlap, and it is now checkable against main rather than a branch. #815 landed as ca01719e6. git show --pretty=format: --name-only ca01719e6 lists no nemotron_h_* file, and main's own nemotron_h_weights.cpp contains zero occurrences of CopyDense and neither of F1's two casts. The site F1 repairs does not exist on main; it arrives with this PR, which is why #772's sweep could not have seen it. Established with a positive control rather than a silent grep: the regex that is silent on the repaired file fires on voxtral.cpp:51,344 and qwen3_vl.cpp:78 — exactly #815's set. The two changes are complementary and together close the class.

Two things found by re-running the gate rather than by reading a diff.

test_nemotron_h_scaffold went red on the merge of #784 and this loader, though both parents are green and git merge reported no conflict — filed as #818 and repaired here by splitting the subcase, keeping #784's substance (no StubModel, no downcast, no UB). Both halves mutation-armed.

origin/main then moved again before the push and landed scripts/check-commit-style.py (POLICY-SINGLE-PR-AND-STYLE), a gate this branch had never been measured against. Re-merged at a pinned SHA and re-gated from scratch: OK: commit writing style.

Scope, stated plainly in the PR body: this branch makes the weights load. It does not make the model reachable from the public ABI — that is #810, at runner.cpp:525, a line this branch does not touch. Do not read "the real checkpoint runs" as "the server runs it".

Not merging; the operator merges.

@localai-bot localai-bot changed the title MODEL-NEMOTRON-H: the WEIGHT LOADER — the real checkpoint runs, in the formats it ships in (#517) MODEL-NEMOTRON-H: the WEIGHT LOADER — the real checkpoint LOADS in its packed format (the model is NOT yet reachable from the ABI, see #810) Aug 14, 2026
@localai-bot
localai-bot merged commit bc570da into main Aug 15, 2026
21 of 23 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