Skip to content

L9a: the first-party NVFP4 DiT loads -- it was SWIZZLED and HIGH-nibble-first, not linear (#435) - #571

Merged
localai-bot merged 6 commits into
row/MODEL-DIFFUSION-LTX25from
row/LTX25-L9A-NVFP4-LINEAR
Aug 13, 2026
Merged

L9a: the first-party NVFP4 DiT loads -- it was SWIZZLED and HIGH-nibble-first, not linear (#435)#571
localai-bot merged 6 commits into
row/MODEL-DIFFUSION-LTX25from
row/LTX25-L9A-NVFP4-LINEAR

Conversation

@localai-bot

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

Copy link
Copy Markdown
Collaborator

Closes the L9a gap in #435.
Also opens #598 (H3's NVFP4 gate is nibble-blind).
Specs: .agents/specs/nvfp4-nibble-order.md (new, committed BEFORE implementation), .agents/specs/ltx-2-5.md §4.1/§4.2.

The premise was wrong, and measuring it first is why nothing shipped broken

L9a was briefed to add a LINEAR [N, K/16] scale arm. The file is not linear. It is
SWIZZLED — the permutation Ltx2UnswizzleNvfp4BlockScale already inverts — merely declared in
the cuBLAS-padded framing instead of torchao's to_blocked one. For every layer in that file
N % 128 == 0 and G % 4 == 0, so the padded framing is numerically identical to the
linear shape. That coincidence is why the wrong diagnosis looked confirmed, and why no shape
test could ever have settled it. It also packs element 2j in the HIGH nibble.

Building the briefed arm would have made the file load and render silently wrong. L9a returned
NEEDS_DECISION instead; the operator retracted the diagnosis and ratified the design here.

How it was established

The vonkaiser FP8 DiT quantizes the same base weights, so it is an oracle that is not ours:

reading corr vs FP8 rel rms
LINEAR / low-first (the brief) 0.000414 1.786
LINEAR / high-first 0.257746 1.558
SWIZZLED / low-first (shipped dequant) 0.032296 1.394
SWIZZLED / high-first 0.995560 0.0946

Control: the same read against four other modules' FP8 weights gives 0.021, 0.005, 0.002,
0.001. Confirmed independently in Lightricks' own runtime (ltx-kernels/docs/NVFP4.md:27-29,
csrc/nvfp4/quantize.cu:26-31, ltx-core/quantization/nvfp4/linear.py:6-7).

What lands

  • Nvfp4NibbleOrder on DequantNvfp4ToBf16, defaulting to low-first, so the H3, Laguna,
    DeepSeek-V4 and Qwen3-32B callers are untouched by construction.
  • Ltx2ResolveNvfp4Producer: the torchao_nvfp4 marker decides, the framing corroborates,
    and every combination the shape can separate refuses by name. torchao always writes that
    marker, so its absence excludes torchao — an inference stated at the code site with its
    evidence, and with the limit of that refusal stated beside it (see F1 below).
  • A correlation gate, not a one-off script: committed real bytes, a control arm, a
    deliberately-wrong-order arm, and two scale/oracle-integrity arms, all asserted to collapse.
    It also asserts absmax is identical under both nibble orders, which is why "finite and
    correctly scaled" was never evidence here.
  • All 1176 quantized modules pushed through the resolver from the real 7876-tensor manifest:
    markers=0, resolved kNvfp4Prequant=1176, ambiguous_with_linear=1176.

Review repair (fresh review returned FAIL; six findings, all closed)

F1 — a "refuses by name" guarantee that was FALSE, stated to users. A marker-less NVFP4
checkpoint whose weight_scale is stored LINEAR [N, K/16] is shape-identical to the padded
framing for every geometry with N % 128 == 0 and G % 4 == 0, so it RESOLVES as
nvfp4-prequant and is read swizzled and high-first: finite, correctly shaped, correctly
scaled, wrong. That is the normal ModelOpt / llm-compressor / compressed-tensors layout —
vLLM allocates exactly it at modelopt.py:1335-1345 and
compressed_tensors_w4a4_nvfp4.py:73-76 — and none of the three emits a .torchao_nvfp4
sidecar, so the marker's absence excludes torchao and nothing else.

The decision is still right: the shipped DiT's __metadata__ carries only config,
gemma_source_checkpoint, model_version, license — no quantization_config, no producer
key, no quantizer-named tensor over all 7876 — so there is nothing better to key on. The
gate was NOT weakened; the sentence was corrected
in ltx2_loader.h, docs/USAGE.md and the
spec's risk table, and the residual hazard is now a tracked condition at spec §3.1.1 beside the
existing H3 reversal condition.

F2 — the ten-gate "byte-identical" evidence was half vacuous. Instrumented
DequantNvfp4ToBf16 with a call counter and re-ran mutation M3 (flip the shared default to
kHighFirst) across all ten gates:

gate live calls under M3
test_nvfp4_dequant 6 RED
test_gguf_nvfp4 6 RED
test_ltx2_loader 294 RED
test_qwen3_forward 30 GREEN — blind
test_minimax_h3 44 GREEN — blind (57,395 assertions)
the other five 0 GREEN — vacuous

Three of ten can see a nibble-order change. If H3 is ever routed through the new kHighFirst
while MiniMaxH3Nvfp4HighNibbleFirst() stays default-ON, the two compose into a double flip
and nothing fires — #598, linked from the
roadmap issue table and spec §5.5, which now carries the per-gate call counts.

F3 — a recorded number the gate does not produce. §7 recorded the wrong-order arm at
0.00514, matching no row of its own table. The gate reports corr -0.00239115 / rel
1.41856. §5.1 also named a throw as the red-before for a change with two independent
halves; both reds are now stated separately with the value each produces.

F4 — a comment contradicted by four call sites. nvfp4_dequant.h claimed the order is
"never defaulted per call site". It is, deliberately, and minimax_h3_nvfp4.cpp:112,
minimax_h3_device.cpp:1311, qwen3_5.cpp:1298 and dense_nvfp4_gemm.h all rely on it.

F5 — the correlation tolerance, RE-BOUNDED strictly stronger. rel_rms is a predicted
quantity
(0.100672), not an error budget. rel <= 0.15 admitted a +10% uniform group-scale
error, and Pearson correlation is scale-invariant — corr reads 0.994968 to every printed
digit for every multiplier — so nothing else could catch it. It also had no floor, so an arm
reproducing the FP8 oracle scored rel 0.0 / corr 1.0 and passed every correlation assertion.
Replaced by 0.085 <= rel <= 0.115 plus corr <= 0.998, proven strictly stronger by A/B on
the same binary path with only the bound differing:

mutation old bound new band
x1.09 group scale inside the dequant (rel 0.1411) GREEN 45/45 Status: SUCCESS! RED
the FP8 oracle as the gate's own answer every correlation assertion passes RED on the result itself

Both are now permanent arms of the gate, not one-off logs.

F6 — the witnesses, recorded honestly. torchao is neither installed nor vendored here, so
kernels.py:160 / :137-139 are upstream source only. vLLM's break_fp4_bytes is reached
only from dequantize_to_dtype (ModelOpt / compressed-tensors); vLLM's torchao path
(torchao.py:290-318) delegates to torchao.quantization.quantize_ and never calls it. §1.1
now tabulates what each witness proves and how it was verified. The default is unchanged.

Evidence

  • RED before (corr = -0.0024, rel_rms = 1.419), GREEN after (0.994968 / 0.100672).
  • Mutations, tree restored byte-for-byte after each: forcing low-first, resolving
    marker-less-padded as torchao, an apostrophe in a refusal, M3 (shared default flip), M4
    (x1.09 and x1.10 group scale), and the too-good oracle arm.
  • ctest -N 409; full ctest 409/409 passed, 0 failed, 1 skipped (test_voxtral_e2e).
    Release, CUDA=OFF, BUILD_EXIT=0, no No space left/BFD assertion in any build log.
  • The ten NVFP4 gates, nine unchanged and one moved: test_nvfp4_dequant 5/69,
    test_gguf_nvfp4 14/2352, test_qwen36_weights 7/45, test_qwen3_forward 7/1557,
    test_minimax_h3 79/57395, test_ops_nvfp4_matmul 4/1, test_ops_moe_grouped 6/3,
    test_ops_nvfp4_fp4 22/919, test_ltx2_device 13/498, test_ltx2_loader 24/4809
    (4793 -> 4809, the +16 from the re-banding and its two built-in mutation arms).
  • GB10, one flock hold 02:31:03-02:37:15: both shipped DiTs stage device-resident and
    forward. NVFP4 (18,721,432,024 B, 7876 tensors) 5626 assertions, absmax video 0.275391 /
    audio 1.02344. FP8 5624 assertions, absmax video 0.300781 / audio 2.14062 — reproducing the
    previously recorded GB10 figures to the digit.

ltx-2-5.md §4.2 is closed with no defect: torchao is low-first, so the shipped
text-encoder arm was already correct and its gate is now source-anchored instead of comparing
our helper to itself. (The earlier "three independent witnesses" phrasing is corrected in
spec §1.1 per F6.)

Known pre-existing: check-doc-checkpoint flags three commits inherited by this branch
(b0aa475a3, d67f8125e, 7d08e220a) for not updating docs/FEATURES.md. Identical before
and after this repair, and docs/FEATURES.md is the lock recorded in
#595. The staged-change checkpoint passes.

🤖 Generated with Claude Code

mudler added 5 commits August 13, 2026 02:07
…rs disagree (#435)

`DequantNvfp4ToBf16` is low-nibble-first, which is right for torchao and
ModelOpt and wrong for Lightricks' `nvfp4-prequant` and for the H3 community
converter. Read the wrong way round, every adjacent fp4 pair is transposed:
finite, correctly shaped, and wrong.

The header is shared with the MiniMax-H3, Laguna, DeepSeek-V4 and Qwen3-32B
NVFP4 arms, so this is not LTX-2.5 loader work and does not ride inside that
row. Spec committed before implementation.

Records four things the implementation then has to honour:

  * the convention per producer, each with the line that packs or unpacks it
    (torchao `kernels.py:160`, vLLM `nvfp4_emulation_utils.py:321-324`,
    ltx-kernels `docs/NVFP4.md:27-29`);
  * that ltx-2-5.md section 4.2's open question is ANSWERED -- torchao is
    low-first on three independent witnesses, so the shipped text-encoder arm
    is correct and there is no defect to chase;
  * why H3's existing nibble-swap-at-load is NOT reused here, and the exact
    condition under which that decision must be revisited -- an fp4-resident
    LTX path, which a host-side dequant parameter could not fix;
  * a correlation gate against the vonkaiser FP8 DiT as an independent oracle,
    WITH a control arm, because a gate that cannot separate a correct read from
    a wrong one is section 7.0(c) over again.

The parameter defaults to today's behaviour, so existing callers are untouched
by construction; the proof obligation is that all ten NVFP4 gates keep their
exact case and assertion counts, and those baselines are recorded here.

FOLLOWING_AGENTS_PROTOCOL

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

The file was refused, and the refusal carried a WRONG diagnosis: it said the
group scale was stored LINEAR [N, K/16]. It is not. The bytes are SWIZZLED --
the permutation Ltx2UnswizzleNvfp4BlockScale already inverts -- merely declared
in the cuBLAS-padded framing [round_up(N,128), round_up(G,4)] instead of the
to_blocked [32*ceil(N/128), 16*ceil(G/4)] the loader knew. For every layer in
that file N % 128 == 0 and G % 4 == 0, so the padded framing is NUMERICALLY
IDENTICAL to the linear shape. That coincidence is why the wrong diagnosis
looked confirmed, and why no shape test could ever have settled it.

The file also packs element 2j in the HIGH nibble, which no shape encodes at
all. Both facts came from correlating the dequantized weights against the
vonkaiser FP8 DiT of the same base weights -- an oracle that is not ours --
and were then confirmed in Lightricks' own runtime.

  ltx-kernels/docs/NVFP4.md:27-29        hi_first=True is the default
  ltx-kernels/csrc/nvfp4/quantize.cu:26-31  swizzled_offset, padded framing
  ltx-core/quantization/nvfp4/linear.py:6-7 both statements together
  torchao kernels.py:160                 low-first, the other convention
  vllm nvfp4_emulation_utils.py:321-324  vLLM reads low-first, agreeing

What lands:

  * Nvfp4NibbleOrder on DequantNvfp4ToBf16, DEFAULTING to low-first, so the
    MiniMax-H3, Laguna, DeepSeek-V4 and Qwen3-32B callers are untouched by
    construction rather than by inspection;
  * Ltx2ResolveNvfp4Producer -- the torchao marker decides, the framing
    corroborates, and every other combination REFUSES BY NAME. torchao always
    writes that marker, so its absence excludes torchao; that inference is
    stated at the code site with the evidence behind it, because it is the one
    step here not read directly off the file;
  * a CORRELATION GATE against the FP8 checkpoint, with a CONTROL arm and a
    deliberately-wrong-order arm, both asserted to collapse. corr 0.995, rms
    10.1%, control 0.004, wrong-order 0.005. It also asserts absmax is
    IDENTICAL under both nibble orders -- which is why "the output was finite
    and correctly scaled" was never evidence of anything here.

The synthetic NVFP4 fixture declared the to_blocked framing with NO marker: a
combination neither producer emits. The new discriminator refused it, correctly,
and the fixture was what was wrong -- it now mirrors the shipped artifact.

Ten NVFP4 gates re-run. Eight byte-identical to baseline; the two that rose are
the two this change adds cases to (test_nvfp4_dequant 4/47 -> 5/69,
test_ltx2_loader 20/2363 -> 23/2426). All nine LTX/video baselines unchanged.

Also settles ltx-2-5.md section 4.2: torchao is low-first on three independent
witnesses, so the shipped text-encoder arm is CORRECT and there is no defect to
chase. Its gate is now source-anchored instead of comparing our helper to itself.

FOLLOWING_AGENTS_PROTOCOL

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

The loader refuses in single quotes, and users grep the checkpoint with what
those quotes contain. An apostrophe in ordinary prose opens a quote that closes
on the next one, so the message starts naming a fragment of its own explanation
instead of a tensor. The marker-present branch shipped one: "under the other's
assumption" made the refusal quote

  'transformer_blocks.0.attn1.to_q.weight_scale' ... under the other's

with an ODD number of delimiters.

The whole-file refusal path already asserted this invariant; the resolver's own
two refusals did not, which is how it got in. The discriminator case now scans
both of them: quote count must be EVEN, at least one pair, and every quoted span
must equal the tensor the refusal is about. Reinstating the apostrophe as a
mutation turns that case red on "single-quote count = 3", so the assertion is
gated rather than asserted.

FOLLOWING_AGENTS_PROTOCOL

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

The correlation gate proves ONE module decodes correctly. It does not prove the
discriminator resolves the same way for the other 1175, and "I sampled a few and
they agreed" is precisely how the linear-layout diagnosis got written.

So the shipped NVFP4 DiT's own header goes in as a fixture (7876 tensors, names
and shapes only, no weight bytes) and every U8 weight in it is pushed through
Ltx2ResolveNvfp4Producer. Measured:

  packed=1176  markers=0  weight_scale_2=1176  input_scale=1176
  resolved kNvfp4Prequant=1176  padded framing=1176  to_blocked framing=0
  ambiguous_with_linear=1176

The last number is the one worth keeping. For EVERY module in this file the
cuBLAS-padded framing is numerically identical to the linear [N, K/16] shape, so
a shape test could not have separated swizzled from linear for a single one of
them. That is now a counted, gated fact instead of an argument in a comment.

markers=0 is the other load-bearing one: torchao always writes its sidecar, so
zero of them across 7876 tensors is what excludes torchao and licenses the
marker-less arm. input_scale=1176 records the export as W4A4-shaped, whose
activation scales this weight-only path discards exactly as vLLM's own W4A16
method does (modelopt.py:1264-1268).

test_ltx2_loader 23/2432 -> 24/4793.

FOLLOWING_AGENTS_PROTOCOL

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

Records what neither the code nor git does: the four-way correlation table, the
three designs rejected and why, why the default is low-first, and the GB10 run
where BOTH shipped DiTs stage and forward.

The FP8 arm's absmax reproduces the previously recorded GB10 figures to the
digit. That is what makes the NVFP4 numbers beside it evidence rather than
merely new -- the harness is shown to be the same one that produced the
accepted result.

Also records what was NOT obtained: the device case's MESSAGE text was cut by a
tail in the run harness, and the capture re-run timed out on the GPU lock
(FLOCK_EXIT=1) against a box saturated by two other rows. The facts it would
have printed are asserted among the 5626 passing assertions and gated from the
committed manifest, so this is cosmetic -- said plainly rather than quietly
omitted.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…d the sweep proving nothing (#435, #598)

Six review findings on the L9a nibble-order change. The implementation is
sound and the correctness argument holds; every one of these is an accuracy or
coverage defect in what the change CLAIMS.

F1 -- a safety guarantee that is false, stated to users. Three places said any
other marker/shape combination is "refused by name". It is not. A marker-less
NVFP4 checkpoint whose weight_scale is stored LINEAR [N, K/16] has, for every
geometry with N % 128 == 0 and G % 4 == 0, a shape numerically IDENTICAL to the
cuBLAS-padded framing. Ltx2ResolveNvfp4Producer returns kNvfp4Prequant for it,
the loader then unswizzles scales that were never swizzled AND reads high-first,
and the result is finite, correctly shaped, correctly scaled, WRONG. The refusal
branch is unreachable for that entire class.

That is not an exotic file. LINEAR [N, K/16] is what ModelOpt, llm-compressor
and compressed-tensors all write -- vLLM's own readers allocate exactly that
shape at modelopt.py:1335-1345 and
compressed_tensors/schemes/compressed_tensors_w4a4_nvfp4.py:73-76 (pin
555967922) -- and none of the three emits a .torchao_nvfp4 sidecar. So the
marker's absence excludes torchao and NOTHING ELSE.

The decision is still right, because there is no better evidence in the file,
and that was checked rather than assumed: the shipped DiT's __metadata__ carries
exactly config, gemma_source_checkpoint, model_version and license -- no
quantization_config, no producer key, no nvfp4/torchao/quant substring anywhere
in the config, and no tensor name mentioning the quantizer over all 7876 tensors.
Unlike MiniMax-H3, whose community checkpoint DID name its converter, there is
nothing here to key on. So the gate is NOT weakened; the sentence is corrected,
in ltx2_loader.h, docs/USAGE.md and the spec's risk table, and the residual
hazard becomes a tracked condition at spec section 3.1.1 beside the existing
H3 reversal condition.

F2 -- the ten-gate "byte-identical" evidence is half vacuous, and two live
gates are blind. Instrumented DequantNvfp4ToBf16 with a call counter and re-ran
mutation M3 (flip the shared default to kHighFirst) across all ten:

  RED     test_nvfp4_dequant 6 calls, test_gguf_nvfp4 6, test_ltx2_loader 294
  GREEN   test_qwen3_forward 30 calls, test_minimax_h3 44 calls / 57,395 asserts
  GREEN   the other five make ZERO calls on a default run

Three of ten can see a nibble-order change. Five never execute the function, so
their identical counts are evidence of nothing about it. Two execute it live and
still pass -- and one of those is the project's OTHER high-first family, gated by
exactly the statistic this spec proves is blind. If H3 is ever routed through the
new kHighFirst while MiniMaxH3Nvfp4HighNibbleFirst() stays default-ON, the two
compose into a double flip and nothing in the tree fires. Opened #598 for a
nibble-sensitive H3 gate, linked from the roadmap issue table and the spec.

F3 -- a recorded number the gate does not produce. Section 7 recorded the
wrong-order arm at 0.00514, which matches no row of its own table and no line
of the gate. The committed gate reports corr -0.00239115 / rel 1.41856. The
control on the same sentence, 0.00362, was exact. Section 5.1 also named "the
loader refuses the shape" as THE red-before for a change with two independent
halves; a throw can only ever demonstrate the layout half, so both reds are now
stated separately with the value each produces.

F4 -- a comment contradicted by four call sites. nvfp4_dequant.h said the order
is "never inferred and never defaulted per call site". It IS defaulted, and
deliberately: minimax_h3_nvfp4.cpp:112, minimax_h3_device.cpp:1311,
qwen3_5.cpp:1298 and dense_nvfp4_gemm.h all rely on it. The seam that genuinely
has no default is Ltx2DequantNvfp4ToBf16. Comment corrected to say which is
which and why.

F5 -- the correlation tolerance was loose in one direction and unbounded in the
other, RE-BOUNDED strictly stronger. rel_rms is a PREDICTED QUANTITY (the
disagreement two different quantizations of the same base weights must show,
measured 0.100672), not an error budget. `rel <= 0.15` alone admitted a +10%
uniform group-scale error, and Pearson correlation is scale-INVARIANT -- corr
reads 0.994968 to every printed digit for every multiplier -- so nothing else in
the gate could catch it. It also had no floor, so an arm that reproduced the FP8
oracle exactly scored rel 0.0 / corr 1.0 and passed every correlation assertion.

Replaced by a band: 0.085 <= rel <= 0.115, plus corr <= 0.998. Proven strictly
stronger by A/B on the SAME binary path, only the bound differing:

  x1.09 group-scale error inside DequantNvfp4ToBf16, rel 0.1411
      old `rel <= 0.15`   GREEN  45/45  Status: SUCCESS!
      band               RED    CHECK( 0.1411 <= 0.115 ) is NOT correct!
  the FP8 oracle handed to the gate as its own answer
      old bounds         every CORRELATION assertion passes; only the
                         incidental absmax equality fires
      band               RED on the result itself: rel >= 0.085 AND corr <= 0.998

Both mutations are now permanent arms of the gate rather than one-off logs, in
the same style as the wrong-nibble arm: the gate asserts that a x1.10 scale
error moves corr by less than 1e-6 (measured 7.35e-11) while pushing rel out of
the band, and that the oracle-against-itself lands outside it too.

F6 -- record the limit honestly. Section 1.1 claimed "three mutually consistent
and independent witnesses". torchao is neither installed nor vendored on this
box (import fails; no mx_formats/kernels.py on the filesystem), so its two lines
are upstream source only, not executable here. And vLLM's break_fp4_bytes is
reached only from dequantize_to_dtype, which serves the ModelOpt and
compressed-tensors paths -- vLLM's torchao path (torchao.py:290-318) delegates
to torchao.quantization.quantize_ and never calls it. So vLLM witnesses ModelOpt,
not torchao's writer. Section 1.1 now tabulates what each witness proves and how
it was verified. The default is unchanged; nothing moves either way.

Gates (Release, CUDA=OFF, BUILD_EXIT=0, no ENOSPC/BFD in any build log,
df 84% throughout). ctest -N 409, full ctest 409/409 passed, 0 failed, 1 skipped
(test_voxtral_e2e). The ten NVFP4 gates, nine unchanged and one moved:

  test_nvfp4_dequant     5 / 69        test_ops_nvfp4_matmul   4 / 1
  test_gguf_nvfp4       14 / 2352      test_ops_moe_grouped    6 / 3
  test_qwen36_weights    7 / 45        test_ops_nvfp4_fp4     22 / 919
  test_qwen3_forward     7 / 1557      test_ltx2_device       13 / 498
  test_minimax_h3       79 / 57395     test_ltx2_loader       24 / 4809

test_ltx2_loader 4793 -> 4809 is the +16 from the re-banding and its two
built-in mutation arms; it is the suite this change adds assertions to. Tree
restored byte-for-byte after every mutation.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
@localai-bot
localai-bot merged commit ebbbcc2 into row/MODEL-DIFFUSION-LTX25 Aug 13, 2026
localai-bot pushed a commit that referenced this pull request Aug 13, 2026
…survive measurement (#435)

Eight findings from the L10 fresh review. Six close as written; two close
differently, because the thing they prescribed does not work and the oracle says
so. Both are recorded here rather than quietly worked around, since an
implementer who accepts a prescription that fails is the failure this protocol
exists to catch.

────────────────────────────────────────────────────────────────────────────────
F3 — THE PRESCRIBED FIX IS REFUTED; THE ROPE TABLE IS THE INSTRUMENT

The finding is real: `g.rope_partial_full = 1.0` (full rotary on the full-
attention layers instead of the config's 0.25) left the suite green at 23 cases
/ 3583 assertions. Reproduced here before touching anything.

The prescription was "a fixture whose global_head_dim/seq keep the rope
contribution above the floor". MEASURED against the oracle, per state, as
signal = max|bf16 @0.25 - bf16 @1.00| over floor = max|f32 - bf16|:

    committed        head_dim  8/16  seq  8    worst signal/floor  1.095
    wider full head  head_dim 16/32  seq  8                        0.258
    longer seq       head_dim  8/16  seq 24                        0.764
    wider + longer   head_dim 16/32  seq 24                        0.523
    wider + longer   head_dim 16/32  seq 32                        0.650

Enlarging the fixture makes it WORSE. bf16 accumulation noise grows at least as
fast as the rope contribution, so no reachable fixture size separates them: the
hidden states are the wrong instrument, not a badly sized one.

The right instrument is the table. `BuildProportionalRopeCache`'s host
computation is split out and exported as `Gemma4ProportionalRopeCosSin`, the
generator emits the oracle's own `Gemma4UnifiedTextRotaryEmbedding` cos|sin for
the full-attention layer type (section 6), and the new case compares them in
f32 with nothing accumulating. Measured agreement 1.267e-07 against a 1e-6
bound, plus an EXACT structural check that pairs at and beyond
`int(partial*head_dim//2)` are cos=1, sin=0 and that the pairs below it really
rotate.

    RED  under the mutation: 202 assertions fail, worst 0.56533 vs 1e-6, exit 1
    GREEN restored:          26 cases / 4115 assertions, exit 0

────────────────────────────────────────────────────────────────────────────────
F2 — THE VALUE GATE AND THE LOADER, IN CI; AND M6 IS NOT WHAT IT LOOKED LIKE

`Ltx2EncodePromptToConditioning`, `Ltx2LoadGemmaTowerFromSafetensors` and all
four documented refusals were reachable from exactly ONE place — the opt-in
24 GB case — so none had CI coverage.

They do now. The reduced tower fixture, which is already held to a running
oracle, is written out as a real .safetensors under the CHECKPOINT's tensor
names, loaded back, and compared to the fixture byte for byte; then a tokenizer
whose added tokens spell the oracle's own token ids drives the whole prompt path
and its conditioning is held to the committed LEFT-PADDED oracle run at a floor
propagated through the identical projection.

    concat order q,k,v -> q,v,k          RED  14 assertions, exit 1
    PLE refusal disabled                 RED   1 assertion,  exit 1
    missing-v_proj refusal disabled      RED   1 assertion,  exit 1
    module dtype F16 read as bf16        RED   1 assertion,  exit 1
    norm vector F16 read as bf16         RED   1 assertion,  exit 1
    conditioning at 0.565x / 0.688x of its propagated floor

Now the part that did not survive. The review called `positions[i] = i` "the
exact defect the surrounding comment warns about". It is not a defect at all.
Rotary embedding is RELATIVE and the pads are masked out of attention, so
shifting every position by the pad count cancels. MEASURED in the oracle, same
8 tokens told 12..19 and told 0..7:

    f32   max|diff| 5.11e-05 over max|value| 14.35   3.6e-06 relative
    bf16  max|diff| 1.09                             0.65-1.70x the dtype floor

f32 round-off, and at bf16 the rounding of different absolute angles. So the
comment at ltx2_text_encoder.cpp — "a port that renumbers from zero rotates
every query by the wrong angle" — was an overclaim, and so was its twin in the
left-pad case. Both now carry the measurement. The numbering is still mirrored,
because transformers derives positions from `cache_position` and fidelity is the
reason; arithmetic is not. The new case does red under the renumbering, at 1.10x
the audio floor, and says in its own comment that the narrow margin is a
property of the defect rather than of the gate.

────────────────────────────────────────────────────────────────────────────────
F4 — THE GENERATOR'S LEGS WERE COUPLED, AND NOT WHERE IT LOOKED

`run_tower` did `inner.to(dtype)`, which converts IN PLACE, so every leg after
the bf16 one ran downstream of it. Each leg now runs on a `copy.deepcopy`.

The mechanism is narrower than "bf16-rounded weights": MEASURED on this
transformers build, the parameters round-trip unchanged, and it is the rotary
embedding's non-persistent `inv_freq` BUFFERS that do not — 9.36e-05 on the
full-attention table, 9.77e-05 on the sliding one. Regenerating moved 12 of the
13 padded f32 states (state 12 by 1.03e-02 on values of 2.705) and every entry
of the pad-equivalence vector, while sections 2, 3 and 3b are byte-identical —
which is exactly the partition the in-place conversion predicts. The header's
claims about sections 4 and 5 are corrected to match.

────────────────────────────────────────────────────────────────────────────────
F5, F7, F8, F9

F5  337 -> 329, and pinned exactly rather than `> 300`. The count is arithmetic
    and now says so: 40*7 + 8*6 + 1. A lower bound is satisfied by a loader that
    quietly took a third of the layers from a bf16 fallback.

F7  The rationale was inverted. Upstream calls `self.tokenizer(text, ...)` —
    `__call__` with its default `add_special_tokens=True` — so upstream DOES run
    the post-processor and we do not. Identical on this checkpoint because its
    `special_tokens` map is empty, measured. "THE TWO REFERENCES DISAGREE" also
    overstated it: both let the post-processor run, and only the explicit BOS
    prepend differs. Both corrected.

F8  `kv.dtype` on the production prompt path was f32 where upstream resolves
    bf16 and where the attention itself runs bf16. Narrowed, not annotated. It
    was never wrong — it was WIDER, which is why nothing could see it: with the
    cache back at f32 the new conditioning gate reproduces 0.0617859 / 0.0394362
    byte for byte. Half the cache bytes, and it stops taking `Gemma4AttnBlock`'s
    two-cast-buffers-plus-CastF32 arm on every layer.

F9  The dropped `docs/FEATURES.md` edit is reapplied onto the campaign's
    rewritten row, truthfully: "Text tower RUNS" alongside the `encoder_path`
    refusal, which another change owns and this one does not touch. Row 533
    chars, cells 60/28/217/215.

    `docs/USAGE.md` is owed too, and the debt turned out to be real rather than
    procedural: line 372 still said "the Gemma-4 12B text tower is not ported",
    which is false and which the paragraph 85 lines below it already
    contradicted. One document, two answers about one model. Corrected to state
    that the tower runs and to defer to that paragraph for what still blocks a
    prompt. The `encoder_path` passage itself is untouched — it belongs to the
    change that owns F1.

────────────────────────────────────────────────────────────────────────────────
NOT CLOSED HERE, AND OWED

F1 and F6 are out of scope by instruction — another implementer owns whether the
`encoder_path` refusal can be lifted now that L9c landed the connector weights.

The spec is operator-owned, so this reports rather than edits it. Two things it
needs. First, §4.2's open question stands and should not be narrowed by anything
above: the shipped NVFP4 tower's output is still never compared to an
independent oracle, so "all 49 hidden states within the oracle's bf16 noise
floor" is proven for the SYNTHETIC reduced tower with bf16 weights and not for
the quantized one that ships. PR #571 built the independent-oracle correlation
technique that would close it. Second, the position-numbering claim appears in
the spec in the same overclaiming form corrected here.

────────────────────────────────────────────────────────────────────────────────
GATE

    cmake -S . -B bld -G Ninja -DCMAKE_BUILD_TYPE=Release -DVLLM_CPP_BUILD_EXAMPLES=OFF
    cmake --build bld -j 12                    BUILD_EXIT=0, no ENOSPC/BFD, df 88%
    ctest -N                                   409 tests
    ctest -j 8 --output-on-failure             409/409 passed, exit 0
    ./bld/tests/test_ltx2_text_encoder         26 cases / 4115 assertions, exit 0
                                               (baseline was 23 / 3583)

`scripts/agent-preflight.sh` fails `doc-checkpoint range` on commits b0aa475,
d67f812 and aa6aa0e. All three are ancestors of the branch head this work
started from and none is touched here.

Issue: #435

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
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