Expand description
Durable perception fan-out drainer.
Detection ingest fans a committed batch out to consumers (zones / ANPR / movement) AFTER the
transaction commits — so a process crash between commit and fan-out would drop the consumer
notification entirely. This loop closes that gap: it periodically replays any outbox batch whose
fanned_out_at is still NULL (a batch that was committed but never fully fanned out), rebuilding
the batch from the persisted detections and driving the consumers.
Replay is safe because [consumer::fan_out] claims each (consumer, camera_id, frame_id)
at-most-once via consumer_fanout: a consumer that already processed a frame is skipped, so a
replay never double-drives it. Only batches with a frame_id (the worker’s idempotency key) are
replayable; batches without one are inline-only.