Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion app/services/director_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -2192,8 +2192,10 @@ def _backfill_clip_video_attempts(state: dict, state_dir: str) -> dict:
selected = ""
clip["selected_video_filename"] = selected or None
if selected:
# A Studio selection is the playback authority, but it does not
# refresh inputs. Image reruns keep video_stale so Rejoin/export
# cannot assemble a take that no longer matches the start frame.
clip["video_filename"] = selected
clip["video_stale"] = False
clip["video_attempts"] = sorted(
attempts_by_clip[index].values(),
key=lambda item: (float(item.get("created_at") or 0), item["filename"]),
Expand Down
40 changes: 40 additions & 0 deletions tests/test_director_cancellation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1153,6 +1153,46 @@ def test_rejoin_rejects_stale_video_instead_of_omitting_clip(self):

concatenate.assert_not_called()

def test_rejoin_rejects_stale_video_even_when_a_take_is_selected(self):
pid = "pipe-stale-selected-rejoin"
record = self._add_pipeline(pid, "completed")
record["clip_plans"] = [
{"image_prompt": "one", "video_prompt": "one"},
{"image_prompt": "two", "video_prompt": "two"},
]
record["_clip_video_files"] = ["one.mp4", "two.mp4"]
for filename in record["_clip_video_files"]:
self._write_media(filename, b"video")
self.assertTrue(pipeline._save_pipeline_state(pid))

def mark_selected_stale(state):
clip = state["clips"][0]
clip["selected_video_filename"] = clip["video_filename"]
clip["video_stale"] = True

pipeline._update_saved_pipeline(self.temp_dir.name, pid, mark_selected_stale)
loaded = pipeline.load_pipeline_state(self.temp_dir.name, pid)
self.assertTrue(loaded["clips"][0]["video_stale"])
self.assertEqual(loaded["clips"][0]["selected_video_filename"], "one.mp4")

def keep_notes(state):
state["clips"][0]["review_notes"] = "keep stale"

pipeline._update_saved_pipeline(self.temp_dir.name, pid, keep_notes)
raw_path = pipeline._find_pipeline_file(self.temp_dir.name, pid)
with open(raw_path, encoding="utf-8") as handle:
saved = json.load(handle)
self.assertTrue(saved["clips"][0]["video_stale"])
self.assertEqual(saved["clips"][0]["review_notes"], "keep stale")

concatenate = Mock(return_value=True)
pipeline._wgp.concatenate_multi_clip_videos = concatenate
with self.assertRaisesRegex(
ValueError, "stale video clip.*1.*before rejoining",
):
pipeline.rejoin_clips(self.temp_dir.name, pid)
concatenate.assert_not_called()

def test_rejoin_rejects_clip_whose_start_image_is_missing(self):
pid = "pipe-missing-rejoin-start"
record = self._add_pipeline(pid, "completed")
Expand Down
22 changes: 22 additions & 0 deletions tests/test_director_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,25 @@ def test_switching_an_approved_take_updates_h3_selection_without_approving_it(tm
assert saved['clips'][0]['h3_segments'][0]['filename'] == 'old.mp4'
assert saved['clips'][0]['h3_segments'][0]['stale'] is False
assert 'old.mp4' in saved['output_files']


def test_review_notes_keep_a_stale_selected_take_stale(tmp_path):
path, state = fixture(tmp_path)
state['clips'][0].update(
selected_video_filename='old.mp4',
video_filename='old.mp4',
video_stale=True,
tag='good',
)
path.write_text(json.dumps(state))
loaded = pipeline.load_pipeline_state(str(tmp_path), 'review-test')
assert loaded['clips'][0]['video_stale'] is True
assert loaded['clips'][0]['selected_video_filename'] == 'old.mp4'
save_review(str(tmp_path), 'review-test', [
{'type': 'note_clip', 'pipelineId': 'review-test', 'clipIndex': 0, 'notes': 'keep stale'},
])
saved = json.loads(path.read_text())
assert saved['clips'][0]['video_stale'] is True
assert saved['clips'][0]['selected_video_filename'] == 'old.mp4'
assert saved['clips'][0]['review_notes'] == 'keep stale'
assert saved['clips'][0]['tag'] == 'good'
Loading