diff --git a/src/lib/analytics/__tests__/mood-series.test.ts b/src/lib/analytics/__tests__/mood-series.test.ts index 07ec24220..e29667876 100644 --- a/src/lib/analytics/__tests__/mood-series.test.ts +++ b/src/lib/analytics/__tests__/mood-series.test.ts @@ -83,6 +83,19 @@ describe("buildMoodDailySeries", () => { expect(series.summary.count).toBe(2); }); + it("bounds the live walk to the window the rollup read covers", async () => { + await buildMoodDailySeries("user-1"); + const [rollupUser, since] = vi.mocked(readMoodDayRollups).mock.calls[0] as [ + string, + Date, + ]; + expect(rollupUser).toBe("user-1"); + const args = vi.mocked(prisma.moodEntry.findMany).mock.calls[0]?.[0] as { + where: { moodLoggedAt?: { gte: Date } }; + }; + expect(args.where.moodLoggedAt?.gte).toEqual(since); + }); + it("returns an empty series for a user with no rollups and no raw entries", async () => { const series = await buildMoodDailySeries("user-1"); expect(series.entries).toEqual([]); diff --git a/src/lib/analytics/mood-series.ts b/src/lib/analytics/mood-series.ts index 676eb62e4..8e57d64e3 100644 --- a/src/lib/analytics/mood-series.ts +++ b/src/lib/analytics/mood-series.ts @@ -116,11 +116,12 @@ export async function buildMoodDailySeries( return { entries, summary, entryCount, source: "rollup" }; } - // Coverage fallback — no rollup rows yet. Run the legacy live walk ONCE; - // the warm-up above mints the rollups for the next request. + // Coverage fallback — no rollup rows yet. Run the live walk ONCE over the + // same window the rollup read covers; the warm-up above mints the rollups + // for the next request. const moodEntries = await client.moodEntry.findMany({ // v1.7.0 sync — exclude tombstoned rows from the fallback. - where: { userId, deletedAt: null }, + where: { userId, deletedAt: null, moodLoggedAt: { gte: since } }, orderBy: { moodLoggedAt: "asc" }, select: { date: true, score: true }, });