perf(dashboard): reuse the probed coverage map in the summaries slice

The snapshot builder probed rollup coverage up front to gate the thick
extras phase, then called computeSummariesSlice which re-ran the
identical probeRollupCoverage query. Thread the already-probed map into
the slice as an optional argument so the snapshot's hot path issues the
probe once. The argument is optional with the internal probe as the
fallback, so every other caller is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.8 committed 2026-06-05 13:51:54 +02:00
1 parent 6de5de0284
commit 437a627a66
3 files changed
+37 -2

No files matched your search

+12 -1
View File
@@ -70,6 +70,7 @@ import {
import {
isFullyCovered,
probeRollupCoverage,
type RollupCoverageMap,
} from "@/lib/rollups/measurement-coverage";
import { readBestGranularityRollups } from "@/lib/rollups/measurement-read-wmy";
import {
@@ -220,6 +221,16 @@ export interface SummariesSlice {
export async function computeSummariesSlice(
userId: string,
/**
* v1.12.7 A5 — optional pre-probed coverage map. The dashboard
* snapshot already calls `probeRollupCoverage` up front to decide
* whether to run the thick `extras` phase, then called this slice
* which re-probed the identical query. Threading the map in lets the
* slice reuse it and saves one round-trip on the snapshot's hot path.
* Omit it (every other caller) to keep the internal probe as the
* fallback — byte-stable for those callers.
*/
precomputedCoverage?: RollupCoverageMap,
): Promise<SummariesSlice> {
// v1.4.37.1 hotfix — fire-and-forget. See `src/app/api/analytics/route.ts`
// for the full rationale: awaiting this on the read path can stall
@@ -242,7 +253,7 @@ export async function computeSummariesSlice(
// only take the rollup path when EVERY type the user has logged is
// covered. Partial coverage falls back to the live aggregate so the
// brand-new-type case stays correct.
const coverage = await probeRollupCoverage(userId);
const coverage = precomputedCoverage ?? (await probeRollupCoverage(userId));
if (isFullyCovered(coverage)) {
return withSleepNightTotals(userId, await computeFromRollups(userId));
}
@@ -145,6 +145,28 @@ describe("buildDashboardSnapshot — envelope shape", () => {
expect(snap.layout).toBeDefined();
expect(typeof snap.generatedAt).toBe("string");
});
it("probes rollup coverage once and threads it into the summaries slice (A5)", async () => {
const coverageMap = new Map([["WEIGHT", true]]);
probeRollupCoverage.mockResolvedValue(coverageMap);
isFullyCovered.mockReturnValue(true);
computeBpInTargetFastPath.mockResolvedValue({
last7Days: { pct: 70 },
last30Days: { pct: 80 },
allTime: { pct: 75 },
priorMonth: { pct: 60 },
priorYear: { pct: 50 },
});
await buildDashboardSnapshot(fakePrisma, baseUser());
// The snapshot probes coverage exactly once up front — the slice no
// longer re-runs the identical probe internally.
expect(probeRollupCoverage).toHaveBeenCalledTimes(1);
// The already-probed map is passed as the slice's second argument so
// it reuses it instead of probing again.
expect(computeSummariesSlice).toHaveBeenCalledWith("user-1", coverageMap);
});
});
describe("buildDashboardSnapshot — two-phase null extras", () => {
+3 -1
View File
@@ -609,7 +609,9 @@ export async function buildDashboardSnapshot(
const warm = isFullyCovered(coverage);
const [slim, mood, extras, flags] = await Promise.all([
time("summaries", () => computeSummariesSlice(user.id)),
// A5 — reuse the coverage map already probed above so the slice
// doesn't re-run the identical `probeRollupCoverage` query.
time("summaries", () => computeSummariesSlice(user.id, coverage)),
time("mood", () => buildMoodBlock(prisma, user.id)),
warm
? time("extras", () => buildExtras(prisma, user, userTz, coverage))