feat(ar-024): enforce the invariant statically, and delete the fallback it caught
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
This commit is contained in:
@@ -243,9 +243,25 @@ def build_minimal(annotations, movie, fps, cfg) -> dict:
|
||||
"anneal_sec": anneal, "actors": actors}
|
||||
|
||||
|
||||
CFG_KEYS = ["detector_conf", "prob_threshold", "match_prior", "match_threshold", "match_ratio",
|
||||
"match_ratio_ceil", "track_alpha", "track_min_iou", "track_max_embed_dist",
|
||||
"track_max_frames_missing", "cut_revive_sim", "cut_inactive_max_frames",
|
||||
# TRACES: AR-024 | SR-002
|
||||
# Keys the C++ Config actually still has. Seven names were removed here, all of
|
||||
# them accepted silently for months after the fields behind them were deleted:
|
||||
#
|
||||
# match_threshold, match_ratio, match_ratio_ceil — the raw-cosine accept
|
||||
# fallback, retired with AR-024's enforcement.
|
||||
# track_max_embed_dist, cut_revive_sim — raw cosines, retired
|
||||
# earlier by AR-024 when association moved into probability space.
|
||||
# track_max_frames_missing, cut_inactive_max_frames — frame counts whose
|
||||
# meaning changed with sample_fps, retired by AR-008/AR-013 in favour of
|
||||
# track_extinction_sec.
|
||||
#
|
||||
# A sweep that varied one of these was measuring nothing, and reported a
|
||||
# perfectly ordinary-looking F1 for its trouble. kpn_bindings.cpp reads config
|
||||
# keys with a contains() check, so an unknown key is not an error — which makes
|
||||
# a stale entry here silently inert rather than loudly wrong.
|
||||
CFG_KEYS = ["detector_conf", "prob_threshold", "match_prior",
|
||||
"track_alpha", "track_min_iou", "track_assoc_min_prob",
|
||||
"track_extinction_sec",
|
||||
"extinction_sec", "anneal_sec"]
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user