mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
feat(coach): extend the snapshot window enum with lastYear
Adds a year-in-review window between last90days and allTime so the Coach drawer can ground a long-horizon question (seasonal mood patterns, year-over-year weight trajectory) without falling back to the unbounded `allTime` window. The new enum value flows through the scope schema, the snapshot builder's window-to-day-count mapping, the provenance window-set seeding so the source-chips render the year-in-review chip, and the Coach source-chips Record. Extends the snapshot test with a `lastYear`-specific assertion that pins the scope window and the provenance envelope.
This commit is contained in:
1 parent
988bbf1a2f
commit
6a76f7463e
4 files changed
+45
-1
No files matched your search
@@ -51,6 +51,10 @@ const WINDOW_KEYS: Record<CoachProvenance["windows"][number], string> = {
|
||||
last7days: "insights.coach.window.last7days",
|
||||
last30days: "insights.coach.window.last30days",
|
||||
last90days: "insights.coach.window.last90days",
|
||||
// v1.4.27 B7 / BL-P6-4 — year-in-review window. The i18n key
|
||||
// resolves to a localised label; absent translations fall back
|
||||
// through the resolver to the English source.
|
||||
lastYear: "insights.coach.window.lastYear",
|
||||
allTime: "insights.coach.window.allTime",
|
||||
};
|
||||
|
||||
|
||||
@@ -132,6 +132,24 @@ describe("buildCoachSnapshot", () => {
|
||||
expect(parsed.pulse.timeline.recent.length).toBe(1);
|
||||
});
|
||||
|
||||
it("respects the scope.window — lastYear flags the year-in-review window", async () => {
|
||||
featuresMock.mockResolvedValue({
|
||||
bloodPressure: { avg30Sys: 124, coverage: { count: 50 } },
|
||||
});
|
||||
prismaMock.measurement.findMany.mockResolvedValue([
|
||||
daysAgo(120, 124, "BLOOD_PRESSURE_SYS"),
|
||||
daysAgo(120, 81, "BLOOD_PRESSURE_DIA"),
|
||||
]);
|
||||
|
||||
const out = await buildCoachSnapshot("user-1", {
|
||||
sources: ["bp"],
|
||||
window: "lastYear",
|
||||
});
|
||||
const parsed = JSON.parse(out.snapshotJson);
|
||||
expect(parsed.scope.window).toBe("lastYear");
|
||||
expect(out.provenance.windows).toContain("lastYear");
|
||||
});
|
||||
|
||||
it("defaults to all-source last30days when no scope is provided", async () => {
|
||||
const out = await buildCoachSnapshot("user-1");
|
||||
const parsed = JSON.parse(out.snapshotJson);
|
||||
|
||||
@@ -69,6 +69,13 @@ function windowToDays(window: CoachScopeWindow): number {
|
||||
return 30;
|
||||
case "last90days":
|
||||
return 90;
|
||||
case "lastYear":
|
||||
// v1.4.27 B7 / BL-P6-4 — year-in-review window. Same 365-day
|
||||
// ceiling as the historical `allTime` cap so the prompt budget
|
||||
// stays bounded, but with explicit semantics — the Coach knows
|
||||
// the user is asking about a long-horizon view rather than the
|
||||
// unbounded "all time" backfill.
|
||||
return 365;
|
||||
case "allTime":
|
||||
// Cap "allTime" at one year for the timeline. The aggregate
|
||||
// section already cites multi-year ranges via the features
|
||||
@@ -331,6 +338,14 @@ export async function buildCoachSnapshot(
|
||||
// budget for free-tier accounts.
|
||||
const snapshot: Record<string, unknown> = {};
|
||||
const windows = new Set<CoachProvenance["windows"][number]>();
|
||||
// v1.4.27 B7 / BL-P6-4 — seed the provenance window set with the
|
||||
// user's resolved scope so the year-in-review window surfaces in the
|
||||
// provenance envelope even when the per-metric branches below only
|
||||
// emit `last30days` / `last90days` chips. Older windows are added
|
||||
// by the metric branches as before.
|
||||
if (window === "lastYear" || window === "allTime") {
|
||||
windows.add(window);
|
||||
}
|
||||
const metrics = new Set<CoachProvenance["metrics"][number]>();
|
||||
const counts: NonNullable<CoachProvenance["counts"]> = {};
|
||||
|
||||
|
||||
@@ -41,6 +41,11 @@ export const coachScopeWindowSchema = z.enum([
|
||||
"last7days",
|
||||
"last30days",
|
||||
"last90days",
|
||||
// v1.4.27 B7 / BL-P6-4 — long-horizon window for the year-in-review
|
||||
// surfaces. Sits between `last90days` and `allTime` so the snapshot
|
||||
// builder can sample a denser timeline (one row per week) than the
|
||||
// unbounded fallback while still surfacing seasonal patterns.
|
||||
"lastYear",
|
||||
"allTime",
|
||||
]);
|
||||
|
||||
@@ -145,7 +150,9 @@ export interface CoachProvenance {
|
||||
* Time windows the assistant drew on. Same enum the strict insight
|
||||
* schema uses elsewhere so the UI can pin a mini-chart to the chip.
|
||||
*/
|
||||
windows: ReadonlyArray<"last7days" | "last30days" | "last90days" | "allTime">;
|
||||
windows: ReadonlyArray<
|
||||
"last7days" | "last30days" | "last90days" | "lastYear" | "allTime"
|
||||
>;
|
||||
/**
|
||||
* Metric topics referenced. Stable contract keys — translated by the
|
||||
* UI, never by the server.
|
||||
|
||||
Reference in new issue
Block a user