Commit Graph
2 Commits
Author SHA1 Message Date
dtourolle 88c42573a5 fix(pipeline): finish three changes that had only been half applied
Each of these was recorded as done and was done in one place out of two.

AR-011 -- the TransNetV2 dedup window. The derived window
(dedup_window_sec, median observed interval halved) 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 it "matches the dedup scenes.json applies, so the two
views agree". They did not agree. 0.04 is one frame at 25 fps and wider
than a frame at 30, so two cuts on consecutive frames merged into one
and the loss was invisible: the pipeline simply saw fewer boundaries.
The detector now supplies the window it derived.

AR-019 -- ownership. The register says ownership "comes from the
registry, not a second local tally". Both existed: promotion fired on a
local accepted-frame count and fell back to a local per-actor plurality
when the registry had not yet claimed the track. That fallback was
reachable in the live pipeline, not just in tests -- three accepted
frames arrive well before a posterior crosses the ownership threshold --
so in practice the plurality usually decided, and it could not see the
AR-025 correlation discounting it was meant to defer to. The tally is
gone; promotion now requires the registry's verdict, with the accepted
-frame count demoted to an explicit evidence floor.

AR-017 -- the route. DeadTrack carried belief but no route, and the sink
wrote the literal string "live", so a field the schema publishes could
not distinguish anything. AR-017's own verification asks for "deferred
and pooled routes distinguishable". Route is now an enum on the claim.
Only `live` occurs today; `deferred` exists so AR-020's pass has
somewhere to write instead of a serialisation change to make.

Also: TrackGallery::forget had no callers, under a comment asserting the
matcher called it "on a cut or track disappearance". The cut half was
true by another route; the disappearance half was not, so a track that
died quietly kept its diversity buffer until the next cut cleared
everything. Replaced with prune_dead against the registry's own
liveness, the same shape as the tracker's prune_boxes -- a second
opinion about which tracks exist is a second thing that can be wrong.

Removes dead logistic/logit helpers and fixes five TRACES tags that used
a comma where a pipe separates requirement types, which the gate had
been reporting as diagnostics.

TRACES: AR-011, AR-017, AR-019 | IR-002 | SR-002, SR-005
2026-08-05 17:33:12 +02:00
dtourolleandClaude Opus 5 13bdc27566 feat: join the decode butterfly so scene boundaries reach the face branch
AR-010 — is_scene_boundary had no producer: SceneDetectorFunc was a terminal
sink writing scenes.json and never annotating the frames flowing to face
detection. The flag was permanently false, so the boundary half of AR-007's
frame-dependent association was dead code that a test could still exercise
synthetically and appear to verify.

The topology already forks after decode — dense frames to TransNetV2, sampled
frames to face detection — so this is a fork-join. SceneBoundaries is the join:
the detector publishes each window's verdict with a watermark, and an annotator
on the sampled branch stamps the flag.

The watermark is the part that matters. TransNetV2 buffers 100 frames before it
can score any of them, so at any instant it has an opinion up to some time T and
none after. Without recording T a consumer cannot tell "no boundary" from "not
scored yet", and those demand opposite behaviour — treating unscored frames as
boundary-free is exactly what makes a downstream check pass while verifying
nothing.

Buffering alone does not work, which was my first attempt. Channel depth creates
lag only when the consumer is slower, and the face branch runs four orders of
magnitude faster per frame than TransNetV2 (0.01ms vs 400ms), so its channels
drain instantly and no lag accumulates. Measured: 106 of 364 frames outran the
detector. The annotator therefore waits on the watermark explicitly. The
detector signals completion so the tail cannot deadlock, and publishes from
flush_remaining too — without that the final frames arrive with no verdict.

Boundaries are deduped on publish, matching what scenes.json does at write time.
A run of adjacent high-scoring frames is one boundary, not several; leaving them
raw made this view report 357 where the file said 13. Now the two agree exactly.

Frames past the detector's last scored window remain unverified and are counted
as such rather than silently marked boundary-free.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

TRACES: AR-007, AR-010 | SR-002
2026-07-31 14:56:38 +02:00