From 9d1f21408f552cc86e7eda477ce7889d06907ef6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Mon, 27 Jul 2026 23:45:00 +0200 Subject: [PATCH] fix(insights): floor the same-time band from the metric, not by hand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two parallel lines of work reached the same conclusion independently: a baseline band over a quantity that cannot go negative must not report a lower edge below zero. One of them answered it locally with a `Math.max(0, …)` at the call site; the other gave every metric's numeric domain a single home and made `buildBaselineBand` take the metric so the floor comes from the declaration. Keep the second and drop the first. The required parameter is what surfaced this at all: the new call site could not compile without naming its metric, which is the whole reason it was made required rather than defaulted. --- src/lib/insights/derived/same-time-baseline.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/lib/insights/derived/same-time-baseline.ts b/src/lib/insights/derived/same-time-baseline.ts index 6bd74b813..2285cd949 100644 --- a/src/lib/insights/derived/same-time-baseline.ts +++ b/src/lib/insights/derived/same-time-baseline.ts @@ -210,12 +210,16 @@ export async function computeSameTimeBaseline( const typicalValue = typicalCurve[asOfHour]; // The band comes off the same estimator the vitals baseline uses, applied to - // the window's totals AT THIS HOUR rather than to daily means. Floored at - // zero: a cumulative total cannot be negative, and a band edge below zero - // would widen the "within" verdict on the low side for free. + // the window's totals AT THIS HOUR rather than to daily means. Passing the + // metric is what floors the lower edge at zero: a cumulative total cannot be + // negative, and a band edge below zero would widen the "within" verdict on + // the low side for free. That floor used to be a local `Math.max(0, …)` here. + // It is gone because `buildBaselineBand` now answers the question for every + // caller from the metric's declared domain, and one question with two answers + // in the same tree is the defect this release exists to remove. const atHour = history.map((p) => p.hourlyCumulative[asOfHour]); - const spread = buildBaselineBand(atHour); - const typicalLow = Math.max(0, spread ? spread.low : typicalValue); + const spread = buildBaselineBand(atHour, type); + const typicalLow = spread ? spread.low : typicalValue; const typicalHigh = spread ? spread.high : typicalValue; const band: SameTimeBand =