Guard every pulse mean reader behind the day-mean helper

A structural test lists every file that takes a database or in-memory mean
over measurement values and names pulse, and requires each to use the shared
statistic, hand the type to a fold that does, or state why it never averages
pulse readings. A new plain mean over pulse, or a reader that drops the type,
fails it.
This commit is contained in:
Marc-André Bombeck committed 2026-10-04 11:39:33 +02:00
1 parent 8f730484e0
commit 06f210b56f
1 file changed
+249
@@ -0,0 +1,249 @@
/**
* Structural guard: every reader that averages pulse goes through the
* day-mean helper.
*
* A watch samples pulse every few minutes at rest and every few seconds in a
* workout, so a plain mean over pulse readings lets one workout hour outweigh
* the rest of the day. A day of pulse is the mean of its hours' means and a
* window the mean of its days (`src/lib/measurements/day-statistic.ts`), and
* `src/lib/measurements/day-mean.ts` is the one place that computes it. The
* statistic first shipped in the chart and the rollup tier while some twenty
* other readers kept the plain mean, so the dashboard's year delta compared
* one statistic against another.
*
* Two matchers, both frozen both ways (a new unlisted match fails, a listed
* file that no longer matches fails):
*
* 1. Database means over measurement values: `AVG(value)`, the per-day
* folds `SUM(total) / SUM(cnt)` and `SUM(count * mean)`, and Prisma's
* `_avg: { value }`. A file that holds one imports the shared statistic
* (it averages pulse among other types and the helper's CASE keeps the
* others on the plain mean).
*
* 2. In-memory means in a file that names pulse: a left fold divided by a
* length, `avgInWindow(`, `summarize(`, `bucketWeekly(`,
* `buildDailyValueRows(` or `applyPayloadBudget(`. A file that holds one
* imports the shared statistic, hands the type to a fold that does, or
* is listed with the reason it never averages pulse readings.
*
* Comments are stripped before matching, the matchers are whitespace-tolerant,
* and the floors fail the guard if either matcher stops finding anything. The
* planted cases run each matcher over an offender; dropping the type from the
* mood correlation's fold, or a new file with a plain `AVG(value)` over pulse,
* fails the two list checks. It is a tripwire, not a proof: a mean written
* some other way slips it.
*/
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
/** The shared statistic: the helper, or the type set it is keyed on. */
const HELPER_IMPORT =
/from\s+["'](?:@\/lib\/measurements\/|\.\/)day-(?:mean|statistic)["']/;
/** Comments go first: a mean named in prose is not a mean computed. */
function stripComments(text: string): string {
return text
.replace(/\/\*[\s\S]*?\*\//g, "")
.replace(/^\s*\/\/.*$/gm, "")
.replace(/^\s*--.*$/gm, "");
}
/**
* Database means over a measurement value: SQL `AVG(value)`, the per-day folds
* `SUM(total) / SUM(cnt)` and `SUM(count * mean)`, and Prisma's
* `_avg: { value: ... }`.
*/
const SQL_MEAN =
/_avg\s*:\s*\{\s*value\s*:|\bAVG\s*\(\s*(?:[a-z_]+\s*\.\s*)?"?value"?\s*\)|\bSUM\s*\(\s*(?:[a-z_]+\s*\.\s*)?"?total"?\s*\)\s*\/\s*SUM\s*\(\s*(?:[a-z_]+\s*\.\s*)?"?cnt"?\s*\)|\bSUM\s*\(\s*"?count"?\s*\*\s*"?mean"?\s*\)/gi;
/** In-memory means and the folds that make them, counted in files that name pulse. */
const TS_MEAN =
/\.reduce\(\s*\(\s*\w+\s*,\s*\w+\s*\)\s*=>\s*\w+\s*\+\s*[\w.]+\s*,\s*0\s*\)\s*\/\s*[\w.]+\.length|\bavgInWindow\s*\(|\bsummarize\s*\(|\bbucketWeekly\s*\(|\bbuildDailyValueRows\s*\(|\bapplyPayloadBudget\s*\(/g;
const NAMES_PULSE = /\bPULSE\b/;
type Entry =
/** Averages pulse and imports the shared statistic. */
| { helper: true }
/** Averages pulse through a fold that imports it, and hands that fold the type. */
| { via: string; passes: RegExp }
/** Never averages pulse readings; the reason is the claim. */
| { exempt: string };
const HELPER: Entry = { helper: true };
/** Files with a database mean over values. */
const SQL_READERS: Record<string, Entry> = {
"app/api/measurements/series/route.ts": HELPER,
"lib/ai/coach/tools/availability.ts": HELPER,
"lib/analytics/summaries-slice.ts": HELPER,
"lib/doctor-report/dense-buckets.ts": HELPER,
"lib/insights/comprehensive-aggregator.ts": HELPER,
"lib/insights/comprehensive-generate.ts": HELPER,
"lib/measurements/daily-series-read.ts": HELPER,
"lib/rollups/measurement-rollups.ts": HELPER,
"lib/rollups/tiered-context.ts": HELPER,
};
/** Files that name pulse and hold an in-memory mean or a mean-making fold. */
const TS_READERS: Record<string, Entry> = {
"app/api/measurements/series/route.ts": HELPER,
"lib/doctor-report/collect.ts": HELPER,
"lib/doctor-report-pdf/clinical-summary.ts": HELPER,
"lib/insights/comprehensive-generate.ts": HELPER,
"lib/insights/features.ts": HELPER,
"lib/insights/mood-status.ts": {
via: "lib/insights/bucket-series.ts",
passes: /\{\s*now\s*,\s*tz\s*,\s*type\s*\}/,
},
"lib/insights/pulse-status.ts": {
via: "lib/insights/bucket-series.ts",
passes:
/applyPayloadBudget\(\s*pulsePoints\s*,\s*\{[^}]*type\s*:\s*"PULSE"/,
},
"lib/insights/signals-of-day.ts": {
via: "lib/insights/features.ts",
passes: /byType\(\s*"PULSE"\s*\)[\s\S]{0,80}type\s*:\s*"PULSE"/,
},
"lib/ai/coach/snapshot-blocks/core-metrics-block.ts": {
via: "lib/ai/coach/snapshot-series.ts",
passes: /buildDailyValueRows\([^)]*"PULSE"/,
},
"components/charts/health-chart.tsx": {
exempt:
"a rolling average over the points the chart draws: display smoothing, not a stated figure",
},
"lib/analytics/correlations-fast-path.ts": {
exempt: "mood mean; pulse enters as the resting series, never a day mean",
},
"lib/dashboard/snapshot.ts": {
exempt: "summarises water-intake days and glucose contexts",
},
"lib/gamification/expansion-metrics.ts": {
exempt: "means of mood day means; pulse is only counted",
},
"lib/illness/correlation.ts": { exempt: "mean of episode durations" },
"lib/insights/mood-aggregates.ts": { exempt: "the mood series only" },
"lib/insights/narrative/period-narrative.ts": {
exempt: "means of day-keyed series, already one value per day",
},
"lib/mcp/rich-reads.ts": {
exempt:
"changepoints over rollup bucket means, which weigh pulse days once (readCanonicalRollupBuckets)",
},
"lib/medications/efficacy/build-efficacy.ts": {
exempt: "means of the day-mean series (readDayMeanSeries)",
},
"lib/targets/build-response.ts": {
exempt:
"pulse is excluded from the 30-day averages; the resting proxy stands in",
},
"lib/targets/vitals-builder.ts": {
exempt:
"trend halves over the other vitals and the resting proxy's day points",
},
"app/api/insights/cards/route.ts": {
exempt: "pulse is summarised from day means (readDayMeanSeries)",
},
"app/api/insights/comprehensive/route.ts": {
exempt: "summarises the mood series only",
},
};
function scan(): { sql: Map<string, number>; ts: Map<string, number> } {
const files = walkSourceFiles(SRC, { floor: 1500 }).filter(
(f) =>
!f.startsWith("generated/") &&
!f.includes("__tests__/") &&
!/\.test\.tsx?$/.test(f) &&
f !== "lib/measurements/day-mean.ts",
);
const sql = new Map<string, number>();
const ts = new Map<string, number>();
for (const f of files) {
const text = stripComments(readFileSync(join(SRC, f), "utf8"));
const s = text.match(SQL_MEAN)?.length ?? 0;
if (s > 0) sql.set(f, s);
if (NAMES_PULSE.test(text)) {
const t = text.match(TS_MEAN)?.length ?? 0;
if (t > 0) ts.set(f, t);
}
}
return { sql, ts };
}
const { sql, ts } = scan();
const source = (f: string) => readFileSync(join(SRC, f), "utf8");
function check(found: Map<string, number>, listed: Record<string, Entry>) {
const unlisted = [...found.keys()].filter((f) => !(f in listed)).sort();
const stale = Object.keys(listed)
.filter((f) => !found.has(f))
.sort();
const broken: string[] = [];
for (const [f, entry] of Object.entries(listed)) {
if (!found.has(f)) continue;
if ("helper" in entry && !HELPER_IMPORT.test(source(f))) {
broken.push(`${f}: does not import the day-mean helper`);
}
if ("via" in entry) {
if (!HELPER_IMPORT.test(source(entry.via))) {
broken.push(`${f}: ${entry.via} does not import the day-mean helper`);
}
if (!entry.passes.test(source(f))) {
broken.push(`${f}: no longer hands the type to ${entry.via}`);
}
}
}
return { unlisted, stale, broken };
}
describe("pulse day-mean reader guard", () => {
it("finds the SQL means it is meant to find", () => {
expect(sql.size).toBeGreaterThanOrEqual(9);
expect([...sql.values()].reduce((a, b) => a + b, 0)).toBeGreaterThanOrEqual(
15,
);
});
it("finds the in-memory pulse means it is meant to find", () => {
expect(ts.size).toBeGreaterThanOrEqual(20);
});
it("every SQL mean over values is listed, and every listed pulse reader uses the helper", () => {
expect(check(sql, SQL_READERS)).toEqual({
unlisted: [],
stale: [],
broken: [],
});
});
it("every in-memory pulse mean is listed, and every listed reader uses the helper", () => {
expect(check(ts, TS_READERS)).toEqual({
unlisted: [],
stale: [],
broken: [],
});
});
it("catches a planted plain AVG and a planted fold", () => {
expect(
`SELECT AVG( m."value" ) FROM measurements m`.match(SQL_MEAN),
).toHaveLength(1);
expect(`(SUM(c.total) / SUM(c.cnt))`.match(SQL_MEAN)).toHaveLength(1);
expect(`SUM("count" * "mean")`.match(SQL_MEAN)).toHaveLength(1);
expect(`aggregate({ _avg: { value: true } })`.match(SQL_MEAN)).toHaveLength(
1,
);
expect(stripComments("// AVG(value) in prose").match(SQL_MEAN)).toBeNull();
const planted = `const pulse = byType("PULSE");
const avg = pulse.reduce((s, r) => s + r.value, 0) / pulse.length;`;
expect(NAMES_PULSE.test(planted)).toBe(true);
expect(planted.match(TS_MEAN)).toHaveLength(1);
});
});