From c265103b69096217d41e1c5e8162edee207aa274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 16 May 2026 11:19:46 +0200 Subject: [PATCH] fix(charts): sum cumulative types in the client-side daily aggregator The 7-day window on the dashboard chart still pulls raw rows from `/api/measurements` (the server-side `aggregate=daily` path kicks in only for windows over a week). The client-side daily aggregator then reduced every per-day bucket with `sum / count`, which averages step counts across the per-sample rows Apple Health emits instead of summing them. Steps on a 7-day view rendered as the per-sample average (hundreds), not the daily total. The reduction now branches on `CUMULATIVE_HK_TYPES` (the same set that drives the server-side SQL aggregator in v1.4.29): cumulative types reduce with `sum`, spot metrics keep the `sum / count` average. --- src/components/charts/health-chart.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/charts/health-chart.tsx b/src/components/charts/health-chart.tsx index dbf6e2674..a48baa39b 100644 --- a/src/components/charts/health-chart.tsx +++ b/src/components/charts/health-chart.tsx @@ -38,6 +38,8 @@ import type { ChartOverlayKey, ComparisonBaseline, } from "@/lib/dashboard-layout"; +import { CUMULATIVE_HK_TYPES } from "@/lib/measurements/apple-health-mapping"; +import type { MeasurementType } from "@/generated/prisma/client"; import { ChartOverlayControls } from "./chart-overlay-controls"; import { useChartOverlayPrefs } from "@/hooks/use-chart-overlay-prefs"; import { useViewportWidth } from "@/hooks/use-viewport-width"; @@ -629,7 +631,16 @@ export function HealthChart({ }; for (const [type, stats] of Object.entries(bucket.values)) { - point[type] = stats.sum / stats.count; + // v1.4.29.1 — cumulative HealthKit types (steps, active energy, + // distance, flights, daylight) must reduce with sum, not the + // per-sample average. The server already does this when the + // chart fetches with `aggregate=daily` (windows over 7 days); + // the 7-day path still pulls raw rows and aggregates here, + // so the same distinction must hold client-side. + const isCumulative = CUMULATIVE_HK_TYPES.has( + type as MeasurementType, + ); + point[type] = isCumulative ? stats.sum : stats.sum / stats.count; } return point;