mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
fix(verify): rewrite counted baselines only when a count was lowered (#10669)
* fix(verify): rewrite counted baselines only when a count was lowered * test(verify): own the baseline write decision in a tested helper
This commit is contained in:
1 parent
133e7762b6
commit
e652f4409e
4 files changed
+81
-12
No files matched your search
@@ -3,7 +3,10 @@ import { existsSync } from "node:fs";
|
||||
import { readFile, readdir, writeFile } from "node:fs/promises";
|
||||
import { join, relative, sep } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { compareCountedBaseline } from "./counted-baseline.mjs";
|
||||
import {
|
||||
compareCountedBaseline,
|
||||
recordLoweredBaseline,
|
||||
} from "./counted-baseline.mjs";
|
||||
|
||||
// Architecture guards for the strict-identity / best-effort-inference split.
|
||||
// - Composite dedup keys must not NUL-join variable-length or free-form
|
||||
@@ -205,10 +208,7 @@ const checkCounted = (label, key, selected, pattern, owners) => {
|
||||
failures.push(
|
||||
`${label}; new copies are not allowed:\n${lines(compared.grown)}`,
|
||||
);
|
||||
if (compared.baseline !== (baselines[key] ?? {})) {
|
||||
baselines[key] = compared.baseline;
|
||||
baselinesShrunk = true;
|
||||
}
|
||||
if (recordLoweredBaseline(baselines, key, compared)) baselinesShrunk = true;
|
||||
if (compared.stale.length > 0)
|
||||
failures.push(
|
||||
`${label}; copies were removed, so lower the baseline with \`node scripts/verify/architecture-guards.mjs --shrink-baselines\`:\n${lines(compared.stale)}`,
|
||||
|
||||
@@ -14,4 +14,16 @@ export function compareCountedBaseline(
|
||||
readonly grown: CountedBaselineDifference[];
|
||||
readonly stale: CountedBaselineDifference[];
|
||||
readonly baseline: Record<string, number>;
|
||||
/** True only when `shrink` lowered or removed a recorded count. */
|
||||
readonly lowered: boolean;
|
||||
};
|
||||
|
||||
/** Record a lowered baseline under `key`; true when the map changed. */
|
||||
export function recordLoweredBaseline(
|
||||
baselines: Record<string, Record<string, number>>,
|
||||
key: string,
|
||||
compared: {
|
||||
readonly baseline: Record<string, number>;
|
||||
readonly lowered: boolean;
|
||||
},
|
||||
): boolean;
|
||||
@@ -2,7 +2,8 @@
|
||||
* Compare observed per-file counts with a counted baseline. A file may not
|
||||
* exceed its recorded count. A count below the baseline is stale; with
|
||||
* `shrink`, the returned baseline lowers it (and drops zero entries) but never
|
||||
* raises any count.
|
||||
* raises any count; `lowered` says whether it did, so callers rewrite a
|
||||
* baseline only when it changed.
|
||||
*/
|
||||
export const compareCountedBaseline = (counts, baseline, shrink) => {
|
||||
const grown = [];
|
||||
@@ -15,10 +16,23 @@ export const compareCountedBaseline = (counts, baseline, shrink) => {
|
||||
const count = counts.get(path) ?? 0;
|
||||
if (count < allowed) stale.push({ path, count, allowed });
|
||||
}
|
||||
if (!shrink || stale.length === 0) return { grown, stale, baseline };
|
||||
const lowered = { ...baseline };
|
||||
if (!shrink || stale.length === 0)
|
||||
return { grown, stale, baseline, lowered: false };
|
||||
const shrunk = { ...baseline };
|
||||
for (const { path, count } of stale)
|
||||
if (count === 0) delete lowered[path];
|
||||
else lowered[path] = count;
|
||||
return { grown, stale: [], baseline: lowered };
|
||||
if (count === 0) delete shrunk[path];
|
||||
else shrunk[path] = count;
|
||||
return { grown, stale: [], baseline: shrunk, lowered: true };
|
||||
};
|
||||
|
||||
/**
|
||||
* Record a comparison's lowered baseline under `key` in the full baseline
|
||||
* map. Returns whether the map changed, so the caller rewrites the file only
|
||||
* then. A key whose last count was removed is deleted rather than kept empty.
|
||||
*/
|
||||
export const recordLoweredBaseline = (baselines, key, compared) => {
|
||||
if (!compared.lowered) return false;
|
||||
if (Object.keys(compared.baseline).length === 0) delete baselines[key];
|
||||
else baselines[key] = compared.baseline;
|
||||
return true;
|
||||
};
|
||||
@@ -1,6 +1,9 @@
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import { compareCountedBaseline } from "../../../scripts/verify/counted-baseline.mjs";
|
||||
import {
|
||||
compareCountedBaseline,
|
||||
recordLoweredBaseline,
|
||||
} from "../../../scripts/verify/counted-baseline.mjs";
|
||||
|
||||
it("rejects a file that gains copies or is missing from the baseline", () => {
|
||||
const compared = compareCountedBaseline(
|
||||
@@ -30,6 +33,19 @@ it("reports removed copies as stale until the baseline is lowered", () => {
|
||||
{ path: "src/gone.ts", count: 0, allowed: 1 },
|
||||
]);
|
||||
expect(compared.baseline).toBe(baseline);
|
||||
expect(compared.lowered).toBe(false);
|
||||
});
|
||||
|
||||
it("leaves an absent baseline unchanged so the guard writes no empty entry", () => {
|
||||
for (const shrink of [false, true]) {
|
||||
const compared = compareCountedBaseline(new Map(), {}, shrink);
|
||||
expect(compared).toEqual({
|
||||
grown: [],
|
||||
stale: [],
|
||||
baseline: {},
|
||||
lowered: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("only lowers counts when shrinking, never raising one that grew", () => {
|
||||
@@ -45,5 +61,32 @@ it("only lowers counts when shrinking, never raising one that grew", () => {
|
||||
expect(compared.baseline).toEqual({ "src/a.ts": 1, "src/b.ts": 1 });
|
||||
expect(compared.grown).toEqual([{ path: "src/b.ts", count: 5, allowed: 1 }]);
|
||||
expect(compared.stale).toEqual([]);
|
||||
expect(compared.lowered).toBe(true);
|
||||
expect(baseline).toEqual({ "src/a.ts": 2, "src/b.ts": 1, "src/gone.ts": 4 });
|
||||
});
|
||||
|
||||
it("leaves the baseline map unchanged for a key with no baseline", () => {
|
||||
for (const shrink of [false, true]) {
|
||||
const baselines: Record<string, Record<string, number>> = {
|
||||
other: { "src/a.ts": 1 },
|
||||
};
|
||||
const compared = compareCountedBaseline(
|
||||
new Map(),
|
||||
baselines["new-key"] ?? {},
|
||||
shrink,
|
||||
);
|
||||
expect(recordLoweredBaseline(baselines, "new-key", compared)).toBe(false);
|
||||
expect(baselines).toEqual({ other: { "src/a.ts": 1 } });
|
||||
}
|
||||
});
|
||||
|
||||
it("removes a key when shrinking removes its last recorded count", () => {
|
||||
const gone = { "src/a.ts": 1 };
|
||||
const baselines: Record<string, Record<string, number>> = {
|
||||
gone,
|
||||
kept: { "src/b.ts": 2 },
|
||||
};
|
||||
const compared = compareCountedBaseline(new Map(), gone, true);
|
||||
expect(recordLoweredBaseline(baselines, "gone", compared)).toBe(true);
|
||||
expect(baselines).toEqual({ kept: { "src/b.ts": 2 } });
|
||||
});
|
||||
Reference in new issue
Block a user