Add scripts/test-value-audit.mjs + scripts/lib/test-value-audit-lib.mjs: a heuristic that scores every test file under packages/*/src/**/__tests__/** and packages/dashboard/app/**/__tests__/** from git history, classifying commits as positive (fix+source co-change, Symptom Verification regressions, added-with-source) vs negative (flake/quarantine/timeout churn, test-only modifies, quarantine-ledger membership). Joins per-file durations from scripts/test-timings.json so SLOW + LOW-VALUE files rank first as deletion candidates. Emits docs/test-value-audit.json + docs/test-value-audit.md (top 40 + methodology + caveats). Pure scoring logic is unit-tested with synthetic commit records. The script never deletes tests — evidence only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
172 lines
6.8 KiB
JavaScript
172 lines
6.8 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
classifyCommit,
|
|
scoreFile,
|
|
isFixSubject,
|
|
WEIGHTS,
|
|
NEGATIVE_KEYWORDS,
|
|
} from "../lib/test-value-audit-lib.mjs";
|
|
|
|
/*
|
|
FNXC:TestInfrastructure 2026-06-25-00:00:
|
|
Unit coverage for the test-value-audit classifier. Feeds synthetic commit records and
|
|
asserts the scoring so the heuristic's behavior is pinned independent of git/FS IO.
|
|
*/
|
|
|
|
// --- isFixSubject ---
|
|
test("isFixSubject matches conventional fix subjects incl. fix(FN-XXXX)", () => {
|
|
assert.ok(isFixSubject("fix(FN-1234): correct merge race"));
|
|
assert.ok(isFixSubject("fix: handle null"));
|
|
assert.ok(isFixSubject("fix!: breaking repair"));
|
|
assert.ok(!isFixSubject("feat(FN-1): add thing"));
|
|
assert.ok(!isFixSubject("prefix change"));
|
|
});
|
|
|
|
// --- classifyCommit positive signals ---
|
|
test("fix subject + source change is strongest positive", () => {
|
|
const c = classifyCommit({ subject: "fix(FN-9): bug", body: "", status: "M", touchedSource: true });
|
|
assert.equal(c.category, "positive");
|
|
assert.equal(c.weight, WEIGHTS.fixWithSource);
|
|
assert.ok(c.signals.includes("fix+source"));
|
|
});
|
|
|
|
test("fix subject without source change is a weaker positive", () => {
|
|
const c = classifyCommit({ subject: "fix: bug", body: "", status: "M", touchedSource: false });
|
|
assert.equal(c.weight, WEIGHTS.fix);
|
|
assert.ok(c.signals.includes("fix"));
|
|
});
|
|
|
|
test("symptom verification marker adds positive weight on top of fix", () => {
|
|
const c = classifyCommit({
|
|
subject: "fix(FN-5893): invariant",
|
|
body: "## Symptom Verification\nOriginal symptom: ...",
|
|
status: "M",
|
|
touchedSource: true,
|
|
});
|
|
assert.equal(c.weight, WEIGHTS.fixWithSource + WEIGHTS.symptomVerification);
|
|
assert.ok(c.signals.includes("symptom-verification"));
|
|
});
|
|
|
|
test("added with source is positive; added alone is weak positive", () => {
|
|
const withSrc = classifyCommit({ subject: "feat: x", status: "A", touchedSource: true });
|
|
assert.equal(withSrc.weight, WEIGHTS.addedWithSource);
|
|
assert.ok(withSrc.signals.includes("added-with-source"));
|
|
|
|
const alone = classifyCommit({ subject: "test: x", status: "A", touchedSource: false });
|
|
assert.equal(alone.weight, WEIGHTS.added);
|
|
assert.ok(alone.signals.includes("added"));
|
|
});
|
|
|
|
test("non-fix test+source modify is a mild positive", () => {
|
|
const c = classifyCommit({ subject: "refactor: rework", status: "M", touchedSource: true });
|
|
assert.equal(c.weight, WEIGHTS.testPlusSource);
|
|
assert.ok(c.signals.includes("test+source"));
|
|
});
|
|
|
|
// --- classifyCommit negative signals ---
|
|
test("flake/quarantine keywords produce negative weight", () => {
|
|
for (const kw of NEGATIVE_KEYWORDS) {
|
|
const c = classifyCommit({ subject: `chore: ${kw} the test`, status: "M", touchedSource: false });
|
|
assert.ok(c.weight <= WEIGHTS.churnKeyword, `keyword ${kw} should be negative`);
|
|
assert.ok(c.signals.includes("churn-keyword"));
|
|
}
|
|
});
|
|
|
|
test("test-only modify (no source, no fix) is churn", () => {
|
|
const c = classifyCommit({ subject: "chore: tidy assertions", status: "M", touchedSource: false });
|
|
assert.equal(c.category, "negative");
|
|
assert.equal(c.weight, WEIGHTS.testOnlyChurn);
|
|
assert.ok(c.signals.includes("test-only-churn"));
|
|
});
|
|
|
|
test("a fix that also mentions a churn keyword nets toward neutral (mixed signal)", () => {
|
|
const c = classifyCommit({
|
|
subject: "fix(FN-1): widen timeout to stabilize merge",
|
|
status: "M",
|
|
touchedSource: true,
|
|
});
|
|
// churnKeyword(-3) + fixWithSource(+3) = 0 -> neutral, both signals recorded.
|
|
assert.equal(c.weight, 0);
|
|
assert.equal(c.category, "neutral");
|
|
assert.ok(c.signals.includes("churn-keyword"));
|
|
assert.ok(c.signals.includes("fix+source"));
|
|
});
|
|
|
|
// --- scoreFile aggregation ---
|
|
test("scoreFile sums weights and recommends keep for net-positive files", () => {
|
|
const commits = [
|
|
classifyCommit({ subject: "test: add", status: "A", touchedSource: true }), // +2
|
|
classifyCommit({ subject: "fix(FN-2): real bug", status: "M", touchedSource: true }), // +3
|
|
];
|
|
const s = scoreFile({ commits, durationMs: 500, testCount: 4 });
|
|
assert.equal(s.valueScore, 5);
|
|
assert.equal(s.positiveCount, 2);
|
|
assert.equal(s.recommendation, "keep");
|
|
assert.equal(s.safeDelete, false);
|
|
});
|
|
|
|
test("scoreFile recommends delete + safeDelete for pure churn with no positives", () => {
|
|
const commits = [
|
|
classifyCommit({ subject: "chore: tweak", status: "M", touchedSource: false }), // -1
|
|
classifyCommit({ subject: "chore: deflake", status: "M", touchedSource: false }), // -3 (and -1 churn? no: keyword path only)
|
|
];
|
|
const s = scoreFile({ commits, durationMs: 9000, testCount: 3 });
|
|
assert.ok(s.valueScore < 0);
|
|
assert.equal(s.positiveCount, 0);
|
|
assert.equal(s.recommendation, "delete");
|
|
assert.equal(s.safeDelete, true);
|
|
});
|
|
|
|
test("quarantine ledger membership forces delete and applies the penalty", () => {
|
|
const commits = [classifyCommit({ subject: "fix(FN-3): bug", status: "M", touchedSource: true })]; // +3
|
|
const s = scoreFile({ commits, durationMs: 100, testCount: 2, quarantined: true });
|
|
// +3 then -5 quarantine = -2 => delete; but positiveCount=1 so NOT safeDelete.
|
|
assert.equal(s.valueScore, WEIGHTS.fixWithSource + WEIGHTS.quarantineLedger);
|
|
assert.equal(s.recommendation, "delete");
|
|
assert.equal(s.quarantined, true);
|
|
assert.equal(s.safeDelete, false);
|
|
});
|
|
|
|
test("deletionPriority surfaces slow + low-value above slow + valuable", () => {
|
|
const lowValueSlow = scoreFile({
|
|
commits: [classifyCommit({ subject: "chore: tweak", status: "M", touchedSource: false })],
|
|
durationMs: 10_000,
|
|
testCount: 1,
|
|
});
|
|
const highValueSlow = scoreFile({
|
|
commits: [
|
|
classifyCommit({ subject: "fix(FN-4): bug", status: "M", touchedSource: true }),
|
|
classifyCommit({ subject: "fix(FN-5): bug2", status: "M", touchedSource: true }),
|
|
],
|
|
durationMs: 10_000,
|
|
testCount: 1,
|
|
});
|
|
assert.ok(
|
|
lowValueSlow.deletionPriority > highValueSlow.deletionPriority,
|
|
"low-value slow file must outrank high-value slow file",
|
|
);
|
|
});
|
|
|
|
test("missing duration yields zero deletionPriority (unknown cost)", () => {
|
|
const s = scoreFile({
|
|
commits: [classifyCommit({ subject: "chore: tweak", status: "M", touchedSource: false })],
|
|
durationMs: null,
|
|
testCount: 1,
|
|
});
|
|
assert.equal(s.deletionPriority, 0);
|
|
assert.equal(s.durationMs, null);
|
|
});
|
|
|
|
test("testOnlyRatio reflects churn fraction", () => {
|
|
const commits = [
|
|
classifyCommit({ subject: "test: add", status: "A", touchedSource: true }), // not churn
|
|
classifyCommit({ subject: "chore: tidy", status: "M", touchedSource: false }), // churn
|
|
classifyCommit({ subject: "chore: tidy2", status: "M", touchedSource: false }), // churn
|
|
];
|
|
const s = scoreFile({ commits, durationMs: 1, testCount: 1 });
|
|
assert.equal(s.testOnlyCount, 2);
|
|
assert.equal(s.testOnlyRatio, Number((2 / 3).toFixed(3)));
|
|
});
|