From de2200bd5cfc8e370d470a33ca64da404ac42146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 27 Sep 2026 13:03:31 +0200 Subject: [PATCH] fix(coach): make table weeks and months mean one thing per metric A total's weeks and months are now the sum of its days, labelled as a total, and a level's stay a mean. All time is read as UTC calendar months from the rollup tier's MONTH fold, or the same fold of the live table when the tier has no rows, so a month no longer reads as a mean of daily totals for a short history and a monthly total for a long one. Months are keyed by their UTC start instead of being re-read in the user's zone, which named every month one early west of UTC. The chart's long ranges had the same shift: tier rows are now stamped at noon UTC of the bucket's first day, which falls inside the bucket's own week and month in every zone. Step length and walking speed keep two decimals, loud-sound events count as a total in whole events, and HRV counts a night measured by both estimators once and charts the estimator the person mostly has. The model summary names what a period's value is and gives a total's range total. --- .../results/__tests__/chart-spec.test.ts | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/lib/ai/coach/results/__tests__/chart-spec.test.ts b/src/lib/ai/coach/results/__tests__/chart-spec.test.ts index 33c723f88..3b78d9997 100644 --- a/src/lib/ai/coach/results/__tests__/chart-spec.test.ts +++ b/src/lib/ai/coach/results/__tests__/chart-spec.test.ts @@ -249,7 +249,7 @@ describe("deriveChartSpec: time series", () => { it("draws at most two series, the first compatible pair", () => { const table = timeSeries({ - domain: "hrv", + domain: "pulse", columns: [ DAY, valueColumn("sdnn", "ms"), @@ -269,7 +269,25 @@ describe("deriveChartSpec: time series", () => { }); }); - it("leaves the reading count off the chart", () => { + it("draws one HRV estimator, not SDNN and RMSSD as a pair", () => { + // The two columns are alternative estimators of one quantity; drawn + // together they read as a comparison they are not. + const table = timeSeries({ + domain: "hrv", + columns: [DAY, valueColumn("rmssd", "ms"), valueColumn("sdnn", "ms")], + rows: [ + [dayKey(0), 40, 55], + [dayKey(1), 42, 57], + ], + }); + expect(deriveChartSpec(table)).toEqual({ + kind: "line", + x: "day", + series: ["rmssd"], + }); + }); + + it("leaves the reading count off the chart", () => { const spec = deriveChartSpec(daySeries("pulse", [60, 62], "bpm")); expect(spec && "series" in spec ? spec.series : []).not.toContain( "readings",