Derive score-version fixtures from the SCORE_VERSION constant

Eight test and fixture files hardcoded scoreVersion: 2, a value the
constant has not held since v1.35.0. Now they import SCORE_VERSION and
use it, so a future bump cannot leave a fixture pinned to a stale
number.

The one genuinely historical case (record.test.ts, proving the input
fingerprint moves when the algorithm version moves) now derives both
its "previous" and "current" markers from SCORE_VERSION instead of two
unrelated literals, so the pair keeps its meaning after the next bump.
This commit is contained in:
Marc-André Bombeck committed 2026-08-02 00:15:29 +02:00
1 parent 7df25a6d92
commit af35346687
8 files changed
+35 -19

No files matched your search

+8 -3
View File
@@ -2,6 +2,8 @@ import { expect, test } from "./setup/test";
import { STORAGE_STATE_PATH } from "./setup/global-setup";
import { settleBeforeMeasure } from "./utils/settle";
import { SCORE_VERSION } from "@/lib/analytics/score/types";
import { healthScoreAlgorithmItemKey } from "@/lib/daily/priority-item-key";
/**
* Settings → Health Score: the surface that decides which pillars count.
@@ -65,11 +67,14 @@ function scoreReport() {
],
delta: null,
deltaReason: "no_current_score",
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
weightGoal: insufficient("no_goal"),
// Raised and never dismissed, which is the state every account is in:
// nothing has ever rendered this notice.
algorithmNotice: { itemKey: "health_score_algorithm:2", dismissed: false },
algorithmNotice: {
itemKey: healthScoreAlgorithmItemKey(SCORE_VERSION),
dismissed: false,
},
};
}
@@ -223,7 +228,7 @@ test.describe("Settings → Health Score", () => {
await notice.locator('[data-slot="score-change-notice-dismiss"]').click();
await expect(notice).toHaveCount(0);
expect(dismissed).toBe("health_score_algorithm:2");
expect(dismissed).toBe(healthScoreAlgorithmItemKey(SCORE_VERSION));
});
test("refuses a selection too narrow to produce a score, in plain language", async ({
+3 -2
View File
@@ -4,6 +4,7 @@ import {
SECTION_MOBILITY,
SECTION_VITALS,
} from "@/components/insights/derived/use-dashboard-derived";
import { SCORE_VERSION } from "@/lib/analytics/score/types";
/**
* A POPULATED Insights overview fixture.
@@ -170,7 +171,7 @@ const HEALTH_SCORE = {
composition: ["BLOOD_PRESSURE", "ACTIVITY", "SLEEP", "ADIPOSITY"],
configured: false,
noiseFloor: 3,
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
},
coverage: coverage(),
confidence: confidence(),
@@ -187,7 +188,7 @@ const HEALTH_SCORE = {
],
delta: 2,
deltaReason: null,
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
weightGoal: {
status: "ok" as const,
value: {
+2 -1
View File
@@ -2,6 +2,7 @@ import { mkdir } from "node:fs/promises";
import { join } from "node:path";
import type { Page, TestInfo } from "@playwright/test";
import type { DailyDigest } from "@/lib/daily/digest";
import { SCORE_VERSION } from "@/lib/analytics/score/types";
import { expect, test } from "./setup/test";
import { STORAGE_STATE_PATH } from "./setup/global-setup";
@@ -23,7 +24,7 @@ const NARRATIVE_DIGEST: DailyDigest = {
band: "green",
delta: -2,
deltaReason: null,
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
composition: ["BLOOD_PRESSURE", "ACTIVITY", "SLEEP"],
},
topSignal: LONG_HEADLINE_BRIEFING.signalsOfDay?.[0] ?? null,
@@ -22,6 +22,8 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
import { NextRequest } from "next/server";
import { Buffer } from "node:buffer";
import { SCORE_VERSION } from "@/lib/analytics/score/types";
process.env.ENCRYPTION_KEY =
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
@@ -269,7 +271,7 @@ function sourceClient() {
timezone: "Europe/Berlin",
composite: 76,
band: "yellow",
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
composition: ["BLOOD_PRESSURE", "SLEEP", "ADIPOSITY"],
pillarScores: { BLOOD_PRESSURE: 86, SLEEP: 100, ADIPOSITY: 42 },
inputFingerprint: "a".repeat(64),
@@ -629,7 +631,7 @@ describe("backup round trip — export, wire schema, restore", () => {
timezone: "Europe/Berlin",
composite: 76,
band: "yellow",
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
inputFingerprint: "a".repeat(64),
});
// The composition and the per-pillar scores are what keep the stored day
@@ -3,6 +3,7 @@ import { NextRequest } from "next/server";
import { apiError } from "@/lib/api-response";
import type { DailyDigest } from "@/lib/daily/digest";
import { SCORE_VERSION } from "@/lib/analytics/score/types";
/**
* `GET /api/daily/digest` — the P3 read seam.
@@ -63,7 +64,7 @@ const DIGEST: DailyDigest = {
band: "good",
delta: 3,
deltaReason: null,
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
composition: ["BLOOD_PRESSURE", "ACTIVITY", "SLEEP"],
},
topSignal: null,
@@ -6,6 +6,7 @@ import { I18nProvider } from "@/lib/i18n/context";
import { TodayHero } from "../today-hero";
import type { DailyDigest } from "@/lib/daily/digest";
import type { PriorityItem } from "@/lib/daily/priority-item";
import { SCORE_VERSION } from "@/lib/analytics/score/types";
// The hero now wires the coach check-in card's keep / let-go taps through
// `useCoachCheckinAction`, so it needs a QueryClient in the tree.
@@ -57,7 +58,7 @@ function digest(over: Partial<DailyDigest> = {}): DailyDigest {
band: "green",
delta: 3,
deltaReason: null,
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
composition: ["BLOOD_PRESSURE", "ACTIVITY", "SLEEP"],
},
topSignal: {
@@ -114,7 +115,7 @@ describe("<TodayHero>", () => {
band: "green",
delta: 20,
deltaReason: "algorithm_changed",
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
composition: ["BLOOD_PRESSURE", "ACTIVITY", "SLEEP"],
},
})}
@@ -144,8 +144,12 @@ describe("stored bands", () => {
});
describe("input fingerprint", () => {
// The fixture only needs two DIFFERENT version markers to prove the
// fingerprint is sensitive to a version move — pinned relative to
// SCORE_VERSION so the pair stays "previous vs current" rather than
// going stale (or colliding) the next time the constant bumps.
const base = {
scoreVersion: 1,
scoreVersion: SCORE_VERSION - 1,
composition: ["BLOOD_PRESSURE", "SLEEP", "ADIPOSITY"] as ScorePillarId[],
pillars: HEALTHY,
};
@@ -157,9 +161,9 @@ describe("input fingerprint", () => {
});
it("moves when the algorithm version moves", () => {
expect(healthScoreInputFingerprint({ ...base, scoreVersion: 2 })).not.toBe(
healthScoreInputFingerprint(base),
);
expect(
healthScoreInputFingerprint({ ...base, scoreVersion: SCORE_VERSION }),
).not.toBe(healthScoreInputFingerprint(base));
});
it("moves when the composition narrows", () => {
+5 -4
View File
@@ -77,7 +77,7 @@ vi.mock("@/lib/analytics/score/reader", () => ({
bandSetter: "BLOOD_PRESSURE" as const,
composition: ["BLOOD_PRESSURE", "ACTIVITY", "SLEEP"] as const,
noiseFloor: 2,
scoreVersion: 2 as const,
scoreVersion: SCORE_VERSION,
},
coverage,
confidence: { score: 100, band: "high" as const },
@@ -94,7 +94,7 @@ vi.mock("@/lib/analytics/score/reader", () => ({
pillars: [],
delta: legacy?.delta ?? null,
deltaReason: null,
scoreVersion: 2 as const,
scoreVersion: SCORE_VERSION,
weightGoal: {
status: "insufficient" as const,
coverage,
@@ -154,6 +154,7 @@ import {
} from "../snapshot";
import type { ModuleKey } from "@/lib/modules/gate";
import { MODULE_KEYS } from "@/lib/modules/registry";
import { SCORE_VERSION } from "@/lib/analytics/score/types";
const emptySummary = {
count: 0,
@@ -370,7 +371,7 @@ describe("buildDashboardSnapshot — per-type thick-phase gate", () => {
confidence: { score: 100, band: "high" },
composition: ["BLOOD_PRESSURE", "ACTIVITY", "SLEEP"],
deltaReason: null,
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
bandSetter: "BLOOD_PRESSURE",
// v1.21.2 (A5 / A6) — additive narrative fields, null absent a
// disagreeing readiness set / a returned metric (the fake derived
@@ -516,7 +517,7 @@ describe("buildDashboardSnapshot — healthScore (warm phase only)", () => {
confidence: { score: 100, band: "high" },
composition: ["BLOOD_PRESSURE", "ACTIVITY", "SLEEP"],
deltaReason: null,
scoreVersion: 2,
scoreVersion: SCORE_VERSION,
bandSetter: "BLOOD_PRESSURE",
// v1.21.2 (A5 / A6) — additive narrative fields, null here.
tension: null,