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