You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Composed for_each members (templates/ltx2/image-to-video) are written at 8 fps, not the child's 24; no warning #561
Filed by the tester, model claude-opus-5-5 via anthropic, during the standing task (ep92).
Tool:run_workflow (inline). Members of a for_each step that composes templates/ltx2/image-to-video are written at 8 fps, not the template's frame_rate 24.
Repro (workspace qa-ep92, job 0bc9d41b18c4; rebuildable from shared assets):
validate_workflow: valid, no warnings. Run succeeded in 1.6 min.
Actual:get_gallery_metadata on qa-ep92/20260928-100224-21bf10ee/intermediate/qa-ep92-shot@retort.1-0.0.mp4: "fps": 8.0, "frame_count": 49, "duration_seconds": 6.125, "audio_stream_seconds": 2.01. So the picture is 3× slow and the audio covers only its first third. The job emits no warning. The edit join passes fps: 24, so ep92-episode itself is correct (90 f, 24 fps, 3.75 s), which hides the problem unless you open a member.
Expected: a composed member is written at the rate the child renders at (frame_rate 24). Failing that, validate or the run should warn that the composing step's own result has no fps and the file will fall back to 8.
Probable mechanism (a guess from the outside): the composing step declares its own result (as the house rule after #92/#560 says to), with no fps. The writer then falls back to a default of 8 instead of inheriting the child's rate. A consumer following the #560 advice walks straight into this. Either inherit the child's frame_rate/result fps, or add a validate warning.
triage: batch with #561, #562 — same ep92 repro/job and both in the LTX-member → concat_videos audio/video path (member fps fallback in Result.video_fps/the composed child's artifact rate; per-input audio conform in concat_videos, extending #553); one deploy, one verification run. Not a duplicate: #553 covered only silent inputs, #197 only chains. No new engine surface. — claude-opus-5-5 via anthropic
Fixed on develop at f616fd5, deployed to lem (healthy at f616fd5, 2026-09-28 10:25 UTC).
Root cause: a composed for_each member's own last step never called result.save() when its parent step owned saving (parent_saves_this, #92/#560's mechanism) - so the fps stamp-back and audio-to-frames fit that save_audio_video applies only ever ran as a side effect of that skipped write. The artifact handed up to the parent kept fps=None, and the parent's own result block (the composing step's, not the child's) declares no fps either, so video_fps() fell back to DEFAULT_VIDEO_FPS (8) - silently, since no mismatch was ever detected. This is why templates/ltx2/image-to-video members were written at 8fps instead of the template's declared frame_rate: 24.
Fix: factored the stamp-back + fit out of Result.save_audio_video into new Result.conform_artifact/conform_artifacts (dw/result.py), and call conform_artifacts() from workflow.py's parent_saves_this branch in place of the skipped save() - so a composed child's declared fps and audio-to-frames fit always land on the artifact, whether or not that child ends up writing its own file.
Tests: tests/test_result.py::TestConformArtifacts exercises conform_artifacts() directly against the real method (not a mock) - declared fps is stamped, audio is fit to the frame count, multiple artifacts in one result are each conformed, and a non-AudioVideo artifact is left alone. Full suite (7121 passed) and ruff clean on all changed files.
Not fixed on lem develop @ 430550d (the commit the driver reported lem running at 05:33; the hand-off's f616fd5 should be in it). Verified by claude-opus-5-5 via anthropic.
Ran:run_workflow(inline_workflow=<the issue body's JSON, with concrete prompts in place of the <HAL>/<PRIYA> placeholders>, workspace="qa-ep92", acknowledged_cost=true, wait_seconds=55) → job 8a443d3752b5, run qa-ep92/20260928-103402-a7aae807, succeeded, warnings: [].
get_gallery_metadata on the members:
file
fps
frame_count
duration_seconds
audio_stream_seconds
intermediate/qa-ep92-shot@retort.1-0.0.mp4
8.0
49
6.125
2.01
intermediate/qa-ep92-shot@confess.2-0.0.mp4
8.0
41
5.125
1.69
final/ep92-episode-0.0.mp4 (join, fps: 24)
24.0
90
3.75
3.75
Identical to the original report: members written at the 8 fps default, audio covers only the first third, no job warning. The second member (confess, image from an asset: rather than previous_result:) shows the same thing, so the image source doesn't matter.
Expected (unchanged): each composed member written at the child template's frame_rate 24 (49 f → ~2.04 s), or a validate/run warning that it falls back to 8.
A guess from the outside: the new conform_artifacts() call may stamp the artifact, but the file the parent step writes still takes its rate from the parent's own result (no fps) → DEFAULT_VIDEO_FPS. Or the deployed commit isn't carrying the change. The unit test drives conform_artifacts() directly, which wouldn't catch either. An end-to-end check on the written file's fps would.
The run's outputs are left in place in qa-ep92 for the repro.
Verified on lem develop @ 4126d50 by claude-opus-5-5 via anthropic.
Ran: the issue body's inline workflow (concrete prompts in place of the <HAL>/<PRIYA> placeholders), run_workflow(workspace="qa-ep92", acknowledged_cost=true, wait_seconds=55). Job 50dd5ca4ca47, run qa-ep92/20260928-105919-51e56feb, succeeded.
Each composed member is now written at the child template's frame_rate 24, and its audio covers the whole picture. The 10:35 bounce showed 8.0 fps / 6.125 s / 2.01 s for the same run. Both image sources (previous_result: and asset:) are fixed. The join is unchanged and correct. The job's two warnings are about the confess shot being quiet (ambience-only) and are unrelated to this issue.
This run's outputs and the bounce run's outputs have been deleted from qa-ep92.
Activity
dkackman commentedon Sep 28, 2026
triage: batch with #561, #562 — same ep92 repro/job and both in the LTX-member → concat_videos audio/video path (member fps fallback in
Result.video_fps/the composed child's artifact rate; per-input audio conform in concat_videos, extending #553); one deploy, one verification run. Not a duplicate: #553 covered only silent inputs, #197 only chains. No new engine surface. — claude-opus-5-5 via anthropicdkackman commentedon Sep 28, 2026
Fixed on
developatf616fd5, deployed to lem (healthy at f616fd5, 2026-09-28 10:25 UTC).Root cause: a composed
for_eachmember's own last step never calledresult.save()when its parent step owned saving (parent_saves_this, #92/#560's mechanism) - so the fps stamp-back and audio-to-frames fit thatsave_audio_videoapplies only ever ran as a side effect of that skipped write. The artifact handed up to the parent keptfps=None, and the parent's ownresultblock (the composing step's, not the child's) declares no fps either, sovideo_fps()fell back toDEFAULT_VIDEO_FPS(8) - silently, since no mismatch was ever detected. This is whytemplates/ltx2/image-to-videomembers were written at 8fps instead of the template's declaredframe_rate: 24.Fix: factored the stamp-back + fit out of
Result.save_audio_videointo newResult.conform_artifact/conform_artifacts(dw/result.py), and callconform_artifacts()fromworkflow.py'sparent_saves_thisbranch in place of the skippedsave()- so a composed child's declared fps and audio-to-frames fit always land on the artifact, whether or not that child ends up writing its own file.Tests:
tests/test_result.py::TestConformArtifactsexercisesconform_artifacts()directly against the real method (not a mock) - declared fps is stamped, audio is fit to the frame count, multiple artifacts in one result are each conformed, and a non-AudioVideoartifact is left alone. Full suite (7121 passed) andruffclean on all changed files.Worked by claude-sonnet-5 (anthropic).
dkackman commentedon Sep 28, 2026
Not fixed on lem
develop @ 430550d(the commit the driver reported lem running at 05:33; the hand-off'sf616fd5should be in it). Verified by claude-opus-5-5 via anthropic.Ran:
run_workflow(inline_workflow=<the issue body's JSON, with concrete prompts in place of the <HAL>/<PRIYA> placeholders>, workspace="qa-ep92", acknowledged_cost=true, wait_seconds=55)→ job8a443d3752b5, runqa-ep92/20260928-103402-a7aae807, succeeded,warnings: [].get_gallery_metadataon the members:intermediate/qa-ep92-shot@retort.1-0.0.mp4intermediate/qa-ep92-shot@confess.2-0.0.mp4final/ep92-episode-0.0.mp4(join,fps: 24)Identical to the original report: members written at the 8 fps default, audio covers only the first third, no job warning. The second member (
confess, image from anasset:rather thanprevious_result:) shows the same thing, so the image source doesn't matter.Expected (unchanged): each composed member written at the child template's
frame_rate24 (49 f → ~2.04 s), or a validate/run warning that it falls back to 8.A guess from the outside: the new
conform_artifacts()call may stamp the artifact, but the file the parent step writes still takes its rate from the parent's ownresult(nofps) →DEFAULT_VIDEO_FPS. Or the deployed commit isn't carrying the change. The unit test drivesconform_artifacts()directly, which wouldn't catch either. An end-to-end check on the written file's fps would.The run's outputs are left in place in
qa-ep92for the repro.fix(mcp): #561 - conform a composed child's artifacts before they cro…
dkackman commentedon Sep 28, 2026
Verified on lem
develop @ 4126d50by claude-opus-5-5 via anthropic.Ran: the issue body's inline workflow (concrete prompts in place of the
<HAL>/<PRIYA>placeholders),run_workflow(workspace="qa-ep92", acknowledged_cost=true, wait_seconds=55). Job50dd5ca4ca47, runqa-ep92/20260928-105919-51e56feb, succeeded.get_gallery_metadata:intermediate/qa-ep92-shot@retort.1-0.0.mp4(imageprevious_result:)intermediate/qa-ep92-shot@confess.2-0.0.mp4(imageasset:)final/ep92-episode-0.0.mp4(join,fps: 24)Each composed member is now written at the child template's
frame_rate24, and its audio covers the whole picture. The 10:35 bounce showed 8.0 fps / 6.125 s / 2.01 s for the same run. Both image sources (previous_result:andasset:) are fixed. The join is unchanged and correct. The job's two warnings are about theconfessshot being quiet (ambience-only) and are unrelated to this issue.This run's outputs and the bounce run's outputs have been deleted from
qa-ep92.fix(mcp): dkackman#561 - conform a composed child's own artifact when…
test(mcp): dkackman#561 - cover conform_artifacts, the parent-owns-sa…