You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A mask camera that stops (or never starts) streaming stalls the reduced-mode side average until scan stop; abort the scan instead #298
SideAverageStage (omotion/pipeline/stages/side_avg.py) emits corrected side-average frames (cam_id=-1, the "final" channel) only below a cross-camera watermark. _watermark returns None until every mask-enabled camera has closed a corrected interval, then the MIN over cameras of their progress (right_abs of each camera's last closed interval).
A mask camera that never streams keeps the watermark at None for the whole scan.
A camera that dies mid-scan freezes its progress; the watermark stalls from that point.
Every later side-average frame piles up in self._frames[side] and is emitted only by on_scan_stop. In reduced (clinical) mode ScanDBSink persists only the cam_id=-1 rows, so the side's persisted clinical record is empty until stop:
a crash or power loss mid-scan loses all of it;
memory grows with scan length;
stop does one large burst write.
The _watermark docstring already admits the never-streams case.
Detection already exists, but nothing acts on it
ClassifyStage._track_camera_delivery emits CameraStreamGap(state="missing") after a mask camera is absent from 9 consecutive packets on its side, and "resumed" when it returns. This covers both the never-started and the died-mid-scan cases. The CameraStreamGap docstring says a "prolonged-loss watchdog remains responsible for stopping the scan", but no such watchdog exists in the SDK.
Proposed fix
Abort the scan when a mask camera stays missing longer than a limit, rather than trying to keep averaging without it:
Add ScanRequest.camera_dropout_abort_s: float | None. Default 5 s for clinical scans; None turns it off. run_collection_scan (calibration and contact-quality sub-scans) passes None, because those collectors do their own per-camera judgement.
Watch CameraStreamGap events on the diagnostics channel, and trip the existing abort path used for a mid-scan disconnect (_scan_abort_reason, _stop_evt). The normal teardown then runs, and on_scan_stop flushes the buffered side average, so the database keeps the record up to the abort point.
Report the reason (for example left cam 3 delivered no frames for 5.0 s) through last_scan_error and ScanRequest.on_error.
An abort puts a ~5 s bound on the watermark stall, so the alternative (drop cameras lagging the leader from the watermark via stale_lag_frames) is on hold.
Draft PR is up: #299 (feature/298-camera-dropout-abort → next).
Abort, not a relaxed watermark. The classifier emits one CameraDropoutTimeout per camera once it has been missing for camera_dropout_abort_s of packet time. A watchdog sink then stops the scan through the existing _stop_evt path. Data up to the abort is flushed and persisted, and the scan reports a CameraDropoutError (side, camera, never-delivered vs stopped) via last_scan_error / on_error.
Defaults. 5 s for clinical scans; off (None) in run_collection_scan sub-scans. The stale_lag_frames watermark alternative is on hold, since the abort bounds the stall.
Tests. New unit tests fail against next and pass with the change. Not yet verified on hardware; the bench check is in the PR body.
Tracking. Adding this issue to Project Evt2 #11 and setting source = claude still needs doing by hand: no Projects API was available in this session.
Activity
boringethan commentedon Sep 30, 2026
Draft PR is up: #299 (
feature/298-camera-dropout-abort→next).CameraDropoutTimeoutper camera once it has been missing forcamera_dropout_abort_sof packet time. A watchdog sink then stops the scan through the existing_stop_evtpath. Data up to the abort is flushed and persisted, and the scan reports aCameraDropoutError(side, camera, never-delivered vs stopped) vialast_scan_error/on_error.None) inrun_collection_scansub-scans. Thestale_lag_frameswatermark alternative is on hold, since the abort bounds the stall.nextand pass with the change. Not yet verified on hardware; the bench check is in the PR body.source = claudestill needs doing by hand: no Projects API was available in this session.Generated by Claude Code