Res2sTwoStageRecipe is this tree's port of TI2VidTwoStagesHQPipeline
(ti2vid_two_stages_hq.py:59 @ Lightricks/LTX-2 fd4ded7f), and HQ is the one
pipeline in scope that runs the SAME adapter on both stages at DIFFERENT
strengths. It builds distilled_lora_stage_1 and distilled_lora_stage_2 from
one path at distilled_lora_strength_stage_1 / _stage_2
(ti2vid_two_stages_hq.py:92-101) and hands one to each
DiffusionStage.from_checkpoint (:154, :165). The CLI defaults them 0.25
and 0.5 (utils/args.py:1174-1184).
Today res2s_two_stage runs both stages at 1.0. Neither of
Res2sTwoStageRecipe's phases sets Ltx2PhaseRecipe::loras, so both take the
kAllAdapters default, and the engine carries ONE strength for the whole load
(lora_strength absent is 1.0, include/vllm/multimodal/ltx2_video.h:214-218) —
there is no per-phase strength anywhere. Nothing refuses, nothing changes shape,
and the clip comes back at the size, frame count and sample rate asked for. The
only instrument that sees it is a render against upstream on the same checkpoint,
take and seed.
Why a new field on Ltx2PhaseRecipe does NOT close this
Row LTX25-PHASE-LORA (#1118, PR #1140) landed the per-phase adapter seam, so
the old "we hold one DiT fused at load" blocker is gone. But the seam's state is
a boolean, and adding Ltx2PhaseRecipe::lora_strength on top of it would
fail SILENTLY:
// src/vllm/model_executor/models/ltx2_loader.cpp, Ltx2RebindDitLoras
const bool currently_fused = checkpoint.lora_fused_tensors > 0;
if (currently_fused == fuse) return;
Ltx2RebindDitLoras's header calls this "a no-op it detects itself". It detects
"already FUSED", never "already fused AT THIS STRENGTH". HQ has both stages
fused, so currently_fused == fuse holds at the stage boundary, the rebind
returns having done nothing, and stage 2 renders at stage 1's strength — the
exact defect the field was added to fix, wearing a green.
What closing this needs
Two changes beyond the field, and they are modest growth rather than a redesign:
bool fuse becomes a type that can carry a strength (upstream's
LoraPathStrengthAndSDOps, effectively).
Ltx2DitCheckpoint records which adapter state is applied rather than
merely whether one is, so the no-op test compares states instead of a bit.
The re-materialize-and-write-back mechanism itself is untouched by either:
re-materializing from the pristine file already reaches any strength in one pass,
which is the property #1118 chose it for.
Also needed, and cheap once the above exists: a --distilled-lora-strength-stage-1
/ -stage-2 pair on the request surface, since one lora_strength extra cannot
spell two values.
Why this is filed rather than inherited by #921
#921 owned the per-phase strength in .agents/specs/ltx25-phase-lora.md's
## Owed, and it was closed as completed on 2026-08-17 by
LTX25-RES2S-LOOP (PR #1125, 4d7748646), which landed the res_2s sampler.
That row named "the distilled LoRA per stage" as explicitly out of scope and
"unchanged by this one" — correctly — but did not list it under its own
## Owed, so the debt outlived its issue with no open owner. This restores one.
The trap is written beside the early return in
include/vllm/model_executor/models/ltx2_loader.h so the next person to grow the
seam meets it in the header rather than in a render, and this issue is listed
under ## Owed in
.agents/specs/ltx25-phase-lora.md.
Found during the review-repair of PR #1140.
Res2sTwoStageRecipeis this tree's port ofTI2VidTwoStagesHQPipeline(
ti2vid_two_stages_hq.py:59@ Lightricks/LTX-2fd4ded7f), and HQ is the onepipeline in scope that runs the SAME adapter on both stages at DIFFERENT
strengths. It builds
distilled_lora_stage_1anddistilled_lora_stage_2fromone path at
distilled_lora_strength_stage_1/_stage_2(
ti2vid_two_stages_hq.py:92-101) and hands one to eachDiffusionStage.from_checkpoint(:154,:165). The CLI defaults them 0.25and 0.5 (
utils/args.py:1174-1184).Today
res2s_two_stageruns both stages at 1.0. Neither ofRes2sTwoStageRecipe's phases setsLtx2PhaseRecipe::loras, so both take thekAllAdaptersdefault, and the engine carries ONE strength for the whole load(
lora_strengthabsent is 1.0,include/vllm/multimodal/ltx2_video.h:214-218) —there is no per-phase strength anywhere. Nothing refuses, nothing changes shape,
and the clip comes back at the size, frame count and sample rate asked for. The
only instrument that sees it is a render against upstream on the same checkpoint,
take and seed.
Why a new field on
Ltx2PhaseRecipedoes NOT close thisRow
LTX25-PHASE-LORA(#1118, PR #1140) landed the per-phase adapter seam, sothe old "we hold one DiT fused at load" blocker is gone. But the seam's state is
a boolean, and adding
Ltx2PhaseRecipe::lora_strengthon top of it wouldfail SILENTLY:
Ltx2RebindDitLoras's header calls this "a no-op it detects itself". It detects"already FUSED", never "already fused AT THIS STRENGTH". HQ has both stages
fused, so
currently_fused == fuseholds at the stage boundary, the rebindreturns having done nothing, and stage 2 renders at stage 1's strength — the
exact defect the field was added to fix, wearing a green.
What closing this needs
Two changes beyond the field, and they are modest growth rather than a redesign:
bool fusebecomes a type that can carry a strength (upstream'sLoraPathStrengthAndSDOps, effectively).Ltx2DitCheckpointrecords which adapter state is applied rather thanmerely whether one is, so the no-op test compares states instead of a bit.
The re-materialize-and-write-back mechanism itself is untouched by either:
re-materializing from the pristine file already reaches any strength in one pass,
which is the property #1118 chose it for.
Also needed, and cheap once the above exists: a
--distilled-lora-strength-stage-1/
-stage-2pair on the request surface, since onelora_strengthextra cannotspell two values.
Why this is filed rather than inherited by #921
#921 owned the per-phase strength in
.agents/specs/ltx25-phase-lora.md's## Owed, and it was closed as completed on 2026-08-17 byLTX25-RES2S-LOOP(PR #1125,4d7748646), which landed the res_2s sampler.That row named "the distilled LoRA per stage" as explicitly out of scope and
"unchanged by this one" — correctly — but did not list it under its own
## Owed, so the debt outlived its issue with no open owner. This restores one.The trap is written beside the early return in
include/vllm/model_executor/models/ltx2_loader.hso the next person to grow theseam meets it in the header rather than in a render, and this issue is listed
under
## Owedin.agents/specs/ltx25-phase-lora.md.Found during the review-repair of PR #1140.