v1 has no libfftw3. SAE_SCENE_XGB is on by default and pulls the learned
scene-boundary detector into result_sink, whose find_library(FFTW3_LIB
fftw3 REQUIRED) at CMakeLists.txt:377 runs at CONFIGURE time -- so cmake
fails before any target is chosen, and building only `sae_tests` does not
get you past it. The image predates the detector; nothing rebuilt it when
the detector landed, which is precisely the gap DP-007's own register row
records.
-DSAE_SCENE_XGB=OFF would also have made the configure pass. It is the
wrong fix and worth saying why: CI is the only place these tests run, so
a flag that silences a subsystem there silences it everywhere, and the
job would have gone green over a detector nobody was compiling.
The image's self-check gains a line, because an image that ships a
library CMake cannot find the way CMake looks for it is the failure this
block exists to catch. FFTW is checked as a bare .so rather than through
pkg-config, since find_library is what CMakeLists.txt actually calls --
checking fftw3.pc would pass on an image whose libfftw3.so was absent.
Tag bumped v1 -> v2 here, in build_builder_image.sh and in the workflow's
run-time assert, in one commit, as this image's contract requires. v2 is
built and published. Rehearsed in the image before pinning it: configure,
build and 151 tests now run.
TRACES: DP-007 | PR-004
Eleven rows corrected, in both directions.
Overstated: AR-011 (the derived dedup window reached scenes.json only),
AR-017 (route was a literal), AR-019 (the local plurality tally was
still deciding), AR-024 (its "static check" enforcement did not exist),
DP-001 (scene_preview had forked and stopped compiling), VR-002 (the
Python replay bindings have not compiled since the tracker redesign, and
the fixtures it calls committed are gitignored registry artifacts).
Understated: VR-010 was marked Planned while five VR-010 tags sat in the
code implementing it.
Rescoped: VR-007 now names the four AR-025 constants it was already
being deferred to for, and which no sweep could reach until this pass.
The Withdrawn note gets the longest correction, because it asserted a
removal that had not happened and nothing could have caught that: the
gate reads tags, and a withdrawn requirement has no tag to be orphaned.
The general form is now written down there -- a status column is a
claim, and the only claims this project checks automatically are the
ones a test or a static check makes. Four of the rows above are the same
pattern: recorded as done, and done in one place out of two.
New: VR-016, a cadence study for cut_threshold. It is the one always-on
signal with no recorded provenance, and its input rate depends on an
unrelated flag -- with --scene-detect off, camera_pos compares frames a
full second apart at the default sample_fps, and with it on, native-rate
frames. Same constant, two meanings, and is_cut drives track_alpha to 0
and clears every expansion buffer.
Also stops check_raw_cosine.py inflating its own metric: the extractor
scans scripts/, so the tool's prose describing the exception tag was
counted as four recorded exceptions. The count now reads 1, which is the
number of real ones.
TRACES: AR-011, AR-017, AR-019, AR-024, AR-025 | DP-001, DP-007 | IR-004 | VR-002, VR-007, VR-010, VR-016
AR-024's register row gives its verification tier as "Static check -- no
bare cosine outside a tagged EXCEPTION". No such check existed, so the
invariant was enforced by reading, and reading had missed a live
violation.
scripts/ci/check_raw_cosine.py is that check, wired into the
traceability workflow as a blocking step. It is honest about its reach:
it catches direct cosine_similarity() uses not routed through a
calibration, and it cannot follow a cosine through a variable across
statements. That limit is documented in the script rather than left for
someone to discover after trusting a pass.
What it caught, and what this commit removes with it:
The identity matcher's no-calibration fallback thresholded raw cosine
distance (match_threshold) plus a ratio test (match_ratio,
match_ratio_ceil). Worse than the invariant breach: it fed
max(0, cosine) into TrackRegistry::observe, whose contract reads
"posterior is a calibrated probability, never a raw cosine (AR-024) ...
so the accumulation cannot be fed an uncalibrated number by a careless
caller". It could, and did. And it disagreed with the rest of the
pipeline about what "the fit failed" means -- same_person_probability
answers that with the untuned default sigmoid and a loud warning, so
association stayed in probability space while matching alone left it.
One run, two policies, no announcement.
Now one rule: cal_.probability() always, with a warning when the fit is
not real. A worse answer than a fitted calibration, a better one than a
number whose units nothing else shares.
TrackGallery::set_calibration is mandatory for the same reason. Its
default was max(0, cosine), which made expand_band_lo = 0.90 mean
"cosine > 0.9" in a test and "P(same person) > 0.9" in production.
FaceTrackerFunc already threw without one; the expansion store now
matches.
One exception is recorded, in the calibration's own dedup. It is not a
close call: at 1 - 1e-7 it asks whether two vectors are the same vector,
and it runs on the fit's input, so a calibrated comparison there would
have to be calibrated by the fit it is feeding.
Also drops seven dead keys from the optimizer's CFG_KEYS. Config keys
are read with a contains() check, so each one had been silently inert
since the field behind it was deleted -- a sweep varying one of them
measured nothing and reported an ordinary-looking F1.
TRACES: AR-024, AR-023 | SR-002