From 364182cc39cde1ef7c8fd7857b68f56387708e47 Mon Sep 17 00:00:00 2001 From: 0xDevNinja Date: Thu, 2 Jul 2026 16:52:00 +0530 Subject: [PATCH] fix(variation_checker): measure longest run for consecutive same-size shots Check 2 flagged 'N consecutive same-size shots' from a count of every equal adjacent pair across the whole plan, not the length of any real run. So three separate 2-shot groups (wide,wide,cu,cu,med,med) tripped a false '3 consecutive' violation, while a genuine run of 3 (only 2 pairs) was never flagged. Track the current run length, reset on change, and compare the longest run >= 3. Adds regression tests: non-consecutive pairs pass, a true run of 3 is flagged, unspecified shots don't form a run. Closes #268 --- lib/variation_checker.py | 15 +++++++--- tests/lib/test_variation_checker_runs.py | 37 ++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 tests/lib/test_variation_checker_runs.py diff --git a/lib/variation_checker.py b/lib/variation_checker.py index 2604a941..47829f10 100644 --- a/lib/variation_checker.py +++ b/lib/variation_checker.py @@ -56,13 +56,20 @@ def check_scene_variation(scenes: list[dict[str, Any]]) -> dict[str, Any]: suggestions.append("Mix wide establishing shots with close-ups for visual rhythm.") # --- Check 2: Consecutive same-size shots --- - consecutive_same = 0 + # Track the longest actual run of identical shot sizes. Summing every equal + # adjacent pair across the whole plan would count non-consecutive groups + # (e.g. wide,wide,cu,cu,med,med -> 3 pairs) as a single "3 consecutive" run. + longest_run = 1 if shot_sizes else 0 + current_run = 1 for i in range(1, len(shot_sizes)): if shot_sizes[i] == shot_sizes[i-1] and shot_sizes[i] != "unspecified": - consecutive_same += 1 - if consecutive_same >= 3: + current_run += 1 + longest_run = max(longest_run, current_run) + else: + current_run = 1 + if longest_run >= 3: violations.append( - f"{consecutive_same} consecutive same-size shots. " + f"{longest_run} consecutive same-size shots. " f"Vary shot sizes between scenes for editorial rhythm." ) diff --git a/tests/lib/test_variation_checker_runs.py b/tests/lib/test_variation_checker_runs.py new file mode 100644 index 00000000..fcec201f --- /dev/null +++ b/tests/lib/test_variation_checker_runs.py @@ -0,0 +1,37 @@ +"""Regression test for check_scene_variation consecutive-run counting. + +The "consecutive same-size shots" check summed every equal adjacent pair across +the whole plan instead of measuring the longest actual run, so an editorially +varied plan of separate 2-shot groups (wide,wide,cu,cu,med,med) falsely tripped +a "3 consecutive same-size shots" violation. +""" + +import sys +from pathlib import Path + +PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent +sys.path.insert(0, str(PROJECT_ROOT)) + +from lib.variation_checker import check_scene_variation # noqa: E402 + + +def _scenes(sizes): + return [{"shot_language": {"shot_size": s}} for s in sizes] + + +def test_non_consecutive_same_size_pairs_do_not_trip_run_check(): + # Three separate 2-shot groups — longest run is 2, not 3. + res = check_scene_variation(_scenes(["wide", "wide", "cu", "cu", "medium", "medium"])) + assert not any("consecutive same-size" in v for v in res["violations"]) + + +def test_true_run_of_three_is_flagged(): + res = check_scene_variation(_scenes(["wide", "wide", "wide", "cu", "medium"])) + assert any("3 consecutive same-size" in v for v in res["violations"]) + + +def test_unspecified_shots_do_not_form_a_run(): + res = check_scene_variation( + _scenes(["unspecified", "unspecified", "unspecified", "unspecified"]) + ) + assert not any("consecutive same-size" in v for v in res["violations"])