Found during the rebase of #1032 (row/LTX25-T2A-ONE-STAGE), verified in the source at head 3d9d9c9bb812c531b08c1443d4a4530b55f736fe. The branch is not merged, so this is a defect in code about to land rather than on main.
What upstream does
Upstream hands the denoiser an X0Model, so the guider combines denoised (x0) predictions:
packages/ltx-pipelines/src/ltx_pipelines/utils/blocks.py:480-482 — the transformer is an X0Model
packages/ltx-core/src/ltx_core/model/transformer/model.py:601-604 — X0Model.forward returns to_denoised(latent, v, timesteps)
packages/ltx-core/src/ltx_core/utils.py:39-52 — to_denoised = sample - velocity * sigma
packages/ltx-pipelines/src/ltx_pipelines/utils/denoisers.py:188-203 — the guider combines those x0 tensors
What we do
We combine the raw DiT velocities and convert once afterwards. At src/vllm/model_executor/models/ltx2_t2a.cpp, the local is named velocity, is assigned cond.audio — an Ltx2DitForward output — and is what the guider receives:
std::vector<float> velocity = cond.audio;
...
velocity = Ltx2MultiModalGuidance(g, cond.audio.data(), ...);
...
last_denoised = ToDenoised(latent, velocity, timesteps, tokens, width);
ToDenoised runs on the result of the guidance, not on its inputs.
Why it is not merely a refactor
The linear terms are invariant under x0 = latent - sigma*v, so the two forms agree exactly whenever rescale_scale == 0. The rescale branch is not invariant. At src/vllm/model_executor/models/ltx2_pipeline.cpp:504-522:
const float factor_raw = unbiased_std(cond) / unbiased_std(pred.data());
const float factor = rescale_scale * factor_raw + (1.0 - rescale_scale);
for (float& value : pred) value *= factor;
Ours is std(v_cond)/std(v_pred) scaling the velocity; upstream (guiders.py:268-271) is std(latent - sigma*v_cond)/std(latent - sigma*v_pred) scaling the whole x0. Scaling v by f yields latent - sigma*f*v, while scaling x0 yields f*(latent - sigma*v). The two differ by (f-1)*latent.
The default makes this the normal path, not a corner
rescale_scale = 0.7 is the shipped T2A default — params.audio_guider.rescale_scale = 0.7 at ltx2_pipeline.cpp:900, mirroring utils/constants.py:63 and args.py:1101-1106. So every default T2A render takes the divergent branch.
Magnitude — illustrative, NOT measured
On synthetic tensors (NumPy, cfg 7.0 / stg 1.0 / sigma 1.0) the two forms differ by 18.17 % relative RMS at rescale_scale = 0.7, and agree to 5.7e-6 at rescale_scale = 0.0 — the latter being the control that localises the divergence entirely to the rescale branch.
This is algebra on synthetic inputs. It is not a measurement against upstream on real weights: dgx.casa is currently down, and no LTX-2.5 checkpoint was loaded. The direction of the finding is proven by source; the magnitude on a real render is unmeasured and this issue does not claim it.
Nothing can currently see it
Every T2A assertion in the suite is self-consistency — arms differ, forward counts move — and there is no oracle-derived numeric golden for the guided step. A token or shape gate cannot see a guidance-space error, in the same way a token gate cannot see a dtype that is too wide.
What a fix owes
- Combine in x0 space, mirroring
denoisers.py:188-203, or equivalently move the rescale into x0 space so the factor is computed and applied on latent - sigma*v.
- A red-first test that fails on the current form and passes on the mirrored one, with
rescale_scale at its 0.7 default so the assertion sits on the shipped path. The rescale_scale = 0.0 agreement is the natural control.
- Note that the guider is shared with the video path (
params.video_guider), so check whether the video arm has the same shape before fixing only the audio one.
Blocks #1032 in my view, because a default-path divergence from the reference is exactly what "Mirror vLLM" — here Lightricks, per .agents/oracles/ — exists to prevent. Related: #1005, #1013, campaign #644.
FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]
Found during the rebase of #1032 (
row/LTX25-T2A-ONE-STAGE), verified in the source at head3d9d9c9bb812c531b08c1443d4a4530b55f736fe. The branch is not merged, so this is a defect in code about to land rather than onmain.What upstream does
Upstream hands the denoiser an
X0Model, so the guider combines denoised (x0) predictions:packages/ltx-pipelines/src/ltx_pipelines/utils/blocks.py:480-482— the transformer is anX0Modelpackages/ltx-core/src/ltx_core/model/transformer/model.py:601-604—X0Model.forwardreturnsto_denoised(latent, v, timesteps)packages/ltx-core/src/ltx_core/utils.py:39-52—to_denoised = sample - velocity * sigmapackages/ltx-pipelines/src/ltx_pipelines/utils/denoisers.py:188-203— the guider combines those x0 tensorsWhat we do
We combine the raw DiT velocities and convert once afterwards. At
src/vllm/model_executor/models/ltx2_t2a.cpp, the local is namedvelocity, is assignedcond.audio— anLtx2DitForwardoutput — and is what the guider receives:std::vector<float> velocity = cond.audio; ... velocity = Ltx2MultiModalGuidance(g, cond.audio.data(), ...); ... last_denoised = ToDenoised(latent, velocity, timesteps, tokens, width);ToDenoisedruns on the result of the guidance, not on its inputs.Why it is not merely a refactor
The linear terms are invariant under
x0 = latent - sigma*v, so the two forms agree exactly wheneverrescale_scale == 0. The rescale branch is not invariant. Atsrc/vllm/model_executor/models/ltx2_pipeline.cpp:504-522:Ours is
std(v_cond)/std(v_pred)scaling the velocity; upstream (guiders.py:268-271) isstd(latent - sigma*v_cond)/std(latent - sigma*v_pred)scaling the whole x0. Scalingvbyfyieldslatent - sigma*f*v, while scalingx0yieldsf*(latent - sigma*v). The two differ by(f-1)*latent.The default makes this the normal path, not a corner
rescale_scale = 0.7is the shipped T2A default —params.audio_guider.rescale_scale = 0.7atltx2_pipeline.cpp:900, mirroringutils/constants.py:63andargs.py:1101-1106. So every default T2A render takes the divergent branch.Magnitude — illustrative, NOT measured
On synthetic tensors (NumPy, cfg 7.0 / stg 1.0 / sigma 1.0) the two forms differ by 18.17 % relative RMS at
rescale_scale = 0.7, and agree to 5.7e-6 atrescale_scale = 0.0— the latter being the control that localises the divergence entirely to the rescale branch.This is algebra on synthetic inputs. It is not a measurement against upstream on real weights:
dgx.casais currently down, and no LTX-2.5 checkpoint was loaded. The direction of the finding is proven by source; the magnitude on a real render is unmeasured and this issue does not claim it.Nothing can currently see it
Every T2A assertion in the suite is self-consistency — arms differ, forward counts move — and there is no oracle-derived numeric golden for the guided step. A token or shape gate cannot see a guidance-space error, in the same way a token gate cannot see a dtype that is too wide.
What a fix owes
denoisers.py:188-203, or equivalently move the rescale into x0 space so the factor is computed and applied onlatent - sigma*v.rescale_scaleat its 0.7 default so the assertion sits on the shipped path. Therescale_scale = 0.0agreement is the natural control.params.video_guider), so check whether the video arm has the same shape before fixing only the audio one.Blocks #1032 in my view, because a default-path divergence from the reference is exactly what "Mirror vLLM" — here Lightricks, per
.agents/oracles/— exists to prevent. Related: #1005, #1013, campaign #644.FOLLOWING_AGENTS_PROTOCOL
Following-Agents-Protocol: true
AI-Assisted: true
Assisted-by: AGENT:claude-opus-5 [claude-code]