Skip to content

Merge #491: feat(sensing-server): adaptive person count — RollingP95 + dedup_factor (integration on schwarztim's behalf)#633

Merged
ruvnet merged 2 commits into
mainfrom
integrate/pr-491-adaptive-person-count
May 19, 2026
Merged

Merge #491: feat(sensing-server): adaptive person count — RollingP95 + dedup_factor (integration on schwarztim's behalf)#633
ruvnet merged 2 commits into
mainfrom
integrate/pr-491-adaptive-person-count

Conversation

@ruvnet

@ruvnet ruvnet commented May 19, 2026

Copy link
Copy Markdown
Owner

Integration PR for #491 (@schwarztim's adaptive person count work).

The original PR #491 had fallen out-of-date with current main (5+ weeks of churn). A direct rebase silently dropped the PR's commits when applied against origin/main. Applying as an explicit merge from the fork head (schwarztim/pr/adaptive-person-count) preserves the diff exactly as the contributor authored it.

What lands

  • RollingP95 adaptive normaliser for the person-count feature scaling — streaming P95 over a 600-sample / ~30 s sliding window. Cold-start (<60 samples) falls back to the legacy fixed denominators (variance/300, motion_band_power/250, spectral_power/500) so day-0 behaviour is preserved.
  • RuntimeConfig struct + load_runtime_config / save_runtime_config persisted to data/config.json. Exposes dedup_factor via REST so multi-node deployments can tune cluster-deduplication without a rebuild, with an auto-tune endpoint that derives optimal dedup from a known person count (calibration mode).
  • compute_person_score() signature: &FeatureInfo&AppStateInner + &FeatureInfo. All 3 call sites updated.
  • AppStateInner new fields: p95_variance, p95_motion_band_power, p95_spectral_power, dedup_factor, data_dir.

Builds + tests locally

$ cargo check -p wifi-densepose-sensing-server --no-default-features
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.97s

$ cargo test -p wifi-densepose-sensing-server --no-default-features --lib
test result: ok. 233 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 25.03s

Closes / addresses

After merge, schwarztim's original PR #491 should auto-close (since this carries the same diff). Will comment there with credit + the merge link.

🤖 Generated with claude-flow

Deploy Bot and others added 2 commits April 28, 2026 15:32
…or runtime API

RollingP95 adaptive normalizer (ADR-044 §5.2):
- Streaming P95 estimator (600-sample / ~30 s window) replaces fixed-scale
  denominators (variance/300, motion/250, spectral/500) that saturated against
  live ESP32 values, collapsing dynamic range to zero.
- Cold-start (<60 samples) falls back to legacy denominators — day-0 behaviour
  is preserved.
- Three new fields on AppStateInner: p95_variance, p95_motion_band_power,
  p95_spectral_power (all RollingP95::new(600, 60)).
- compute_person_score() refactored to accept &AppStateInner; all three call
  sites (wifi, wifi-fallback, simulated) updated.
- 5 unit tests in rolling_p95_tests module.

dedup_factor runtime API (ADR-044 §5.3):
- New field dedup_factor: f64 (default 3.0) on AppStateInner.
- fuse_or_fallback() gains dedup_factor param; fallback switches from max() to
  sum/dedup_factor (ceiling), matching the fork's sum-based aggregation.
- RuntimeConfig struct + load/save_runtime_config() for data/config.json
  persistence across restarts.
- Three new REST endpoints:
    GET  /api/v1/config/dedup-factor
    POST /api/v1/config/dedup-factor
    POST /api/v1/config/ground-truth (auto-tune from known person count)

Explicitly NOT included:
- lambda=5.0 (upstream keeps its 0.1 default — deployment-specific tuning)
- CC intensity threshold 0.3 and min-cluster-size 4 hardcodes
- max_cc_size filter removal
…+ dedup_factor runtime API

Integrating @schwarztim's PR #491 into main on their behalf — their fork has
fallen too far behind for a clean rebase (the PR's commit graph dropped
silently during `git rebase origin/main`), so applying as a merge from the
fork head to preserve the diff cleanly.

What this lands:
- `RollingP95` adaptive normaliser for the person-count feature scaling.
  Streaming P95 over a 600-sample / ~30 s sliding window. Cold-start
  (<60 samples) falls back to the legacy denominators (variance/300,
  motion_band_power/250, spectral_power/500) so day-0 behaviour is
  preserved on every deployment.
- `RuntimeConfig` struct + `load_runtime_config` / `save_runtime_config`
  persisted to `data/config.json`. Exposes `dedup_factor` via REST so
  multi-node deployments can tune cluster-deduplication without a rebuild,
  including an auto-tune endpoint that derives optimal dedup from a known
  person count (calibration mode).
- `compute_person_score()` now takes &AppStateInner alongside &FeatureInfo
  so the adaptive denominators are reachable. All 3 call sites updated.
- New `AppStateInner` fields: `p95_variance`, `p95_motion_band_power`,
  `p95_spectral_power`, `dedup_factor`, `data_dir`.

Closes #491. Directly addresses:
- #499 (double skeletons, multi-node) — the slot-clustering problem this
  PR's adaptive normaliser was designed to fix
- #519 Bug 1 (ghost person detection on edge-tier 1 & 2 multi-node)
- #496 (person count over-reporting on single-room single-person)

Verified locally:
- cargo check -p wifi-densepose-sensing-server --no-default-features: 1.0s
- cargo test -p wifi-densepose-sensing-server --no-default-features --lib:
  233/233 passed in 25.0s

Co-authored-by: @schwarztim
Co-Authored-By: claude-flow <ruv@ruv.net>
@ruvnet
ruvnet merged commit 961c01f into main May 19, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant