- 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>
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>
For segmented beats, the repair stage now searches for the source action
window using the segment's own description first; the full beat context is
used only as a fallback or when it scores noticeably higher. The trailer-
offset shift is applied only when the beat context is actually chosen.
Also harden vision-call retries to catch read-side network errors
(TimeoutError, socket.timeout, ConnectionError, OSError) and wrap the
filter/repair loop so a transient vision failure preserves the previously
cached match instead of dropping it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>