The boundary-detection paragraph understated the detector. Replace the stale
"~34% F1 vs ~27%" (a pre-C++-retrain figure with no backing artifact) with the
measured numbers at the shipped ±20s tolerance:
- leave-one-out macro boundary F1 = 44.1% (honest generalisation)
- grayscale baseline = 29.8%
- train-all (shipped model) = 72.9% (per-film 51-86%)
computed from experiments/results/scene_boundary/xgb_report.json and per-film
leave-one-out runs of train_xgb_cpp.py. Also correct the false claim that the
low-contrast grades "cannot generalise held out" — Scarface held out scores 32%,
Café Society 51%, both above grayscale (0% and 31%).
Split the evolution figure into two panels so the strict-±2s feature-development
curve is no longer mistaken for the shipped result: left = feature progress at
±2s, right = shipped detector at the ±20s tolerance the pipeline uses.
dump_error_frames.py drew every identified box green, so a false positive looked
like a true positive and a missed cast member was invisible. Make the annotation
ground-truth aware, matching what the per-second scorer classifies:
- GREEN true positive — a name X-Ray also credits to this scene
- RED false positive — a name X-Ray does NOT credit here (the real error)
- ORANGE unknown detection
- BLUE a text panel listing X-Ray cast present with no detected face (the
structural false-negatives — no box exists to draw)
Add two representative annotated frames to the scene-detector page: a clean
green-TP second, and the face-vs-scene-cast case (a red FP lead + six off-camera
cast in blue) that makes the recall ceiling visual. Frames are generated by the
script from replay.py --raw-out output; the two committed examples are hand-picked
doc assets (bulk experiments/dump_review is regenerable and gitignored).
New docs/scene-boundary-detector.md: why the grayscale cut detector wasn't
enough (Scarface: 1 cut in 10k frames → flood-fill P=26%), what X-Ray boundaries
are and why they're hard, the feature/model design (delta histograms, multi-scale
ramp bank, scene-length debounce, soft-target XGBoost regressor, per-film knee),
and the measured dead ends (audio-only, raw features, LSTM, TransNetV2).
Headline result, honest leave-one-out (each film scored by a detector trained on
the other eight): flood + learned detector = 74.9% macro presence F1, vs 64.0%
for grayscale-cut flood and 62.6% for track-extent — +12.3pp, improving all nine
films. Fixes the Scarface flood collapse (grayscale 40.9 → learned 74.9, on a
film the detector never trained on) and swings Downton +37pp.
Figures are generated by scripts/scene_detector/make_figures.py from the saved
results (experiments/results/scene_boundary/downstream_loo.json); the PNGs
themselves follow the repo convention of not committing regenerable chart assets.
Added to the mkdocs nav.