style: apply prettier across the tree

One-shot prettier pass so the new format:check gate starts from a clean
baseline. Formatting only — no behaviour change. Generator-owned and
vendored artifacts stay untouched via .prettierignore.
This commit is contained in:
Marc-André Bombeck committed 2026-06-19 22:20:31 +02:00
1 parent b3fea2ef59
commit 1f4ba5939d
1000 files changed
+12130 -8385

No files matched your search

@@ -111,13 +111,17 @@ describe("computeEpisodeCorrelation — rollup-vs-live parity", () => {
// trailing (to == now) episode-window read; the bounded baseline read
// goes through measurement.findMany (to != now). ──
const dayCoverage = onlyRhr(
new Map<string, boolean>(ILLNESS_SCAN_TYPES.map((t) => [String(t), t === "RESTING_HEART_RATE"])),
new Map<string, boolean>(
ILLNESS_SCAN_TYPES.map((t) => [String(t), t === "RESTING_HEART_RATE"]),
),
);
rollup.probeRollupCoverage.mockResolvedValue(dayCoverage);
rollup.readBestGranularityRollups.mockImplementation(
async (_u: string, type: string, windowDays: number) => {
if (type !== "RESTING_HEART_RATE") return null;
const since = new Date(NOW.getTime() - windowDays * 24 * 60 * 60 * 1000);
const since = new Date(
NOW.getTime() - windowDays * 24 * 60 * 60 * 1000,
);
const sinceKey = since.toISOString().slice(0, 10);
const rows = DAILY.filter((d) => d.day >= sinceKey).map((d) => ({
bucketStart: new Date(`${d.day}T00:00:00Z`),
@@ -133,10 +137,16 @@ describe("computeEpisodeCorrelation — rollup-vs-live parity", () => {
return rows.length > 0 ? { granularity: "DAY" as const, rows } : null;
},
);
db.measurement.findMany.mockImplementation(async ({ where }: { where: { type: string; measuredAt: { gte: Date; lt: Date } } }) => {
if (where.type !== "RESTING_HEART_RATE") return [];
return rawRowsWithin(where.measuredAt.gte, where.measuredAt.lt);
});
db.measurement.findMany.mockImplementation(
async ({
where,
}: {
where: { type: string; measuredAt: { gte: Date; lt: Date } };
}) => {
if (where.type !== "RESTING_HEART_RATE") return [];
return rawRowsWithin(where.measuredAt.gte, where.measuredAt.lt);
},
);
const dayOut = await computeEpisodeCorrelation("u1", EPISODE, "UTC", NOW);
@@ -151,7 +161,11 @@ describe("computeEpisodeCorrelation — rollup-vs-live parity", () => {
rollup.probeRollupCoverage.mockResolvedValue(noCoverage);
rollup.readBestGranularityRollups.mockResolvedValue(null);
db.measurement.findMany.mockImplementation(
async ({ where }: { where: { type: string; measuredAt: { gte: Date; lt?: Date } } }) => {
async ({
where,
}: {
where: { type: string; measuredAt: { gte: Date; lt?: Date } };
}) => {
if (where.type !== "RESTING_HEART_RATE") return [];
const from = where.measuredAt.gte;
const to = where.measuredAt.lt ?? NOW;
@@ -192,7 +206,9 @@ describe("computeEpisodeCorrelation — user-tz day keying", () => {
// The vital series must key by the user's day so it lines up with the
// tz-keyed onset/feltBetter markers (the off-by-one this fix closes).
rollup.probeRollupCoverage.mockResolvedValue(
new Map<string, boolean>(ILLNESS_SCAN_TYPES.map((t) => [String(t), false])),
new Map<string, boolean>(
ILLNESS_SCAN_TYPES.map((t) => [String(t), false]),
),
);
rollup.readBestGranularityRollups.mockResolvedValue(null);
@@ -203,7 +219,10 @@ describe("computeEpisodeCorrelation — user-tz day keying", () => {
let cursor = Date.parse("2025-12-20T20:00:00Z");
const jit = [-2, -1, 0, 1, 2];
for (let i = 0; i < 20; i++) {
rows.push({ value: 55 + jit[i % jit.length], measuredAt: new Date(cursor) });
rows.push({
value: 55 + jit[i % jit.length],
measuredAt: new Date(cursor),
});
cursor += 24 * 60 * 60 * 1000;
}
// Episode-span readings, including the boundary-crossing 03:00Z spike.
@@ -215,7 +234,11 @@ describe("computeEpisodeCorrelation — user-tz day keying", () => {
rows.push({ value: 58, measuredAt: new Date("2026-01-17T20:00:00Z") });
db.measurement.findMany.mockImplementation(
async ({ where }: { where: { type: string; measuredAt: { gte: Date; lt?: Date } } }) => {
async ({
where,
}: {
where: { type: string; measuredAt: { gte: Date; lt?: Date } };
}) => {
if (where.type !== "RESTING_HEART_RATE") return [];
const from = where.measuredAt.gte.getTime();
const to = where.measuredAt.lt?.getTime() ?? NOW.getTime();
@@ -249,12 +272,18 @@ describe("computeEpisodeCorrelation — user-tz day keying", () => {
describe("computeEpisodeCorrelation — contamination-guard read window", () => {
it("never queries baseline rows on or after the pre-onset lookback start", async () => {
rollup.probeRollupCoverage.mockResolvedValue(
new Map<string, boolean>(ILLNESS_SCAN_TYPES.map((t) => [String(t), false])),
new Map<string, boolean>(
ILLNESS_SCAN_TYPES.map((t) => [String(t), false]),
),
);
rollup.readBestGranularityRollups.mockResolvedValue(null);
const seen: Array<{ gte: Date; lt?: Date }> = [];
db.measurement.findMany.mockImplementation(
async ({ where }: { where: { type: string; measuredAt: { gte: Date; lt?: Date } } }) => {
async ({
where,
}: {
where: { type: string; measuredAt: { gte: Date; lt?: Date } };
}) => {
if (where.type === "RESTING_HEART_RATE") seen.push(where.measuredAt);
return [];
},
+50 -12
View File
@@ -24,11 +24,18 @@ import {
const NOW = new Date("2026-02-01T00:00:00Z");
/** Build a flat baseline series of `days` days at `value`, ending `endDay`. */
function flatBaseline(value: number, days: number, endDay: string): VitalDayPoint[] {
function flatBaseline(
value: number,
days: number,
endDay: string,
): VitalDayPoint[] {
const out: VitalDayPoint[] = [];
let cursor = Date.parse(`${endDay}T00:00:00Z`);
for (let i = 0; i < days; i++) {
out.unshift({ day: new Date(cursor).toISOString().slice(0, 10), mean: value });
out.unshift({
day: new Date(cursor).toISOString().slice(0, 10),
mean: value,
});
cursor -= 24 * 60 * 60 * 1000;
}
return out;
@@ -39,16 +46,30 @@ function flatBaseline(value: number, days: number, endDay: string): VitalDayPoin
* is non-zero and stable. Means cycle through `center − jitter … center +
* jitter` so the median is `center` and the MAD is ~`jitter/2`.
*/
function jitteredBaseline(center: number, jitter: number, days: number, endDay: string): VitalDayPoint[] {
function jitteredBaseline(
center: number,
jitter: number,
days: number,
endDay: string,
): VitalDayPoint[] {
const base = flatBaseline(center, days, endDay);
const offsets = [-jitter, -jitter / 2, 0, jitter / 2, jitter];
return base.map((p, i) => ({ ...p, mean: center + offsets[i % offsets.length] }));
return base.map((p, i) => ({
...p,
mean: center + offsets[i % offsets.length],
}));
}
function input(over: Partial<IllnessCorrelationInput>): IllnessCorrelationInput {
function input(
over: Partial<IllnessCorrelationInput>,
): IllnessCorrelationInput {
return {
episodeId: "ep1",
window: { onsetDay: "2026-01-10", feltBetterDay: "2026-01-17", lifecycle: "ACUTE" },
window: {
onsetDay: "2026-01-10",
feltBetterDay: "2026-01-17",
lifecycle: "ACUTE",
},
series: [],
source: "DAY",
now: NOW,
@@ -60,7 +81,8 @@ describe("computeIllnessCorrelation — coverage gate", () => {
it("returns insufficient with no baselined vitals", () => {
const out = computeIllnessCorrelation(input({ series: [] }));
expect(out.status).toBe("insufficient");
if (out.status === "insufficient") expect(out.reason).toBe("no_baselined_vitals");
if (out.status === "insufficient")
expect(out.reason).toBe("no_baselined_vitals");
});
it("returns insufficient when a vital lacks the min baseline days", () => {
@@ -164,7 +186,11 @@ describe("computeIllnessCorrelation — golden recovery-gap", () => {
];
const out = computeIllnessCorrelation(
input({
window: { onsetDay: "2026-01-10", feltBetterDay: "2026-01-15", lifecycle: "CHRONIC_ONGOING" },
window: {
onsetDay: "2026-01-10",
feltBetterDay: "2026-01-15",
lifecycle: "CHRONIC_ONGOING",
},
series: [{ type, baselineDays, episodeDays }],
}),
);
@@ -185,7 +211,11 @@ describe("computeIllnessCorrelation — golden recovery-gap", () => {
];
const out = computeIllnessCorrelation(
input({
window: { onsetDay: "2026-01-10", feltBetterDay: null, lifecycle: "ACUTE" },
window: {
onsetDay: "2026-01-10",
feltBetterDay: null,
lifecycle: "ACUTE",
},
series: [{ type, baselineDays, episodeDays }],
}),
);
@@ -354,7 +384,9 @@ describe("computeIllnessCorrelation — red-flag escalation", () => {
);
expect(out.status).toBe("ok");
if (out.status !== "ok") return;
const fever = out.value.redFlags.find((f) => f.reason === "sustained_fever");
const fever = out.value.redFlags.find(
(f) => f.reason === "sustained_fever",
);
expect(fever).toBeDefined();
expect(fever?.days).toBe(3);
expect(fever?.worstValue).toBe(39.2);
@@ -391,7 +423,9 @@ describe("computeIllnessCorrelation — red-flag escalation", () => {
);
expect(out.status).toBe("ok");
if (out.status !== "ok") return;
const fever = out.value.redFlags.find((f) => f.reason === "sustained_fever");
const fever = out.value.redFlags.find(
(f) => f.reason === "sustained_fever",
);
expect(fever).toBeDefined();
expect(fever?.days).toBe(3);
});
@@ -418,7 +452,11 @@ describe("computeIllnessCorrelation — return anchor", () => {
];
const out = computeIllnessCorrelation(
input({
window: { onsetDay: "2026-01-10", feltBetterDay: "2026-01-15", lifecycle: "ACUTE" },
window: {
onsetDay: "2026-01-10",
feltBetterDay: "2026-01-15",
lifecycle: "ACUTE",
},
series: [{ type, baselineDays, episodeDays }],
}),
);
@@ -114,7 +114,12 @@ describe("upsertIllnessDayLog", () => {
it("reports inserted (existed=false) on a fresh row", async () => {
db.illnessDayLog.findUnique.mockResolvedValue(null);
const result = await upsertIllnessDayLog("u1", "ep1", base, "Europe/Berlin");
const result = await upsertIllnessDayLog(
"u1",
"ep1",
base,
"Europe/Berlin",
);
expect(result.existed).toBe(false);
const args = db.illnessDayLog.upsert.mock.calls[0][0];
expect(args.where).toEqual({
@@ -143,7 +148,12 @@ describe("upsertIllnessDayLog", () => {
noteEncrypted: null,
});
// Only fever supplied — functionalImpact must keep the stored 3.
await upsertIllnessDayLog("u1", "ep1", { date: "2026-06-16", feverC: 37 }, null);
await upsertIllnessDayLog(
"u1",
"ep1",
{ date: "2026-06-16", feverC: 37 },
null,
);
const args = db.illnessDayLog.upsert.mock.calls[0][0];
expect(args.update.functionalImpact).toBe(3);
expect(args.update.feverC).toBe(37);
@@ -28,7 +28,13 @@ describe("summarizeIllnessRetrospective", () => {
it("counts episodes, resolved, by-month, by-type", () => {
const out = summarizeIllnessRetrospective([
ep({ id: "a", onsetDay: "2026-01-05", type: "INFECTION" }),
ep({ id: "b", onsetDay: "2026-11-20", type: "INFECTION", resolved: false, recoveryGapDays: null }),
ep({
id: "b",
onsetDay: "2026-11-20",
type: "INFECTION",
resolved: false,
recoveryGapDays: null,
}),
ep({ id: "c", onsetDay: "2026-11-02", type: "ALLERGY" }),
]);
expect(out.episodeCount).toBe(3);
@@ -94,7 +94,9 @@ describe("notifySafetyFloor", () => {
it("stamps the ledger anchor (keyed by reason) before dispatching", async () => {
await notifySafetyFloor({ userId: "u9", decision: bpHigh });
expect(createMock).toHaveBeenCalledTimes(1);
expect(createMock.mock.calls[0][0].data.reason).toContain("bp_hypertensive");
expect(createMock.mock.calls[0][0].data.reason).toContain(
"bp_hypertensive",
);
expect(createMock.mock.calls[0][0].data.eventType).toBe("SYSTEM_ALERT");
});
+34 -7
View File
@@ -81,7 +81,9 @@ export async function computeEpisodeCorrelation(
const end = episode.resolvedAt ?? now;
// Window seams (UTC instants; the day keys are read in the user's tz).
const preOnsetStart = new Date(onset.getTime() - PRE_ONSET_LOOKBACK_DAYS * MS_PER_DAY);
const preOnsetStart = new Date(
onset.getTime() - PRE_ONSET_LOOKBACK_DAYS * MS_PER_DAY,
);
const baselineEnd = preOnsetStart; // baseline ends where the lookback starts
const baselineStart = new Date(
baselineEnd.getTime() - BASELINE_WINDOW_DAYS * MS_PER_DAY,
@@ -106,8 +108,24 @@ export async function computeEpisodeCorrelation(
ILLNESS_SCAN_TYPES.map((type) =>
limit(async () => {
const [baseline, episodeWin] = await Promise.all([
readWindowMeans(userId, type, baselineStart, baselineEnd, coverage, tz, now),
readWindowMeans(userId, type, preOnsetStart, end, coverage, tz, now),
readWindowMeans(
userId,
type,
baselineStart,
baselineEnd,
coverage,
tz,
now,
),
readWindowMeans(
userId,
type,
preOnsetStart,
end,
coverage,
tz,
now,
),
]);
return { type, baseline, episodeWin };
}),
@@ -120,8 +138,10 @@ export async function computeEpisodeCorrelation(
let anyLive = false;
let anyDay = false;
for (const { type, baseline, episodeWin } of perType) {
if (baseline.points.length === 0 && episodeWin.points.length === 0) continue;
if (baseline.source === "live" || episodeWin.source === "live") anyLive = true;
if (baseline.points.length === 0 && episodeWin.points.length === 0)
continue;
if (baseline.source === "live" || episodeWin.source === "live")
anyLive = true;
if (baseline.source === "DAY" || episodeWin.source === "DAY") anyDay = true;
series.push({
type,
@@ -129,7 +149,10 @@ export async function computeEpisodeCorrelation(
episodeDays: episodeWin.points.map((p) => ({ day: p.day, mean: p.mean })),
// Per-day max over the episode window — the fever red-flag prefers it so
// an evening spike averaged toward normal in the daily mean is not masked.
episodeDayMax: episodeWin.points.map((p) => ({ day: p.day, mean: p.max })),
episodeDayMax: episodeWin.points.map((p) => ({
day: p.day,
mean: p.max,
})),
});
}
@@ -173,7 +196,11 @@ async function readWindowMeans(
Math.ceil((to.getTime() - from.getTime()) / MS_PER_DAY),
);
const resolved = await readBestGranularityRollups(userId, type, windowDays);
if (resolved && resolved.granularity === "DAY" && resolved.rows.length > 0) {
if (
resolved &&
resolved.granularity === "DAY" &&
resolved.rows.length > 0
) {
const fromKey = dayKeyForUserTz(from, tz);
// DAY buckets are minted at the UTC midnight of the user-tz day, so
// keying `bucketStart` through the user tz is exact.
+32 -17
View File
@@ -76,19 +76,20 @@ export const MIN_EPISODE_COVERAGE_DAYS = 4;
* Weight/glucose have no single illness-adverse direction → omitted (their
* deviation magnitude is still surfaced, direction stays neutral).
*/
export const ADVERSE_DIRECTION: Partial<Record<MeasurementType, "up" | "down">> =
{
RESTING_HEART_RATE: "up",
PULSE: "up",
BODY_TEMPERATURE: "up",
SKIN_TEMPERATURE: "up",
RESPIRATORY_RATE: "up",
BLOOD_PRESSURE_SYS: "up",
BLOOD_PRESSURE_DIA: "up",
HEART_RATE_VARIABILITY: "down",
RECOVERY_SCORE: "down",
OXYGEN_SATURATION: "down",
};
export const ADVERSE_DIRECTION: Partial<
Record<MeasurementType, "up" | "down">
> = {
RESTING_HEART_RATE: "up",
PULSE: "up",
BODY_TEMPERATURE: "up",
SKIN_TEMPERATURE: "up",
RESPIRATORY_RATE: "up",
BLOOD_PRESSURE_SYS: "up",
BLOOD_PRESSURE_DIA: "up",
HEART_RATE_VARIABILITY: "down",
RECOVERY_SCORE: "down",
OXYGEN_SATURATION: "down",
};
/**
* Vitals scanned by the illness engine. Superset of the typical-range set
@@ -316,7 +317,14 @@ export function computeIllnessCorrelation(
// Only vitals with a trustworthy own-baseline band participate.
const banded = input.series
.map((s) => ({ series: s, band: bandFor(s) }))
.filter((b): b is { series: VitalSeries; band: { center: number; spread: number } } => b.band !== null);
.filter(
(
b,
): b is {
series: VitalSeries;
band: { center: number; spread: number };
} => b.band !== null,
);
const inputs = banded.map((b) => String(b.series.type));
const provenance = {
@@ -447,8 +455,12 @@ export function computeIllnessCorrelation(
return buildOk<IllnessCorrelationValue>({
value: {
episodeId: input.episodeId,
preOnset: preOnset.sort((a, b) => Math.abs(b.deviationSd) - Math.abs(a.deviationSd)),
nadir: nadir.sort((a, b) => Math.abs(b.deviationSd) - Math.abs(a.deviationSd)),
preOnset: preOnset.sort(
(a, b) => Math.abs(b.deviationSd) - Math.abs(a.deviationSd),
),
nadir: nadir.sort(
(a, b) => Math.abs(b.deviationSd) - Math.abs(a.deviationSd),
),
returns,
recoveryGapDays,
feltBetterDay: window.feltBetterDay,
@@ -526,7 +538,10 @@ function detectRedFlags(input: IllnessCorrelationInput): IllnessRedFlag[] {
}
for (const p of input.dayLogFever ?? []) {
if (!inActive(p)) continue;
feverByDay.set(p.day, Math.max(feverByDay.get(p.day) ?? -Infinity, p.feverC));
feverByDay.set(
p.day,
Math.max(feverByDay.get(p.day) ?? -Infinity, p.feverC),
);
}
if (feverByDay.size > 0) {
const fevPoints: VitalDayPoint[] = [...feverByDay.entries()].map(
+1 -4
View File
@@ -15,10 +15,7 @@
* dropped silently.
*/
import { prisma } from "@/lib/db";
import {
decryptFromBytes,
encryptToBytes,
} from "@/lib/ai/coach/bytes-codec";
import { decryptFromBytes, encryptToBytes } from "@/lib/ai/coach/bytes-codec";
import type { IllnessDayLogInput } from "@/lib/validations/illness";
import { dayLogSymptomInclude, toIllnessDayLogDTO } from "@/lib/illness/dto";
import type { IllnessDayLogDTO } from "@/lib/illness/dto";
+2 -1
View File
@@ -86,7 +86,8 @@ export async function getActiveIllnessEpisodes(
// `findMany`. Dedupe them to a single read per request. An explicit client
// (a test stub or a transaction) bypasses the memo so its query is never
// served a default-client cached result.
if (client !== defaultPrisma) return readActiveIllnessEpisodes(userId, asOf, client);
if (client !== defaultPrisma)
return readActiveIllnessEpisodes(userId, asOf, client);
return memoizePerRequest(
`illness-active-episodes:${userId}:${asOf.getTime()}`,
() => readActiveIllnessEpisodes(userId, asOf, client),