bedf3c55f0
Fold the whole raw-retention window of already-recorded KpiSample rows into KpiRollupHourly once shortly after the recorder singleton starts, so long-range (30 d/90 d) trend charts aren't blank until enough wall-clock passes after deploy. Reuses Task 3's idempotent FoldHourlyRollupsAsync over [TruncateToHour(now) - RetentionDays, TruncateToHour(now)); runs at most once per actor lifetime (_backfillDone latch) and defers past / blocks the periodic lookback fold via a dedicated _backfillInFlight guard so the two idempotent upserts never race on overlapping rows. Best-effort: no exception escapes; logs start, window, and elapsed on completion. No Host or options change. Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj