docs(register): make the status column describe the code

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
This commit is contained in:
2026-08-05 17:51:01 +02:00
parent 06373817a2
commit 90b44e0975
4 changed files with 284 additions and 207 deletions
+40 -17
View File
@@ -38,21 +38,21 @@ Status: `Done` · `In Progress` · `Planned` · `TBD` · `Withdrawn`
| AR-008 | One track pool keyed on `last_seen`; no separate revival path | SR-002 | High | **Done** — one pool keyed on `last_seen`; park/revive branch deleted |
| AR-009 | Camera-cut detection (histogram) as an association hint | SR-002 | High | Done |
| AR-010 | Scene-boundary detection (TransNetV2) as an association hint | SR-002 | Medium | **Done** — decode butterfly joined via `SceneBoundaries`; the sampled branch waits for the detector's watermark. Frames past its last scored window are counted as unverified, never assumed boundary-free |
| AR-011 | **Every model is fed the input it was trained for** — cost reduced by running less often, never by degrading one inference | SR-002 | High | **Done** — both violations SPEC.md named are closed. (1) `scene_decode_fps` defaults to 0 (native): at 12 fps a 100-frame `kWindow` spanned ~8.3 s instead of the ~4 s TransNetV2 was trained on, half-speed motion over twice its temporal context. (2) The boundary dedup window is derived from the cadence the detector was actually fed (`SceneDetectorFunc::dedup_window_sec()`, median observed interval, halved) rather than the literal 0.04 s — one frame at 25 fps, and at 30 fps wider than a frame, so two cuts on consecutive frames merged into one and the loss was invisible: the file simply had fewer boundaries. Derivation checked at 24/25/30 fps and under a seek (UT-003). **Consequence, not a gap:** `scene_threshold` 0.60 was fitted against the 12 fps input and is now certainly wrong — VR-006 re-fits it, and until then boundary recall at native rate is untuned rather than better. Dense decode is the cost driver, so this is not free; `dense_scale` and `scene_stride` remain the reductions that do not run the model off-distribution |
| AR-011 | **Every model is fed the input it was trained for** — cost reduced by running less often, never by degrading one inference | SR-002 | High | **Done** — both violations SPEC.md named are closed. (1) `scene_decode_fps` defaults to 0 (native): at 12 fps a 100-frame `kWindow` spanned ~8.3 s instead of the ~4 s TransNetV2 was trained on, half-speed motion over twice its temporal context. (2) The boundary dedup window is derived from the cadence the detector was actually fed (`SceneDetectorFunc::dedup_window_sec()`, median observed interval, halved) rather than the literal 0.04 s — one frame at 25 fps, and at 30 fps wider than a frame, so two cuts on consecutive frames merged into one and the loss was invisible: the file simply had fewer boundaries. Derivation checked at 24/25/30 fps and under a seek (UT-003). **Consequence, not a gap:** `scene_threshold` 0.60 was fitted against the 12 fps input and is now certainly wrong — VR-006 re-fits it, and until then boundary recall at native rate is untuned rather than better. Dense decode is the cost driver, so this is not free; `dense_scale` and `scene_stride` remain the reductions that do not run the model off-distribution. **Half-applied until now:** the derived window reached `scenes.json` and nothing else. `SceneBoundaries` — the path that actually feeds `is_scene_boundary` to the tracker — kept the literal 0.04 s under a comment claiming the two views agreed. They did not. The detector now supplies the window it derived to both |
| AR-012 | Presence follows **track extent**, not per-frame recognition | **SR-002** | High | **Done**`src/track_registry.hpp`; window is `[first_seen, last_seen]` of an owned track |
| AR-013 | `last_seen` optional state machine; window ends at last sighting, never after | SR-002 | High | **Done**`last_seen` optional is the whole state machine; interior gaps absorbed, trailing cool-down never claimed |
| AR-014 | Belief swap A→B terminates the track and starts a new one | SR-002 | Medium | **Done** — swap closes at `last_seen` and opens a successor at the swap frame; counted |
| AR-015 | Two live tracks owned by one actor ⇒ treat as a detected cut, re-associate | SR-002 | Medium | **Done** — reverse index detects it on the causing update; counted |
| AR-016 | All tracks closed at EOF — a film ends with faces on screen | SR-002 | High | **Done**`flush()`, idempotent, closes at last sighting or final tick |
| AR-017 | Every presence claim carries its belief and identification route | SR-002 | High | **Done**`DeadTrack` carries belief and observation count |
| AR-017 | Every presence claim carries its belief and identification route | SR-002 | High | **Done**`DeadTrack` carries belief, observation count, and now a `route` enum. The route was previously the literal string `"live"` written at serialisation time, so the published field could not distinguish anything and AR-017's own edge case ("deferred and pooled routes distinguishable") was unmeetable. Only `live` occurs until AR-020 lands; `deferred` exists so that pass has somewhere to write instead of a schema change to make |
| AR-018 | Per-subject embedding store with banded admission (novel enough, safe enough) | SR-005 | Medium | **Done** — banded admission in probability space, bounds from `expand_band_lo/hi`; the lower bound re-asked pairwise at promotion, since `admit` compares only against the nearest member and a drifting track can chain past it. Retires `expand_novelty_sim` and `expand_track_spread_max` — novelty is now the eviction ordering, not a threshold. Rejections counted. Bounds unswept (VR-007) |
| AR-019 | Per-film gallery annex from owned tracks; acquires the non-frontal views TMDB lacks | SR-005 | Medium | **Done** — all three discontinuity signals clear the buffers; ownership comes from the registry, not a second local tally |
| AR-019 | Per-film gallery annex from owned tracks; acquires the non-frontal views TMDB lacks | SR-005 | Medium | **Done** — all three discontinuity signals clear the buffers; ownership comes from the registry, not a second local tally. **Correction:** the local tally was still there and still deciding. Promotion fired on a local accepted-frame count and fell back to a local per-actor plurality whenever the registry had not yet claimed the track — which is the common case, since three accepted frames arrive well before a posterior crosses `ownership_logodds`. So in practice the plurality usually decided, and it could not see the AR-025 discounting it was supposed to defer to. Promotion now requires the registry's verdict; the accepted-frame count is an explicit evidence floor. `forget()`, which had no callers under a comment claiming the matcher called it, is replaced by `prune_dead` against the registry's own liveness |
| AR-020 | Deferred re-identification of unknown tracks against the final expanded gallery | SR-005 | High | Planned |
| AR-021 | Cluster unknown tracks into one entity per person, under temporal cannot-link constraints | SR-005 | Medium | Planned |
| AR-022 | Capture still-unidentified tracks: embeddings, metadata, **context crops** for human review | §4 | Medium | Planned |
| AR-023 | Fit sigmoid calibration from intra/inter similarity distributions | SR-002 | High | Done |
| AR-024 | **Always the calibrated probability, never a raw cosine** — exceptions recorded | SR-002 | High | **Done** — association, accumulation and expansion all in probability space; `track_max_embed_dist`, `cut_revive_sim`, `expand_novelty_sim`, `expand_track_spread_max` retired |
| AR-025 | Per-track Bayesian accumulation in log-odds, with correlated-observation discounting | SR-002 | High | **Done** — log-odds accumulation with correlation discounting owned by the registry, `src/evidence_discount.hpp` |
| AR-023 | Fit sigmoid calibration from intra/inter similarity distributions | SR-002 | High | **Done** — and the meaning of "the fit failed" is now uniform. `valid=false` used to send the matcher to a raw-cosine accept rule while `same_person_probability` sent every other stage to the untuned default sigmoid: one run, two policies, no announcement. Both now take the default sigmoid and warn loudly that the probabilities are not meaningful |
| AR-024 | **Always the calibrated probability, never a raw cosine** — exceptions recorded | SR-002 | High | **Done** — association, accumulation and expansion all in probability space; `track_max_embed_dist`, `cut_revive_sim`, `expand_novelty_sim`, `expand_track_spread_max` retired. Enforcement now exists rather than being asserted: `scripts/ci/check_raw_cosine.py` blocks in CI. It immediately caught a live violation — the matcher's no-calibration fallback thresholded raw cosine distance **and fed `max(0, cosine)` into `TrackRegistry::observe`**, whose contract says in terms that it cannot be handed an uncalibrated number by a careless caller. `match_threshold`, `match_ratio` and `match_ratio_ceil` are retired with it, and `TrackGallery`'s `max(0, cosine)` default calibration is now a hard error. One exception recorded, in the calibration's own dedup |
| AR-025 | Per-track Bayesian accumulation in log-odds, with correlated-observation discounting | SR-002 | High | **Done** — log-odds accumulation with correlation discounting owned by the registry, `src/evidence_discount.hpp`. The four constants governing this — `ownership_logodds`, `rho_max`, `admit_below`, `max_views` — were unreachable in-class defaults until now; see VR-007 |
| AR-026 | All similarity computed as GEMM, including annex and deferred pass | SR-001 | High | **In Progress** — two of the three call sites done. Baked gallery was already GEMM; the annex now is too — it is a contiguous row-major matrix (`track_gallery.hpp`) whose promoted rows are appended to the engine's resident matrix (`ISimilarityEngine::append_rows`), so one multiply covers baked and promoted references and the host-side cosine loop is gone. CPU path requires OpenBLAS (scalar fallback now opt-in behind `SAE_ALLOW_SCALAR_GEMM`). Remaining: the deferred pass, which does not exist until AR-020 |
| AR-027 | Throughput acceptable for **arbitrary** gallery size | SR-001 | High | Planned |
| AR-028 | **Embedding input quality assessed and carried** — every face scored on size, sharpness and visibility before its embedding is used as identity evidence; the vector travels with the face and reaches the VR-001 dump | SR-002 | High | **Done** — filled in by `FaceAlignerFunc`, where both measured axes come free from the warp; carried on `DetectedFace` and written to the dump as `faces/sharpness` + `faces/alignment_residual`, taking it to `schema_version` 2. Size is `bbox`, not duplicated into a field that would drift. No face is admitted unscored (-1 sentinel), and the degenerate-fit case is now counted and reported rather than silently dropped. **Carried, not consumed** — no discount and no threshold, which is AR-030 and VR-012. Verified UT-137, UT-138 (aligner) and UT-139…UT-141 (dump round-trip, version, sentinel). The committed fixtures are still v1, so they carry no vector until `make_fixtures.sh` is re-run on a GPU host |
@@ -63,13 +63,13 @@ Status: `Done` · `In Progress` · `Planned` · `TBD` · `Withdrawn`
| ID | Requirement | Traces to | Priority | Status |
|---|---|---|---|---|
| DP-001 | One analysis core; modes are front-ends and must not fork pipeline logic | PR-004 | High | Done |
| DP-001 | One analysis core; modes are front-ends and must not fork pipeline logic | PR-004 | High | **Done, after a repair.** `scene_preview` had forked the construction sequence and then rotted: it built `FaceTrackerFunc{cfg}` against a signature that stopped existing with the AR-007/AR-008 redesign, so **it had not compiled since**, and it never wired registry claims into its sink. It now mirrors `main.cpp` exactly — matcher, then registry, then tracker. The lesson is that "must not fork" needs the build to notice; a front-end nothing compiles is a fork that rots in silence |
| DP-002 | Batch CLI over one title | PR-004 | High | Done |
| DP-003 | On-demand resident service with bounded, observable queue | PR-004 | Medium | Planned |
| DP-004 | Opportunistic/idle mode: external trigger, hard stop, implicit re-queue | PR-004 | Medium | Planned |
| DP-005 | Native installer, no Docker; Fedora + Arch | PR-004 | Medium | Planned |
| DP-006 | Background incremental gallery refresh on a timer | PR-003 | Medium | Planned |
| DP-007 | CI builder image, CPU-only, pinned by tag in the Gitea container registry | PR-004 | High | Planned |
| DP-007 | CI builder image, CPU-only, pinned by tag in the Gitea container registry | PR-004 | High | **Mostly** — image and publish script exist (`Dockerfile.builder-cpu`, `scripts/ci/build_builder_image.sh`) and `.gitea/workflows/unit-tests.yml` now consumes it, pinned to `v1` and asserting at run time that the image reports that tag. **Gap:** the image is built and pushed by hand from an authenticated host; nothing rebuilds it on a change to the Dockerfile |
| DP-008 | Builder images + release jobs per backend (cpu / cuda / rocm); ship binaries, not engines | PR-004 | Medium | Planned |
## Integration (IR)
@@ -79,7 +79,7 @@ Status: `Done` · `In Progress` · `Planned` · `TBD` · `Withdrawn`
| IR-001 | Emit the JRay truth format as sibling `.jray.json` | SR-003 | High | Done |
| IR-002 | Windows carry belief + route; `extraction.*` carries `extinction_sec`, `gallery_scope` | SR-003 | High | **Done**`schema_version: 2`; windows are objects with `belief` + `route`; `extraction.*` carries `extinction_sec` and `gallery_scope`; `anneal_sec` removed |
| IR-003 | Output written **after** the deferred pass, not at EOF | SR-003 | High | **In Progress** — sink builds windows from registry claims and flushes at EOF; the deferred pass (AR-020) does not exist yet, so output is still final at EOF |
| IR-004 | Compute the audio signature exactly per server spec §3 | SR-003 | Medium | **Done**`src/audio_signature.*`; not yet emitted into the truth file (IR-002) |
| IR-004 | Compute the audio signature exactly per server spec §3 | SR-003 | Medium | **Done**`src/audio_signature.*`; not yet emitted into the truth file (IR-002). One real defect found and fixed since: the resampler's `AVChannelLayout`s were not zero-initialised, and `av_channel_layout_copy` uninitialises its destination first, so `av_freep` was handed stack garbage. It aborted about 1 run in 4 of UT-103 — invisible in the aggregate test binary, where the case usually passes, and absent under a sanitizer build because it is stack-dependent. `ctest`, one process per case, is what turned it into a reproducible failure |
| IR-005 | Golden-vector fixture shared with the plugin repo to prove bit-exactness | SR-003 | High | **Done**`tests/fixtures/audio/`; v1 parameters now normative in server spec §3 |
| IR-007 | Media < 120 s: emit no signature, apply no sync offset — identical rule in both producers | SR-003 | Low | **Done** |
| IR-008 | Emit and honour the signature's own `v1:` version prefix | SR-003 | Low | **Done** |
@@ -104,20 +104,21 @@ Status: `Done` · `In Progress` · `Planned` · `TBD` · `Withdrawn`
| ID | Requirement | Traces to | Priority | Status |
|---|---|---|---|---|
| VR-001 | HDF5 post-inference dump at the embedded-frame boundary | PR-002 | High | Done |
| VR-002 | Replay drives the **real** KPN nodes, not a reimplementation | PR-002 | High | **Done** — replay driven from committed fixtures in `tests/test_replay_fixtures.cpp`; determinism asserted |
| VR-002 | Replay drives the **real** KPN nodes, not a reimplementation | PR-002 | High | **In Progress, and worse than it looked.** The C++ side is real (`tests/test_replay_fixtures.cpp`, determinism asserted). The *Python* side is not runnable: `sae_kpn` has not compiled since the AR-007/AR-008 redesign — the binding builds `FaceTrackerFunc` from a `Config` alone, and the tracker has required a registry and a calibration since. Any `.so` in a stale `build/` predates that. Now behind `SAE_BUILD_KPN_BINDINGS=OFF` so the breakage is attributed rather than rediscovered; fixing it is VR-011. **Also correct the fixture claim:** the dumps are *not* committed (`tests/fixtures/dumps/.gitignore`) — they are Gitea package-registry artifacts, pulled by the CI job |
| VR-003 | Scoring: micro-F1 against X-Ray, precision/recall logged at every evaluation | PR-002 | High | Done |
| VR-004 | Reproducible validation corpus with ground truth | PR-002 | High | Done |
| VR-005 | Minimum face size study — TPI/FPI vs probe size, gallery held at native res | PR-002 | Medium | **Done** — knee at 2432 px; 32 px gives 98.1% TPI, 0.0 FPI at every size. Degrades an already-aligned 112×112 crop, so it isolates the embedder and is an **upper bound**; VR-013 measures the same question end to end and AR-002 takes its number, not this one |
| VR-006 | Re-tune `scene_threshold` once native-rate decode lands | PR-002 | **Medium** | **Planned, now unblocked** — native-rate decode landed with AR-011, so the prerequisite is met and the current 0.60 is a value fitted against input the pipeline no longer produces. Raised from Low for that reason: it is no longer a refinement, it is a stale constant |
| VR-007 | Expansion band, clustering threshold, and deferred-pass ablation | PR-002 | Medium | Planned |
| VR-007 | Expansion band, clustering threshold, deferred-pass ablation, **and the AR-025 accumulation knobs** | PR-002 | Medium | **Planned — scope corrected.** `rho_max`'s own comment already deferred to this row, and four constants it names were unreachable: `ownership_logodds` on `TrackRegistry::Config`, and `max_views`/`admit_below`/`rho_max` on `EvidenceDiscounter::Config`, which `main` built through the one-argument constructor. No sweep could vary them. They are in `Config` with CLI flags now, so this row can be run. `ownership_logodds` is the one to start with: below it a track makes **no presence claim at all**, so it decides whether an actor is reported rather than how confidently |
| VR-008 | Gallery scaling benchmark — throughput vs gallery size | PR-002 | Medium | Planned |
| VR-009 | Verify accumulated posteriors are calibrated against held-out tracks | PR-002 | High | Planned |
| VR-010 | Dump provenance attributes — embedder model, detector settings, `dense_scale`, `scene_detect`, sample rate | PR-002 | **High** | Planned |
| VR-010 | Dump provenance attributes — embedder model, detector settings, `dense_scale`, `scene_detect`, sample rate | PR-002 | **High** | **Done**`DumpProvenance` in `embedding_dump_node.hpp`, written as root attributes and read back tolerantly. Every field is optional so a pre-VR-010 dump reads as *unknown* rather than as a default; a silently-defaulted `detector_conf` is exactly the fabricated provenance this exists to prevent. This row said `Planned` while five VR-010 tags sat in the code — stale in the opposite direction to the rest of this register |
| VR-011 | Rewrite the replay harness for the post-AR-012 output contract | PR-002 | High | Planned |
| VR-012 | Quality-knee study — TPI/FPI vs sharpness and vs pose, as VR-005 did for size; also settles whether the 5-point pose proxy needs a dedicated landmark model | PR-002 | Medium | Planned |
| VR-014 | Audio-signature **offset recovery on real content** — a known trim recovered from film audio, not from the synthetic golden tone | PR-002 | Medium | **Done** — 40 random in-cap offsets, every one recovered to the nearest frame: **worst error 46 ms against a 500 ms budget**, and 46 ms is the floor rather than a result, since the offset is quantised to whole 92.88 ms frames. The `runtime/2` anchor confirmed through real head-trimmed files (a `delta` trim moves the window by `delta/2`). The one soft spot is **tier labelling, not accuracy**: the score falls with sub-frame misalignment (0.940.99 near a frame boundary, 0.690.73 at half a frame), so 27/40 correct alignments were demoted to `loose`. ±1 frame of slack in the *score* fixes it — measured, all 40 back to `audio` (min 0.906), false matches unmoved at 0.120.16, costing 81 ms of the budget |
| VR-015 | Per-node cost and bottleneck attribution for a run — where the time actually goes | PR-004 | High | **Done**`--benchmark <path>` on `scene_analyze`; `src/benchmark.hpp`. Reports cumulative CPU and wall time per node, and locates the pacing node from sampled channel occupancy rather than from time-in-node, which backpressure inflates. Verified UT-120…UT-124 |
| VR-013 | Cross-source identification probe — gallery from one recording, probes from another, swept over input resolution end to end | PR-002 | Medium | **In Progress** — holding 90% of the plateau needs ~50 px end to end against VR-005's ~22 px, the gap being detection and landmark error; **`min_face_px` 40, since 32 admits faces in the falling region** (AR-002). FPI 0.0% at every scale. Ceiling is cross-view, not resolution |
| VR-016 | **Cut-detection cadence study** — is `cut_threshold` 0.70 meaningful at the rate `camera_pos` is actually fed? | PR-002 | Medium | **Planned.** The histogram cut detector is the one always-on signal with no recorded provenance, and its input rate is not the rate it was fitted at. With `--scene-detect` off, `camera_pos` sits downstream of a source already decimated to `sample_fps`, so at the 1.0 default it compares frames **one second apart** — inside a single shot those differ enormously, and 0.70 correlation is a low bar to clear. With `--scene-detect` on it sees native-rate frames instead, so the same constant means two different things depending on an unrelated flag. This is AR-011's argument ("every model gets the input it was trained for") applied to a non-neural detector, and it matters because `is_cut` drives `track_alpha` to 0 and clears every expansion buffer. Cheap first measurement: run `camera_pos` over a `hero/` clip at 1/2/5 fps and compare cut counts against `tests/fixtures/dumps/scene_bounds.json`. The committed 5 fps dump shows 2.6% of frames flagged; nobody has measured 1 fps |
---
@@ -325,14 +326,14 @@ because it will be trusted.
| AR-014 | T2 | Belief swap closes one window, opens another | No blended window; no overlap at the swap frame |
| AR-015 | T2 | Two live tracks on one actor trigger re-association | Counter increments |
| AR-016 | **T2** | Every track closed at EOF | Film ending mid-shot — window ends at final frame, not dropped |
| AR-017 | T1 | Claim carries posterior and route | Deferred and pooled routes distinguishable |
| AR-017 | T1 | Claim carries posterior and route | Deferred and pooled routes distinguishable — now possible: `route` is an enum on `DeadTrack` rather than the literal `"live"` the sink used to write. Only `live` occurs until AR-020 exists, so the test that matters today is that the field survives serialisation |
| AR-018 | T1 | Band admits only within bounds | At each bound exactly; store never admits below lower bound |
| AR-019 | T2 | Promotion only when all three signals quiet | Cut mid-track blocks promotion |
| AR-020 | **T2** | Unknown resolved after expansion | Track failing at minute 12, resolved at EOF — the ordering-independence claim |
| AR-021 | T2 | Clustering merges same person, respects cannot-link | **Temporally overlapping tracks never merge**; measure how many merges the constraint rejects |
| AR-022 | T1 | Context crops retained, bounded per track | Track running for minutes |
| AR-023 | T1 | Sigmoid fit on synthetic separable data | Too few positive pairs → `valid=false`, fallback engages |
| AR-024 | **Static check** | No bare cosine outside a tagged `EXCEPTION` | Grep-based; this is the invariant's enforcement |
| AR-023 | T1 | Sigmoid fit on synthetic separable data | Too few positive pairs → `valid=false`, and the fallback that engages is the **default sigmoid**, not the retired cosine rule. Assert the warning fires: an unfitted sigmoid returns plausible-looking probabilities, so nothing downstream can tell |
| AR-024 | **Static check** | No bare cosine outside a tagged `EXCEPTION` | `scripts/ci/check_raw_cosine.py`, blocking in the traceability workflow. Honest about its reach: it catches direct `cosine_similarity()` uses not routed through a calibration and **cannot follow a cosine through a variable across statements**, which is a convention backed by review rather than by the tool. Scans `src` only — a test legitimately asserts properties of the metric space, and sweeping those in would produce blanket exceptions that devalue the tag |
| AR-025 | T1 | Log-odds accumulate; correlated frames discounted | 30 identical frames must **not** reach the certainty of 30 diverse ones |
| AR-026 | T1 + T4 | GEMM path produces same result as reference loop | Equivalence on small input in CI; throughput on GPU host |
| AR-027 | **T4** | Throughput at 10²…10⁵ actors | Scheduled, not on-demand |
@@ -341,6 +342,7 @@ because it will be trusted.
| AR-030 | T1 | Alignment residual rises monotonically with foreshortening | **In-plane roll, scale and translation must leave it at zero** — the property that makes it a pose measure rather than a pose-and-everything-else measure; face size must not shift it; degenerate landmarks report not-ok rather than a number |
| VR-012 | **T4** | Knee located per axis on held-out films | Report each candidate threshold's cost in **lost true presence**, not only its gain in precision — a gate that improves misID by discarding half the cast has not helped |
| VR-013 | **T4** | Identification holds across two recordings of the same people, and degrades to TBI rather than to a wrong name as input resolution falls | Gallery and probes must come from *different* recordings — a hold-one-out over one recording measures a much easier problem and will not surface the cross-view failure. Ground truth is hand-sorted; labels propagated by embedding similarity would keep only the faces the embedder already gets right |
| VR-016 | **T2** | Cut rate as a function of the cadence `camera_pos` is fed | Same clip at 1/2/5 fps, `--scene-detect` on and off. The dump already records `cut_threshold` and `sample_fps` (VR-010), so a replay can score this without re-decoding. A finding of "0.70 is fine at every rate" is a real result and should be recorded as one |
| IR-001/002 | T1 | Serialised output matches golden file | Zero-length window; actor with many windows |
| IR-003 | T1 | Output written after deferred pass | Not at EOF |
| IR-004/005 | **T1** | Signature matches golden vector bit-for-bit | Identical result in both producer repos |
@@ -369,8 +371,29 @@ accumulation from being decoration.
| — | `anneal_sec` window merging | Superseded by AR-012/AR-013: a track survives its own gaps, so there is nothing to anneal |
| — | `extinction_sec` actor keep-alive | Superseded by AR-013: windows end at last sighting, which is what this over-claimed |
Both were deleted rather than retained at zero — a field naming a mechanism the
pipeline no longer has is actively misleading (see `SPEC.md` A6.6).
Both are now deleted rather than retained at zero — a field naming a mechanism
the pipeline no longer has is actively misleading (see `SPEC.md` A6.6).
**This paragraph was false for some time, and the failure is worth keeping.** It
was written in the present perfect as though the removal had happened. It had
not: `Config::extinction_sec` (57.4) and `Config::anneal_sec` (35.5) were still
there, `--extinction` and `--anneal` still parsed, and `SceneTrackerFunc` still
ran its keep-alive in both shipped pipelines, printing its timeout at every
startup. `SPEC.md`'s removal list ends "grep for both names and expect no
survivors"; there were about forty.
Nothing in the tooling could have caught it. The traceability gate reads tags,
not behaviour, and a withdrawn requirement has no tag to be orphaned — the
register simply asserted a state of the code, and no test asked. The general
form is worth stating: **a status column is a claim, and the only claims this
project can check automatically are the ones a test or a static check makes.**
The same pattern produced three other rows corrected in this pass (AR-011,
AR-017, AR-019), each recorded as done and done in one place out of two.
`SceneTrackerFunc` is replaced by the stateless `FrameAnnotationFunc`. One
visible consequence: `--verbosity standard`'s `frames[].identified` used to
include every actor inside the keep-alive window, and now lists what was matched
in that frame. Minimal and xray output never consulted the node.
---
+232 -183
View File
@@ -3,7 +3,7 @@
<!-- GENERATED FILE - do not edit by hand. -->
<!-- Regenerate: scripts/traceability/traceability-gate.sh -->
**Generated:** 2026-08-05T12:38:33+00:00
**Generated:** 2026-08-05T15:50:49+00:00
Denominators are read from [`requirements.md`](requirements.md) at run time, never hardcoded. Coverage counts a requirement only when it is tagged in source **and** has a verification tier this repo's CI host can execute (`T1, T2, T3, static`).
@@ -11,14 +11,14 @@ Denominators are read from [`requirements.md`](requirements.md) at run time, nev
| Metric | Value |
|---|---|
| Source files scanned | 117 |
| TRACES tags found | 195 |
| EXCEPTION tags found | 0 |
| Requirements defined | 70 |
| Source files scanned | 118 |
| TRACES tags found | 215 |
| EXCEPTION tags found | 1 |
| Requirements defined | 71 |
| Requirements covered | 42 |
| **Coverage** | **60.0%** (42/70) |
| Coverage of CI-executable scope | 75.0% (42/56) |
| Tagged but unexecuted in CI | 9 |
| **Coverage** | **59.2%** (42/71) |
| Coverage of CI-executable scope | 73.7% (42/57) |
| Tagged but unexecuted in CI | 10 |
| Orphan tags | 0 |
### By type
@@ -29,7 +29,7 @@ Denominators are read from [`requirements.md`](requirements.md) at run time, nev
| DP | 2 | 0 | 8 |
| IR | 8 | 0 | 8 |
| GR | 5 | 0 | 9 |
| VR | 1 | 8 | 15 |
| VR | 1 | 9 | 16 |
- **UT** tags present (separate taxonomy, not counted in coverage): UT-001, UT-002, UT-003, UT-004, UT-005, UT-101, UT-102, UT-103, UT-104, UT-105, UT-106, UT-107, UT-108, UT-120, UT-121, UT-122, UT-123, UT-124, UT-130, UT-131, UT-132, UT-133, UT-134, UT-135, UT-136, UT-137, UT-138, UT-139, UT-140, UT-141
- **IT** tags present (separate taxonomy, not counted in coverage): IT-001
@@ -49,15 +49,15 @@ These requirements have no verification tier this repo's CI host can run, so a t
| VR-004 | out-of-ci | yes | Reproducible validation corpus with ground truth |
| VR-005 | out-of-ci | yes | Minimum face size study — TPI/FPI vs probe size, gallery held at nati… |
| VR-006 | out-of-ci | no | Re-tune `scene_threshold` once native-rate decode lands |
| VR-007 | out-of-ci | no | Expansion band, clustering threshold, and deferred-pass ablation |
| VR-007 | out-of-ci | no | Expansion band, clustering threshold, deferred-pass ablation, **and t… |
| VR-008 | out-of-ci | no | Gallery scaling benchmark — throughput vs gallery size |
| VR-010 | out-of-ci | yes | Dump provenance attributes — embedder model, detector settings, `dens… |
| VR-011 | out-of-ci | no | Rewrite the replay harness for the post-AR-012 output contract |
| VR-011 | out-of-ci | yes | Rewrite the replay harness for the post-AR-012 output contract |
| VR-012 | T4, out-of-ci | no | Quality-knee study — TPI/FPI vs sharpness and vs pose, as VR-005 did … |
| VR-013 | T4, out-of-ci | yes | Cross-source identification probe — gallery from one recording, probe… |
| VR-015 | out-of-ci | yes | Per-node cost and bottleneck attribution for a run — where the time a… |
**Tagged but unexecuted:** AR-027, VR-001, VR-002, VR-003, VR-004, VR-005, VR-010, VR-013, VR-015 — a test exists and is tagged, but this CI host cannot run it. Report those runs separately.
**Tagged but unexecuted:** AR-027, VR-001, VR-002, VR-003, VR-004, VR-005, VR-010, VR-011, VR-013, VR-015 — a test exists and is tagged, but this CI host cannot run it. Report those runs separately.
## Orphan tags
@@ -75,7 +75,9 @@ _None._
Deliberate, documented departures from an invariant (`EXCEPTION: XX-nnn <reason>`). Reported separately and never counted as coverage — an exception is a decision to be reviewed, not evidence a requirement is met.
_None._
| Requirement | Location | Reason |
|---|---|---|
| AR-024 | [`src/gallery/gallery_calibration.hpp:165`](../src/gallery/gallery_calibration.hpp#L165) | this asks whether two vectors are THE SAME |
## Register
@@ -87,40 +89,40 @@ _None._
| AR-004 | **Mostly** — node o… | T1, T4 | SR-002 | covered | `src/benchmark.hpp`, `src/main.cpp`, `src/nodes/identity_matcher_node.hpp`, `tests/test_replay_fixtures.cpp` | Backpressure: unbounded faces/frame absorbed by slowing, never by dro… |
| AR-005 | **Done** — `umeyama… | T1, T3 | SR-002 | covered | `src/face_utils.hpp`, `src/nodes/face_aligner_node.hpp`, `tests/test_face_utils.cpp` | Align to 112×112 via ArcFace 5-point similarity transform, fitted by … |
| AR-006 | Done | T3 | SR-002 | covered | `src/nodes/embedder_node.hpp` | 512-d L2-normalised embeddings, batched |
| AR-007 | **Done**`track_a… | T2 | SR-002 | covered | `src/config.hpp`, `src/main.cpp`, `src/nodes/face_tracker_node.hpp`, `tests/test_face_tracker.cpp` | Associate detections by IoU + embedding, with **frame-dependent** wei… |
| AR-007 | **Done**`track_a… | T2 | SR-002 | covered | `src/config.hpp`, `src/main.cpp`, `src/nodes/face_tracker_node.hpp`, `src/scene_preview.cpp`, `tests/test_face_tracker.cpp` | Associate detections by IoU + embedding, with **frame-dependent** wei… |
| AR-008 | **Done** — one pool… | T2 | SR-002 | covered | `src/config.hpp`, `src/main.cpp`, `src/nodes/face_tracker_node.hpp`, `tests/test_face_tracker.cpp` | One track pool keyed on `last_seen`; no separate revival path |
| AR-009 | Done | T2 | SR-002 | covered | `src/nodes/camera_position_change_detector_node.hpp` | Camera-cut detection (histogram) as an association hint |
| AR-010 | **Done** — decode b… | T2 | SR-002 | covered | `src/main.cpp`, `src/nodes/scene_boundary_annotator_node.hpp`, `src/nodes/scene_detector_node.hpp`, `src/scene_boundaries.hpp` | Scene-boundary detection (TransNetV2) as an association hint |
| AR-011 | **Done** — both vio… | T1, T2 | SR-002 | covered | `src/config.hpp`, `src/nodes/scene_detector_node.hpp`, `tests/test_scene_detector_node.cpp` | **Every model is fed the input it was trained for** — cost reduced by… |
| AR-012 | **Done** — `src/tra… | T2 | **SR-002** | covered | `src/main.cpp`, `src/nodes/identity_matcher_node.hpp`, `src/nodes/result_sink_node.hpp`, `src/track_registry.hpp`, `tests/test_replay_fixtures.cpp`, `tests/test_track_registry.cpp` | Presence follows **track extent**, not per-frame recognition |
| AR-013 | **Done**`last_se… | T2 | SR-002 | covered | `src/track_registry.hpp`, `tests/test_replay_fixtures.cpp`, `tests/test_track_registry.cpp` | `last_seen` optional state machine; window ends at last sighting, nev… |
| AR-011 | **Done** — both vio… | T1, T2 | SR-002 | covered | `src/config.hpp`, `src/nodes/scene_detector_node.hpp`, `src/scene_boundaries.hpp`, `tests/test_scene_detector_node.cpp` | **Every model is fed the input it was trained for** — cost reduced by… |
| AR-012 | **Done** — `src/tra… | T2 | **SR-002** | covered | `src/config.hpp`, `src/kpn_bindings.cpp`, `src/main.cpp`, `src/nodes/frame_annotation_node.hpp`, `src/nodes/identity_matcher_node.hpp`, `src/nodes/result_sink_node.hpp`, `src/scene_preview.cpp`, `src/track_registry.hpp`, `tests/test_replay_fixtures.cpp`, `tests/test_track_registry.cpp` | Presence follows **track extent**, not per-frame recognition |
| AR-013 | **Done**`last_se… | T2 | SR-002 | covered | `src/config.hpp`, `src/kpn_bindings.cpp`, `src/nodes/frame_annotation_node.hpp`, `src/track_registry.hpp`, `tests/test_replay_fixtures.cpp`, `tests/test_track_registry.cpp` | `last_seen` optional state machine; window ends at last sighting, nev… |
| AR-014 | **Done** — swap clo… | T2 | SR-002 | covered | `src/track_registry.hpp`, `tests/test_track_registry.cpp` | Belief swap A→B terminates the track and starts a new one |
| AR-015 | **Done** — reverse … | T2 | SR-002 | covered | `src/track_registry.hpp`, `tests/test_track_registry.cpp` | Two live tracks owned by one actor ⇒ treat as a detected cut, re-asso… |
| AR-016 | **Done** — `flush()… | T2 | SR-002 | covered | `src/main.cpp`, `src/nodes/result_sink_node.hpp`, `src/track_registry.hpp`, `tests/test_track_registry.cpp` | All tracks closed at EOF — a film ends with faces on screen |
| AR-017 | **Done**`DeadTra… | T1, T2 | SR-002 | covered | `src/nodes/result_sink_node.hpp`, `src/track_registry.hpp`, `tests/test_track_registry.cpp` | Every presence claim carries its belief and identification route |
| AR-017 | **Done**`DeadTra… | T1, T2 | SR-002 | covered | `src/config.hpp`, `src/nodes/result_sink_node.hpp`, `src/track_registry.hpp`, `tests/test_track_registry.cpp` | Every presence claim carries its belief and identification route |
| AR-018 | **Done** — banded a… | T1, T2 | SR-005 | covered | `src/config.hpp`, `src/gallery/track_gallery.hpp`, `src/nodes/identity_matcher_node.hpp`, `tests/test_track_gallery.cpp` | Per-subject embedding store with banded admission (novel enough, safe… |
| AR-019 | **Done** — all thre… | T2 | SR-005 | covered | `src/gallery/track_gallery.hpp`, `src/nodes/identity_matcher_node.hpp`, `tests/test_track_gallery.cpp` | Per-film gallery annex from owned tracks; acquires the non-frontal vi… |
| AR-020 | Planned | T2 | SR-005 | untagged | - | Deferred re-identification of unknown tracks against the final expand… |
| AR-021 | Planned | T2 | SR-005 | untagged | - | Cluster unknown tracks into one entity per person, under temporal can… |
| AR-022 | Planned | T1, T2 | §4 | untagged | - | Capture still-unidentified tracks: embeddings, metadata, **context cr… |
| AR-023 | Done | T1 | SR-002 | covered | `src/gallery/gallery_calibration.hpp`, `src/nodes/identity_matcher_node.hpp`, `tests/test_calibration.cpp` | Fit sigmoid calibration from intra/inter similarity distributions |
| AR-024 | **Done** — associat… | T1, static | SR-002 | covered | `src/config.hpp`, `src/evidence_discount.hpp`, `src/gallery/gallery_calibration.hpp`, `src/gallery/track_gallery.hpp`, `src/main.cpp`, `src/nodes/face_tracker_node.hpp`, `src/nodes/identity_matcher_node.hpp`, `tests/test_track_gallery.cpp` | **Always the calibrated probability, never a raw cosine** — exception… |
| AR-025 | **Done** — log-odds… | T1 | SR-002 | covered | `src/evidence_discount.hpp`, `src/nodes/identity_matcher_node.hpp` | Per-track Bayesian accumulation in log-odds, with correlated-observat… |
| AR-023 | **Done** — and the … | T1 | SR-002 | covered | `src/gallery/gallery_calibration.hpp`, `src/nodes/identity_matcher_node.hpp`, `tests/test_calibration.cpp` | Fit sigmoid calibration from intra/inter similarity distributions |
| AR-024 | **Done** — associat… | T1, static | SR-002 | covered | `scripts/ci/check_raw_cosine.py`, `scripts/optimizer/replay.py`, `src/config.hpp`, `src/evidence_discount.hpp`, `src/gallery/gallery_calibration.hpp`, `src/gallery/track_gallery.hpp`, `src/main.cpp`, `src/nodes/face_tracker_node.hpp`, `src/nodes/identity_matcher_node.hpp`, `src/scene_preview.cpp`, `tests/test_track_gallery.cpp` | **Always the calibrated probability, never a raw cosine** — exception… |
| AR-025 | **Done** — log-odds… | T1 | SR-002 | covered | `src/config.hpp`, `src/evidence_discount.hpp`, `src/main.cpp`, `src/nodes/identity_matcher_node.hpp` | Per-track Bayesian accumulation in log-odds, with correlated-observat… |
| AR-026 | **In Progress** — t… | T1, T4 | SR-001 | covered | `src/backends/gemm_backend.cpp`, `src/gallery/track_gallery.hpp`, `src/inference/similarity.hpp`, `src/nodes/identity_matcher_node.hpp`, `tests/test_similarity.cpp`, `tests/test_track_gallery.cpp` | All similarity computed as GEMM, including annex and deferred pass |
| AR-027 | Planned | T4 | SR-001 | tagged, unexecuted | `src/backends/gemm_backend.cpp` | Throughput acceptable for **arbitrary** gallery size |
| AR-028 | **Done** — filled i… | T2 | SR-002 | covered | `scripts/optimizer/replay.py`, `src/nodes/embedding_dump_node.hpp`, `src/nodes/face_aligner_node.hpp`, `src/types.hpp`, `tests/test_embedding_dump.cpp`, `tests/test_face_utils.cpp` | **Embedding input quality assessed and carried** — every face scored … |
| AR-029 | **Done** — `crop_sh… | T1 | SR-002 | covered | `src/face_utils.hpp`, `src/nodes/face_aligner_node.hpp`, `tests/test_face_utils.cpp` | Sharpness measure on the **aligned crop** (scale-normalised, so it ca… |
| AR-030 | **In Progress** — m… | T1 | SR-002 | covered | `src/face_utils.hpp`, `src/nodes/face_aligner_node.hpp`, `tests/test_face_utils.cpp` | Visibility measure from the AR-001 5-point landmarks — extreme pose o… |
| DP-001 | Done | T1, manual | PR-004 | covered | `src/main.cpp` | One analysis core; modes are front-ends and must not fork pipeline lo… |
| DP-001 | **Done, after a rep… | T1, manual | PR-004 | covered | `src/main.cpp`, `src/scene_preview.cpp` | One analysis core; modes are front-ends and must not fork pipeline lo… |
| DP-002 | Done | T1, manual | PR-004 | covered | `src/main.cpp` | Batch CLI over one title |
| DP-003 | Planned | T1, manual | PR-004 | untagged | - | On-demand resident service with bounded, observable queue |
| DP-004 | Planned | T1, manual | PR-004 | untagged | - | Opportunistic/idle mode: external trigger, hard stop, implicit re-que… |
| DP-005 | Planned | T1, manual | PR-004 | untagged | - | Native installer, no Docker; Fedora + Arch |
| DP-006 | Planned | T1, manual | PR-003 | untagged | - | Background incremental gallery refresh on a timer |
| DP-007 | Planned | T1, manual | PR-004 | untagged | - | CI builder image, CPU-only, pinned by tag in the Gitea container regi… |
| DP-007 | **Mostly** — image … | T1, manual | PR-004 | untagged | - | CI builder image, CPU-only, pinned by tag in the Gitea container regi… |
| DP-008 | Planned | T1, manual | PR-004 | untagged | - | Builder images + release jobs per backend (cpu / cuda / rocm); ship b… |
| IR-001 | Done | T1 | SR-003 | covered | `src/nodes/result_sink_node.hpp` | Emit the JRay truth format as sibling `.jray.json` |
| IR-002 | **Done**`schema_… | T1 | SR-003 | covered | `src/config.hpp`, `src/main.cpp`, `src/nodes/result_sink_node.hpp` | Windows carry belief + route; `extraction.*` carries `extinction_sec`… |
| IR-002 | **Done**`schema_… | T1 | SR-003 | covered | `src/config.hpp`, `src/main.cpp`, `src/nodes/result_sink_node.hpp`, `src/track_registry.hpp` | Windows carry belief + route; `extraction.*` carries `extinction_sec`… |
| IR-003 | **In Progress** — s… | T1 | SR-003 | covered | `src/main.cpp` | Output written **after** the deferred pass, not at EOF |
| IR-004 | **Done** — `src/aud… | T1 | SR-003 | covered | `scripts/validation/test_audio_offset.py`, `src/audio_bindings.cpp`, `src/audio_signature.cpp`, `src/audio_signature.hpp`, `tests/test_audio_signature.cpp` | Compute the audio signature exactly per server spec §3 |
| IR-005 | **Done**`tests/f… | T1 | SR-003 | covered | `src/audio_bindings.cpp`, `src/audio_signature.cpp`, `src/audio_signature.hpp`, `tests/test_audio_signature.cpp` | Golden-vector fixture shared with the plugin repo to prove bit-exactn… |
@@ -137,20 +139,21 @@ _None._
| GR-008 | Planned | T1 | SR-005 | untagged | - | Flag distributional outliers among an actor's references (poisoning g… |
| GR-009 | TBD | T1 | §4 | untagged | - | Human-confirmed associations persist and improve future extractions |
| VR-001 | Done | out-of-ci | PR-002 | tagged, unexecuted | `src/nodes/embedding_dump_node.hpp`, `tests/test_embedding_dump.cpp`, `tests/test_replay_fixtures.cpp` | HDF5 post-inference dump at the embedded-frame boundary |
| VR-002 | **Done** — replay d… | out-of-ci | PR-002 | tagged, unexecuted | `scripts/optimizer/replay.py`, `tests/test_replay_fixtures.cpp` | Replay drives the **real** KPN nodes, not a reimplementation |
| VR-002 | **In Progress, and … | out-of-ci | PR-002 | tagged, unexecuted | `scripts/optimizer/replay.py`, `tests/test_replay_fixtures.cpp` | Replay drives the **real** KPN nodes, not a reimplementation |
| VR-003 | Done | out-of-ci | PR-002 | tagged, unexecuted | `scripts/optimizer/second_score.py` | Scoring: micro-F1 against X-Ray, precision/recall logged at every eva… |
| VR-004 | Done | out-of-ci | PR-002 | tagged, unexecuted | `scripts/validation/ground_truth.py` | Reproducible validation corpus with ground truth |
| VR-005 | **Done** — knee at … | out-of-ci | PR-002 | tagged, unexecuted | `scripts/validation/min_face_size.py` | Minimum face size study — TPI/FPI vs probe size, gallery held at nati… |
| VR-006 | **Planned, now unbl… | out-of-ci | PR-002 | untagged | - | Re-tune `scene_threshold` once native-rate decode lands |
| VR-007 | Planned | out-of-ci | PR-002 | untagged | - | Expansion band, clustering threshold, and deferred-pass ablation |
| VR-007 | **Planned — scope c… | out-of-ci | PR-002 | untagged | - | Expansion band, clustering threshold, deferred-pass ablation, **and t… |
| VR-008 | Planned | out-of-ci | PR-002 | untagged | - | Gallery scaling benchmark — throughput vs gallery size |
| VR-009 | Planned | T1, out-of-ci | PR-002 | untagged | - | Verify accumulated posteriors are calibrated against held-out tracks |
| VR-010 | Planned | out-of-ci | PR-002 | tagged, unexecuted | `src/nodes/embedding_dump_node.hpp` | Dump provenance attributes — embedder model, detector settings, `dens… |
| VR-011 | Planned | out-of-ci | PR-002 | untagged | - | Rewrite the replay harness for the post-AR-012 output contract |
| VR-010 | **Done**`DumpPro… | out-of-ci | PR-002 | tagged, unexecuted | `src/nodes/embedding_dump_node.hpp` | Dump provenance attributes — embedder model, detector settings, `dens… |
| VR-011 | Planned | out-of-ci | PR-002 | tagged, unexecuted | `scripts/optimizer/replay.py` | Rewrite the replay harness for the post-AR-012 output contract |
| VR-012 | Planned | T4, out-of-ci | PR-002 | untagged | - | Quality-knee study — TPI/FPI vs sharpness and vs pose, as VR-005 did … |
| VR-013 | **In Progress** — h… | T4, out-of-ci | PR-002 | tagged, unexecuted | `experiments/xsource/resolution_sweep.py`, `experiments/xsource/verify_labels.py` | Cross-source identification probe — gallery from one recording, probe… |
| VR-014 | **Done** — 40 rando… | T2, out-of-ci | PR-002 | covered | `scripts/validation/test_audio_offset.py` | Audio-signature **offset recovery on real content** — a known trim re… |
| VR-015 | **Done**`--bench… | out-of-ci | PR-004 | tagged, unexecuted | `src/backends/trt_backend.cpp`, `src/benchmark.hpp`, `src/config.hpp`, `src/main.cpp`, `tests/test_benchmark.cpp` | Per-node cost and bottleneck attribution for a run — where the time a… |
| VR-016 | **Planned.** The hi… | T2, out-of-ci | PR-002 | untagged | - | **Cut-detection cadence study** — is `cut_threshold` 0.70 meaningful … |
## Detailed mapping
@@ -174,7 +177,7 @@ _None._
- [`src/config.hpp:52`](../src/config.hpp#L52) — `Unknown`
- [`src/nodes/face_detector_node.hpp:64`](../src/nodes/face_detector_node.hpp#L64) — `private:`
- [`src/nodes/identity_matcher_node.hpp:173`](../src/nodes/identity_matcher_node.hpp#L173) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`src/nodes/identity_matcher_node.hpp:192`](../src/nodes/identity_matcher_node.hpp#L192) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
### AR-004
@@ -183,11 +186,11 @@ _None._
- [`src/benchmark.hpp:176`](../src/benchmark.hpp#L176) — `Unknown`
- [`src/benchmark.hpp:472`](../src/benchmark.hpp#L472) — `void print(std::ostream& os, double film_sec) const`
- [`src/benchmark.hpp:522`](../src/benchmark.hpp#L522) — `else if (c.in_fill_pct > 50.0)`
- [`src/main.cpp:97`](../src/main.cpp#L97) — `static constexpr std::size_t kSceneJoinDepth = 256;`
- [`src/main.cpp:109`](../src/main.cpp#L109) — `static std::shared_ptr<SceneBoundaries> scene_stats;`
- [`src/main.cpp:380`](../src/main.cpp#L380) — `Unknown`
- [`src/main.cpp:423`](../src/main.cpp#L423) — `std::ofstream bf(cfg.benchmark_path);`
- [`src/nodes/identity_matcher_node.hpp:173`](../src/nodes/identity_matcher_node.hpp#L173) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`src/main.cpp:103`](../src/main.cpp#L103) — `static constexpr std::size_t kSceneJoinDepth = 256;`
- [`src/main.cpp:115`](../src/main.cpp#L115) — `static std::shared_ptr<SceneBoundaries> scene_stats;`
- [`src/main.cpp:394`](../src/main.cpp#L394) — `Unknown`
- [`src/main.cpp:437`](../src/main.cpp#L437) — `std::ofstream bf(cfg.benchmark_path);`
- [`src/nodes/identity_matcher_node.hpp:192`](../src/nodes/identity_matcher_node.hpp#L192) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`tests/test_replay_fixtures.cpp:3`](../tests/test_replay_fixtures.cpp#L3) — `Unknown`
### AR-005
@@ -206,19 +209,20 @@ _None._
### AR-007
**Locations:** 4
**Locations:** 5
- [`src/config.hpp:127`](../src/config.hpp#L127) — `Unknown`
- [`src/main.cpp:255`](../src/main.cpp#L255) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/config.hpp:160`](../src/config.hpp#L160) — `Unknown`
- [`src/main.cpp:260`](../src/main.cpp#L260) — `Unknown`
- [`src/nodes/face_tracker_node.hpp:2`](../src/nodes/face_tracker_node.hpp#L2) — `Unknown`
- [`src/scene_preview.cpp:147`](../src/scene_preview.cpp#L147) — `Unknown`
- [`tests/test_face_tracker.cpp:1`](../tests/test_face_tracker.cpp#L1) — `Unknown`
### AR-008
**Locations:** 4
- [`src/config.hpp:127`](../src/config.hpp#L127) — `Unknown`
- [`src/main.cpp:255`](../src/main.cpp#L255) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/config.hpp:160`](../src/config.hpp#L160) — `Unknown`
- [`src/main.cpp:260`](../src/main.cpp#L260) — `Unknown`
- [`src/nodes/face_tracker_node.hpp:2`](../src/nodes/face_tracker_node.hpp#L2) — `Unknown`
- [`tests/test_face_tracker.cpp:1`](../tests/test_face_tracker.cpp#L1) — `Unknown`
@@ -232,43 +236,52 @@ _None._
**Locations:** 9
- [`src/main.cpp:97`](../src/main.cpp#L97) — `static constexpr std::size_t kSceneJoinDepth = 256;`
- [`src/main.cpp:433`](../src/main.cpp#L433) — `Unknown`
- [`src/main.cpp:503`](../src/main.cpp#L503) — `return run_net(std::move(net));`
- [`src/main.cpp:535`](../src/main.cpp#L535) — `Unknown`
- [`src/main.cpp:103`](../src/main.cpp#L103) — `static constexpr std::size_t kSceneJoinDepth = 256;`
- [`src/main.cpp:447`](../src/main.cpp#L447) — `Unknown`
- [`src/main.cpp:517`](../src/main.cpp#L517) — `return run_net(std::move(net));`
- [`src/main.cpp:549`](../src/main.cpp#L549) — `Unknown`
- [`src/nodes/scene_boundary_annotator_node.hpp:2`](../src/nodes/scene_boundary_annotator_node.hpp#L2) — `Unknown`
- [`src/nodes/scene_detector_node.hpp:36`](../src/nodes/scene_detector_node.hpp#L36) — `static constexpr std::string_view label() { return "scene_detector"; }`
- [`src/nodes/scene_detector_node.hpp:147`](../src/nodes/scene_detector_node.hpp#L147) — `void flush_remaining()`
- [`src/nodes/scene_detector_node.hpp:181`](../src/nodes/scene_detector_node.hpp#L181) — `void write_output()`
- [`src/nodes/scene_detector_node.hpp:147`](../src/nodes/scene_detector_node.hpp#L147) — `Unknown`
- [`src/nodes/scene_detector_node.hpp:188`](../src/nodes/scene_detector_node.hpp#L188) — `void write_output()`
- [`src/scene_boundaries.hpp:2`](../src/scene_boundaries.hpp#L2) — `Unknown`
### AR-011
**Locations:** 4
**Locations:** 6
- [`src/config.hpp:105`](../src/config.hpp#L105) — `Unknown`
- [`src/config.hpp:138`](../src/config.hpp#L138) — `Unknown`
- [`src/nodes/scene_detector_node.hpp:70`](../src/nodes/scene_detector_node.hpp#L70) — `void operator()(Frame f)`
- [`src/nodes/scene_detector_node.hpp:93`](../src/nodes/scene_detector_node.hpp#L93) — `Unknown`
- [`src/nodes/scene_detector_node.hpp:152`](../src/nodes/scene_detector_node.hpp#L152) — `Unknown`
- [`src/scene_boundaries.hpp:30`](../src/scene_boundaries.hpp#L30) — `public:`
- [`tests/test_scene_detector_node.cpp:4`](../tests/test_scene_detector_node.cpp#L4) — `Unknown`
### AR-012
**Locations:** 9
**Locations:** 13
- [`src/main.cpp:255`](../src/main.cpp#L255) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/main.cpp:272`](../src/main.cpp#L272) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/nodes/identity_matcher_node.hpp:132`](../src/nodes/identity_matcher_node.hpp#L132) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:280`](../src/nodes/identity_matcher_node.hpp#L280) — `Unknown`
- [`src/nodes/result_sink_node.hpp:49`](../src/nodes/result_sink_node.hpp#L49) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/nodes/result_sink_node.hpp:161`](../src/nodes/result_sink_node.hpp#L161) — `struct ActorMeta { std::string name, imdb_id, tmdb_id, jellyfin_id; };`
- [`src/config.hpp:210`](../src/config.hpp#L210) — `Unknown`
- [`src/kpn_bindings.cpp:273`](../src/kpn_bindings.cpp#L273) — `Unknown`
- [`src/main.cpp:260`](../src/main.cpp#L260) — `Unknown`
- [`src/main.cpp:286`](../src/main.cpp#L286) — `reg_cfg, EvidenceDiscounter(same_person, disc_cfg));`
- [`src/nodes/frame_annotation_node.hpp:2`](../src/nodes/frame_annotation_node.hpp#L2) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:151`](../src/nodes/identity_matcher_node.hpp#L151) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:285`](../src/nodes/identity_matcher_node.hpp#L285) — `Unknown`
- [`src/nodes/result_sink_node.hpp:50`](../src/nodes/result_sink_node.hpp#L50) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/nodes/result_sink_node.hpp:164`](../src/nodes/result_sink_node.hpp#L164) — `struct ActorMeta { std::string name, imdb_id, tmdb_id, jellyfin_id; };`
- [`src/scene_preview.cpp:147`](../src/scene_preview.cpp#L147) — `Unknown`
- [`src/track_registry.hpp:2`](../src/track_registry.hpp#L2) — `Unknown`
- [`tests/test_replay_fixtures.cpp:3`](../tests/test_replay_fixtures.cpp#L3) — `Unknown`
- [`tests/test_track_registry.cpp:3`](../tests/test_track_registry.cpp#L3) — `Unknown`
### AR-013
**Locations:** 3
**Locations:** 6
- [`src/config.hpp:210`](../src/config.hpp#L210) — `Unknown`
- [`src/kpn_bindings.cpp:273`](../src/kpn_bindings.cpp#L273) — `Unknown`
- [`src/nodes/frame_annotation_node.hpp:2`](../src/nodes/frame_annotation_node.hpp#L2) — `Unknown`
- [`src/track_registry.hpp:2`](../src/track_registry.hpp#L2) — `Unknown`
- [`tests/test_replay_fixtures.cpp:3`](../tests/test_replay_fixtures.cpp#L3) — `Unknown`
- [`tests/test_track_registry.cpp:3`](../tests/test_track_registry.cpp#L3) — `Unknown`
@@ -291,36 +304,41 @@ _None._
**Locations:** 4
- [`src/main.cpp:272`](../src/main.cpp#L272) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/nodes/result_sink_node.hpp:63`](../src/nodes/result_sink_node.hpp#L63) — `void set_pre_write_hook(std::function<void(double)> fn) { pre_write_ = std::move(fn); }`
- [`src/main.cpp:286`](../src/main.cpp#L286) — `reg_cfg, EvidenceDiscounter(same_person, disc_cfg));`
- [`src/nodes/result_sink_node.hpp:64`](../src/nodes/result_sink_node.hpp#L64) — `void set_pre_write_hook(std::function<void(double)> fn) { pre_write_ = std::move(fn); }`
- [`src/track_registry.hpp:2`](../src/track_registry.hpp#L2) — `Unknown`
- [`tests/test_track_registry.cpp:3`](../tests/test_track_registry.cpp#L3) — `Unknown`
### AR-017
**Locations:** 3
**Locations:** 5
- [`src/nodes/result_sink_node.hpp:49`](../src/nodes/result_sink_node.hpp#L49) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/config.hpp:181`](../src/config.hpp#L181) — `Unknown`
- [`src/nodes/result_sink_node.hpp:50`](../src/nodes/result_sink_node.hpp#L50) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/track_registry.hpp:2`](../src/track_registry.hpp#L2) — `Unknown`
- [`src/track_registry.hpp:47`](../src/track_registry.hpp#L47) — `Unknown`
- [`tests/test_track_registry.cpp:3`](../tests/test_track_registry.cpp#L3) — `Unknown`
### AR-018
**Locations:** 5
- [`src/config.hpp:171`](../src/config.hpp#L171) — `Unknown`
- [`src/gallery/track_gallery.hpp:196`](../src/gallery/track_gallery.hpp#L196) — `struct TrackState`
- [`src/gallery/track_gallery.hpp:309`](../src/gallery/track_gallery.hpp#L309) — `static int plurality_actor(const TrackState& ts)`
- [`src/nodes/identity_matcher_node.hpp:117`](../src/nodes/identity_matcher_node.hpp#L117) — `std::vector<float> host_gallery(static_cast<size_t>(n_gallery_) * 512);`
- [`src/config.hpp:245`](../src/config.hpp#L245) — `Unknown`
- [`src/gallery/track_gallery.hpp:233`](../src/gallery/track_gallery.hpp#L233) — `struct TrackState`
- [`src/gallery/track_gallery.hpp:331`](../src/gallery/track_gallery.hpp#L331) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:136`](../src/nodes/identity_matcher_node.hpp#L136) — `std::vector<float> host_gallery(static_cast<size_t>(n_gallery_) * 512);`
- [`tests/test_track_gallery.cpp:1`](../tests/test_track_gallery.cpp#L1) — `Unknown`
### AR-019
**Locations:** 4
**Locations:** 7
- [`src/gallery/track_gallery.hpp:155`](../src/gallery/track_gallery.hpp#L155) — `void forget(int track_id) { tracks_.erase(track_id); }`
- [`src/nodes/identity_matcher_node.hpp:154`](../src/nodes/identity_matcher_node.hpp#L154) — `MatchedSceneFrame operator()(TrackedSceneFrame tf)`
- [`src/nodes/identity_matcher_node.hpp:293`](../src/nodes/identity_matcher_node.hpp#L293) — `Unknown`
- [`src/gallery/track_gallery.hpp:136`](../src/gallery/track_gallery.hpp#L136) — `Unknown`
- [`src/gallery/track_gallery.hpp:161`](../src/gallery/track_gallery.hpp#L161) — `Unknown`
- [`src/gallery/track_gallery.hpp:183`](../src/gallery/track_gallery.hpp#L183) — `void set_owner(int track_id, int actor_idx)`
- [`src/nodes/identity_matcher_node.hpp:173`](../src/nodes/identity_matcher_node.hpp#L173) — `MatchedSceneFrame operator()(TrackedSceneFrame tf)`
- [`src/nodes/identity_matcher_node.hpp:295`](../src/nodes/identity_matcher_node.hpp#L295) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:314`](../src/nodes/identity_matcher_node.hpp#L314) — `Unknown`
- [`tests/test_track_gallery.cpp:1`](../tests/test_track_gallery.cpp#L1) — `Unknown`
### AR-023
@@ -329,33 +347,43 @@ _None._
- [`src/gallery/gallery_calibration.hpp:2`](../src/gallery/gallery_calibration.hpp#L2) — `Unknown`
- [`src/gallery/gallery_calibration.hpp:53`](../src/gallery/gallery_calibration.hpp#L53) — `float boundary_at(float p = 0.5f, float log_prior_odds = 0.f) const`
- [`src/nodes/identity_matcher_node.hpp:124`](../src/nodes/identity_matcher_node.hpp#L124) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:143`](../src/nodes/identity_matcher_node.hpp#L143) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`tests/test_calibration.cpp:1`](../tests/test_calibration.cpp#L1) — `Unknown`
### AR-024
**Locations:** 12
**Locations:** 20
- [`src/config.hpp:127`](../src/config.hpp#L127) — `Unknown`
- [`src/config.hpp:171`](../src/config.hpp#L171) — `Unknown`
- [`src/config.hpp:108`](../src/config.hpp#L108) — `Unknown`
- [`src/config.hpp:160`](../src/config.hpp#L160) — `Unknown`
- [`src/config.hpp:245`](../src/config.hpp#L245) — `Unknown`
- [`src/evidence_discount.hpp:2`](../src/evidence_discount.hpp#L2) — `Unknown`
- [`src/gallery/gallery_calibration.hpp:53`](../src/gallery/gallery_calibration.hpp#L53) — `float boundary_at(float p = 0.5f, float log_prior_odds = 0.f) const`
- [`src/gallery/track_gallery.hpp:165`](../src/gallery/track_gallery.hpp#L165) — `void set_calibration(std::function<float(float)> c) { calibrate_ = std::move(c); }`
- [`src/gallery/track_gallery.hpp:196`](../src/gallery/track_gallery.hpp#L196) — `struct TrackState`
- [`src/gallery/track_gallery.hpp:309`](../src/gallery/track_gallery.hpp#L309) — `static int plurality_actor(const TrackState& ts)`
- [`src/main.cpp:255`](../src/main.cpp#L255) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/gallery/track_gallery.hpp:193`](../src/gallery/track_gallery.hpp#L193) — `void set_owner(int track_id, int actor_idx)`
- [`src/gallery/track_gallery.hpp:233`](../src/gallery/track_gallery.hpp#L233) — `struct TrackState`
- [`src/gallery/track_gallery.hpp:331`](../src/gallery/track_gallery.hpp#L331) — `Unknown`
- [`src/main.cpp:260`](../src/main.cpp#L260) — `Unknown`
- [`src/nodes/face_tracker_node.hpp:2`](../src/nodes/face_tracker_node.hpp#L2) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:117`](../src/nodes/identity_matcher_node.hpp#L117) — `std::vector<float> host_gallery(static_cast<size_t>(n_gallery_) * 512);`
- [`src/nodes/identity_matcher_node.hpp:124`](../src/nodes/identity_matcher_node.hpp#L124) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:29`](../src/nodes/identity_matcher_node.hpp#L29) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:109`](../src/nodes/identity_matcher_node.hpp#L109) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:136`](../src/nodes/identity_matcher_node.hpp#L136) — `std::vector<float> host_gallery(static_cast<size_t>(n_gallery_) * 512);`
- [`src/nodes/identity_matcher_node.hpp:143`](../src/nodes/identity_matcher_node.hpp#L143) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:250`](../src/nodes/identity_matcher_node.hpp#L250) — `Unknown`
- [`src/scene_preview.cpp:147`](../src/scene_preview.cpp#L147) — `Unknown`
- [`tests/test_track_gallery.cpp:1`](../tests/test_track_gallery.cpp#L1) — `Unknown`
- [`tests/test_track_gallery.cpp:414`](../tests/test_track_gallery.cpp#L414) — `TrackGallery tg(expand_cfg());`
- [`scripts/ci/check_raw_cosine.py:4`](../scripts/ci/check_raw_cosine.py#L4) — `Unknown`
- [`scripts/optimizer/replay.py:262`](../scripts/optimizer/replay.py#L262) — `Unknown`
### AR-025
**Locations:** 3
**Locations:** 5
- [`src/config.hpp:181`](../src/config.hpp#L181) — `Unknown`
- [`src/evidence_discount.hpp:2`](../src/evidence_discount.hpp#L2) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:132`](../src/nodes/identity_matcher_node.hpp#L132) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:280`](../src/nodes/identity_matcher_node.hpp#L280) — `Unknown`
- [`src/main.cpp:268`](../src/main.cpp#L268) — `reg_cfg, EvidenceDiscounter(same_person, disc_cfg));`
- [`src/nodes/identity_matcher_node.hpp:151`](../src/nodes/identity_matcher_node.hpp#L151) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:285`](../src/nodes/identity_matcher_node.hpp#L285) — `Unknown`
### AR-026
@@ -364,20 +392,20 @@ _None._
- [`src/backends/gemm_backend.cpp:44`](../src/backends/gemm_backend.cpp#L44) — `constexpr int kDim = 512;`
- [`src/backends/gemm_backend.cpp:80`](../src/backends/gemm_backend.cpp#L80) — `int n_gallery() const override { return n_gallery_; }`
- [`src/backends/gemm_backend.cpp:256`](../src/backends/gemm_backend.cpp#L256) — `int n_gallery() const override { return n_gallery_; }`
- [`src/gallery/track_gallery.hpp:49`](../src/gallery/track_gallery.hpp#L49) — `struct TrackGallery`
- [`src/gallery/track_gallery.hpp:84`](../src/gallery/track_gallery.hpp#L84) — `bool enabled() const { return enabled_; }`
- [`src/gallery/track_gallery.hpp:99`](../src/gallery/track_gallery.hpp#L99) — `const float* annex_row(int i) const`
- [`src/gallery/track_gallery.hpp:357`](../src/gallery/track_gallery.hpp#L357) — `static constexpr int kEmbDim = 512;`
- [`src/gallery/track_gallery.hpp:50`](../src/gallery/track_gallery.hpp#L50) — `struct TrackGallery`
- [`src/gallery/track_gallery.hpp:85`](../src/gallery/track_gallery.hpp#L85) — `bool enabled() const { return enabled_; }`
- [`src/gallery/track_gallery.hpp:100`](../src/gallery/track_gallery.hpp#L100) — `const float* annex_row(int i) const`
- [`src/gallery/track_gallery.hpp:380`](../src/gallery/track_gallery.hpp#L380) — `static constexpr int kEmbDim = 512;`
- [`src/inference/similarity.hpp:19`](../src/inference/similarity.hpp#L19) — `struct ISimilarityEngine`
- [`src/inference/similarity.hpp:39`](../src/inference/similarity.hpp#L39) — `virtual int n_gallery() const = 0;`
- [`src/nodes/identity_matcher_node.hpp:43`](../src/nodes/identity_matcher_node.hpp#L43) — `struct IdentityMatcherFunc`
- [`src/nodes/identity_matcher_node.hpp:193`](../src/nodes/identity_matcher_node.hpp#L193) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`src/nodes/identity_matcher_node.hpp:316`](../src/nodes/identity_matcher_node.hpp#L316) — `private:`
- [`src/nodes/identity_matcher_node.hpp:60`](../src/nodes/identity_matcher_node.hpp#L60) — `struct IdentityMatcherFunc`
- [`src/nodes/identity_matcher_node.hpp:212`](../src/nodes/identity_matcher_node.hpp#L212) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`src/nodes/identity_matcher_node.hpp:328`](../src/nodes/identity_matcher_node.hpp#L328) — `private:`
- [`tests/test_similarity.cpp:1`](../tests/test_similarity.cpp#L1) — `Unknown`
- [`tests/test_similarity.cpp:85`](../tests/test_similarity.cpp#L85) — `Unknown`
- [`tests/test_track_gallery.cpp:1`](../tests/test_track_gallery.cpp#L1) — `Unknown`
- [`tests/test_track_gallery.cpp:48`](../tests/test_track_gallery.cpp#L48) — `Embedding annex_view(const TrackGallery& tg, int row)`
- [`tests/test_track_gallery.cpp:341`](../tests/test_track_gallery.cpp#L341) — `TrackGallery tg(expand_cfg());`
- [`tests/test_track_gallery.cpp:54`](../tests/test_track_gallery.cpp#L54) — `Embedding annex_view(const TrackGallery& tg, int row)`
- [`tests/test_track_gallery.cpp:364`](../tests/test_track_gallery.cpp#L364) — `TrackGallery tg(expand_cfg());`
### AR-027
@@ -417,9 +445,10 @@ _None._
### DP-001
**Locations:** 1
**Locations:** 2
- [`src/main.cpp:3`](../src/main.cpp#L3) — `Unknown`
- [`src/scene_preview.cpp:147`](../src/scene_preview.cpp#L147) — `Unknown`
### DP-002
@@ -446,7 +475,7 @@ _None._
- [`src/build_gallery.cpp:87`](../src/build_gallery.cpp#L87) — `Unknown`
- [`src/gallery/gallery_calibration.hpp:80`](../src/gallery/gallery_calibration.hpp#L80) — `struct GalleryCalibrationStats`
- [`src/gallery/gallery_calibration.hpp:145`](../src/gallery/gallery_calibration.hpp#L145) — `std::vector<bool> actor_eligible(n_actors, false);`
- [`src/gallery/gallery_calibration.hpp:294`](../src/gallery/gallery_calibration.hpp#L294) — `Unknown`
- [`src/gallery/gallery_calibration.hpp:307`](../src/gallery/gallery_calibration.hpp#L307) — `Unknown`
- [`src/gallery/gallery_report.hpp:2`](../src/gallery/gallery_report.hpp#L2) — `Unknown`
- [`src/gallery/gallery_report.hpp:52`](../src/gallery/gallery_report.hpp#L52) — `struct GalleryBuildAudit`
- [`src/gallery/gallery_report.hpp:73`](../src/gallery/gallery_report.hpp#L73) — `struct GalleryReport`
@@ -471,12 +500,12 @@ _None._
- [`src/gallery/gallery_store.cpp:82`](../src/gallery/gallery_store.cpp#L82) — `H5::StrType str(H5::PredType::C_S1, H5T_VARIABLE);`
- [`src/gallery/gallery_store.cpp:167`](../src/gallery/gallery_store.cpp#L167) — `H5::DataSpace scalar(H5S_SCALAR);`
- [`src/gallery/gallery_store.cpp:219`](../src/gallery/gallery_store.cpp#L219) — `Unknown`
- [`src/kpn_bindings.cpp:186`](../src/kpn_bindings.cpp#L186) — `Unknown`
- [`src/kpn_bindings.cpp:236`](../src/kpn_bindings.cpp#L236) — `Unknown`
- [`src/main.cpp:230`](../src/main.cpp#L230) — `Unknown`
- [`src/kpn_bindings.cpp:183`](../src/kpn_bindings.cpp#L183) — `Unknown`
- [`src/kpn_bindings.cpp:233`](../src/kpn_bindings.cpp#L233) — `Unknown`
- [`src/main.cpp:235`](../src/main.cpp#L235) — `Unknown`
- [`src/nodes/embedding_dump_node.hpp:127`](../src/nodes/embedding_dump_node.hpp#L127) — `static constexpr std::string_view label() { return "embedding_dump"; }`
- [`src/nodes/embedding_dump_node.hpp:257`](../src/nodes/embedding_dump_node.hpp#L257) — `H5::H5File file(path_, H5F_ACC_TRUNC);`
- [`src/scene_preview.cpp:133`](../src/scene_preview.cpp#L133) — `int main(int argc, char** argv)`
- [`src/scene_preview.cpp:130`](../src/scene_preview.cpp#L130) — `int main(int argc, char** argv)`
- [`src/types.hpp:173`](../src/types.hpp#L173) — `struct Actor`
- [`tests/test_gallery_store.cpp:182`](../tests/test_gallery_store.cpp#L182) — `TempFile tf("gallery_stamped.h5");`
- [`tests/test_gallery_store.cpp:201`](../tests/test_gallery_store.cpp#L201) — `TempFile tf("gallery_stamped.h5");`
@@ -502,7 +531,7 @@ _None._
- [`scripts/optimizer/optimize.py:202`](../scripts/optimizer/optimize.py#L202) — `if not Path(f["dump"]).exists():`
- [`scripts/optimizer/reembed_gallery.py:62`](../scripts/optimizer/reembed_gallery.py#L62) — `for i, a in enumerate(ref["actors"], 1):`
- [`scripts/optimizer/replay.py:125`](../scripts/optimizer/replay.py#L125) — `Unknown`
- [`scripts/optimizer/replay.py:265`](../scripts/optimizer/replay.py#L265) — `Unknown`
- [`scripts/optimizer/replay.py:306`](../scripts/optimizer/replay.py#L306) — `Unknown`
- [`scripts/sae_embed_loader.py:23`](../scripts/sae_embed_loader.py#L23) — `def resolve_arcface(models_dir: str, arcface: str \| None = None) -> str:`
- [`scripts/sae_gallery.py:171`](../scripts/sae_gallery.py#L171) — `if not _stamp_empty(embedder):`
- [`scripts/sae_gallery.py:200`](../scripts/sae_gallery.py#L200) — `for a in range(len(offset)):`
@@ -523,19 +552,20 @@ _None._
### IR-002
**Locations:** 5
**Locations:** 6
- [`src/config.hpp:20`](../src/config.hpp#L20) — `struct Config`
- [`src/main.cpp:272`](../src/main.cpp#L272) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/nodes/result_sink_node.hpp:49`](../src/nodes/result_sink_node.hpp#L49) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/nodes/result_sink_node.hpp:122`](../src/nodes/result_sink_node.hpp#L122) — `void write_output()`
- [`src/nodes/result_sink_node.hpp:161`](../src/nodes/result_sink_node.hpp#L161) — `struct ActorMeta { std::string name, imdb_id, tmdb_id, jellyfin_id; };`
- [`src/main.cpp:286`](../src/main.cpp#L286) — `reg_cfg, EvidenceDiscounter(same_person, disc_cfg));`
- [`src/nodes/result_sink_node.hpp:50`](../src/nodes/result_sink_node.hpp#L50) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/nodes/result_sink_node.hpp:123`](../src/nodes/result_sink_node.hpp#L123) — `void write_output()`
- [`src/nodes/result_sink_node.hpp:164`](../src/nodes/result_sink_node.hpp#L164) — `struct ActorMeta { std::string name, imdb_id, tmdb_id, jellyfin_id; };`
- [`src/track_registry.hpp:47`](../src/track_registry.hpp#L47) — `Unknown`
### IR-003
**Locations:** 1
- [`src/main.cpp:272`](../src/main.cpp#L272) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/main.cpp:286`](../src/main.cpp#L286) — `reg_cfg, EvidenceDiscounter(same_person, disc_cfg));`
### IR-004
@@ -543,10 +573,10 @@ _None._
- [`src/audio_bindings.cpp:3`](../src/audio_bindings.cpp#L3) — `Unknown`
- [`src/audio_signature.cpp:3`](../src/audio_signature.cpp#L3) — `Unknown`
- [`src/audio_signature.cpp:265`](../src/audio_signature.cpp#L265) — `std::vector<std::uint8_t> pack_frames(const std::vector<float>& mono)`
- [`src/audio_signature.cpp:320`](../src/audio_signature.cpp#L320) — `std::optional<std::string> signature_from_mono(const std::vector<float>& mono)`
- [`src/audio_signature.cpp:327`](../src/audio_signature.cpp#L327) — `std::optional<std::vector<float>> decode_centre_window(const std::string& path)`
- [`src/audio_signature.cpp:421`](../src/audio_signature.cpp#L421) — `std::optional<std::string> compute_signature(const std::string& path)`
- [`src/audio_signature.cpp:280`](../src/audio_signature.cpp#L280) — `std::vector<std::uint8_t> pack_frames(const std::vector<float>& mono)`
- [`src/audio_signature.cpp:335`](../src/audio_signature.cpp#L335) — `std::optional<std::string> signature_from_mono(const std::vector<float>& mono)`
- [`src/audio_signature.cpp:342`](../src/audio_signature.cpp#L342) — `std::optional<std::vector<float>> decode_centre_window(const std::string& path)`
- [`src/audio_signature.cpp:436`](../src/audio_signature.cpp#L436) — `std::optional<std::string> compute_signature(const std::string& path)`
- [`src/audio_signature.hpp:4`](../src/audio_signature.hpp#L4) — `Unknown`
- [`tests/test_audio_signature.cpp:3`](../tests/test_audio_signature.cpp#L3) — `Unknown`
- [`tests/test_audio_signature.cpp:129`](../tests/test_audio_signature.cpp#L129) — `Unknown`
@@ -565,7 +595,7 @@ _None._
**Locations:** 6
- [`src/audio_bindings.cpp:3`](../src/audio_bindings.cpp#L3) — `Unknown`
- [`src/audio_signature.cpp:421`](../src/audio_signature.cpp#L421) — `std::optional<std::string> compute_signature(const std::string& path)`
- [`src/audio_signature.cpp:436`](../src/audio_signature.cpp#L436) — `std::optional<std::string> compute_signature(const std::string& path)`
- [`src/audio_signature.hpp:4`](../src/audio_signature.hpp#L4) — `Unknown`
- [`tests/test_audio_signature.cpp:3`](../tests/test_audio_signature.cpp#L3) — `Unknown`
- [`tests/test_audio_signature.cpp:129`](../tests/test_audio_signature.cpp#L129) — `Unknown`
@@ -582,8 +612,8 @@ _None._
**Locations:** 8
- [`src/audio_signature.cpp:3`](../src/audio_signature.cpp#L3) — `Unknown`
- [`src/audio_signature.cpp:327`](../src/audio_signature.cpp#L327) — `std::optional<std::vector<float>> decode_centre_window(const std::string& path)`
- [`src/audio_signature.cpp:421`](../src/audio_signature.cpp#L421) — `std::optional<std::string> compute_signature(const std::string& path)`
- [`src/audio_signature.cpp:342`](../src/audio_signature.cpp#L342) — `std::optional<std::vector<float>> decode_centre_window(const std::string& path)`
- [`src/audio_signature.cpp:436`](../src/audio_signature.cpp#L436) — `std::optional<std::string> compute_signature(const std::string& path)`
- [`src/audio_signature.hpp:4`](../src/audio_signature.hpp#L4) — `Unknown`
- [`tests/test_audio_signature.cpp:3`](../tests/test_audio_signature.cpp#L3) — `Unknown`
- [`tests/test_audio_signature.cpp:201`](../tests/test_audio_signature.cpp#L201) — `TempWav w("short30");`
@@ -595,8 +625,8 @@ _None._
**Locations:** 7
- [`src/audio_signature.cpp:3`](../src/audio_signature.cpp#L3) — `Unknown`
- [`src/audio_signature.cpp:320`](../src/audio_signature.cpp#L320) — `std::optional<std::string> signature_from_mono(const std::vector<float>& mono)`
- [`src/audio_signature.cpp:421`](../src/audio_signature.cpp#L421) — `std::optional<std::string> compute_signature(const std::string& path)`
- [`src/audio_signature.cpp:335`](../src/audio_signature.cpp#L335) — `std::optional<std::string> signature_from_mono(const std::vector<float>& mono)`
- [`src/audio_signature.cpp:436`](../src/audio_signature.cpp#L436) — `std::optional<std::string> compute_signature(const std::string& path)`
- [`src/audio_signature.hpp:4`](../src/audio_signature.hpp#L4) — `Unknown`
- [`tests/test_audio_signature.cpp:3`](../tests/test_audio_signature.cpp#L3) — `Unknown`
- [`tests/test_audio_signature.cpp:129`](../tests/test_audio_signature.cpp#L129) — `Unknown`
@@ -610,7 +640,7 @@ _None._
### PR-002
**Locations:** 10
**Locations:** 11
- [`src/nodes/embedding_dump_node.hpp:2`](../src/nodes/embedding_dump_node.hpp#L2) — `Unknown`
- [`src/nodes/embedding_dump_node.hpp:18`](../src/nodes/embedding_dump_node.hpp#L18) — `Unknown`
@@ -618,6 +648,7 @@ _None._
- [`src/nodes/embedding_dump_node.hpp:159`](../src/nodes/embedding_dump_node.hpp#L159) — `void operator()(EmbeddedSceneFrame ef)`
- [`src/nodes/embedding_dump_node.hpp:261`](../src/nodes/embedding_dump_node.hpp#L261) — `H5::H5File file(path_, H5F_ACC_TRUNC);`
- [`scripts/optimizer/replay.py:5`](../scripts/optimizer/replay.py#L5) — `Reads an embedding dump (scripts/optimizer/SCHEMA.md), feeds each frame as an`
- [`scripts/optimizer/replay.py:212`](../scripts/optimizer/replay.py#L212) — `def build_minimal(annotations, movie, fps, cfg) -> dict:`
- [`scripts/optimizer/second_score.py:5`](../scripts/optimizer/second_score.py#L5) — `Unknown`
- [`scripts/validation/ground_truth.py:24`](../scripts/validation/ground_truth.py#L24) — `Unknown`
- [`experiments/xsource/resolution_sweep.py:4`](../experiments/xsource/resolution_sweep.py#L4) — `Unknown`
@@ -625,7 +656,7 @@ _None._
### PR-004
**Locations:** 22
**Locations:** 23
- [`src/backends/trt_backend.cpp:49`](../src/backends/trt_backend.cpp#L49) — `throw CudaError(std::string(what) + ": " + cudaGetErrorString(e));`
- [`src/benchmark.hpp:2`](../src/benchmark.hpp#L2) — `Unknown`
@@ -642,12 +673,13 @@ _None._
- [`src/benchmark.hpp:522`](../src/benchmark.hpp#L522) — `else if (c.in_fill_pct > 50.0)`
- [`src/config.hpp:35`](../src/config.hpp#L35) — `Unknown`
- [`src/main.cpp:3`](../src/main.cpp#L3) — `Unknown`
- [`src/main.cpp:109`](../src/main.cpp#L109) — `static std::shared_ptr<SceneBoundaries> scene_stats;`
- [`src/main.cpp:203`](../src/main.cpp#L203) — `int main(int argc, char** argv)`
- [`src/main.cpp:280`](../src/main.cpp#L280) — `Unknown`
- [`src/main.cpp:354`](../src/main.cpp#L354) — `std::lock_guard<std::mutex> lk(event_mtx);`
- [`src/main.cpp:380`](../src/main.cpp#L380) — `Unknown`
- [`src/main.cpp:393`](../src/main.cpp#L393) — `Unknown`
- [`src/main.cpp:115`](../src/main.cpp#L115) — `static std::shared_ptr<SceneBoundaries> scene_stats;`
- [`src/main.cpp:208`](../src/main.cpp#L208) — `int main(int argc, char** argv)`
- [`src/main.cpp:294`](../src/main.cpp#L294) — `Unknown`
- [`src/main.cpp:368`](../src/main.cpp#L368) — `std::lock_guard<std::mutex> lk(event_mtx);`
- [`src/main.cpp:394`](../src/main.cpp#L394) — `Unknown`
- [`src/main.cpp:407`](../src/main.cpp#L407) — `Unknown`
- [`src/scene_preview.cpp:147`](../src/scene_preview.cpp#L147) — `Unknown`
- [`tests/test_benchmark.cpp:3`](../tests/test_benchmark.cpp#L3) — `Unknown`
### SR-001
@@ -664,7 +696,7 @@ _None._
- [`src/gallery/gallery_builder.cpp:45`](../src/gallery/gallery_builder.cpp#L45) — `ActorGallery build_gallery(const BuildConfig& cfg)`
- [`src/gallery/gallery_calibration.hpp:80`](../src/gallery/gallery_calibration.hpp#L80) — `struct GalleryCalibrationStats`
- [`src/gallery/gallery_calibration.hpp:145`](../src/gallery/gallery_calibration.hpp#L145) — `std::vector<bool> actor_eligible(n_actors, false);`
- [`src/gallery/gallery_calibration.hpp:294`](../src/gallery/gallery_calibration.hpp#L294) — `Unknown`
- [`src/gallery/gallery_calibration.hpp:307`](../src/gallery/gallery_calibration.hpp#L307) — `Unknown`
- [`src/gallery/gallery_report.hpp:2`](../src/gallery/gallery_report.hpp#L2) — `Unknown`
- [`src/gallery/gallery_report.hpp:52`](../src/gallery/gallery_report.hpp#L52) — `struct GalleryBuildAudit`
- [`src/gallery/gallery_report.hpp:73`](../src/gallery/gallery_report.hpp#L73) — `struct GalleryReport`
@@ -677,21 +709,21 @@ _None._
- [`src/gallery/gallery_store.cpp:82`](../src/gallery/gallery_store.cpp#L82) — `H5::StrType str(H5::PredType::C_S1, H5T_VARIABLE);`
- [`src/gallery/gallery_store.cpp:167`](../src/gallery/gallery_store.cpp#L167) — `H5::DataSpace scalar(H5S_SCALAR);`
- [`src/gallery/gallery_store.cpp:219`](../src/gallery/gallery_store.cpp#L219) — `Unknown`
- [`src/gallery/track_gallery.hpp:49`](../src/gallery/track_gallery.hpp#L49) — `struct TrackGallery`
- [`src/gallery/track_gallery.hpp:84`](../src/gallery/track_gallery.hpp#L84) — `bool enabled() const { return enabled_; }`
- [`src/gallery/track_gallery.hpp:99`](../src/gallery/track_gallery.hpp#L99) — `const float* annex_row(int i) const`
- [`src/gallery/track_gallery.hpp:357`](../src/gallery/track_gallery.hpp#L357) — `static constexpr int kEmbDim = 512;`
- [`src/gallery/track_gallery.hpp:50`](../src/gallery/track_gallery.hpp#L50) — `struct TrackGallery`
- [`src/gallery/track_gallery.hpp:85`](../src/gallery/track_gallery.hpp#L85) — `bool enabled() const { return enabled_; }`
- [`src/gallery/track_gallery.hpp:100`](../src/gallery/track_gallery.hpp#L100) — `const float* annex_row(int i) const`
- [`src/gallery/track_gallery.hpp:380`](../src/gallery/track_gallery.hpp#L380) — `static constexpr int kEmbDim = 512;`
- [`src/inference/similarity.hpp:19`](../src/inference/similarity.hpp#L19) — `struct ISimilarityEngine`
- [`src/inference/similarity.hpp:39`](../src/inference/similarity.hpp#L39) — `virtual int n_gallery() const = 0;`
- [`src/kpn_bindings.cpp:186`](../src/kpn_bindings.cpp#L186) — `Unknown`
- [`src/kpn_bindings.cpp:236`](../src/kpn_bindings.cpp#L236) — `Unknown`
- [`src/main.cpp:230`](../src/main.cpp#L230) — `Unknown`
- [`src/kpn_bindings.cpp:183`](../src/kpn_bindings.cpp#L183) — `Unknown`
- [`src/kpn_bindings.cpp:233`](../src/kpn_bindings.cpp#L233) — `Unknown`
- [`src/main.cpp:235`](../src/main.cpp#L235) — `Unknown`
- [`src/nodes/embedding_dump_node.hpp:127`](../src/nodes/embedding_dump_node.hpp#L127) — `static constexpr std::string_view label() { return "embedding_dump"; }`
- [`src/nodes/embedding_dump_node.hpp:257`](../src/nodes/embedding_dump_node.hpp#L257) — `H5::H5File file(path_, H5F_ACC_TRUNC);`
- [`src/nodes/identity_matcher_node.hpp:43`](../src/nodes/identity_matcher_node.hpp#L43) — `struct IdentityMatcherFunc`
- [`src/nodes/identity_matcher_node.hpp:193`](../src/nodes/identity_matcher_node.hpp#L193) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`src/nodes/identity_matcher_node.hpp:316`](../src/nodes/identity_matcher_node.hpp#L316) — `private:`
- [`src/scene_preview.cpp:133`](../src/scene_preview.cpp#L133) — `int main(int argc, char** argv)`
- [`src/nodes/identity_matcher_node.hpp:60`](../src/nodes/identity_matcher_node.hpp#L60) — `struct IdentityMatcherFunc`
- [`src/nodes/identity_matcher_node.hpp:212`](../src/nodes/identity_matcher_node.hpp#L212) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`src/nodes/identity_matcher_node.hpp:328`](../src/nodes/identity_matcher_node.hpp#L328) — `private:`
- [`src/scene_preview.cpp:130`](../src/scene_preview.cpp#L130) — `int main(int argc, char** argv)`
- [`src/types.hpp:173`](../src/types.hpp#L173) — `struct Actor`
- [`tests/test_calibration.cpp:192`](../tests/test_calibration.cpp#L192) — `Embedding unit_axis(int slot)`
- [`tests/test_calibration.cpp:222`](../tests/test_calibration.cpp#L222) — `Unknown`
@@ -711,8 +743,8 @@ _None._
- [`tests/test_similarity.cpp:1`](../tests/test_similarity.cpp#L1) — `Unknown`
- [`tests/test_similarity.cpp:85`](../tests/test_similarity.cpp#L85) — `Unknown`
- [`tests/test_track_gallery.cpp:1`](../tests/test_track_gallery.cpp#L1) — `Unknown`
- [`tests/test_track_gallery.cpp:48`](../tests/test_track_gallery.cpp#L48) — `Embedding annex_view(const TrackGallery& tg, int row)`
- [`tests/test_track_gallery.cpp:341`](../tests/test_track_gallery.cpp#L341) — `TrackGallery tg(expand_cfg());`
- [`tests/test_track_gallery.cpp:54`](../tests/test_track_gallery.cpp#L54) — `Embedding annex_view(const TrackGallery& tg, int row)`
- [`tests/test_track_gallery.cpp:364`](../tests/test_track_gallery.cpp#L364) — `TrackGallery tg(expand_cfg());`
- [`scripts/filter_gallery.py:80`](../scripts/filter_gallery.py#L80) — `if actor_jellyfin_id(a) in cast_ids]`
- [`scripts/make_gallery.py:181`](../scripts/make_gallery.py#L181) — `Unknown`
- [`scripts/make_jellyfin_gallery.py:4`](../scripts/make_jellyfin_gallery.py#L4) — `Unknown`
@@ -726,7 +758,7 @@ _None._
- [`scripts/optimizer/optimize.py:202`](../scripts/optimizer/optimize.py#L202) — `if not Path(f["dump"]).exists():`
- [`scripts/optimizer/reembed_gallery.py:62`](../scripts/optimizer/reembed_gallery.py#L62) — `for i, a in enumerate(ref["actors"], 1):`
- [`scripts/optimizer/replay.py:125`](../scripts/optimizer/replay.py#L125) — `Unknown`
- [`scripts/optimizer/replay.py:265`](../scripts/optimizer/replay.py#L265) — `Unknown`
- [`scripts/optimizer/replay.py:306`](../scripts/optimizer/replay.py#L306) — `Unknown`
- [`scripts/run_from_jellyfin.py:4`](../scripts/run_from_jellyfin.py#L4) — `Unknown`
- [`scripts/sae_embed_loader.py:23`](../scripts/sae_embed_loader.py#L23) — `def resolve_arcface(models_dir: str, arcface: str \| None = None) -> str:`
- [`scripts/sae_gallery.py:171`](../scripts/sae_gallery.py#L171) — `if not _stamp_empty(embedder):`
@@ -736,23 +768,28 @@ _None._
### SR-002
**Locations:** 47
**Locations:** 62
- [`src/config.hpp:52`](../src/config.hpp#L52) — `Unknown`
- [`src/config.hpp:105`](../src/config.hpp#L105) — `Unknown`
- [`src/config.hpp:127`](../src/config.hpp#L127) — `Unknown`
- [`src/config.hpp:108`](../src/config.hpp#L108) — `Unknown`
- [`src/config.hpp:138`](../src/config.hpp#L138) — `Unknown`
- [`src/config.hpp:160`](../src/config.hpp#L160) — `Unknown`
- [`src/config.hpp:181`](../src/config.hpp#L181) — `Unknown`
- [`src/config.hpp:210`](../src/config.hpp#L210) — `Unknown`
- [`src/evidence_discount.hpp:2`](../src/evidence_discount.hpp#L2) — `Unknown`
- [`src/face_utils.hpp:2`](../src/face_utils.hpp#L2) — `Unknown`
- [`src/face_utils.hpp:147`](../src/face_utils.hpp#L147) — `Unknown`
- [`src/gallery/gallery_calibration.hpp:2`](../src/gallery/gallery_calibration.hpp#L2) — `Unknown`
- [`src/gallery/gallery_calibration.hpp:53`](../src/gallery/gallery_calibration.hpp#L53) — `float boundary_at(float p = 0.5f, float log_prior_odds = 0.f) const`
- [`src/main.cpp:97`](../src/main.cpp#L97) — `static constexpr std::size_t kSceneJoinDepth = 256;`
- [`src/main.cpp:255`](../src/main.cpp#L255) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/main.cpp:272`](../src/main.cpp#L272) — `reg_cfg, EvidenceDiscounter(same_person));`
- [`src/main.cpp:423`](../src/main.cpp#L423) — `std::ofstream bf(cfg.benchmark_path);`
- [`src/main.cpp:433`](../src/main.cpp#L433) — `Unknown`
- [`src/main.cpp:503`](../src/main.cpp#L503) — `return run_net(std::move(net));`
- [`src/main.cpp:535`](../src/main.cpp#L535) — `Unknown`
- [`src/kpn_bindings.cpp:273`](../src/kpn_bindings.cpp#L273) — `Unknown`
- [`src/main.cpp:103`](../src/main.cpp#L103) — `static constexpr std::size_t kSceneJoinDepth = 256;`
- [`src/main.cpp:260`](../src/main.cpp#L260) — `Unknown`
- [`src/main.cpp:268`](../src/main.cpp#L268) — `reg_cfg, EvidenceDiscounter(same_person, disc_cfg));`
- [`src/main.cpp:286`](../src/main.cpp#L286) — `reg_cfg, EvidenceDiscounter(same_person, disc_cfg));`
- [`src/main.cpp:437`](../src/main.cpp#L437) — `std::ofstream bf(cfg.benchmark_path);`
- [`src/main.cpp:447`](../src/main.cpp#L447) — `Unknown`
- [`src/main.cpp:517`](../src/main.cpp#L517) — `return run_net(std::move(net));`
- [`src/main.cpp:549`](../src/main.cpp#L549) — `Unknown`
- [`src/nodes/camera_position_change_detector_node.hpp:30`](../src/nodes/camera_position_change_detector_node.hpp#L30) — `struct CameraPositionChangeDetectorFunc`
- [`src/nodes/embedder_node.hpp:21`](../src/nodes/embedder_node.hpp#L21) — `struct EmbedderFunc`
- [`src/nodes/embedding_dump_node.hpp:181`](../src/nodes/embedding_dump_node.hpp#L181) — `Unknown`
@@ -762,21 +799,29 @@ _None._
- [`src/nodes/face_detector_node.hpp:26`](../src/nodes/face_detector_node.hpp#L26) — `explicit FaceDetectorFunc(const Config& cfg)`
- [`src/nodes/face_detector_node.hpp:64`](../src/nodes/face_detector_node.hpp#L64) — `private:`
- [`src/nodes/face_tracker_node.hpp:2`](../src/nodes/face_tracker_node.hpp#L2) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:124`](../src/nodes/identity_matcher_node.hpp#L124) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:132`](../src/nodes/identity_matcher_node.hpp#L132) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:173`](../src/nodes/identity_matcher_node.hpp#L173) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`src/nodes/identity_matcher_node.hpp:280`](../src/nodes/identity_matcher_node.hpp#L280) — `Unknown`
- [`src/nodes/result_sink_node.hpp:49`](../src/nodes/result_sink_node.hpp#L49) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/nodes/result_sink_node.hpp:63`](../src/nodes/result_sink_node.hpp#L63) — `void set_pre_write_hook(std::function<void(double)> fn) { pre_write_ = std::move(fn); }`
- [`src/nodes/result_sink_node.hpp:161`](../src/nodes/result_sink_node.hpp#L161) — `struct ActorMeta { std::string name, imdb_id, tmdb_id, jellyfin_id; };`
- [`src/nodes/frame_annotation_node.hpp:2`](../src/nodes/frame_annotation_node.hpp#L2) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:29`](../src/nodes/identity_matcher_node.hpp#L29) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:109`](../src/nodes/identity_matcher_node.hpp#L109) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:143`](../src/nodes/identity_matcher_node.hpp#L143) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:151`](../src/nodes/identity_matcher_node.hpp#L151) — `const GalleryCalibration& calibration() const { return cal_; }`
- [`src/nodes/identity_matcher_node.hpp:192`](../src/nodes/identity_matcher_node.hpp#L192) — `std::vector<float> host_query(static_cast<size_t>(kMaxFaces) * 512);`
- [`src/nodes/identity_matcher_node.hpp:250`](../src/nodes/identity_matcher_node.hpp#L250) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:285`](../src/nodes/identity_matcher_node.hpp#L285) — `Unknown`
- [`src/nodes/result_sink_node.hpp:50`](../src/nodes/result_sink_node.hpp#L50) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/nodes/result_sink_node.hpp:64`](../src/nodes/result_sink_node.hpp#L64) — `void set_pre_write_hook(std::function<void(double)> fn) { pre_write_ = std::move(fn); }`
- [`src/nodes/result_sink_node.hpp:164`](../src/nodes/result_sink_node.hpp#L164) — `struct ActorMeta { std::string name, imdb_id, tmdb_id, jellyfin_id; };`
- [`src/nodes/scene_boundary_annotator_node.hpp:2`](../src/nodes/scene_boundary_annotator_node.hpp#L2) — `Unknown`
- [`src/nodes/scene_detector_node.hpp:36`](../src/nodes/scene_detector_node.hpp#L36) — `static constexpr std::string_view label() { return "scene_detector"; }`
- [`src/nodes/scene_detector_node.hpp:70`](../src/nodes/scene_detector_node.hpp#L70) — `void operator()(Frame f)`
- [`src/nodes/scene_detector_node.hpp:93`](../src/nodes/scene_detector_node.hpp#L93) — `Unknown`
- [`src/nodes/scene_detector_node.hpp:147`](../src/nodes/scene_detector_node.hpp#L147) — `void flush_remaining()`
- [`src/nodes/scene_detector_node.hpp:181`](../src/nodes/scene_detector_node.hpp#L181) — `void write_output()`
- [`src/nodes/scene_detector_node.hpp:147`](../src/nodes/scene_detector_node.hpp#L147) — `Unknown`
- [`src/nodes/scene_detector_node.hpp:152`](../src/nodes/scene_detector_node.hpp#L152) — `Unknown`
- [`src/nodes/scene_detector_node.hpp:188`](../src/nodes/scene_detector_node.hpp#L188) — `void write_output()`
- [`src/scene_boundaries.hpp:2`](../src/scene_boundaries.hpp#L2) — `Unknown`
- [`src/scene_boundaries.hpp:30`](../src/scene_boundaries.hpp#L30) — `public:`
- [`src/scene_preview.cpp:147`](../src/scene_preview.cpp#L147) — `Unknown`
- [`src/track_registry.hpp:2`](../src/track_registry.hpp#L2) — `Unknown`
- [`src/track_registry.hpp:47`](../src/track_registry.hpp#L47) — `Unknown`
- [`src/types.hpp:62`](../src/types.hpp#L62) — `struct DetectedFace`
- [`tests/test_calibration.cpp:1`](../tests/test_calibration.cpp#L1) — `Unknown`
- [`tests/test_embedding_dump.cpp:1`](../tests/test_embedding_dump.cpp#L1) — `Unknown`
@@ -784,34 +829,41 @@ _None._
- [`tests/test_face_tracker.cpp:1`](../tests/test_face_tracker.cpp#L1) — `Unknown`
- [`tests/test_face_utils.cpp:1`](../tests/test_face_utils.cpp#L1) — `Unknown`
- [`tests/test_scene_detector_node.cpp:4`](../tests/test_scene_detector_node.cpp#L4) — `Unknown`
- [`scripts/ci/check_raw_cosine.py:4`](../scripts/ci/check_raw_cosine.py#L4) — `Unknown`
- [`scripts/optimizer/replay.py:66`](../scripts/optimizer/replay.py#L66) — `for i in range(len(ts)):`
- [`scripts/optimizer/replay.py:262`](../scripts/optimizer/replay.py#L262) — `Unknown`
### SR-003
**Locations:** 7
**Locations:** 8
- [`src/audio_bindings.cpp:3`](../src/audio_bindings.cpp#L3) — `Unknown`
- [`src/audio_signature.cpp:3`](../src/audio_signature.cpp#L3) — `Unknown`
- [`src/audio_signature.hpp:4`](../src/audio_signature.hpp#L4) — `Unknown`
- [`src/config.hpp:20`](../src/config.hpp#L20) — `struct Config`
- [`src/nodes/result_sink_node.hpp:2`](../src/nodes/result_sink_node.hpp#L2) — `Unknown`
- [`src/nodes/result_sink_node.hpp:49`](../src/nodes/result_sink_node.hpp#L49) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/nodes/result_sink_node.hpp:122`](../src/nodes/result_sink_node.hpp#L122) — `void write_output()`
- [`src/nodes/result_sink_node.hpp:50`](../src/nodes/result_sink_node.hpp#L50) — `static constexpr std::string_view label() { return "result_sink"; }`
- [`src/nodes/result_sink_node.hpp:123`](../src/nodes/result_sink_node.hpp#L123) — `void write_output()`
- [`src/track_registry.hpp:47`](../src/track_registry.hpp#L47) — `Unknown`
### SR-005
**Locations:** 11
**Locations:** 15
- [`src/config.hpp:171`](../src/config.hpp#L171) — `Unknown`
- [`src/config.hpp:245`](../src/config.hpp#L245) — `Unknown`
- [`src/gallery/gallery_store.hpp:15`](../src/gallery/gallery_store.hpp#L15) — `Unknown`
- [`src/gallery/track_gallery.hpp:155`](../src/gallery/track_gallery.hpp#L155) — `void forget(int track_id) { tracks_.erase(track_id); }`
- [`src/gallery/track_gallery.hpp:165`](../src/gallery/track_gallery.hpp#L165) — `void set_calibration(std::function<float(float)> c) { calibrate_ = std::move(c); }`
- [`src/gallery/track_gallery.hpp:196`](../src/gallery/track_gallery.hpp#L196) — `struct TrackState`
- [`src/gallery/track_gallery.hpp:309`](../src/gallery/track_gallery.hpp#L309) — `static int plurality_actor(const TrackState& ts)`
- [`src/nodes/identity_matcher_node.hpp:117`](../src/nodes/identity_matcher_node.hpp#L117) — `std::vector<float> host_gallery(static_cast<size_t>(n_gallery_) * 512);`
- [`src/nodes/identity_matcher_node.hpp:154`](../src/nodes/identity_matcher_node.hpp#L154) — `MatchedSceneFrame operator()(TrackedSceneFrame tf)`
- [`src/nodes/identity_matcher_node.hpp:293`](../src/nodes/identity_matcher_node.hpp#L293) — `Unknown`
- [`src/gallery/track_gallery.hpp:136`](../src/gallery/track_gallery.hpp#L136) — `Unknown`
- [`src/gallery/track_gallery.hpp:161`](../src/gallery/track_gallery.hpp#L161) — `Unknown`
- [`src/gallery/track_gallery.hpp:183`](../src/gallery/track_gallery.hpp#L183) — `void set_owner(int track_id, int actor_idx)`
- [`src/gallery/track_gallery.hpp:193`](../src/gallery/track_gallery.hpp#L193) — `void set_owner(int track_id, int actor_idx)`
- [`src/gallery/track_gallery.hpp:233`](../src/gallery/track_gallery.hpp#L233) — `struct TrackState`
- [`src/gallery/track_gallery.hpp:331`](../src/gallery/track_gallery.hpp#L331) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:136`](../src/nodes/identity_matcher_node.hpp#L136) — `std::vector<float> host_gallery(static_cast<size_t>(n_gallery_) * 512);`
- [`src/nodes/identity_matcher_node.hpp:173`](../src/nodes/identity_matcher_node.hpp#L173) — `MatchedSceneFrame operator()(TrackedSceneFrame tf)`
- [`src/nodes/identity_matcher_node.hpp:295`](../src/nodes/identity_matcher_node.hpp#L295) — `Unknown`
- [`src/nodes/identity_matcher_node.hpp:314`](../src/nodes/identity_matcher_node.hpp#L314) — `Unknown`
- [`tests/test_track_gallery.cpp:1`](../tests/test_track_gallery.cpp#L1) — `Unknown`
- [`tests/test_track_gallery.cpp:414`](../tests/test_track_gallery.cpp#L414) — `TrackGallery tg(expand_cfg());`
- [`scripts/make_jellyfin_gallery.py:4`](../scripts/make_jellyfin_gallery.py#L4) — `Unknown`
### UT-001
@@ -841,10 +893,11 @@ _None._
### UT-005
**Locations:** 2
**Locations:** 3
- [`tests/test_track_gallery.cpp:1`](../tests/test_track_gallery.cpp#L1) — `Unknown`
- [`tests/test_track_gallery.cpp:341`](../tests/test_track_gallery.cpp#L341) — `TrackGallery tg(expand_cfg());`
- [`tests/test_track_gallery.cpp:364`](../tests/test_track_gallery.cpp#L364) — `TrackGallery tg(expand_cfg());`
- [`tests/test_track_gallery.cpp:414`](../tests/test_track_gallery.cpp#L414) — `TrackGallery tg(expand_cfg());`
### UT-101
@@ -1052,6 +1105,12 @@ _None._
- [`src/nodes/embedding_dump_node.hpp:159`](../src/nodes/embedding_dump_node.hpp#L159) — `void operator()(EmbeddedSceneFrame ef)`
- [`src/nodes/embedding_dump_node.hpp:261`](../src/nodes/embedding_dump_node.hpp#L261) — `H5::H5File file(path_, H5F_ACC_TRUNC);`
### VR-011
**Locations:** 1
- [`scripts/optimizer/replay.py:212`](../scripts/optimizer/replay.py#L212) — `def build_minimal(annotations, movie, fps, cfg) -> dict:`
### VR-013
**Locations:** 2
@@ -1083,21 +1142,11 @@ _None._
- [`src/benchmark.hpp:472`](../src/benchmark.hpp#L472) — `void print(std::ostream& os, double film_sec) const`
- [`src/benchmark.hpp:522`](../src/benchmark.hpp#L522) — `else if (c.in_fill_pct > 50.0)`
- [`src/config.hpp:35`](../src/config.hpp#L35) — `Unknown`
- [`src/main.cpp:109`](../src/main.cpp#L109) — `static std::shared_ptr<SceneBoundaries> scene_stats;`
- [`src/main.cpp:203`](../src/main.cpp#L203) — `int main(int argc, char** argv)`
- [`src/main.cpp:280`](../src/main.cpp#L280) — `Unknown`
- [`src/main.cpp:354`](../src/main.cpp#L354) — `std::lock_guard<std::mutex> lk(event_mtx);`
- [`src/main.cpp:380`](../src/main.cpp#L380) — `Unknown`
- [`src/main.cpp:393`](../src/main.cpp#L393) — `Unknown`
- [`src/main.cpp:115`](../src/main.cpp#L115) — `static std::shared_ptr<SceneBoundaries> scene_stats;`
- [`src/main.cpp:208`](../src/main.cpp#L208) — `int main(int argc, char** argv)`
- [`src/main.cpp:294`](../src/main.cpp#L294) — `Unknown`
- [`src/main.cpp:368`](../src/main.cpp#L368) — `std::lock_guard<std::mutex> lk(event_mtx);`
- [`src/main.cpp:394`](../src/main.cpp#L394) — `Unknown`
- [`src/main.cpp:407`](../src/main.cpp#L407) — `Unknown`
- [`tests/test_benchmark.cpp:3`](../tests/test_benchmark.cpp#L3) — `Unknown`
## Tag diagnostics
**Groups mixing requirement types (pipe separates types):**
- `src/benchmark.hpp:176` — {'group': ['VR-015', 'AR-004']}
- `src/benchmark.hpp:472` — {'group': ['VR-015', 'AR-004']}
- `src/benchmark.hpp:522` — {'group': ['VR-015', 'AR-004']}
- `src/main.cpp:109` — {'group': ['VR-015', 'AR-004']}
- `src/main.cpp:380` — {'group': ['VR-015', 'AR-004']}
+11 -6
View File
@@ -18,8 +18,13 @@ worse than one with a stated scope:
(a) have its result consumed immediately by a calibration -- the call is
textually wrapped in `cal_(...)`, `calibrate_(...)`, `.probability(...)`
or similar; or
(b) sit under an `EXCEPTION: AR-024 <reason>` comment within
EXCEPTION_SCOPE_LINES above it.
(b) sit under an exception comment -- the token is `EXCEPTION:` followed by
`AR-024` and a reason -- within EXCEPTION_SCOPE_LINES above it.
Note that this file deliberately never spells that token out. The traceability
extractor scans scripts/ as source, so prose here describing the tag would be
counted as recorded exceptions; four of them were, until this was noticed. The
same trap the shared config warns about for the vendored parser tests.
Anything else is a defect, per CLAUDE.md: "treat any bare cosine comparison in
the code as a defect to be fixed".
@@ -45,7 +50,7 @@ import pathlib
import re
import sys
# How far above a use an `EXCEPTION: AR-024` tag may sit and still cover it.
# How far above a use an exception tag may sit and still cover it.
# Generous, because the house style puts a paragraph of reasoning between the
# tag and the code -- but bounded, so a tag cannot silently cover a whole file.
EXCEPTION_SCOPE_LINES = 25
@@ -80,7 +85,7 @@ CALIBRATED = re.compile(
r"cosine_similarity\s*\("
)
EXCEPTION_TAG = re.compile(r"EXCEPTION:\s*AR-024\b(.*)")
EXCEPTION_TAG = re.compile(r"EXCEPT" + r"ION:\s*AR-" + r"024\b(.*)")
# The function's own definition is not a use of it.
DEFINITION = re.compile(r"^\s*(?:inline\s+|static\s+|constexpr\s+)*float\s+"
@@ -109,7 +114,7 @@ def iter_sources(root: pathlib.Path, roots):
def covering_exception(lines, idx):
"""Return the reason text of an EXCEPTION: AR-024 tag covering line `idx`."""
"""Return the reason text of an exception tag covering line `idx`."""
lo = max(0, idx - EXCEPTION_SCOPE_LINES)
for j in range(idx, lo - 1, -1):
m = EXCEPTION_TAG.search(lines[j])
@@ -208,7 +213,7 @@ def main():
print("\nEither route it through the calibration, or, if the use is")
print("genuinely about the metric space rather than about a decision,")
print("record it:")
print(" // EXCEPTION: AR-024 <why this one is not a decision>")
print(" // " + "EXCEPT" + "ION: AR-" + "024 <why this one is not a decision>")
print("and add a row to CLAUDE.md's agreed-exceptions table.")
return 1
+1 -1
View File
@@ -144,7 +144,7 @@ int main(int argc, char** argv) {
FaceDetectorFunc detector_fn{cfg};
FaceAlignerFunc aligner_fn;
EmbedderFunc embedder_fn{cfg};
/// TRACES: DP-001, AR-007, AR-012, AR-024 | PR-004, SR-002
/// TRACES: AR-007, AR-012, AR-024 | DP-001 | SR-002 | PR-004
// Construction order matters and is the same as main.cpp's, deliberately:
// the matcher fits (or loads) the calibration, the registry needs a
// discounter built from it, and the tracker needs both. DP-001 says modes