v1.4.39.1 wired the rollup write hook into the previously-bypassed Withings sync, /api/import, and admin-restore paths and widened the boot-time backfill discovery to per-(user, type, day). Two follow-ups remained from the post-deploy trace: the dashboard chart still painted its < 3 daily points empty-state on the 30-point range for accounts whose historic rollup partition had not yet been folded, and the cold-mount UX waterfall left every per-type tile waiting on the heavy /api/analytics envelope.
Fixed
GET /api/measurements?source=rollupnow reconciles the rollup table against the livemeasurementstable when the read returns suspiciously few rows. The route probesCOUNT(DISTINCT date_trunc('day', measured_at))againstmeasurementsfor the requested window when the rollup carries fewer than three rows on a window of at least seven days; if the live table holds more distinct days than the rollup, the route folds the(user, type, DAY, [from, to])partition inline viarecomputeUserRollupsand re-reads. The chart paints the full window on the same request without paying the cost on subsequent requests. The probe is gated on rollup sparsity so covered-tenant hot paths stay single-read.
Changed
- Dashboard analytics fan-out split across two parallel queries. The per-type tile strip now reads from the slim
?slice=summariesbranch and paints as soon as the slim slice resolves; the BD-Zielbereich and glucose tiles stream in from the thick branch afterwards. Both queries share thecaches.analytics60 s LRU server-side so warm hits stay free.
Notes
- No schema migration. Runtime-only fix on top of the v1.4.39.1 write-path hooks.
- Tests 4651 → 4654 (1 long-standing skip).
- The inline rollup fold cost is bounded by the requested window and one measurement type — for the dashboard chart's 30-day BP_SYS window that is a single 30-row upsert against the composite primary key.