Files
meshcore-analyzer/cmd/server
you cc92a8d5c4 fix: bimodal clock hysteresis — don't flip to 'No Clock' on transient bad bursts
Symptom: Kpa Roof Solar (and other historically-bimodal nodes) briefly
flip to '🚫 No Clock' when the last 5 adverts in the recent-1h window
all happen to have nonsense timestamps, even though the very next advert
decoded with a valid 2026 timestamp.

Root cause: the bimodal classifier from #845 looks at the last 5 samples
within the past hour. When a bimodal node hits a transient burst of bad
RTC samples, recent goodFraction = 0 and severity flips to no_clock
regardless of the long-term picture (16k+ samples, ~38% historically good).

Fix (option C from triage):
1. Widen the recent window: 5 → 20 samples, 1h → 6h time bound
   (more data, less jitter, still recent).
2. Add hysteresis: only drop to no_clock when BOTH recent goodFraction
   AND long-term goodFraction are < 10%. A node with historical good
   samples stays bimodal even when the recent window is 100% bad.
3. When recent has zero good samples, fall back to long-term good median
   for the displayed skew so the operator sees a meaningful number
   instead of stale poison.

API: add longTermGoodFraction to /api/nodes/{pk}/clock-skew so operators
can see the hysteresis input directly.

Tests:
- TestBimodalHysteresis: recent all-bad + long-term mixed → bimodal_clock
- TestNoClock_BothWindowsBad: recent all-bad + long-term all-bad → no_clock
- Updated TestSeverityUsesRecentNotMedian + TestReporterScenario_789 to
  match the new wider window and accept bimodal_clock for nodes with
  massive historical poison (#845's whole premise: bimodal deserves a flag,
  not OK status).
2026-04-22 15:29:40 +00:00
..