Skip to content

fix(LTX25-RETIRE-DEAD-ARMS): retire the invented refusals, and the assertion that could not fail (#644, #611) - #882

Merged
localai-bot merged 6 commits into
mainfrom
row/LTX25-RETIRE-DEAD-ARMS-CLEAN
Aug 15, 2026
Merged

fix(LTX25-RETIRE-DEAD-ARMS): retire the invented refusals, and the assertion that could not fail (#644, #611)#882
localai-bot merged 6 commits into
mainfrom
row/LTX25-RETIRE-DEAD-ARMS-CLEAN

Conversation

@localai-bot

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

Copy link
Copy Markdown
Collaborator

Retires the arms of the LTX-2.5 out-of-scope ledger that do not exist upstream, refuses the load extra that was accepted and read by nothing, and — after four rounds of review — repairs the ledger's own claim about which refusals a request can reach. 12 files, +2148/−54: spec, header, refusal messages, two public documents, and the tests that hold each claim.

Tracks #611 and #644 items D–I and N. Pattern this row is an instance of: #604. Spec: .agents/specs/ltx25-retire-dead-arms.md. Pins: Lightricks/LTX-2 @ fd4ded7f, huggingface/diffusers @ 3a2f35d4, vllm-project/vllm-omni @ a4ea67a21.

Closes #889. Closes #890. Closes #892.

#893 stays open on purpose and must not be closed by this merge: it is the ## Nothing lands dead disclosure for Ltx2Schedule, which this branch labels honestly rather than wires. #611 and #691 also stay open, with their remaining halves named at the end.

The body that was here belonged to #880, and replacing it is part of this change. The repository sets squash_merge_commit_message = PR_BODY, so this field is the landed commit message. It carried, verbatim, the already-merged body of #880 (keyframes_abs_pos_embedding) — a different row, a different issue, a different diff, 22 files that are not these 12. Landing it would have written a permanent commit message describing work already on main. No gate can catch that: the trailer and style checkers validate the body's shape, and its shape was perfect. Recorded rather than quietly swapped, because "the body is the commit message" only protects the history if somebody checks that it describes this change.

What was wrong

Ltx2UnportedPipelineFeature is a ledger of arms this port refuses by name. Read as a whole it claimed more than was true, in five separate ways.

  1. One arm was fabricated. kMultishot refused "multishot generation" and cited "ltx-pipelines multishot entry points". No such entry point, symbol or string exists in either reference. Retired.
  2. One arm was stale. kVideoEngineWiring said the end-to-end composition "is phase L7, not L5". L7 landed in cefacd2d0. A refusal whose subject shipped is a false statement. Retired.
  3. One arm's name described something upstream does not do. kCfgParallelism was anchored to ltx-pipelines/multigpu, which contains no CFG batching. Renamed kMultiGpuParallelism and re-anchored.
  4. "Refused by name" overstated a marker. Most entries have no product call site: nothing a caller can send reaches them. A declared boundary is worth having — calling it a refusal was the defect. The ledger, the header, the messages and both public documents now distinguish a reachable refusal from a declared-out-of-scope marker.
  5. duration_head_path was accepted and read by nothing (LTX-2.5: duration_head_path is accepted and never read — a caller who supplies it silently gets the recipe default #611). A caller who pointed at a duration head silently got the recipe default. Now refused by name, with the full ten-key kKnownLoadExtras inventory recorded and gated.

The four review rounds

Every finding is written into the spec's ## Outcome rather than summarised away, because the findings are the row's subject.

Round Finding Where it had shipped
1 "int8 appears upstream only in the trainer" is false; hadamard is not 0 hits the user-visible refusal message, and §1.2
2 Nine reader anchors stale, off by 37 lines and then by another 25 §2.1, cited in the file they were wrong about
3 scene asserted trainer-only; the shot file list offered as exhaustive at five when it is seven the shipped header, and §1.1
4 cfg asserted absent from both multigpu trees; a fourth form omitted (#892) the shipped header and message, and §1.3
4 kBetaScheduler published as reachable with no caller (#889) header, docs/FEATURES.md, docs/USAGE.md, §1.6
4 The one genuinely reachable refusal shadowed by a guard over the same variable (#890) ltx2_video.cpp

The first four are one defect: an absence asserted from our own vocabulary, with no positive control, three of them behind a path filter that excluded the files carrying the answer. A row whose stated purpose is retiring instances of #604 committed four of them, three into files a user or a porter reads.

The last two are a different defect and worth separating. They were not inaccurate citations. They were classification and control flow, and between them the ledger's reachable column was empty in practice while two public surfaces published two entries in it.

#889 — a refusal nothing calls

The header defines a reachable refusal as one "a caller CAN trip", and docs/USAGE.md published "Both are reachable — a render asking for either gets a refusal naming the missing piece." Neither was true of kBetaScheduler. Its site ltx2_pipeline.cpp:199 sits inside Ltx2Schedule, and Ltx2Schedule has zero call sites in src/, include/ or examples/. The engine calls Ltx2SigmaSchedule directly, and no ABI field, load extra or CLI flag carries a scheduler kind. The only driver is the unit test that constructs the enumerator by hand.

§1.6 had asked whether an enumerator appears in src/. That question's true answer is the wrong answer: a case label is not a caller.

Upstream decides the repair, and it forbids the wiring one. At fd4ded7f, BetaScheduler is defined at ltx-core components/schedulers.py:91 and constructed nowhere in the repository. All seven ltx-pipelines entry points hard-code LTX2Scheduler(): ti2vid_one_stage.py:81, ti2vid_two_stages.py:87, ti2vid_two_stages_hq.py:90, a2vid_two_stage.py:78, t2a_one_stage.py:67, keyframe_interpolation.py:82, retake.py:96. vLLM-Omni a4ea67a21 has zero hits for the name, against 81 files carrying ltx as the control. Routing the engine through Ltx2Schedule would have invented a scheduler-selection surface upstream does not have, so mirroring upstream means reclassifying the arm as a marker.

The split is now derived rather than written. test_ltx2_pipeline gains "the reachable/marker split matches the source": it walks the product tree, counts callers of each arm's entry function, and requires the message to agree in both directions — no caller demands DECLARED, NOT REQUESTABLE, and a caller appearing later forbids it. Two positive controls ride in the same walk, plus a file-count floor, because this is an absence claim about our own tree and this row has already shipped four of those. That is the anti-tautological shape #691 asks for, applied to the beta arm; #691 stays open for the three markers that have no call site to derive from.

#890 — the shadowed arm

The phase guard tested im.upsampler_cfg.temporal_upsample alone. Every both-flags config satisfies that too, so the two guards were an implication over one variable and this one always fired first. A caller supplying a genuine spatiotemporal checkpoint was told it is the TEMPORAL x2 upsampler and pointed at the spatial one: wrong on both counts, and pointing them at the arm they already had. It also made the ledger refusal at ltx2_upsampler.cpp:465 unreachable from any request — so after #889, the reachable column was empty.

Narrowed to temporal_upsample && !spatial_upsample, so a both-flags config falls through to the refusal that names the correct arm.

The reviewer who found this named a real limit on their own evidence: no fixture drove a both-flags checkpoint through LoadVideoEngine, so mutation could not separate "unreachable" from "untested", and only the static implication settled it. That hole is closed here, and closed the way AGENTS.md ## Nothing lands dead requires — the new subcase drives the checkpoint through LoadVideoEngine + Generate, not through a direct call to Ltx2LatentUpsample.

#892 — a fourth form, hidden by a path filter

The header shipped an assertion that cfg is absent from both multigpu trees; the refusal shipped "three forms". Re-derived at the pin, with the file list as the control in the same pass:

git ls-files -- '*multigpu*'        ->  33 files   (the control)
git grep -n -i cfg -- '*multigpu*'  ->   5 lines   (not 0)

Two of the five are substantive prose at docs/multigpu/gemma.md:103-104. The spec's grep was correct and its path filter was wrong: scoped to the two SOURCE trees, it excluded docs/multigpu/, where the answer is written out. There is also a fourth BuilderProtocol in the directory the refusal cites — multigpu/bp_gemma_builder.py:42, BatchParallelGemmaBuilder, which partitions a prompt list across ranks.

The disposition is unchanged and stronger. gemma.md:104 records that the distilled pipeline this port runs takes no negative_prompt and "runs without CFG", so the one form that would carry a CFG pair is the one upstream tells you not to use here. A reason beats an absence.

Nothing lands dead: the disclosure this owes

AGENTS.md ## Nothing lands dead and .agents/reachability.md landed in 8f49ac3be (#886) while this repair was in flight, and they name #889's shape exactly: the test-only driver, where the only thing that calls the new code is the test written for it. The guide ships no checker and says why, so there is no exit code to report.

Per that rule, stated here, in the commit body, and under ## Owed in the spec: Ltx2Schedule and Ltx2SchedulerKind are UNREACHED. Owned by row LTX25-RETIRE-DEAD-ARMS, tracked by #893. This is not a staged slice awaiting a wiring wave — upstream selects no scheduler anywhere, so there is nothing to wire it to. The open decision is retire-or-keep-as-recorded-mirror, and that is a behaviour change owing its own red-first evidence, which is why this branch labels the arm honestly and does not also delete the dispatcher.

Red before, green after

Repair RED before GREEN after
#889 split case reports Ltx2Schedule callers = <none> with both controls live; DECLARED, NOT REQUESTABLE absent from the message test_ltx2_pipeline 42/42 cases, 2485 assertions, exit 0
#890 SPATIOTEMPORAL absent; it is the TEMPORAL x2 upsampler and Supply the spatial upsampler both present test_ltx2_video 40/40 cases, 827 assertions, exit 0
#892 three forms present; four forms / BatchParallelGemmaBuilder / gemma.md absent; header cfg sentence present at offset 32030 included above

The full RED run was test_ltx2_pipeline 39/42 cases with 8 assertions failing, and test_ltx2_video red on the new subcase.

Four mutations, each of which BUILT with 0 errors before it was run — a mutation that fails to compile reads as a passing test:

Mutation BUILT Result
Widen the guard back to temporal_upsample alone yes, 0 errors RED, 3 assertions
Reachability mutation: delete the production call site Ltx2UpsampleVideoLatent yes, 0 errors RED in test_ltx2_video, and it fires the split case's positive control, which then reports Ltx2UpsampleVideoLatent callers = <none>
Drop the marker suffix from the beta refusal yes, 0 errors RED in both the ledger case and the split case
Restore "three forms" in the message yes, 0 errors RED, 2 assertions

The tree was restored byte-for-byte after each, verified by sha256sum -c.

One consequence worth recording, because it cost a build cycle: the header may not QUOTE the retired sentence while explaining it. A text gate matches text and cannot tell a quotation from a claim. The corrected note describes the old sentence instead of reproducing it, and says so in the comment.

Keyed records, edited by key

docs/FEATURES.md and docs/USAGE.md are keyed records. Exactly two FEATURES rows change; the other 365 lines are byte-identical, verified by sha256 of the filtered file, with the filter's own line count (367 → 365 on both sides) as the positive control. docs/FEATURES.md:165 "Temporal x2 ups gated, UNDRIVEN" is untouched, verified by sha256 of that line against HEAD. In docs/USAGE.md only one paragraph moves: lines 1–1956 hash identically, and the tail hashes identically at a 5-line offset.

.agents/issue-index.md gains four rows and loses none — git diff --numstat reads 4 0, against a positive control showing the same tool reporting 11 6 for docs/USAGE.md. scripts/check-issue-index-append-only.py exits 0.

Every file:line anchor was re-derived at this tree and asserted unique, not merely present. Three were correct: ltx2_upsampler.cpp:465, ltx2_pipeline.cpp:199, ltx2_pipeline.cpp:191. Two had moved with the merge and are now named by symbol instead of by line, because ltx2_video.cpp moves on every merge and three anchors in this row went stale inside one branch. The nine derived READER ANCHORS moved five lines when 98f8e046d landed; the gate that derives them caught it, which is what it was built for.

Gate

CPU, this box, clean configure into a fresh build/. Shared and busy: another session was running its own ctest -j 8 concurrently and load average sat between 11 and 84 during the run.

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DVLLM_CPP_CUDA=OFF   CONFIGURE_EXIT=0
cmake --build build -j6                                                      BUILD_EXIT=0
ctest --test-dir build -j4 --output-on-failure                               CTEST_EXIT=0

grep -c ': error:' over the build log = 0. No space left = 0 and BFD assertion = 0, against positive controls of 603 Building CXX and 478 Linking CXX lines, so the log was searchable and carries no ENOSPC. The build ended [1083/1083]. df -h / 32G free (93%) after the build.

ctest -N = 477, which is main's count: this branch registers no new ctest entry. git diff <merge-base>..HEAD -- tests/CMakeLists.txt | grep '^+' | grep -cE 'vllm_cpp_add_test|add_test\(' = 0, against a positive control of 1 for 07457f87c, which did add one. The CMake change is three target_compile_definitions blocks and their comments.

Full suite: 100% tests passed, 0 tests failed out of 477, 250.14 s. Two did not run and neither belongs to this row: test_modelopt_mixed_precision_checkpoint and test_voxtral_e2e, both Skipped. The same ENOSPC grep over the ctest log is 0 against a positive control of 475 Passed lines.

No known-red fired in this run, including test_cpu_x86_llamacpp_floor (#618) despite the load. Read that as this branch not adding one, not as those issues closing.

scripts/agent-preflight.sh reports the seven CI-wiring failures that are pre-existing on main (check-release-binary-contract, check-release-workflow, check-test-registration and their four suites; root cause #873, fix in flight as #878). Proven pre-existing rather than asserted: git diff origin/main HEAD over every input those checkers read — scripts/check-test-registration.py, scripts/check-release-binary-contract.py, scripts/check-release-workflow.py, their four test scripts, and .github/workflows/ — is empty, against a positive control where the same command reports docs/FEATURES.md and src/vllm/multimodal/ltx2_video.cpp.

check-commit-style.py --range <merge-base>..HEAD and check-commit-trailers.py --range <merge-base>..HEAD both exit 0. The trailer gate initially failed on the two git merge commits, which carried no trailer block — rev-list includes merge commits and the checker has no exemption for them. Repaired by redoing the merge with an authored message rather than by exempting anything, and ea6b01f1f remains an ancestor of this head, so the push is a fast-forward and nothing was force-pushed.

Not in scope, still owed

Constructing a duration head (#611; its user-visible half, silent substitution of the recipe default, is closed). The retire-or-keep decision on Ltx2Schedule (#893). The anti-tautological gate for the three markers that have no call site to derive from (#691). .agents/specs/ltx-2-5.md §2 "Out" still lists multishot and is operator-owned (#692).

FOLLOWING_AGENTS_PROTOCOL

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

mudler added 2 commits August 15, 2026 09:23
…t have (#644, #611)

The LTX-2.5 out-of-scope ledger records seven refusals. Two of them are not
refusals of anything. `kMultishot` cites "ltx-pipelines multishot entry points",
and no such entry point, symbol or string exists in Lightricks/LTX-2 @ fd4ded7f
or huggingface/diffusers @ 3a2f35d4. `kVideoEngineWiring` says the end-to-end
composition "is phase L7, not L5", and L7 shipped in `cefacd2d0`. A third,
`kCfgParallelism`, names something upstream does not do: there is no CFG pass to
split, because the distilled recipe denoises with SimpleDenoiser at both stages.

Three more are recorded as refusals but have no product call site, so nothing a
caller can send reaches them. Calling a declared boundary a refusal overstates
what the port has, and the messages now say which kind they are.

Separately, `duration_head_path` is accepted by `kKnownLoadExtras` and read by
nothing, so a caller who points at a duration head silently gets the recipe
default (#611). The spec carries the full accepted/read inventory of all ten
extras and the derivation of every absence claim, each with its positive control
in the same command.

Section 1.6 was re-derived at integration against `origin/main` `9a8615672`,
because `2e9d95e74` renamed `kTemporalUpsampler` to `kSpatiotemporalUpsampler`
after this row's base. The split it establishes -- two reachable, three markers
-- is unchanged.

Refs #644, #611.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
…sertion that could not fail (#644, #611)

`kMultishot` and `kVideoEngineWiring` are gone: one refused a feature neither
reference has, the other one that shipped in `cefacd2d0`. `kCfgParallelism`
becomes `kMultiGpuParallelism` and its message names upstream's three actual
forms. The three arms with no product call site say `DECLARED, NOT REQUESTABLE`,
so a marker can no longer read as a refusal a caller could trip.
`duration_head_path` is refused by name at load instead of accepted and read by
nothing, which is what silently substituted the recipe default for the file a
caller named (#611).

THE ASSERTION THAT COULD NOT FAIL. The retirement note's `ltx-core` check was
`CHECK(flat.find("ltx-core") != npos)` over the whole flattened header. That
string occurs six times in the file -- the upstream map at :8 and :28,
`parse_model_version`, `kLoraFusion`, and twice in the note itself -- so the
assertion survived deleting the clause it exists to hold, and it passed in this
row's own red-first run. The positive checks are now scoped to the note, sliced
from the `kMultishot` marker to the next enumerator heading and derived rather
than pinned to a line, and the `ltx-core` one asserts the CLAIM: "ships at
INFERENCE inside `ltx-core`". Rewriting the note to say the guidance ships inside
the TRAINER ONLY now fails it -- BUILD_EXIT=0, 40 cases, 1 assertion red -- while
under that same mutation `ltx-core` still occurs five times in the file, which is
the old assertion staying green.

THE DOC ROWS THE MERGE WOULD HAVE FALSIFIED. `2e9d95e74` ported the temporal x2
latent upsampler on this same issue and renamed the enumerator, so the arm this
port still refuses is the SPATIOTEMPORAL one. `docs/FEATURES.md` and
`docs/USAGE.md` now say that, and say plainly that the temporal-only arm is
ported, gated and driven by nothing. main's "Temporal x2 ups gated, UNDRIVEN"
cell is byte-for-byte unchanged. The FEATURES gate's `reachable_words` carried
the bare token `upsampler`, which matches both arms and therefore distinguishes
neither; it reads `spatiotemporal upsampler`, matched case-insensitively, and the
case now also holds the reachable row itself, so a row calling the ported arm
refused is red.

The recorded reader anchors in `ltx2_video.cpp` moved again under the merge and
are re-derived to 655 710 806 822 824 894 919 1024 1065; the derived-anchor gate
is what found them.

#611, #691 and #692 are appended to `.agents/issue-index.md`, the append-only
surface `51e0cb5b1` created, rather than to the `roadmap_v1.md` table main
deleted. A grep for all three returned zero against a #644 control in the same
command, so all three were genuinely missing; each names `ROAD-V1-LTX25` as its
owning row, and the unowned ratchet is unmoved at 33.

Closes #644 in part. Refs #611, #691, #692.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
mudler added 4 commits August 15, 2026 12:00
`main` moved seven commits past this branch while the fourth review round was in
flight, and two of them bind the repair that follows. `8f49ac3be` adds AGENTS.md
`## Nothing lands dead` and `.agents/reachability.md`, which name the exact shape
finding F1 describes: the test-only driver, where the only thing that calls the
new code is the test written for it. `98f8e046d` retires `--allow-unported` on
the LTX-2.5 path.

Merged rather than rebased because `ea6b01f1f` is already the published head of
pull request #882, and `main` is never force-pushed here.

No conflicts. `98f8e046d` moves the nine derived READER ANCHORS in
`ltx2_video.cpp` by five lines, which the anchor gate reports on the next run;
that record edit rides in the commit after this one, with the change that made it
stale.

FOLLOWING_AGENTS_PROTOCOL

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

`ltx2_video.cpp`'s phase guard tested `im.upsampler_cfg.temporal_upsample`
alone. Every BOTH-flags config satisfies that too, so the two guards were an
implication over one variable and this one always fired first. A caller who
supplied a genuine spatiotemporal checkpoint was told it is the TEMPORAL x2
upsampler and pointed at the spatial one: wrong on both counts, and pointing
them at the arm they already had.

The cost is not only the message. It made the ledger refusal that names this
arm, `ltx2_upsampler.cpp:465`, unreachable from any request, so
`docs/FEATURES.md`'s "a product path constructs each and throws" was false for
the one arm it was still true of after #889. Narrowed to
`temporal_upsample && !spatial_upsample` so a both-flags config falls THROUGH to
that refusal.

The reviewer who found this named a real limit on their own evidence: no fixture
drove a both-flags checkpoint through `LoadVideoEngine`, so mutation could not
separate "unreachable" from "untested" and only the static implication settled
it. That hole is closed here. The new subcase writes a both-flags upsampler and
drives it through `LoadVideoEngine` + `Generate` rather than calling
`Ltx2LatentUpsample` directly, because AGENTS.md `## Nothing lands dead` requires
the smallest failing test to enter through a production entry point.

RED before, on the shipped guard: `SPATIOTEMPORAL` absent, and both
`it is the TEMPORAL x2 upsampler` and `Supply the spatial upsampler` present.
Green after, `test_ltx2_video` 40/40, 827 assertions.

Two mutations, each of which BUILT with 0 errors before it was run. Widening the
guard back to `temporal_upsample` alone: RED, 3 assertions. The reachability
mutation from `.agents/reachability.md` — deleting the production call site
`Ltx2UpsampleVideoLatent` in the phase driver: RED, and it also fires the
positive control in `test_ltx2_pipeline`'s new split case, which then reports
`Ltx2UpsampleVideoLatent callers = <none>`. The tree was restored byte-for-byte
after each, verified by sha256.

The recorded READER ANCHORS move by five lines in the same commit. That is the
merge of `origin/main`, not this change: `98f8e046d` added lines above them, and
the derived-anchor gate caught it exactly as it was built to.

FOLLOWING_AGENTS_PROTOCOL

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

Two review findings on the LTX-2.5 out-of-scope ledger, plus the records they
made stale.

## #889 — `kBetaScheduler` was published as reachable and has no caller

The header defines a reachable refusal as one "a caller CAN trip", and
`docs/USAGE.md` published "Both are reachable". Neither was true of
`kBetaScheduler`. Its site `ltx2_pipeline.cpp:199` sits inside `Ltx2Schedule`,
which has zero call sites in `src/`, `include/` or `examples/`; the engine calls
`Ltx2SigmaSchedule` directly and no ABI field, load extra or CLI flag carries a
scheduler kind. The only driver is the unit test that constructs the enumerator
by hand. §1.6 asked whether an enumerator appears in `src/`, and that question's
true answer is the wrong answer.

Reclassified as a marker rather than wired, and UPSTREAM is why, not
convenience. At Lightricks/LTX-2 `fd4ded7f`, `BetaScheduler` is defined at
`ltx-core components/schedulers.py:91` and constructed nowhere in the repository:
all seven `ltx-pipelines` entry points hard-code `LTX2Scheduler()`
(`ti2vid_one_stage.py:81`, `ti2vid_two_stages.py:87`,
`ti2vid_two_stages_hq.py:90`, `a2vid_two_stage.py:78`, `t2a_one_stage.py:67`,
`keyframe_interpolation.py:82`, `retake.py:96`), and vLLM-Omni `a4ea67a21` has
zero hits for the name against 81 files carrying `ltx` as the control. Routing
the engine through `Ltx2Schedule` would have invented a scheduler-selection
surface that upstream does not have, so mirroring upstream forbids the wiring
repair.

The classification is now DERIVED. `test_ltx2_pipeline`'s new "the
reachable/marker split matches the source" walks the product tree, counts callers
of each arm's entry function, and requires the message to agree in both
directions, so a caller appearing later fails the marker wording just as its
absence failed the reachable wording. Two positive controls ride in the same
walk plus a file-count floor, because this is an absence claim about our own tree
and this row has already shipped four of those. That is the anti-tautological
shape #691 asks for, applied to the beta arm; #691 stays open for the three
markers that have no call site to derive from.

## #892 — the multi-GPU marker's `cfg` absence is false, and a form is missing

The header shipped an assertion that `cfg` is absent from both multigpu trees and
the refusal shipped "three forms". At the pin it is 5 hits against 33 files as
the control, two of them prose about CFG at `docs/multigpu/gemma.md:103-104`. The
spec's grep was correct and its PATH FILTER was wrong: scoped to the two SOURCE
trees, it excluded `docs/multigpu/`, where the answer is written out. That is
this row's own transferable lesson committed a fourth time. There is also a
fourth `BuilderProtocol` in the directory the refusal cites,
`multigpu/bp_gemma_builder.py:42` `BatchParallelGemmaBuilder`.

The disposition is unchanged and stronger. `gemma.md:104` records that the
distilled pipeline this port runs takes no `negative_prompt` and "runs without
CFG", so the one form that would carry a CFG pair is the one upstream tells you
not to use here. A reason beats an absence.

## Reachability disclosure

Per AGENTS.md `## Nothing lands dead`, which landed in `8f49ac3be` while this
repair was in flight: `Ltx2Schedule` and `Ltx2SchedulerKind` are UNREACHED. Owned
by row LTX25-RETIRE-DEAD-ARMS, tracked by #893, listed under `## Owed` in the
row's spec. This is not a staged slice awaiting a wiring wave — upstream selects
no scheduler anywhere, so there is nothing to wire it to, and the open decision
is retire-or-keep-as-recorded-mirror. Deciding that is a behavior change with its
own red-first evidence, which is why this commit labels the arm honestly and does
not also delete the dispatcher.

## Evidence

RED before, `test_ltx2_pipeline` 39/42 cases, 8 assertions failing: the beta
marker assertion, four on the multi-GPU message (`three forms` present,
`four forms` / `BatchParallelGemmaBuilder` / `gemma.md` absent), the header's
`cfg` sentence, and the split case reporting `Ltx2Schedule callers = <none>` with
both controls live at `ltx2_video.cpp:1515` and `:1689`. Green after, 42/42, 2485
assertions.

Two mutations, each BUILT with 0 errors before it was run. Dropping the `marker`
suffix from the beta refusal: RED in both the ledger case and the split case.
Restoring "three forms": RED, 2 assertions. Tree restored byte-for-byte after
each, verified by sha256.

One consequence worth recording because it cost a build cycle: the header may not
QUOTE the retired sentence while explaining it. A text gate matches text and
cannot tell a quotation from a claim, so the corrected note describes the old
sentence instead of reproducing it, and says so.

## Records

`docs/FEATURES.md` and `docs/USAGE.md` are keyed records, edited by key: exactly
two FEATURES rows change and the other 365 lines are byte-identical, with the
filter's own line count as the control. `.agents/issue-index.md` gains four rows
and loses none. The spec's §1.1 control count is re-measured at 24 rather than
22, its §2.1 `docs/USAGE.md` anchor is replaced by the paragraph's opening words
after being wrong by ~290 lines, and §4 item 7 now describes the tightened
`ltx-core` assertion that shipped rather than the weak one it replaced. Moving
anchors in `ltx2_video.cpp` are named by symbol, not by line, because three
anchors in this row went stale inside one branch.

FOLLOWING_AGENTS_PROTOCOL

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

Keyed records reconciled by key; the issue index is append-only (merge=union).

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
@localai-bot
localai-bot merged commit 0785cfc into main Aug 15, 2026
1 check failed
localai-bot pushed a commit that referenced this pull request Aug 15, 2026
…chors (#644)

`origin/main` advanced four commits while this branch sat on `00613767d`. Merged
rather than rebased, because a rebase over a pushed branch is a force-push and
`AGENTS.md` forbids one. The merge reported no conflict.

It is not a document-only merge, which is why it is committed on its own. The
one commit that matters here is `0785cfc4d` (#882, `LTX25-RETIRE-DEAD-ARMS`),
which touches the same two files this row's record cites most: it adds 70 lines
to `src/vllm/multimodal/ltx2_video.cpp` and 306 to
`tests/vllm/multimodal/test_ltx2_video.cpp`, all of them AHEAD of every anchor
this spec carries into those files. Seven citations that were correct at
`00613767d` are wrong at this commit, and the repair rides in the next one.

The rest is `04be1390b` (#901) sweeping unchecked registry downcasts across 30
translation units, `b5f27c9a4` (#906) recording issue #904, and `727ac7734`
(#909). None of them is on this row's path.

Verified after merging rather than assumed: `git diff --numstat origin/main`
names `.agents/issue-index.md`, `.agents/model-matrix.md`,
`.agents/specs/ltx25-prompt-adaln.md`, `scripts/gen-ltx2-goldens.py`,
`scripts/measure-ltx2-prompt-adaln.py`, `tests/vllm/models/ltx2_goldens.inc`,
`tests/vllm/models/test_ltx2.cpp` and
`tests/vllm/multimodal/test_ltx2_video.cpp` — and no `src/` or `include/` path,
so the claim in this row's Outcome that it changes no product source still holds
against the NEW `origin/main`.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
localai-bot pushed a commit that referenced this pull request Aug 15, 2026
…alidated, marked UNKNOWN rather than carried (#644, #673)

The merge that repairs seven anchors also invalidates a count, and the count was
about to ride along unexamined — which is the same defect in its other form. An
anchor and a measurement both name a tree, and this row's rule is that neither
survives a merge on the argument that it probably did not move.

`0785cfc4d` (#882) added 306 lines to `tests/vllm/multimodal/test_ltx2_video.cpp`
between `00613767d` and this branch's tip, taking it from 37 to 40 `TEST_CASE`s.
The Outcome quoted 37 / 784 with `LTX2_CHECKPOINT_ROOT` unset and 37 / 9031 with
it set, dated to the PREVIOUS merge, in three places.

What is measured here is the SOURCE count, 37 to 40, by `grep -c '^TEST_CASE'` on
both revisions with the same grep returning matches on `origin/main` as its
control. The doctest CASE and ASSERTION totals were NOT re-run, so they are
recorded as UNKNOWN rather than adjusted, guessed, or left standing. Marking a
number superseded is cheap; inventing its replacement is not available, because
the `set` arm needs the 18.72 GB NVFP4 and 23 GB FP8 DiTs under
`$CHECKPOINT_ROOT` and no CI host has them. That debt is #673's, where it already
lives.

Two claims that DO survive, checked rather than assumed. The #673 ratio finding —
CI executes a single-digit percentage of this suite — does not depend on the
exact totals. And the #900 reachability finding, that deleting the term leaves
`test_ltx2_video` green, is not undone by adding three cases that also do not
observe it.

Scoped by measurement, not by assertion: `test_ltx2_loader.cpp` and
`test_ltx2_device.cpp` are byte-identical across those two revisions —
`git diff --numstat` reports nothing on either, against a positive control that
reports `62 8` on `ltx2_video.cpp` — so their counts are untouched, and
`test_ltx2.cpp` differs only by this branch's own edit.

All 33 citations re-derived again on this tree: 33 FRESH, armed control still 6
STALE of 33. This commit changes one Markdown file and no build input, so the
`BUILD_EXIT=0` / `CTEST_EXIT=0` / `100% tests passed, 0 tests failed out of 480`
gate measured at `7bf2a9297` still describes the tree that lands; `git diff
--name-only 7bf2a92` naming only the spec is the evidence, and it is stated as
an inherited gate rather than a fresh one.

FOLLOWING_AGENTS_PROTOCOL

Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
localai-bot added a commit that referenced this pull request Aug 16, 2026
…rim it back (#930) (#964)

The LTX-2.5 phase loop was fixed at one `Ltx2VideoTokenCount(vshape, 1)`, and that single limitation blocked three conditioning arms. Two rows walked into it hours apart without talking to each other — [#930](#930) from the IC-LoRA port and [#920](#920) from the generated-keyframe-slots port — which is why it gets a seam of its own rather than a fix inside whichever row noticed it last.

Issue: [#930](#930). Spec: [`.agents/specs/ltx25-token-append.md`](.agents/specs/ltx25-token-append.md). Campaign [#644](#644). Pin `Lightricks/LTX-2 @ fd4ded7f2d88d3da713abcdd4ad41ecc4a9314ca`, verified at the working checkout.

## Why this branch replaces #948

**This is a history repair, not a content one.** [#948](#948) carried this row through implementation and a fresh review to PASS at head `a1b1d8da4`. It cannot land, and the reason is entirely in its commit ORDER.

`scripts/check-doc-checkpoint.py` walks a range **per commit** ([#573](#573)). The review-repair commit `b5618b305` edited `include/vllm/model_executor/models/ltx2_conditioning.h` and `include/vllm/multimodal/ltx2_video.h` — the `user_usage` class — while the `docs/USAGE.md` edit that pays for them sat in a sibling commit. The final tree satisfied the obligation; only the ordering failed. Measured on this branch, the checker still REDs on `b5618b305` in isolation and is green on both commits here, so the instrument is armed rather than merely quiet.

A commit message cannot be corrected in place and this repository uses no force variant, so the branch is rebuilt with the shape the checker requires: **one spec commit, then one implementation commit** carrying `docs/USAGE.md` and `docs/FEATURES.md` alongside the code they describe. #678 was rebuilt as #880 and #661 as #882 for exactly this rule.

**The reviewed content is proven unchanged.** Built on `2daa3287f` — `origin/main` when the rebuild started — this branch's head tree hash was `d937252dd06efd6a07c4affebff42153b25075a5`, byte-for-byte equal to `a1b1d8da4^{tree}`, and `git diff a1b1d8d HEAD` was empty. `origin/main` then advanced to `f365cc299` (#958), so the branch was rebased onto it; restricted to this row's ten files, the only remaining differences against `a1b1d8da4` are the two lines #958 itself changed — its own appended issue-index row and its `--offload-config` rewrite in `docs/USAGE.md`. The eight code, test, spec and `docs/FEATURES.md` files are byte-identical. Nothing below was re-derived.

## The sizing in #930 is corrected, not inherited

#930 names two blocked arms. There are three: reference video, the last-frame keyframe, and generated keyframe slots. #930 predates #920 and its author asked for the correction. This spec is the record that supersedes both counts.

## What was actually missing

The appending conditioning ITEMS were already ported and gated. Two halves were not.

`Ltx2ExtendKeyframesMask` mirrors `extend_keyframes_mask` (`conditioning/mask_utils.py:76-105`). Upstream's docstring makes the call an obligation of appending itself — *"Every conditioning item that appends tokens must call this, otherwise the per-token marker goes out of sync with the token sequence"* (`:83-85`) — so it lives inside `AppendTokens` rather than at the three call sites. Both `None` branches are mirrored, including the zero-fill only `marked=true` reaches (`:100-101`), so #920's arm finds it already correct.

`Ltx2ClearConditioning` mirrors `clear_conditioning` (`tools.py:88-117`). Two things there are not a truncation: the denoise mask comes back **all ones** rather than sliced (`:104`), because the returned state describes a finished latent, and `keyframes_mask` is dropped entirely (`:113`).

`Ltx2LatentState` grows a `keyframes_mask` field so the marker can be extended with the sequence it describes.

## Three findings that changed the design

**The attention mask is not the gap, and no field is added for it.** Both appending video items pass a literal `attention_mask=None` (`keyframe_cond.py:70`, `reference_video_cond.py:88`), `update_attention_mask` returns `None` for that case (`mask_utils.py:110-143`), and the only route to a non-`None` mask is `ConditioningItemAttentionStrengthWrapper`, whose sole application site is `iclora_utils.py:169` on the IC-LoRA path. `combined_image_conditionings` — the route this engine mirrors — never wraps. A field here would be one no ported item could populate, which is the unpassed-parameter shape [`.agents/reachability.md`](.agents/reachability.md) enumerates. The refusals that cite the absent field were right to mention it and wrong to offer it as the blocker.

**The sigma schedule must keep reading the target count.** Upstream fixes it twice over: the argument is `math.prod(latent.shape[2:])` of the *unpatchified* target (`schedulers.py:32`), which by construction cannot contain appended tokens, and every pipeline computes its sigmas before a state exists (`ti2vid_one_stage.py:207` passes no latent; `distilled.py:200-201` uses frozen constants). This engine's call sits **after** the conditioning block, so before this change it would have re-shifted the whole trajectory the moment anything appended. It now reads a `target_tokens` local.

**The trim cannot be gated on pixels alone, so it is gated on a guard.** Appended tokens sit at the tail of a contiguous `[tokens, width]` buffer and `Ltx2VideoUnpatchify` takes a bare pointer, so an un-trimmed state would unpatchify the same head bytes and render pixel-identical frames. Correct output for the wrong reason. A `VT_CHECK` at the pointer boundary is what turns "the head happens to be right" into "the buffer *is* the target grid", and it is what makes deleting the trim a RED (mutation M3).

## The arm lifted, and the two left alone

The **last-frame keyframe** arm is served, mirroring `combined_image_conditionings` (`helpers.py:272-308`): one preprocess-and-encode shared by both arms, and a branch on `frame_idx` sending 0 to `VideoConditionByLatentIndex` (`:296`) and anything else to `VideoConditionByKeyframeIndex` (`:302`). Both may be supplied at once. Nothing is added to `include/vllm.h` — `last_frame` was already on the ABI.

**Reference video stays refused and its message is byte-identical.** At this base, PR #938 (`row/LTX25-IC-LORA`) is open and unmerged and `git log --grep '#923'` is empty, so `--lora` does not read the IC-LoRA scale factors and that refusal's stated cause is still true. #930's body describes the message as already rewritten onto token-append; **that is not the state of `origin/main`.** Rewording it would have shipped a refusal naming the first of two causes — the defect a sibling row nearly shipped.

**Generated keyframe slots** (#920, PR #929, also open) and **reference audio** stay refused for their own reasons.

## What lands unreached, named rather than discovered

`Ltx2ExtendKeyframesMask`'s **`marked=true` branch lands with a unit driver and no production caller.** The only upstream construct that passes `true` is `VideoGeneratedKeyframeSlots` (`keyframe_slots.py:121`), which belongs to the generated-keyframe-slots arm and not to this row. Every appending item ported here passes `false`.

It is landed rather than stubbed because building half of `extend_keyframes_mask` is the worse option: the two `None` branches are not symmetric, and a port that mirrors one and guesses the other gets #920's arm silently wrong. Mutation M5 shows the branch is not inert — appending with `marked=true` instead of `false` is RED.

Owner of the wiring: row `LTX25-GENERATED-KEYFRAMES`, issue [#920](#920). Listed under `## Owed` in the spec. Declared here per [`.agents/reachability.md`](.agents/reachability.md) `## Landing a slice that is not reached yet`.

## Evidence

RED first, on the pre-row engine with the tests in place: `test_ltx2_video` FAILED, the new case throwing the last-frame refusal verbatim. That run also printed `assertions: 825 | 825 passed | 0 failed` beside `Status: FAILURE!` — the thrown-case trap, which is why the exit code is the authority throughout.

The witness is on **rendered artifact bytes with a no-op control**, because `Ltx2ConditioningTrace` is filled before denoise and cannot observe the loop. A keyframe render differs from a no-keyframe render in **59773 of 91169** bytes; two different keyframes differ from each other in **334**; the same request twice is byte-identical. The control is what separates "the append reached the maths" from "the instrument is blind" — a sibling row's first attempt found every arm identical *including* its control, and without that control a blind instrument reads as a real-but-subtle effect, which is the direction that ships.

Two new trace fields, `video_tokens` and `schedule_tokens`, are written *inside* the phase loop for that same reason, and the sigma claim is checked as a relation between two measured values rather than against a literal.

Upstream ships **no tests** — `find /home/mudler/_git/LTX-2 -name 'test_*.py'` returns 0 across the whole repository at the pin — so nothing was ported and every case is written against an upstream anchor instead.

## Review repairs

A fresh review returned FAIL on six findings. The seam itself survived: every upstream design decision checked out and the pixel witness reproduced exactly. Two claimed guarantees survived mutation and are now gated.

**The all-ones restore was not gated.** `Ltx2CreateVideoLatentState` already sets every target-range mask value to `1.0`, and the append writes `1 - strength` only at the tail, which the trim drops under either implementation — so "restore all ones" and "slice" produced identical bytes over the range the test walked, and mutation M6 (slice instead of restore) was **GREEN**. The case now conditions token 0 *inside* the target with `Ltx2ConditionVideoByLatentIndex` before the append, which writes `1 - strength` at `start .. start + count` (`latent_cond.py:41`). A slice then leaves `0.4` at token 0. M6 is **RED**, and a `REQUIRE` on `mask.front()` before the trim asserts the instrument is armed rather than assuming it.

**Nothing gated that the keyframe lands on the last frame.** Mutation M10 (`frame_idx` from `frames - 1` to `0`) was **GREEN**: both renders still differed from the no-op control and from each other, and the token count was identical, because a keyframe pinned to the first frame appends exactly as many tokens as one pinned to the last. The engine now asserts the first appended token's temporal position, recomputed from `frames` and `fps` rather than read back from the argument, so the two are independent expressions (`keyframe_cond.py:52-58`). M10 is **RED**.

`origin/main` advanced to `c2019b0e3` (#935) during review and the branch stopped merging. Three conflicts, two with a trap: `docs/FEATURES.md`'s LTX-2.5 cell is at `MAX_CELL_CHARS` exactly, so the obvious merge lands at 226 and REDs — resolved by keeping main's complete cell and trimming only this row's own wording, to 220. And both sides had rewritten the `READER ANCHORS` line, so **neither** value was correct afterwards; it was re-derived a third time from the merged file.

Every upstream `file:line` in this change was re-derived at the final tree by a needle taken from the **claim**, never read out of the cited span, and the load-bearing needles were checked for uniqueness in their files. The sweep covers **119** citations in this row's added lines — 108 explicit and 11 bare `:NN` continuations — and corrected **13**.

Four of those were the review's: `tools.py:103` and `:112` in the `Ltx2ClearConditioning` declaration and in the spec, and `schedulers.py:38-39` in four places including the append-only issue-index row, which is fixed first and SHA-anchored because it could not be corrected after landing.

Three were not, and two of those three are anchors written *during this repair* and caught by the sweep over its own output:

- `ltx2_recipes.py:125-158` names a file that exists neither upstream nor in this tree. The distilled recipe's frozen sigmas are `distilled.py:200-201` over `utils/constants.py:17-23`.
- A bare `(:100-101)` resolves against `tools.py`, the nearest file named above it, whose `:100-101` is a real and unrelated statement. It means `mask_utils.py`. The two bare continuations in `Ltx2ClearConditioning`'s declaration are spelled with their file for the same reason: the nearest name above them is `blocks.py`, and `blocks.py:104` and `:113` are both real imports.
- `latent_cond.py:36-38`, written here for the M6 repair, is `stop_token` and a `clone()`. The `1 - strength` write is `:41`.

**One anchor is left alone deliberately.** `latent_cond.py:38-39` is cited at eight pre-existing sites across specs, golden scripts and other rows' tests for "only `clean_latent` and `denoise_mask` are written". Those writes are `:40-41`; `:38-39` is a `clone()` and a blank line. The drift predates this row and the sites belong to other rows, so correcting them here would be scope this PR did not claim. It is named rather than left for the next sweep to rediscover.

## Gate on the rebuilt branch

Rerun in full rather than inherited, on the rebased head `fd9948f14`, CPU-only Release, `-j6` build and `ctest -j4`:

`CONFIGURE_EXIT=0`, `BUILD_EXIT=0`, `: error:` count **0**, `No space left` **0**, `BFD assertion` **0** (all three greps positive-controlled against a synthetic line), `ctest -N` **485**, `CTEST_EXIT=0`, `100% tests passed, 0 tests failed out of 485`. Load average 4.94 at start and 11.02 at end; 46 G free.

Row suites, run directly for their assertion counts: `test_ltx2_video` 44/44 cases, 1024/1024 assertions; `test_ltx2_vae` 39/39, 3092/3092; `test_ltx2` 43/43, 4388/4388; `test_ltx2_device` 18/18, 546/546.

M6 and M10 were rerun on this branch rather than carried over. **M6** — `Ltx2ClearConditioning` slices instead of restoring — `git diff --stat` one file `1 +/1 -`, BUILT with 0 compile errors, exit **1**: `38 passed | 1 failed`, four `CHECK( 0.4 == 1 )` at mask tokens 0-3. **M10** — `frame_idx` `frames - 1` to `0` — one file `1 +/1 -`, BUILT with 0 compile errors, exit **1**: `42 passed | 2 failed`, both cases THREW the temporal-position `VT_CHECK` (`0.333333` wanted, `0.000000` got). M10 prints `assertions: 923 | 923 passed | 0 failed` beside `Status: FAILURE!`, which is the thrown-case trap; the exit code is the authority. The tree was restored byte-for-byte after each — `git write-tree` back to `d937252dd0` — and rebuilt before remeasuring.

`READER ANCHORS` were re-derived at the final tree and are unchanged: `756 811 907 923 925 1003 1028 1133 1174`. The `docs/FEATURES.md` LTX-2.5 support cell measures **220** characters, exactly `MAX_CELL_CHARS`, with main's `, A2V WAV` and every host and measurement qualifier intact.

Checkers, exit codes captured directly: `check-doc-checkpoint` **0** over the range and **0** on each commit individually, `check-commit-trailers` **0**, `check-commit-style` **0**, `check-issue-index-append-only` **0**, `check-agent-record` **0**, `check-public-doc-tables` **0**.

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

2 participants