Skip to content

fix(LTX25-TILED-DECODE): chunking binds at 81 frames, and the untiled-axis mapper had no gate (#644) - #746

Open
localai-bot wants to merge 16 commits into
mainfrom
row/LTX25-TILED-DECODE-FIX
Open

fix(LTX25-TILED-DECODE): chunking binds at 81 frames, and the untiled-axis mapper had no gate (#644)#746
localai-bot wants to merge 16 commits into
mainfrom
row/LTX25-TILED-DECODE-FIX

Conversation

@localai-bot

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

Copy link
Copy Markdown
Collaborator

Answers the FAIL review of PR #656 and the records FAIL review of this PR. Issue #644, spec .agents/specs/ltx25-tiled-decode.md.

Two reviewers have confirmed the engineering independently: all three refutations reproduced, the tiling goldens regenerated byte-for-byte, the memory probe reproduced at three scales, and Ltx2VideoDecodeStreaming verified bit-identical to the untiled path on the real checkpoint. None of that is re-litigated below. Every finding from both reviews is closed with reproduced RED/GREEN evidence.

F1 (BLOCKING) — temporal chunking binds at 81 frames, not 121

latent_t = (frames - 1) / 8 + 1 reaches 11 at 81 frames, and split_temporal_causal short-circuits only while latent_t <= 10 (tiling.py:239-240). Executed against upstream at the pin over range(1, 137, 8), the interval count goes 1 → 2 exactly at 81.

The row's own golden already said so — kLtx2AutoCases carries 768x768/81f -> t_intervals = 2, chunks = 2 — and docs/FEATURES.md said 81. Five prose sites said 121 and are corrected: ltx2_tiling.h, ltx2_video.cpp, docs/USAGE.md, and §0 / §1 / §2 of the spec.

Root cause, recorded because it is the reusable part. scripts/probe_ltx2_tiling_layout.py swept 9, 25, 25, 25, 121, 241 — it never sampled a frame count between 25 and 121, so it stepped over its own binding point and the number it happened to land on became the threshold. The probe now walks the temporal axis one latent frame at a time and asserts the transition is at 81, naming every file to reconcile if it ever moves. A sweep that skips its binding point now fails instead of publishing a number.

The 81–120 window is stated, not implied. docs/USAGE.md records the recipe default as 1024x1536 at 121 frames, so an ordinary request is inside it. scripts/probe_ltx2_tiled_equivalence.cpp measures it on the shipped conv VAE (ltx-2.5-video-vae-conv-bf16.safetensors, sha256 685b06ee3d9b2039647698fc4ea33175112462fc374e2777312c907897dfce8d) at 81 64 64:

[equiv] 64x64, latent 11,2,2  AUTO h=768/64 w=768/64 f=80/24
[equiv] tiles=2 groups=2  ->  untiled [3,81,64,64]  streamed [3,81,64,64] chunks=2
[equiv] max|diff| = 0.050304323434829712   non-bit-identical floats = 962983 / 995328
[equiv] untiled |out|max = 0.75126725435256958   ratio = 6.6959%
[equiv] (a FLAT append of the chunk buffers — the WRONG layout, kept only to show the size of the artifact — would report max|diff| = 0.71614238619804382, 985849 / 995328)

96.75% of channel values move, by up to 6.70% of the output's own range. That is upstream's behaviour, mirrored — but the one-tile control's safety argument covers below 81 frames and not 81–120, and now says so.

That headline was 0.716 — "95% of the output's own range" — until it was re-derived, and it was 14x too large. The probe reassembled the streamed chunks with a flat append, and a chunk is [C, t, H, W] CHANNEL-MAJOR (ltx2_video_vae.h:212-220), so appending buffers end to end is not [C, T, H, W] once C > 1 and there is more than one chunk — both true here (C = 3, chunks = 2). It was comparing channel 1 against channel 0's later frames. The refuted figure is kept named as refuted, and the corrected probe prints it as a labelled diagnostic on every run, so both columns come out of one binary on one run:

flat-append artifact (REFUTED) corrected
max|diff| 0.71614238619804382 0.050304323434829712
non-bit-identical 985849 / 995328 (99.05%) 962983 / 995328 (96.75%)
untiled |out|max 0.75126725435256958 0.75126725435256958
ratio of range 95.3% 6.6959%

The qualitative conclusion is untouched — nearly every value still moves, 81–120 is still a tiled regime the one-tile control does not cover, and the refusal stands. Only the magnitude was wrong, and it was wrong in the direction that made the argument look stronger.

F2 (BLOCKING) — the !IsTiled() mapper branches shipped ungated

Reproduced first. With map_t/map_s's {1.0f} broadcast masks set to {0.0f} — which multiplies the entire decoded volume by zero, i.e. renders a black clip — at the reviewed head:

test_ltx2_tiling : 9 cases | 9 passed | 0 failed ; 830 assertions | 830 passed  SUCCESS
test_ltx2_video  : 30 cases | 30 passed | 0 failed ; 502 assertions | 502 passed SUCCESS

Measured rather than assumed. Swept over all eight (frames, height, width) × (tiled, untiled) combinations against upstream at the pin:

frames spatial upstream tiled_decode
tiled any combination runs; max|diff| vs forward == 0.0
UNTILED every combination TypeError at conv_video_decoder.py:424

because DEFAULT_MAPPING_OPERATION hands it slice(0, None) and :424 subtracts that None stop. The two halves are therefore not symmetric, and are closed differently:

  • the spatial half is gated end to end — a new UNTILED_SPATIAL arm in the generator (kLtx2TileDec*UpstreamUntiledSpatialVsUntiled, *UntiledSpatialChunkCount) and a (B'') control in RunDecodeArm on both causality arms;
  • the temporal half is refused by name in Ltx2ConvVideoDecodeTiled, mirroring upstream's own failure rather than inventing a concrete stop upstream never computes. kLtx2TileDec*UpstreamUntiledFramesRaises records that upstream raises, so the refusal is mirrored and not local policy;
  • the mapper output itself is pinned by new goldens section 3b (kLtx2UntiledMap*), upstream's create_tiles executed on an all-untiled config.

The same black-out mutation now goes RED: 10 cases → 7 passed / 3 failed, 907 assertions → 5 failed, exit 1, with untiled-spatial control max|diff| vs untiled = 2.31736 against upstream's 0. Restored (git diff empty), rebuilt GREEN.

F3 — the recorded ctest -N did not reproduce

It never could. 416 was the ninja edge count of ninja test_ltx2_tiling test_ltx2_vae test_ltx2_video, whose last line is [416/416] Linking CXX executable tests/test_ltx2_video — a build number read as a test number, so "full ctest 416/416" describes a run that never happened at that denominator. The real value and the configure line that produces it are recorded together under The gate below.

F4–F10

  • F4 ltx2_video_vae.cpp:17-18 no longer records tiled decode as owed; the encoder half still is.
  • F5 the shared Ltx2NoiseStream* across tiles is documented at the declaration and recorded under What is owed. It mirrors upstream (self.forward per tile, one generator) and is inert on the shipped checkpoint (timestep_conditioning: false, no inject_noise); a gate over a noise-drawing config is owed.
  • F6 a new multi-chunk test_ltx2_video case drives chunk.first_frame + f through the PPM writer at 81 frames. Per-chunk numbering goes RED at 35 assertions.
  • F7 a previous render's frame tail is deleted before a new render writes, so a shorter re-render can no longer be muxed past its own end. Disabling the cleanup goes RED at 72 assertions.
  • F8 the "the full pixel volume is NEVER materialized" claim is bounded to the tiled case at both anchors — at one tile the chunk is the volume.
  • F9 the compile line for both probes is recorded in their headers, with why they are deliberately not CMake targets.
  • F10 the fixture's res_x_y block (a global GroupNorm the shipped ladder lacks) is disclosed in the test header, with which claim it affects and which it does not.

The records review of this PR — what closed each finding

F-A (BLOCKING) — this description still published the number the cycle exists to retract. The tree was corrected at five sites; the surface a merger reads was not. This body carried max|diff| = 0.716…, "99.05% of channel values move, by up to 95% of the output's own range", and a ctest -N of 448. That is this row's own defining failure — a 14x-wrong headline on a reader-facing surface — live on the pull request whose subject is repairing it. Closed by rewriting the body from a fresh run of the probe, by its own recorded recipe, on the merged head; the refuted figure stays, named as refuted, because a correction that deletes the wrong number teaches nothing.

F-B (BLOCKING) — 48 commits behind, two keyed records in conflict. git merge-tree --write-tree exited 1 with content conflicts in .agents/roadmap_v1.md and docs/FEATURES.md, both keyed records that must never take an automatic three-way merge. Both took main's file whole against a pinned origin/main SHA — never the moving ref, because this is a shared checkout and a peer's fetch advances it mid-operation. .agents/roadmap_v1.md is now byte-identical to main: this branch's only edit to it was one issue-intake row, and #846 moved that table into the append-only .agents/issue-index.md, where the #644 row already exists and is current, and where check-issue-index-append-only.py forbids editing a row and check_issue_index forbids duplicating one. docs/FEATURES.md differs from main by exactly one added line, this row's own key; every unrelated key is byte-identical, including the Safetensors direct load, no conversion row that was duplicated at the old head and is single on main (#769). The five silent auto-merges against c629b5d0f (the same campaign's image conditioning) were checked by semantics rather than by the absence of a conflict — a clean merge-tree is not a tree that builds — and the result rebuilt and re-gated from scratch.

F-C — the recorded test_op_parity red was expected at the old head and is gone. 043e56862 (fix(GATE-OP-PARITY-MANIFEST), closes #755) is in main and is not in the old head's ancestry (git merge-base --is-ancestor exit 1, positive control on the merge base exit 0). The 1-of-456 failure was therefore a missing fix, not a standing red, and it does not reproduce on this merged head.

F-D (nit) — the density assertion's message named only one of its two causes. The walk requires latent_t to advance by exactly 1 per step, so a step finer than 8 pixel frames repeats a depth and fails too — correct for the anti-fake purpose, but a future editor tightening the sweep would read the failure as "upstream moved the bound". The message now names both directions and says which fix each needs. Both mutations reproduce: step 8 → 80 exits 1 (latent_t jumps [(1, 11)], 2 frame counts visited) and step 8 → 4 exits 1 (17 zero-jumps, 34 frame counts visited); unmutated it exits 0 over 17 densely walked frame counts.

F-E (nit) — the raise-mechanism goldens were emitted into C string literals unescaped. A future upstream message or checkout path carrying a " or a backslash would have produced a golden that does not compile, while the generator reported success. Both fields now go through json.dumps. On today's values the output is byte-identical, proven rather than argued: the regenerated file's sha256 is bf2bdb4d43e73d4da73e360a816ee20e5f4b9224902fab9486fb173822a41d12, equal to the committed one, diff exit 0.

The gate

Head 84e2ec8ee67c839817a2f932dd81dc3c03dd4432, whose tree is e34e10e37b892dc36167fa677c845850ba2445e2 plus this spec's gate record; the gate itself was run on e34e10e37, which merges main pinned at b5a5f3b182d7e8c1b4b3781da32726d3d6eda5ec. Two merge commits, each resolved against a pinned SHA rather than the moving ref: 02444f5ff (main @ 51e0cb5b1, 48 commits, the two keyed-record conflicts of F-B) and e34e10e37 (main @ b5a5f3b18, whose Music3 row sits immediately above this row's docs/FEATURES.md key and conflicts for that reason alone; resolved the same way). Every number below is from this head — nothing is carried forward.

Clean rm -rf build + cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release + ninja -C build. BUILD_EXIT=0 captured separately from the run, [1407/1407] reached. No space left|BFD assertion count 0 against a positive control of 925 Building CXX lines in the same log; warning: count 0. df -h / 80G free (82%) at the end; uptime load average 30.2. The build directory was deleted immediately after the gate.

ctest -N is 474 here and 473 on main, measured with the same command and attributed rather than asserted: test_ltx2_tiling is Test #73 in this listing and absent from main's (grep -c 1 here, 0 there), git diff b5a5f3b18 -- tests/CMakeLists.txt is exactly +7 lines (that one registration) with no target added or removed anywhere else, and grep -c '^vllm_cpp_add_test(' goes 448 on main to 449 here. Main's side was measured by configuring main's own two CMakeLists.txt files in a scratch build directory, which was deleted; both files were restored and verified by sha256sum, not by git status.

Focused, with COUNTS — a changed count is RED unless attributed:

suite cases assertions vs the pre-merge head (70fddfa)
test_ltx2_tiling 10 / 10 915 / 915 unchanged
test_ltx2_vae 36 / 36 3039 / 3039 unchanged
test_ltx2_video 34 / 34 747 / 747 was 32 / 684; the +2 cases arrive with main, not from this row — grep -c '^TEST_CASE(' is 33 on main and 34 here, and git diff b5a5f3b18 on that file adds exactly one TEST_CASE and removes none
test_ltx2_pipeline 37 / 37 2382 / 2382 unchanged

Full: ctest --test-dir build -j6 --output-on-failure474 passed / 0 failed out of 474, 168.50 s, ctest exit 0, with 474 lines matching ^ *[0-9]+/474 Test in the log, so the run's own denominator is asserted against ctest -N rather than assumed equal to it. Two tests report Skipped by their own guards (test_modelopt_mixed_precision_checkpoint, test_voxtral_e2e).

Known-red

None in this gate. Two are worth recording because they were expected and did not happen:

  • test_op_parity is GREEN (Test #422). Its recorded 1-of-456 red at the pre-merge head was a missing fix rather than a standing red — see F-C above.
  • test_serve_low_tools failed in the intermediate -j6 run at 0bf0eb9a8 under load average 90–133 and passed serially in 23.54 s; on the quieter box at this head it passes in the parallel run too. It is -j starvation, not a regression.

test_cpu_x86_llamacpp_floor (#618), windows-msvc-* (#664/#720/#757) and sanitize-cpu (#627) are the in-flight repo-wide reds; untouched here. scripts/agent-preflight.sh passes at this head, test_cpu_x86_llamacpp_floor included.

🤖 Generated with Claude Code

mudler added 10 commits August 13, 2026 17:04
…emise it refutes (#644)

Spec before code, per AGENTS.md.

The row was dispatched on "448x256/25f stops because upstream's default decode
is tiled and we call the untiled path". Executed against the pinned upstream
(fd4ded7f), that half of the premise does not hold: TileSizeConfig.from_long_side
with the Conv auto layout (helpers.py:62-63) resolves to ONE tile and ONE
temporal group at 448x256/25f, because split_by_size short-circuits when
dim <= size (tiling.py:199-200) and the latent is 8x14 against a 14x24 grid tile,
4 frames against a 10-latent-frame temporal tile. Upstream calls forward() once
on the whole volume at that size too. Tiling first binds at 896x512 (spatial)
and 121 frames (temporal).

The decoder's own buffers at that shape are ~2 orders of magnitude too small to
be the 60 GiB: the shipped ladder read from the checkpoint's own metadata gives
a peak on the order of hundreds of MB, and the whole pixel tensor is 32.8 MiB.

The structural port is still owed (ltx2_video_vae.cpp:17-18 records it) and this
spec carries it, together with the derived — not rounded — equivalence bound, the
blend mutation that must RED, and the memory measurement that decides the
attribution.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…60 GiB is not there (#644)

Ports `ConvVideoDecoder.tiled_decode` (conv_video_decoder.py:383-484) with
`_accumulate_temporal_group_into_buffer` (:508-557), the interval algebra and
separable trapezoidal blend (tiling.py:13-49, 174-361, 423-491, 494-571,
619-841), both axis mappers (video_vae.py:549-592) and the CONV AUTO layout
(ltx_pipelines/utils/helpers.py:59-88). Upstream pin fd4ded7f.

`ltx2_video.cpp` now decodes through `Ltx2VideoDecodeStreaming` and writes each
PPM frame as its temporal chunk arrives, mirroring ti2vid_two_stages.py:365-376.
The full pixel volume is never materialized.

MEASURED BEFORE BUILDING, and it refutes the dispatching premise twice.

1. Upstream's own AUTO layout is a NO-OP at 448x256/25f. `split_by_size` returns
   one interval when `dim <= size` (tiling.py:199-200); the latent is 8x14
   against a 14x24 grid tile and 4 frames against a 10-latent-frame temporal
   tile. Executed at the pin and emitted as a golden: 1 tile, 1 group. Tiling
   first binds at 896x512 spatially and 121 frames temporally. So the size that
   failed is a size upstream does not tile either.

2. The decode's own memory is 170x too small to be the 60 GiB. Real shipped conv
   VAE, real 448x256/25f latent decoded to completion, exact operator new
   accounting: heap peak live 361.72 MiB, largest single allocation 99.20 MiB,
   decode-attributed RSS 362.23 MiB. The analytic ladder model predicted the
   largest allocation to three significant figures at two scales. The 60 GiB is
   NOT attributed by this row and the axis stays open with named next steps.

Also newly measured: that decode takes 2681 s (44.7 min) of single-threaded
double-precision convolution, so the reported 24-second window cannot have been
a completed decode. Separate row; phase L6 owes the production-dtype arm.

The equivalence gate the brief asked for does not exist and was not fabricated.
Swept across tile sizes and both causality arms, upstream's own
max|tiled - untiled| is 0.67-1.29 TIMES the output range and does not converge —
the receptive field is wider than the 2-latent-cell overlap. What IS exact is the
ONE-TILE CONTROL: a config whose splits all short-circuit reproduces `forward`
bit for bit, upstream measures 0 and the port is held to == 0.0. That is what
makes the pipeline routing safe at every size run so far.

Gates: BUILD_EXIT=0 clean, no ENOSPC/BFD, ctest -N 416, full ctest 416/416.
test_ltx2_tiling 9/9 830 assertions; test_ltx2_vae 36/36 3039; test_ltx2_video
30/30 502. Blend mutation (linear ramp -> hard cut) REDs 6/9 cases and 39/830
assertions with tiled max|diff| 1.11411 vs a 5e-6 band, and is caught in four
independent places; restored byte-for-byte (md5 e734ee2e35..., rebuild GREEN).

FOLLOWING_AGENTS_PROTOCOL

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

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…-axis mapper had no gate (#644)

PR #656 was reviewed FAIL. The reviewer confirmed all three refutations
independently, regenerated the tiling goldens byte-for-byte, reproduced the
memory probe at three scales and verified `Ltx2VideoDecodeStreaming` bit-identical
to the untiled path on the real checkpoint. None of that is re-litigated here.
Two blocking findings and six minor ones are closed.

F1 (BLOCKING) — the AUTO layout first chunks temporally at 81 frames, not 121.
`latent_t = (frames - 1) / 8 + 1` reaches 11 at 81, and `split_temporal_causal`
short-circuits only while `latent_t <= 10` (tiling.py:239-240). Executed at the
pin over `range(1, 137, 8)`, the interval count goes 1 -> 2 exactly at 81. The
row's own golden already said so (`kLtx2AutoCases`: `768x768/81f ->
t_intervals = 2, chunks = 2`) and `docs/FEATURES.md` said 81; five prose sites
said 121 and are corrected — `ltx2_tiling.h`, `ltx2_video.cpp`, `docs/USAGE.md`
and three places in the spec.

Root cause, recorded because it is the reusable part:
`scripts/probe_ltx2_tiling_layout.py` swept 9, 25, 25, 25, 121, 241 and never
sampled a frame count between 25 and 121, so it stepped over its own binding
point and the number it happened to land on became the threshold. The probe now
WALKS the temporal axis one latent frame at a time and ASSERTS the transition is
at 81, naming every file to reconcile if it ever moves.

The 81..120 window is stated as a user-visible consequence rather than implied:
`docs/USAGE.md` records the recipe default as 1024x1536 at 121 frames, so an
ordinary request is inside it. New `scripts/probe_ltx2_tiled_equivalence.cpp`
measures it on the SHIPPED conv VAE at 64x64/81f, latent 11,2,2 — 2 tiles,
2 chunks, max|diff| 0.716 against the untiled decode on an output whose own |max|
is 0.751, 985849 of 995328 channel values not bit-identical. Upstream's own
behaviour, mirrored; but the ONE-TILE CONTROL's safety argument covers below 81
frames and NOT 81..120, and now says so.

F2 (BLOCKING) — the `!IsTiled()` branches of `map_t` / `map_s` shipped ungated.
Reproduced first: with both `{1.0f}` broadcast masks set to `{0.0f}` — which
multiplies the whole decoded volume by zero, i.e. renders a black clip —
`test_ltx2_tiling` was 9/9 cases, 830/830 assertions, SUCCESS and
`test_ltx2_video` 30/30, 502/502, SUCCESS.

Measured rather than assumed, over all eight (frames, height, width) x (tiled,
untiled) combinations against upstream at the pin: with frames TILED every
spatial combination runs and reproduces `forward` with max|diff| == 0.0; with
frames UNTILED every combination raises TypeError at conv_video_decoder.py:424,
because `DEFAULT_MAPPING_OPERATION` hands it `slice(0, None)` and :424 subtracts
that `None` stop. The two halves are therefore not symmetric and are closed
differently:

* the SPATIAL half is gated end to end — a new UNTILED_SPATIAL arm in the
  generator (`kLtx2TileDec*UpstreamUntiledSpatialVsUntiled`,
  `*UntiledSpatialChunkCount`) and a (B'') control in `RunDecodeArm` on both
  causality arms;
* the TEMPORAL half is REFUSED BY NAME in `Ltx2ConvVideoDecodeTiled`, mirroring
  upstream's own failure rather than inventing a concrete stop upstream never
  computes; `kLtx2TileDec*UpstreamUntiledFramesRaises` records that upstream
  raises, so the refusal is mirrored and not local policy;
* the mapper output itself is pinned by new goldens section 3b
  (`kLtx2UntiledMap*`), upstream's `create_tiles` executed on an all-untiled
  config.

The same black-out mutation now goes RED: 10 cases -> 7 passed / 3 failed, 907
assertions -> 5 failed, exit 1, with `untiled-spatial control max|diff| vs
untiled = 2.31736` against upstream's 0. Restored, `git diff` empty, GREEN again.

F3 — `ctest -N` is 424, not the 416 recorded. 416 was the ninja edge count of
`ninja test_ltx2_tiling test_ltx2_vae test_ltx2_video`, whose last line is
`[416/416] Linking CXX executable tests/test_ltx2_video`. The configure line that
produces 424 is now recorded next to it.

F4 `ltx2_video_vae.cpp:17-18` no longer records tiled decode as owed; the encoder
half still is. F5 the shared `Ltx2NoiseStream*` across tiles is documented at the
declaration and recorded under "What is owed" — it mirrors upstream and is inert
on the shipped checkpoint, but a noise-drawing config has no gate. F6 a new
multi-chunk `test_ltx2_video` case drives `chunk.first_frame + f` through the PPM
writer at 81 frames; per-chunk numbering goes RED at 35 assertions. F7 a previous
render's frame tail is deleted before a new render writes, so a shorter re-render
can no longer be muxed past its own end; disabling the cleanup goes RED at 72
assertions. F8 the "never materialized" claim is bounded to the tiled case at
both anchors. F9 the compile line for both probes is recorded in their headers.
F10 the fixture's `res_x_y` block is disclosed in the test header.

Gate on 424 tests, clean `rm -rf build` + reconfigure:
`cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release`, `BUILD_EXIT=0`,
`No space left|BFD assertion` count 0, 0 warnings, `df -h /` 94% -> 95%.
`ctest -N` 424; full `ctest` 424/424 passed, 0 failed, `CTEST_EXIT=0`.
Focused with COUNTS: `test_ltx2_tiling` 10/10 907/907 (was 9/9 830/830),
`test_ltx2_vae` 36/36 3039/3039, `test_ltx2_video` 31/31 673/673 (was 30/30
502/502), `test_ltx2_pipeline` 37/37 2382/2382. The goldens regenerate
byte-identically apart from the 23 added lines.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
Forward-merge so the review-response gate runs against current main. Two keyed
records conflicted and were resolved by taking main's version wholesale and
reapplying only this row's scoped edit:

* `.agents/roadmap_v1.md` #644 — main rewrote the row as the LTX-2.5 FULL PORT
  campaign naming Row 0 `LTX25-PROMPT-ADALN`; the Row 2 `LTX25-TILED-DECODE`
  sentence is reapplied onto main's cell rather than replacing it.
* `docs/FEATURES.md` — main's rewritten `LTX-2.5 DiT` row is taken whole; the
  separate `LTX-2.5 tiled + streaming Conv VAE decode` row is a different key and
  is kept as this branch has it.

No automatic three-way merge of a keyed record was accepted, and every unrelated
key was verified byte-for-byte.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
Main landed 67dc0aa (`MODEL-MM-indextts2`: the DiT's WaveNet final layer, #738)
between the previous forward-merge and this gate, so the gate runs against it
rather than against a main that no longer exists.

No conflicts. Verified rather than assumed, because a lost add is exactly what a
clean auto-merge hides: `tests/CMakeLists.txt` still registers `test_wavenet` and
`tests/vllm/models/test_wavenet.cpp` is present, and this branch's own keys —
`docs/FEATURES.md`'s `LTX-2.5 tiled + streaming Conv VAE decode` row and
`.agents/roadmap_v1.md`'s #644 row — are unchanged.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…tts2, MSVC fixes)

Main landed four more commits while this row's gate was running — b203871
(`MODEL-MM-dots3-note` scope, #705), 25861b6 (indextts2 offline conversion,
#742), 0011bed (#720, `M_PI` under MSVC) and f8cbc23 (#664, the video
registry's Windows existence probes). The gate is re-run against them rather than
against a main that no longer exists.

No conflicts. Verified rather than assumed, because a clean auto-merge is exactly
what hides a lost edit on a keyed record:

* `.agents/model-matrix.md` now carries main's 371 -> 373 / 375 -> 377 rollup with
  `Dots3NoteForCausalLM` and `Dots3NoteMTPModel` restored — that delta was main
  moving, not this branch reverting it;
* this row's own keys are unchanged — `.agents/roadmap_v1.md`'s #644 row,
  `docs/FEATURES.md`'s `LTX-2.5 tiled + streaming Conv VAE decode` row, and the
  `ltx2_video_vae.cpp` header note recording that the tiled decode is no longer
  owed.

Note for the record: f8cbc23 touches `video_engine.cpp`, which this branch does
not, and no part of this merge touches `ltx2_loader.cpp`'s alignment code (#627).

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…16 that was a build number (#644)

Replaces the `## Outcome` gate block with the run this branch actually performed
after two forward-merges, and closes F3 of the PR #656 review.

**F3 — `ctest -N` was recorded as 416 and does not reproduce.** It never could:
416 is the ninja EDGE count of `ninja test_ltx2_tiling test_ltx2_vae
test_ltx2_video`, whose last line is `[416/416] Linking CXX executable
tests/test_ltx2_video`. A build number was read as a test number, so "full ctest
416/416" describes a run that never happened at that denominator. The configure
line is now recorded next to the number, because a denominator without one cannot
be reproduced.

The denominator moved twice while this gate ran — 424, then 445, then 448 — and
that drift is ATTRIBUTED rather than asserted: `git diff origin/main --
tests/CMakeLists.txt` is exactly +7 lines, this row's `test_ltx2_tiling`
registration, with no target added or removed anywhere else. This branch is main's
count plus one by construction, whatever main's count happens to be that hour.

Gate at this head: clean `rm -rf build` + reconfigure, `BUILD_EXIT=0` captured
separately from the run, `No space left|BFD assertion` count 0, warnings 0,
`df -h /` 89% -> 98%, build directory deleted immediately after. `ctest -N` 448;
full `ctest` 447 passed / 1 failed of 448, 438.02 s, with 448 `N/448 Test` lines
in the log so the run's own denominator is asserted against `-N` rather than
assumed. Focused with COUNTS: `test_ltx2_tiling` 10/10 907/907,
`test_ltx2_vae` 36/36 3039/3039, `test_ltx2_video` 31/31 673/673,
`test_ltx2_pipeline` 37/37 2382/2382.

The single failure is `test_op_parity`, and it is not this row's:

    test_op_parity.cpp:1989: ERROR: test case THREW exception:
      [json.exception.type_error.302] type must be string, but is null

a null field in the MiniMax-Music3 golden manifest that landed on main the same
day, filed as #737 and already reproduced on clean main. This branch touches no
parity path — `git diff origin/main --name-only` matches nothing under
`tests/parity/` and no music3 file.

Two preflight gates also red at this head and neither is this row's:
`audit-live-rows` / `test_audit_live_rows` fail on the stale ACTIVE row
`MODEL-MUSIC-minimax-music3-...`, and this branch changes no matrix file at all —
its only record edits are `.agents/roadmap_v1.md`'s #644 row and this spec — so
those records are byte-identical to main's.

FOLLOWING_AGENTS_PROTOCOL

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

Main landed 5e646d9 (`MODEL-MM-indextts2`: the ported DiT on the real shipped
weights, #743) between this row's gate and its push. Merged forward so the pushed
head is a descendant of main rather than a fast-forward refusal at push time.

No conflicts. Verified rather than assumed: this row's keys are unchanged —
`docs/FEATURES.md`'s `LTX-2.5 tiled + streaming Conv VAE decode` row and
`.agents/roadmap_v1.md`'s #644 row — and the branch's whole record delta versus
main remains those two files plus its own spec, with `tests/CMakeLists.txt`
differing by exactly the `test_ltx2_tiling` registration.

This merge changes no compiled source this row owns, so the gate recorded in
`.agents/specs/ltx25-tiled-decode.md` stands: `test_ltx2_tiling` 10/10 907/907,
`test_ltx2_vae` 36/36 3039/3039, `test_ltx2_video` 31/31 673/673,
`test_ltx2_pipeline` 37/37 2382/2382, full `ctest` 447/448 with the single failure
being #737's MiniMax-Music3 golden manifest on clean main. CI re-runs the suite on
this exact head, which is the check that covers main's own new sources.

FOLLOWING_AGENTS_PROTOCOL

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

Main landed 5e646d9 and d374e83 (`MODEL-MM-indextts2`, #743 and #745) while
this row was finishing its handoff checks. Merged forward so the pushed head is a
descendant of main; a rejected push would otherwise be git protecting someone
else's merge.

No conflicts. Verified rather than assumed: after this merge the branch's entire
record delta versus main is `.agents/roadmap_v1.md` and its own spec, and the
roadmap delta is exactly ONE line — the Row 2 sentence inside issue #644's cell.
`docs/FEATURES.md`'s `LTX-2.5 tiled + streaming Conv VAE decode` row and
`tests/CMakeLists.txt`'s `test_ltx2_tiling` registration are the only other keys
this branch owns, and both are intact.

Three preflight gates are red at this head and none is this row's, recorded here
so the next reader does not re-derive it:

* `audit-live-rows` and `test_audit_live_rows` fail on the stale ACTIVE row
  `MODEL-MUSIC-minimax-music3-...`, which lives in `.agents/model-matrix.md` — a
  file this branch does not touch at all, so its input is byte-identical to main's;
* `test_cpu_x86_llamacpp_floor` exits `NO_QUIET_WINDOW` (busy 125%, load 78) with
  several agents building on the shared box, which is the documented failure mode
  of that floor test rather than a regression.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
mudler added 6 commits August 14, 2026 13:08
…ncoder, music3 W2/W3)

The reviewed head 3fcfba4 was 7 commits behind origin/main, which made the
PR's `git diff origin/main -- tests/CMakeLists.txt` claim read as four targets
REMOVED (test_dit_stack, test_indextts2_talker_loader, test_minimax_music3_ar,
test_minimax_music3_ar_real) rather than one added. After this merge that diff is
exactly +7 lines again — the row's own `test_ltx2_tiling` registration — and
`vllm_cpp_add_test(` goes 431 on main to 432 here.

`docs/FEATURES.md` conflicted and is a KEYED record, so it is NOT an automatic
three-way merge: main's file was taken wholesale with `git checkout origin/main
--`, and this row's single key (`LTX-2.5 tiled + streaming Conv VAE decode`) was
reapplied on top. `git diff origin/main -- docs/FEATURES.md` is one added line
and nothing else. `.agents/roadmap_v1.md` likewise differs from main by its one
`#644` row, in place.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5[1m] [claude-code]
… the probe was measuring its own transposition (#644)

Answers the FAIL review of PR #746. Issue #644, spec
`.agents/specs/ltx25-tiled-decode.md`.

BLOCKING — the headline number was a measurement artifact.
`scripts/probe_ltx2_tiled_equivalence.cpp` reassembled the streamed chunks with a
flat `insert(streamed.end(), chunk.frames.data.begin(), ...)`. A chunk is
[C, t, H, W] CHANNEL-MAJOR (ltx2_video_vae.h:211-219), so that append yields
[c0 t0..][c1 t0..][c2 t0..][c0 t1..].. — not [C, T, H, W] once C > 1 AND there is
more than one chunk, and the published run is [3,81,64,64] with chunks=2, so both
hold. It was comparing channel 1 against channel 0's later frames. The probe even
carried a comment asserting the opposite ("the C-major layout means the
comparison below is elementwise regardless"); that comment was the error, and the
row's own test (Collected::Concat in tests/vllm/models/test_ltx2_tiling.cpp) had
the correct reassembly all along.

Re-derived on the real ltx-2.5-video-vae-conv-bf16.safetensors, same request:

  committed probe : max|diff| = 0.71614238619804382   985849 / 995328
  corrected probe : max|diff| = 0.050304323434829712  962983 / 995328
  both            : untiled |out|max = 0.75126725435256958

So 6.70% of the output's own range, not 95% — a factor of 14. The corrected probe
prints the flat-append figure as a labelled diagnostic, so both columns come out
of ONE binary on ONE run and the artifact is reproducible rather than argued. The
QUALITATIVE conclusion survives: 96.75% of values still move, 81..120 frames is
still a tiled regime the one-tile control does not cover, and the refusal stands.
Corrected at all four published sites — ltx2_tiling.h, ltx2_video.cpp,
docs/USAGE.md (user-facing) and the spec — plus docs/FEATURES.md.

The spec's Outcome now records that this is the THIRD number in campaign #644 to
move by a large factor the first time anyone re-derived it: 60 GiB measured
361.72 MiB (170x), "121 frames" measured 81, and 95% measures 6.70% (14x). That
self-record is worth more than the number.

F1-b — the walk's density was a comment, not an assertion. Reproduced first: the
committed scripts/probe_ltx2_tiling_layout.py with its step changed 8 -> 80 and
nothing else exits 0 and prints "first splits at 81 frames" after examining two
frame counts, skipping latent_t 2..10; saw_untiled and `first_tiled is not None`
cannot see that. The walk now asserts it starts at latent_t 1, that consecutive
steps move latent_t by exactly 1, and that the transition is 10 -> 11 — the
short-circuit's own bound (tiling.py:239-240). The same mutation on the repaired
probe exits 1 ("the walk is NOT dense: latent_t jumps [(1, 11)]"); unmutated it
exits 0 over 17 densely walked frame counts.

MODERATE — the recorded `ctest -N` no longer described the head. Merged
origin/main (7 commits) and re-measured: 456 here against 455 on main @ 7b8919d
with the same command in this tree, the one added listing being
`Test #60: test_ltx2_tiling`; `vllm_cpp_add_test(` goes 431 -> 432 and
`git diff -- tests/CMakeLists.txt` is +7 lines with nothing removed. The
"448 N/448 lines" line is restated as what it is — a `grep -c` compared against
`ctest -N`'s total, both commands recorded — and no longer cited as a committed
instrument.

MINOR — the "upstream raises" golden pinned the type, not the reason. A bare
`except TypeError` kept the constant at 1 for any future TypeError from any line.
The generator now walks the traceback to the innermost frame and emits
*UpstreamUntiledFramesRaiseFile / RaiseLine / RaiseMessage (measured:
conv_video_decoder.py, 424, "unsupported operand type(s) for -: 'NoneType' and
'int'"), with generator-side assertions on the file and message. Goldens
regenerate byte-identically apart from those 6 added lines.

MINOR — ltx2_video_vae_tiled.cpp said every frames-tiled arm "reproduces `forward`
exactly". That holds only where the frames tile exceeds the axis; where it splits,
kLtx2TileDecCausalUpstreamTiledVsUntiled is 2.13274002 against an OutputSpan of
2.31735897. Bounded to the one-tile and untiled-spatial controls, which are the
arms actually pinned at 0.

Gate. Clean `rm -rf build` + `cmake -S . -B build -G Ninja
-DCMAKE_BUILD_TYPE=Release` + `ninja -C build -j4`, BUILD_EXIT=0, 0 warnings,
`No space left|BFD assertion` count 0 against a positive control of 462
"Building" lines. df / 89% -> 96%; build directory deleted after the gate.
`ctest -N` 456; full `ctest -j4 --output-on-failure` 455 passed / 1 failed of
456, exit 8, with 456 lines matching `^ *[0-9]+/456 Test`. The one failure is
test_op_parity (#737, a null in the Music3 golden manifest) which prints
"assertions: 70 | 70 passed | 0 failed" while failing; this branch matches nothing
under tests/parity/ or any music3 file.

  test_ltx2_tiling   10/10   915/915  (was 907; +8 = 4 new CHECKs x 2 arms)
  test_ltx2_vae      36/36  3039/3039
  test_ltx2_video    32/32   684/684  (+1 case / +11 assertions arrive with
                                       fc903b8 (#674) on main, not this row)
  test_ltx2_pipeline 37/37  2382/2382

RED-first for the new assertions, goldens mutated in place and restored,
verified by sha256 (bf2bdb4d…), rebuilt GREEN each time:
  RaiseLine 424 -> 425                     : 8/10 cases, 2 failed assertions, exit 1
  RaiseFile/RaiseMessage -> wrong values   : 8/10 cases, 6 failed assertions, exit 1

docs/FEATURES.md and .agents/roadmap_v1.md are keyed records: verified to differ
from main @ 7b8919d by exactly this row's one key each.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5[1m] [claude-code]
…, image conditioning landed)

48 commits of main, resolved against pinned `origin/main` =
51e0cb5 rather than the moving ref, because this
is a shared checkout and a peer's fetch advances `origin/main` mid-operation.

Two keyed records conflicted, and neither was resolved by an automatic three-way
merge. Both took main's file whole, and the scoped edit was reapplied by key.

`.agents/roadmap_v1.md` is now byte-identical to main. This branch's only edit to
it was one row of the issue intake table, and #846 moved that table out of the
file into the append-only `.agents/issue-index.md`. The #644 row is already there,
already current, and already names Row 0 and Row 1. `check-issue-index-append-only.py`
refuses an edit to an existing row because `merge=union` duplicates one rather than
merging it, and `check_issue_index` refuses a second #644 row. So the scoped edit
has no admissible target on the new surface: the prose about Row 2 belongs in the
row's spec, which carries it. Reapplying it anywhere would have been a gate failure,
not a record.

`docs/FEATURES.md` differs from main by exactly one added line, this row's own
`LTX-2.5 tiled + streaming Conv VAE decode` key. Every other key is byte-identical
to main, including the `Safetensors direct load, no conversion` row, which was
duplicated at this branch's head and is single on main (#769) — taking main whole
resolves it without this branch either fixing or multiplying it.

Five files auto-merged against `c629b5d0f`, the same campaign's image conditioning
row, and a clean `merge-tree` is not a tree that builds. Checked by semantics rather
than by the absence of a conflict: `CMakeLists.txt` +6 and `tests/CMakeLists.txt` +7
are this row's two translation units and its one test target, so `ctest -N` on this
tree is main's count plus one, by construction. `src/vllm/multimodal/ltx2_video.cpp`
drops the `rendered` buffer the counterparty never referenced, hoists the only
`std::error_code ec` in `Generate`, and adds `video_factors`, which does not collide
with the pre-existing `factors` at :1345. `tests/vllm/multimodal/test_ltx2_video.cpp`
appends one case that uses only helpers the counterparty left in place.
`docs/USAGE.md` appends a section after the counterparty's own conditioning prose.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…ses, and two goldens went into C literals unescaped (#644)

Closes the two nits from the records review of PR #746. The blocking half of that
review was about the pull request description and the merge, and is handled by the
rewritten body and the preceding merge commit; this commit is the tree half.

The walk in `scripts/probe_ltx2_tiling_layout.py` requires `latent_t` to advance by
exactly 1 per step, which is correct for the anti-fake purpose and fails in BOTH
directions. A step of 4 pixel frames repeats a latent depth, because
`latent_t = (frames - 1) // 8 + 1` is constant across 8 consecutive frame counts, so
it trips the same assertion as a step of 80 that skips nine depths. The message named
only the skipping half, so a future editor tightening the sweep would have read
"the walk is NOT dense: latent_t jumps [(1, 1), ...]" as upstream moving the bound.
It now names both causes and the fix each needs. Reproduced rather than argued: step
8 -> 80 exits 1 over 2 frame counts, step 8 -> 4 exits 1 over 34, and unmutated the
probe exits 0 over 17 densely walked frame counts and prints "first splits at 81
frames". Each mutant is a copy outside the tree, and the tree's sha256 was verified
unchanged after every run.

`scripts/gen-ltx2-tiling-goldens.py` emitted `untiled_frames_raise_file` and
`untiled_frames_raise_message` into C string literals with an f-string quote. Both are
UPSTREAM text: a future `TypeError` message or a checkout path carrying a `"` or a
backslash would have produced a golden that does not compile, while the generator
exited 0 and looked like it had succeeded. Loud rather than silent, so this was filed
as a nit, but `json.dumps` costs nothing and JSON string escaping is a subset of C's
for these bytes. Byte-identity on today's values is measured, not assumed: a full
regeneration to a scratch path yields sha256
bf2bdb4d43e73d4da73e360a816ee20e5f4b9224902fab9486fb173822a41d12, equal to the
committed `ltx2_tiling_goldens.inc`, with `diff` exit 0. The negative control shows the
old form emitting `"a "quoted" word and a \ backslash"` where the new one emits
`"a \"quoted\" word and a \\ backslash"`.

The spec records both, the records review they answer, and a re-measured gate on the
merged head: `ctest -N` 473 here against 472 on main @ 51e0cb5, focused
10/915, 36/3039, 34/747, 37/2382, full 472 passed / 1 failed of 473 whose one failure
passes serially. `test_op_parity` is green here, so the recorded 1-of-456 red at the
pre-merge head was a missing fix rather than a standing red.

FOLLOWING_AGENTS_PROTOCOL

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

One commit, `b5a5f3b18`, taken against that pinned SHA rather than the moving ref.

`docs/FEATURES.md` conflicted again, and for the reason the record rules predict:
its MiniMax-Music3 row sits immediately above this row's key, so any edit to either
lands in the same hunk. Resolved the same way as the previous merge — main's file
taken whole, then this row's single `LTX-2.5 tiled + streaming Conv VAE decode` key
reapplied. `git diff b5a5f3b -- docs/FEATURES.md` is that one added line and nothing
else, so every unrelated key, including the Music3 row this merge updates, is
byte-identical to main. `.agents/roadmap_v1.md` and `.agents/issue-index.md` are
byte-identical to main and were not touched.

`CMakeLists.txt`, `tests/CMakeLists.txt` and `docs/USAGE.md` auto-merged. Checked by
content rather than by the absence of a conflict: the two CMake diffs against main are
exactly this row's two translation units and its one `vllm_cpp_add_test` registration,
and `docs/USAGE.md` is this row's appended section. The incoming commit adds tests, so
the `ctest -N` denominator moves and is re-measured on both sides at this head.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [Claude Code]
…ch is 474/474 green (#644)

The spec's `### The gate` described `70fddfa32`, and two forward merges have moved the
head since. Each recorded denominator describes only the head it was taken on, so the
pre-merge record is kept below rather than overwritten, and this one is added above it.

Measured on `e34e10e37`, which merges main @ `b5a5f3b18`. Clean `rm -rf build` +
reconfigure + `ninja -C build`: `BUILD_EXIT=0` captured separately from the run,
`[1407/1407]` reached, `No space left|BFD assertion` count 0 against a positive control
of 925 `Building CXX` lines in the SAME log, `warning:` count 0.

`ctest -N` is 474 here and 473 on main, measured with the same command in the same tree.
`test_ltx2_tiling` is Test #73 in this listing and absent from main's, the
`tests/CMakeLists.txt` diff against main is exactly +7 lines for that one registration,
and `grep -c '^vllm_cpp_add_test('` goes 448 to 449. Main's side was configured from
main's own two CMakeLists.txt files into a scratch directory that was deleted; both files
were restored and verified by sha256sum rather than by `git status`.

Focused, with counts: test_ltx2_tiling 10/915, test_ltx2_vae 36/3039, test_ltx2_video
34/747, test_ltx2_pipeline 37/2382. The move from 32/684 is MAIN's — `grep -c
'^TEST_CASE('` is 33 on main and 34 here, and the diff against main adds exactly one case
and removes none. Full ctest: 474 passed / 0 failed of 474, 168.50 s, exit 0, with 474
lines matching `^ *[0-9]+/474 Test` so the run's own denominator is compared against
`ctest -N` rather than assumed equal to it.

There is no known-red left. `test_op_parity` is green, so the previously recorded
1-of-456 was a missing fix rather than a standing red, and `test_serve_low_tools` — which
starved in the intermediate `-j6` run at load average 90-133 and passed serially — passes
in the parallel run on the quieter box.

The equivalence probe was rebuilt from this head's libvllm.a and re-run against the
checkpoint asserted by sha256. Its output is byte-identical to the run on the previous
head, from a different build: two builds, two runs, one result.

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.

test_op_parity is RED on main: RunGoldenPass indexes m["op"] on every manifest, and the MUSIC3 oracle capture has no such key

2 participants