fix(bp-in-target): calendar-aware priorYear read window

The rollup-path read window was `now - 396 * 24h`. On a leap year
the constant is 1 day shy of the intended 12-months-plus-one-day
priorYear span, so the boundary day disappears from the rollup-derived
envelope while the live path's per-event walk keeps it. Replace the
fixed multiplication with calendar arithmetic (`setUTCFullYear(-1)`
+ `setUTCDate(-31)`) so the read window stays calendar-correct on
every year. Below the n=20 surface gate this rarely surfaces in
practice — but the helper can no longer silently shift the priorYear
pct on a leap-year edge.
This commit is contained in:
Marc-André Bombeck committed 2026-05-17 17:25:42 +02:00
1 parent 03952deb41
commit bee09bb75a
1 file changed
+20 -3
+20 -3
View File
@@ -174,10 +174,27 @@ async function computeFromRollups(
tzGuard: "near-utc" | "non-utc-live-fallback",
): Promise<BpInTargetEnvelope> {
// v1.4.22 W5 reconcile (Code-H2) — the priorYear window starts 395
// days ago. We read 396 days so the boundary day rolls cleanly into
// the prior-year bucket without being dropped.
// days ago. We read one extra day so the boundary day rolls cleanly
// into the prior-year bucket without being dropped.
//
// v1.4.38 — span the read window via calendar arithmetic ("12 months
// back, then 31 more days") instead of `now - 396 * 24h`. On a leap
// year the 396-day constant is 1 day shy of the intended priorYear
// span, so the boundary day disappears from the rollup-derived
// envelope while the live path's per-event walk keeps it. Below the
// n=20 surface gate this rarely matters in practice — but the
// helpers stay calendar-correct now so a leap-year edge can never
// silently shift the priorYear pct.
const DAY_MS = 24 * 60 * 60 * 1000;
const readSince = new Date(now.getTime() - 396 * DAY_MS);
const readSince = (() => {
const d = new Date(now.getTime());
d.setUTCFullYear(d.getUTCFullYear() - 1);
// 31 days past the 12-months mark covers the priorYear 395-day
// boundary plus the same one-day cushion the original 396-day
// constant provided.
d.setUTCDate(d.getUTCDate() - 31);
return d;
})();
const [sysBuckets, diaBuckets] = await Promise.all([
readRollupBuckets(