generate_cutter_report.py:
- Frame-Locked Compare video (trailer left / source right, single MP4) per
beat replaces two separate side-by-side clips; rendered via accurate
double-seek + black-fill segmented source reconstruction
- Generation timestamp now includes HH:MM:SS (Uhrzeit-Angabe)
- Per-beat segment list for multi-shot beats (TC, duration, offset, scene,
score per segment)
- Score warning badge (yellow) if score < 0.65
- python cli.py rematch --beat N command hint in every card
- Overview table links to each beat card via #anchor
- Cleaner dark/light CSS using design tokens (--fg/--bg/--card/--bd)
- --no-clips flag (replaces --with-clips; default is now with clips)
cli.py:
- _auto_commit_push_reports(): after every report regeneration, stages the
report output files (CUTTER_REPORT.*, output/cutter_clips/, output/report/)
and auto-commits + pushes to origin/main so remote is always current
- Removed the legacy match_report.html call from _regenerate_cutter_report
(CUTTER_REPORT now supersedes it)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Actor-focused multi-frame temporal scan showed the correct action phase
(left woman back to camera, right woman in profile) at t=2618.8s vs
the previously used 2615.5s where both women were in different positions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Template scan of entire source found the knife/letter-opener close-up at
t=130-133s in the film (scene 17, 127.76-133.04s). Previous wrong match was
pointing at scene 309 (the coffee/window scene) for both shots because the
strong continuity seed from beat 14 overwhelmed the global search.
Two-segment provisional match written to cache manually:
seg[0] knife: scene 17 in=130.32s dur=2.80s score=0.72 (confirmed)
seg[1] coffee: scene 309 in=2615.52s dur=1.28s score=0.38 (provisional)
Regenerated CUTTER_REPORT and match_report with correct beat 15 clips/stills.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- config.toml: revert scoreable_luma/contrast thresholds to 24/58/24 (lowering
them let cross-fade blend frames contaminate content-validation templates,
dropping scores below provisional_content_threshold)
- src/cv/global_scan.py: _is_dark_reference_frame now requires contrast<30 so
genuine dark silhouette frames are not rejected as scoreable; two-path
_is_scoreable_reference_frame separates standard vs fade-content scoring
- cli.py: _keeps_cached_match() guard prevents a weaker single-span rematch
from overwriting a better multi-segment provisional cache entry
- cli.py: _fade_content_shots() restricted to between-island gaps only—
pre-island black leaders were incorrectly emitted as matchable shots
- cli.py: island[0] of _match_unmatched_visual_segments() now uses no
continuity seed so an insert cut at the start of a multi-shot beat is not
forced toward the previous beat's scene
- scripts/generate_cutter_report.py: fix ffmpeg concat demuxer on Windows—
use part.absolute().as_posix() so paths in the concat txt are absolute and
not double-resolved relative to the concat file's directory
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Beat 15 (4.40 s, two women + coffee mugs + snowy window) was matched as a
single 4-second clip at scene 309 in=2626.93 s, score 0.531. The trailer
beat actually contains two shots split by an internal cut at offset 3.12 s,
and the previous match approximated both with the same continuous span,
landing at the wrong phase for the second sub-shot.
After `match --beat 15 --vision` with the per-shot pipeline:
Shot 1 (offset 0.32, dur 2.80 s): scene 309 in=2626.929 score 0.531
Shot 2 (offset 3.12, dur 1.20 s): scene 309 in=2607.254 score 0.608
Same scene, but the second shot is now placed earlier in the source where
the leopard-print woman enters the frame — the right phase for that sub-
shot. Other beats unchanged (0 diffs verified against bak).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1. Action-group classifier conflated object-touches and person-touches.
"man touches the red door with a small object" was being tagged as
forehead_touch because "touch" was in the forehead_touch needles set.
That made the realign pass yank Beat 16 from scene 451 (correct: man
painting red door, IV stand) over to scene 623 (woman/man in bed) —
a totally wrong shot at score 0.344.
Fix: removed generic "touch*" verbs from forehead_touch's needle set.
forehead_touch is now added in _semantic_action_groups() only when a
touch verb is paired with an explicit body-part target (forehead,
face, cheek, head, hand, ...) and not paired with an object target
(door, handle, brush, tool, lock, ...).
Effect on Beat 16 after `match --beat 16 --vision`:
scene 623 in=5476.28 score=0.344 -> scene 451 in=3912.48 score=0.626.
2. Cutter-report stills/clips were keyed by source-video mtime, so a
match-position change without a video change served stale frames from
the previous match. Dropped the mtime cache; both extractors now
render fresh every time. Slower (~minute per full regen) but correct.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The legacy HTML report under output/report/ (match_report.html plus per-beat
ref/src/compare MP4s) is now part of the repository so the remote always
shows the latest preview state. Added gitignore exception. Total ~26 MB on
disk; comparable to the cutter_clips assets we already track.
Auto-regenerated on every match command via _regenerate_cutter_report, so
this stays in sync without manual intervention.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1. Cutter-report source clip for multi-segment beats was using only the
primary in/out, which equals the FIRST segment's range. Beat 10 with
3 shots therefore showed only ~0.88 s of source instead of all 3.32 s.
Added extract_concat_clip(): renders each segment as its own MP4 and
concatenates them via ffmpeg's concat demuxer into one continuous
source clip the same length as the trailer beat.
Per-segment intermediate clips (beat_NN_source_seg00.mp4 etc.) are
kept too so individual shots stay inspectable.
2. _regenerate_cutter_report now also regenerates the legacy
output/report/match_report.html via src.pipeline.reporter.generate_report.
Both reports stay in sync after every match command.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>