Files
ruvnet--RuView/v2
ruv a0226392d0 fix(calibration): PresenceSpecialist reads empty room as present when occ_var < empty_var (#1440)
PresenceSpecialist::train() set its variance decision threshold to the
midpoint between empty-room and occupied-anchor variance, assuming
occupied windows are always noisier than the empty baseline. A still,
quiet occupant can measure LESS variance than an empty room's own
ambient/interference noise floor -- in that case the midpoint sits
BELOW the empty-room baseline itself, so a genuinely empty room reads
"present" on every single frame, at nonzero confidence.

This matches a secondary finding from issue #1440's controlled
reproduction: after room calibration (train_empty_room/
train_still_presence/train_walking/train_active_movement), a known-
empty room read "present" 31/31 frames. The reporter's primary finding
(raw-CSI amplitude-only presence sits at chance, AUC ~= 0.576, once
time-of-day is controlled) is a genuine sensing-difficulty result, not
a code bug, and is already addressed by the maintainer's prior comment
pointing to this per-room calibration path -- this fix addresses the
part of the report that IS a code bug: the calibration path itself
mis-behaving on presence classification, worse than chance (constant
wrong answer) rather than merely noisy.

Fix: only trust the variance channel when occupied variance exceeds
the empty baseline by a margin (VARIANCE_SEPARATION_MARGIN = 5%);
otherwise disable it (threshold = +inf), mirroring how the mean-shift
channel already goes inert when the anchors' means don't separate.
Also fixed a latent confidence-scoring bug this exposed: an infinite
threshold previously drove the variance confidence term to a spurious
1.0 via `(x - inf).abs() / span`, which would have overstated
confidence in a disabled channel's "vote".

Added `presence_inverted_variance_never_reports_empty_room_as_present`,
pinning the exact scenario (occ_var < empty_var, identical means, no
mean-shift channel to fall back on) that isolates the variance-only
bug. All 64 existing + new tests pass, 0 regressions.

Fixes #1440

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-07-27 10:40:14 -04:00
..