fix(anpr): sliding poll window so a car arriving mid-loop isn't lost
A loop started by a far/early car would (a) give up before the REAL car settled at the barrier, and (b) swallow the real car's pushes (the #polling guard dropped them). So a confident-but-wrong far-car plate could win, or the intended car get debounced out after the loop ended — wrong car acted on, right car blocked. Fix: a push that JOINS a running loop now EXTENDS the deadline (lastPush + ANPR_POLL_WINDOW_MS) instead of being dropped, capped at start + ANPR_POLL_MAX_MS (30s) so a continuously-busy lane can't slide forever. Each tick still pulls a FRESH frame, so the loop tracks whoever is at the barrier NOW, not the car that started it. Per-camera sliding deadline in #pollDeadline (cleared with #polling in finally). +1 test (push mid-poll keeps the loop alive past the initial deadline); 171 server tests green. New knob ANPR_POLL_MAX_MS documented in the komodo env reference + the two concurrency guards written up in lane-presence-and-anpr-entry. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -79,6 +79,19 @@ Two new env knobs: `VISION_ENTRY_MIN_CONFIDENCE` (0.85), `ANPR_DEBOUNCE_MS` (12_
|
||||
> on the DS-2CD1047G3H-LIU (whose alarm fires on approach, not at the readable moment — see
|
||||
> [[lpr-camera]] "auto-enter but don't auto-exit"). Still advisory + fail-soft; a barrier never
|
||||
> opens on a low-confidence read.
|
||||
>
|
||||
> **Two concurrency guards on the loop** (the edges a single push-triggered loop creates):
|
||||
> 1. **Credential-mid-poll abort.** If the subscriber scans their card/QR at the reader DURING the
|
||||
> loop, they've already transacted — the bridge watches their `openOccurrenceCount` (baselined
|
||||
> once a frame reads the bound plate) and **aborts without emitting** if it moves, so it never
|
||||
> double-acts (which would exit the NEXT open occurrence — bad for a fleet sub).
|
||||
> 2. **SLIDING window for a different car arriving mid-poll.** A loop started by a far/early car
|
||||
> must not (a) give up before the REAL car settles, nor (b) swallow the real car's pushes. So a
|
||||
> push that joins a running loop **extends the deadline** (`lastPush + ANPR_POLL_WINDOW_MS`),
|
||||
> capped at `start + ANPR_POLL_MAX_MS` (30s) so a continuously-busy lane can't slide forever.
|
||||
> Because each tick pulls a FRESH frame, the loop naturally tracks whoever is at the barrier
|
||||
> *now*, not the car that started it. (Knobs: `ANPR_POLL_MS`, `ANPR_POLL_WINDOW_MS`,
|
||||
> `ANPR_POLL_MAX_MS`.)
|
||||
|
||||
The goal (narrowed deliberately — see Rejected below): **a subscriber's plate, read by the lane
|
||||
camera, admits them through the same gated flow a QR/card scan uses.** Scope was cut to subscribers
|
||||
|
||||
Reference in New Issue
Block a user