From be79603d53fd07b9ef5b5282f6d6d2ddf298c7e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Tue, 20 Oct 2026 10:01:30 +0200 Subject: [PATCH] chore(guards): give the linear-fit guard a match floor and keep SQL out of the i18n scan The linear-fit guard floored only its walk; it now also requires the implementation's call sites it expects. The per-type readings query aliased its driving relation t, which the i18n call-site scanner read as a translation call; it is mt now, as in readLatestEver. --- .../linear-fit-single-implementation-guard.test.ts | 8 ++++++++ src/lib/insights/recent-readings.ts | 10 ++++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/__tests__/linear-fit-single-implementation-guard.test.ts b/src/__tests__/linear-fit-single-implementation-guard.test.ts index b1ee601f5..424ca3b43 100644 --- a/src/__tests__/linear-fit-single-implementation-guard.test.ts +++ b/src/__tests__/linear-fit-single-implementation-guard.test.ts @@ -57,6 +57,14 @@ describe("one least-squares line", () => { ), ); expect(offenders).toEqual([]); + // The six readers now call the implementation: a sweep that finds fewer + // call sites read the wrong tree or lost one. + const callers = files.filter((file) => + /\b(?:linearFit|fitFromSums|trendLineByTime)\s*\(/.test( + stripComments(readFileSync(join(SRC, file), "utf8")), + ), + ); + expect(callers.length).toBeGreaterThanOrEqual(7); // The implementation itself matches, so the sweep read real files. expect( HAND_ROLLED_SLOPE.test( diff --git a/src/lib/insights/recent-readings.ts b/src/lib/insights/recent-readings.ts index f7761440e..3d210cf98 100644 --- a/src/lib/insights/recent-readings.ts +++ b/src/lib/insights/recent-readings.ts @@ -70,7 +70,9 @@ export async function readRecentReadings( * the multi-metric overview. It read the newest 5 000 rows across all types * at once, so a dense stream (pulse every few minutes) filled the whole read * within days and every other type fell out of the overview. One index - * descent per type now bounds each type on its own. + * descent per type now bounds each type on its own. The driving relation is + * aliased `mt`, the way `readLatestEver` aliases it, so the i18n call-site + * scanner does not read the SQL as a translation call. */ export async function readLatestReadingsPerType( userId: string, @@ -81,13 +83,13 @@ export async function readLatestReadingsPerType( const rows = await prisma.$queryRaw< Array<{ type: MeasurementType; value: number; measured_at: Date }> >` - SELECT t."type" AS "type", x."value", x."measured_at" - FROM unnest(${[...types]}::text[]) AS t("type") + SELECT mt."type" AS "type", x."value", x."measured_at" + FROM unnest(${[...types]}::text[]) AS mt("type") CROSS JOIN LATERAL ( SELECT m."value", m."measured_at" FROM measurements m WHERE m."user_id" = ${userId} - AND m."type" = t."type"::measurement_type + AND m."type" = mt."type"::measurement_type AND m."deleted_at" IS NULL ORDER BY m."measured_at" DESC LIMIT ${perType}