Files
HealthLog/src/__tests__/correlation-single-implementation-guard.test.ts
T
Marc-André Bombeck 760f261a5f test(guards): count fixed-path reads through readSourceText in the source-read ratchet
The ratchet on tests that read a source file by path matched readFileSync
and readFile only, so a guard that called readSourceText with a fixed path,
directly or through a local read(rel) wrapper, read the file without the
anchors readSource demands and was never counted. The classifier now counts
both shapes, and leaves alone a readSource call with anchors and a sweep that
feeds the reader from a walk.

The twelve guards that read a fixed file that way now go through readSource
with an anchor each read asserts on, so the baseline stays where it was.
2026-10-22 19:08:15 +02:00

92 lines
3.2 KiB
TypeScript

/**
* Structural guard: one Pearson correlation, one bar.
*
* Three implementations used to answer "how correlated are these two
* series": the engine's `pearson` (exact p-value, `lib/insights/
* correlations.ts`), its gated wrapper `significantPearsonCorrelation`
* (n >= 20 and p < 0.05), and an ungated `pearsonCorrelation` that banded a
* coefficient from |r| alone above five pairs. The ungated one fed the
* /insights envelope and the AI feature payload, so five days of noise
* sloping the right way reached a reader labelled "strong" there while every
* other surface refused the same five points. It is gone; every surface goes
* through the wrapper, and the wrapper through the engine.
*
* The matcher flags a function whose name says Pearson or correlation
* coefficient, declared anywhere but the engine and the wrapper's file, and
* any mention of the deleted name. It is a tripwire: a coefficient computed
* inline under another name slips it. Comments are stripped first; the
* planted cases prove it fires.
*/
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import {
readSource,
readSourceText,
stripComments,
walkSourceFiles,
} from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
const HOMES = new Set([
"lib/insights/correlations.ts",
"lib/analytics/correlations.ts",
]);
const PEARSON_DEFINITION =
/(?:function\s+|const\s+)\w*(?:pearson|correlationCoefficient)\w*\s*(?:=|\()/i;
const DELETED = /(?<![A-Za-z])pearsonCorrelation\b/;
function sourceFiles(): string[] {
return walkSourceFiles(SRC, { floor: 3000 }).filter(
(p) =>
!p.startsWith("generated/") &&
!p.includes("__tests__/") &&
!/\.test\.tsx?$/.test(p),
);
}
describe("one Pearson correlation", () => {
it("the matchers fire on a second implementation", () => {
expect(PEARSON_DEFINITION.test("export function pearsonR(xs, ys) {")).toBe(
true,
);
expect(PEARSON_DEFINITION.test("const quickPearson = (a, b) =>")).toBe(
true,
);
expect(DELETED.test("pearsonCorrelation(pairs)")).toBe(true);
expect(DELETED.test("significantPearsonCorrelation(pairs)")).toBe(false);
});
it("both homes still hold their function", () => {
const engine = readSource(
"src/lib/insights/correlations.ts",
"export function pearson",
);
const wrapper = readSource(
"src/lib/analytics/correlations.ts",
"export function significantPearsonCorrelation",
);
expect(engine).toMatch(/export function pearson\s*\(/);
expect(wrapper).toMatch(
/export function significantPearsonCorrelation\s*\(/,
);
});
it("no other file defines a Pearson coefficient or calls the deleted one", () => {
// The homes match the definition matcher, so a matcher gone blind fails here.
const definers = sourceFiles().filter((file) =>
PEARSON_DEFINITION.test(stripComments(readSourceText(join(SRC, file)))),
);
expect(definers.length).toBeGreaterThanOrEqual(2);
const offenders = sourceFiles().filter((file) => {
const code = stripComments(readSourceText(join(SRC, file)));
if (DELETED.test(code)) return true;
return !HOMES.has(file) && PEARSON_DEFINITION.test(code);
});
expect(offenders).toEqual([]);
});
});