fix(rollups): trail the rollup window from the caller's moment

readBestGranularityRollups opened its window at the wall clock, while the
live fallback beside it used the caller's now. A read anchored on another
moment saw different days depending on whether the account already had
DAY buckets; the Today overview's integration test turned red once its
fixed morning fell out of the wall-clock window. Every caller that holds a
now passes it through.
This commit is contained in:
Marc-André Bombeck committed 2026-10-29 10:13:22 +01:00
1 parent f24589c294
commit a9c2e25099
5 files changed
+23 -3

No files matched your search

+2
View File
@@ -316,6 +316,8 @@ export async function computeRangeDelta(
userId,
type,
windowDays * 2,
undefined,
new Date(now),
);
if (!resolved) {
const empty: WindowAggregate = {
+7 -1
View File
@@ -217,7 +217,13 @@ async function readWindowMeans(
1,
Math.ceil((to.getTime() - from.getTime()) / MS_PER_DAY),
);
const resolved = await readBestGranularityRollups(userId, type, windowDays);
const resolved = await readBestGranularityRollups(
userId,
type,
windowDays,
undefined,
now,
);
if (
resolved &&
resolved.granularity === "DAY" &&
+7 -1
View File
@@ -274,7 +274,13 @@ export async function readDayMeanSeries(
// band from WEEK/MONTH `sd`, and the center reads the DAY `mean`
// which composes exactly. `readBestGranularityRollups` with a
// window < 91 days resolves to DAY by construction.
const resolved = await readBestGranularityRollups(userId, type, windowDays);
const resolved = await readBestGranularityRollups(
userId,
type,
windowDays,
undefined,
now,
);
if (
resolved &&
resolved.granularity === "DAY" &&
+2
View File
@@ -537,6 +537,7 @@ export async function buildGradedSeriesWithRollups(
type,
365,
priority,
now,
);
// Yearly slice: route a multi-year window through the tier.
const yearlyRouted = await readBestGranularityRollups(
@@ -544,6 +545,7 @@ export async function buildGradedSeriesWithRollups(
type,
1095,
priority,
now,
);
const monthlyCovered =
+5 -1
View File
@@ -116,12 +116,16 @@ export async function readBestGranularityRollups(
type: MeasurementType,
windowDays: number,
userPriorityJson?: unknown,
now: Date = new Date(),
): Promise<{
granularity: RollupGranularity;
rows: RollupBucketRow[];
} | null> {
if (!Number.isFinite(windowDays) || windowDays <= 0) return null;
const since = new Date(Date.now() - windowDays * 24 * 60 * 60 * 1000);
// The window trails the caller's `now`, so a read anchored on another
// moment than the wall clock sees the same days through the rollups as
// through the live fallback.
const since = new Date(now.getTime() - windowDays * 24 * 60 * 60 * 1000);
// v1.11.1 — load the source-priority blob once and thread it into every
// granularity probe so the collapse never re-queries the user per floor.
const priority =