fix: restore the GuideEntry dataclass, repairing the i2v guide stack

7106db0 added scene_anchor_media_refs by writing it over the "@dataclass /
class GuideEntry:" header lines. The class body survived as unreachable code
after that function's return, so GuideEntry was referenced in three places but
never defined.

Effect: every code path that switches the per-scene i2v guide stack on raised
NameError -- build_scene_guides_payload and continuity_media_refs both died as
soon as guide_settings.stack_enabled was true. It went unnoticed for seven
weeks because the stack defaults off and no test covered it.

Fix moves the stranded body back out of scene_anchor_media_refs and restores
the two lost header lines. The body is byte-identical to b9f6e74; only its
position and header changed. scene_anchor_media_refs is untouched.

Adds two regression tests, both verified to fail against the unfixed file.
Tests: 22 failed / 462 passed (baseline 22/460 -- +2 passing, 0 new failures).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
digital-garbage
2026-08-01 18:31:50 +03:00
co-authored by Claude Opus 5
parent 8d4ed22853
commit eddeccaf68
2 changed files with 46 additions and 14 deletions
+18 -14
View File
@@ -234,20 +234,8 @@ def continuity_media_refs(full: Project, target: Project) -> list[str]:
return list(dict.fromkeys(refs))
def scene_anchor_media_refs(target: Project) -> list[str]:
"""Media-bin ids required as i2v anchors on generative scenes."""
refs: list[str] = []
for sc in target.scenes:
if sc.excluded or is_video_clip(sc):
continue
src = sc.source
if not src:
continue
stype = source_type(sc)
ref = src.media_ref
if ref and stype in ("image", "generated_frame", "mixed", "anchor_guide"):
refs.append(ref)
return list(dict.fromkeys(refs))
@dataclass
class GuideEntry:
"""Optional per-scene guide (only used when project guide_settings.stack_enabled)."""
enabled: bool = True
source: str = "template" # "template" | "scene" | "image"
@@ -274,6 +262,22 @@ def scene_anchor_media_refs(target: Project) -> list[str]:
return asdict(self)
def scene_anchor_media_refs(target: Project) -> list[str]:
"""Media-bin ids required as i2v anchors on generative scenes."""
refs: list[str] = []
for sc in target.scenes:
if sc.excluded or is_video_clip(sc):
continue
src = sc.source
if not src:
continue
stype = source_type(sc)
ref = src.media_ref
if ref and stype in ("image", "generated_frame", "mixed", "anchor_guide"):
refs.append(ref)
return list(dict.fromkeys(refs))
def is_mixed_source(scene: Scene) -> bool:
return (scene.source.type or "carry") == "mixed"
+28
View File
@@ -239,6 +239,34 @@ def test_guide_settings_default_off():
assert gs["accumulate_prior"] is False
def test_guide_entry_is_importable_and_round_trips():
"""GuideEntry's class header was once overwritten by a neighbouring function,
leaving its body stranded as dead code after a `return`. Nothing caught it because
the guide stack defaults off, so no other test reaches the code that uses it."""
from movie_editor.backend.timeline import GuideEntry
g = GuideEntry.from_dict({"enabled": True, "source": "image", "media_ref": "img1"})
assert g.enabled is True and g.source == "image" and g.media_ref == "img1"
assert g.to_dict()["strength"] == 0.35
def test_guide_stack_enabled_paths_do_not_raise():
"""Both consumers of GuideEntry only run when the stack is switched on — the exact
configuration that used to raise NameError."""
p = _project(
guide_settings={"stack_enabled": True},
scenes=[
{"id": "s1", "text": "a", "source": {"type": "image", "media_ref": "img1"}},
{"id": "s2", "text": "b", "source": {"type": "mixed", "media_ref": "img2"},
"guides": [{"enabled": True, "source": "image", "media_ref": "img3"}]},
],
)
payload = build_scene_guides_payload(p)
assert payload["stack_enabled"] is True
assert payload["scenes"][1][0]["media_ref"] == "img3"
assert "img3" in continuity_media_refs(p, p)
def test_continuity_defaults_auto_on():
cs = normalize_continuity_settings({})
assert cs["auto_enabled"] is True