Commit graph

6 commits

Author SHA1 Message Date
유창욱
f7266f5980 fix(edge): identity-aware GHOST dedup keyed on track_id (FIX 4)
edge/engine.py keyed the ghost cooldown as
(GHOST, round(x), round(y)) — purely spatial, ignoring track identity.
Two distinct workers collapsing at ~the same pixel within the cooldown
window would suppress each other's ghost event, potentially masking a
second CRITICAL incident.

edge/detectors/ghost.py GhostIncidentDetector.update now includes the
candidate's track_id in each emitted dict. edge/engine.py keys the
cooldown as (EventType.GHOST, track_id) and sets the emitted Event's
track_id accordingly, matching how FALL/NO_MOTION/IMMOBILITY/zone events
are already keyed per-track.

Tests: tests/test_ghost.py asserts ghosts[0]["track_id"] == 1 on the
existing reappear-timeout test.
2026-07-11 22:17:48 +09:00
유창욱
3240428380 fix(edge): require sustained non-prone before FallDetector recover (FIX 2)
edge/detectors/fall.py update(): a single frame where prone was false while
state was in {FALLING, FALLEN, NO_MOTION} immediately emitted "recover" and
reset _State. One jittery frame (a momentary pose-estimation miss) could
wipe an in-progress CRITICAL no_motion incident.

Add FallConfig.recover_grace_s (default 1.0s) and _State.not_prone_since.
On the first non-prone frame while in an incident state, start the grace
timer instead of recovering immediately; only reset to STANDING once
recover_grace_s of sustained non-prone has elapsed. A re-prone frame while
in an incident state clears the pending grace timer (cancels the recover
attempt). The non-incident STANDING path is unchanged.

BEHAVIOR CHANGE: recover now requires recover_grace_s of sustained
non-prone instead of firing on a single frame.

Tests: test_recovery_clears_state (tests/test_fall.py) strengthened per
review brief to assert a single standing frame does NOT recover but
sustained standing across the grace window does. Added
test_single_noisy_nonprone_frame_does_not_cancel_no_motion covering the
life-safety scenario: one noisy non-prone frame during NO_MOTION must not
cancel the incident.
2026-07-11 22:15:47 +09:00
유창욱
406c0f5b6c feat(edge): ZoneIntrusionDetector (foot-anchor point-in-polygon, debounce) 2026-07-11 21:05:42 +09:00
유창욱
3bcfdea11d feat(edge): GhostIncidentDetector (collapse-then-occluded spatial incident) 2026-07-11 20:59:31 +09:00
유창욱
bd170c4803 feat(edge): ImmobilityWatchdog (posture-independent prolonged immobility) 2026-07-11 20:51:33 +09:00
유창욱
5545b26779 feat(edge): FallDetector state machine (OR-logic, baseline freeze, post-fall no-motion) 2026-07-11 20:41:11 +09:00