veritas-kanban/scripts/check-coverage-ratchets.test.mjs
Brad Groux f3c26088ae
feat: add governed file-backed work products (#1270)
* feat: add governed file-backed work products

* test: cover file work product delivery paths

* test: cover work product artifact persistence

* fix: harden artifact file handling

* fix: harden work product artifact boundaries

* test: cover artifact source replacement
2026-08-30 03:59:19 -05:00

351 lines
11 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
evaluateCoverage,
executableChangedLineNumbers,
markdownSummary,
normalizeCoverageSummary,
normalizeDetailedCoverage,
parseChangedLineNumbers,
parseChangedLineSpans,
parseSelectedPackages,
} from './check-coverage-ratchets.mjs';
const metric = (covered, total) => ({ covered, total, skipped: 0, pct: (covered / total) * 100 });
const fileCoverage = (covered, total) => ({
lines: metric(covered, total),
branches: metric(covered, total),
functions: metric(covered, total),
statements: metric(covered, total),
});
const policy = {
schemaVersion: 'critical-path-coverage/v1',
longTermTarget: { lines: 80, branches: 80, functions: 80, statements: 80 },
packages: [
{
id: 'server',
runner: { testFiles: ['src/__tests__/auth.test.ts'] },
boundaries: [
{
id: 'auth',
description: 'Authentication boundary.',
include: ['server/src/middleware/**/*.ts'],
thresholds: { lines: 75, branches: 75, functions: 75, statements: 75 },
},
],
},
],
};
test('normalizes absolute report paths to repository-relative POSIX paths', () => {
const summary = {
total: fileCoverage(1, 1),
'/repo/server/src/middleware/auth.ts': fileCoverage(3, 4),
};
assert.deepEqual(Object.keys(normalizeCoverageSummary(summary, '/repo')), [
'server/src/middleware/auth.ts',
]);
assert.deepEqual(
Object.keys(
normalizeDetailedCoverage(
{ '/repo/server/src/middleware/auth.ts': { statementMap: {}, s: {} } },
'/repo'
)
),
['server/src/middleware/auth.ts']
);
});
test('extracts added and modified line numbers from zero-context diffs', () => {
const lines = parseChangedLineNumbers(
'@@ -4 +4,2 @@\n-old\n+new\n+next\n@@ -10,2 +11 @@\n-old\n-old\n+new\n@@ -20 +21,0 @@\n-old\n'
);
assert.deepEqual([...lines], [4, 5, 11]);
});
test('keeps only executable changed lines and ignores comment-only or type-only edits', () => {
const previous = 'const value: OldType = run(\n input\n);\n';
const commentOnly = 'const value: OldType = run(\n // rationale\n input\n);\n';
assert.deepEqual([...executableChangedLineNumbers(commentOnly, new Set([2]), previous)], []);
const typeOnly = 'const value: NewType = run(\n input\n);\n';
assert.deepEqual([...executableChangedLineNumbers(typeOnly, new Set([1]), previous)], []);
const runtimeChange = 'const value: OldType = run(\n replacement\n);\n';
assert.deepEqual([...executableChangedLineNumbers(runtimeChange, new Set([2]), previous)], [2]);
});
test('ignores type-only tokens when the same file also changes runtime behavior', () => {
const previous = 'type Input = OldType;\nconst value = run(input);\n';
const current = 'type Input = NewType;\nconst value = run(replacement);\n';
const diff = [
'@@ -1,2 +1,2 @@',
'-type Input = OldType;',
'-const value = run(input);',
'+type Input = NewType;',
'+const value = run(replacement);',
].join('\n');
const changedLines = parseChangedLineNumbers(diff);
const changedSpans = parseChangedLineSpans(diff);
assert.deepEqual(
[...executableChangedLineNumbers(current, changedLines, previous, changedSpans)],
[2]
);
});
test('distinguishes added type punctuation from deletion-only runtime edits', () => {
const previous = [
'const value = run(input);',
'const result = keep(original);',
'verify(input);',
].join('\n');
const current = [
'const value: Input = run(input);',
'const result = keep(replacement);',
'verify();',
].join('\n');
const diff = [
'@@ -1,3 +1,3 @@',
'-const value = run(input);',
'-const result = keep(original);',
'-verify(input);',
'+const value: Input = run(input);',
'+const result = keep(replacement);',
'+verify();',
].join('\n');
const changedLines = parseChangedLineNumbers(diff);
const changedSpans = parseChangedLineSpans(diff);
assert.deepEqual(
[...executableChangedLineNumbers(current, changedLines, previous, changedSpans)],
[2, 3]
);
});
test('retains runtime-significant whitespace insertions', () => {
const previous = 'const kind = typeofx;\n';
const current = 'const kind = typeof x;\n';
const diff = '@@ -1 +1 @@\n-const kind = typeofx;\n+const kind = typeof x;\n';
const changedLines = parseChangedLineNumbers(diff);
const changedSpans = parseChangedLineSpans(diff);
assert.deepEqual(
[...executableChangedLineNumbers(current, changedLines, previous, changedSpans)],
[1]
);
});
test('treats line-count-only statement formatting as one runtime-neutral hunk', () => {
const previous = ['const value = run(input);', '', 'const result = keep(original);'].join('\n');
const current = [
'const value = run(',
' input',
');',
'',
'const result = keep(replacement);',
].join('\n');
const diff = [
'@@ -1 +1,3 @@',
'-const value = run(input);',
'+const value = run(',
'+ input',
'+);',
'@@ -3 +5 @@',
'-const result = keep(original);',
'+const result = keep(replacement);',
].join('\n');
const changedLines = parseChangedLineNumbers(diff);
const changedSpans = parseChangedLineSpans(diff);
assert.deepEqual(
[...executableChangedLineNumbers(current, changedLines, previous, changedSpans)],
[5]
);
});
test('treats equal-line-count statement formatting as one runtime-neutral hunk', () => {
const previous = [
'const value = run(input);',
'const other = use(input);',
'const result = keep(original);',
].join('\n');
const current = [
'const value = run(',
'input); const other = use(input);',
'const result = keep(replacement);',
].join('\n');
const diff = [
'@@ -1,3 +1,3 @@',
'-const value = run(input);',
'-const other = use(input);',
'-const result = keep(original);',
'+const value = run(',
'+input); const other = use(input);',
'+const result = keep(replacement);',
].join('\n');
const changedLines = parseChangedLineNumbers(diff);
const changedSpans = parseChangedLineSpans(diff);
assert.deepEqual(
[...executableChangedLineNumbers(current, changedLines, previous, changedSpans)],
[3]
);
});
test('aggregates a boundary and accepts its measured floor', () => {
const evaluation = evaluateCoverage(policy, {
server: {
'server/src/middleware/auth.ts': fileCoverage(3, 4),
'server/src/routes/tasks.ts': fileCoverage(0, 10),
},
});
assert.deepEqual(evaluation.failures, []);
assert.equal(evaluation.results[0].metrics.lines.pct, 75);
assert.match(markdownSummary(evaluation, policy.longTermTarget), /server \| auth \| 75%/);
});
test('rejects a metric regression and a boundary without report entries', () => {
const regression = evaluateCoverage(policy, {
server: { 'server/src/middleware/auth.ts': fileCoverage(2, 4) },
});
assert.equal(regression.failures.length, 4);
const missing = evaluateCoverage(policy, {
server: { 'server/src/routes/tasks.ts': fileCoverage(4, 4) },
});
assert.deepEqual(missing.failures, ['server/auth matched no reported source files']);
assert.equal(missing.results[0].status, 'fail');
assert.equal(missing.results[0].metrics.lines.pct, 0);
});
test('requires bounded reviewed exceptions and omits active exceptions', () => {
const withException = globalThis.structuredClone(policy);
withException.packages[0].boundaries[0].exceptions = [
{
path: 'server/src/middleware/legacy.ts',
reason: 'Legacy adapter awaiting removal.',
owner: 'BradGroux',
trackingIssue: '#1169',
reviewBy: '2026-09-30',
},
];
const evaluation = evaluateCoverage(
withException,
{
server: {
'server/src/middleware/auth.ts': fileCoverage(4, 4),
'server/src/middleware/legacy.ts': fileCoverage(0, 4),
},
},
'2026-08-23'
);
assert.deepEqual(evaluation.failures, []);
assert.deepEqual(evaluation.results[0].files, ['server/src/middleware/auth.ts']);
withException.packages[0].boundaries[0].exceptions[0].reviewBy = 'never';
assert.throws(
() => evaluateCoverage(withException, { server: {} }, '2026-08-23'),
/reviewBy must be a real YYYY-MM-DD date/
);
});
test('rejects a changed critical file without covered executable lines', () => {
const uncovered = evaluateCoverage(
policy,
{
server: {
'server/src/middleware/auth.ts': fileCoverage(3, 4),
'server/src/middleware/new-auth.ts': fileCoverage(0, 4),
},
},
'2026-08-23',
['server/src/middleware/new-auth.ts']
);
assert.ok(
uncovered.failures.includes(
'server/auth changed critical file server/src/middleware/new-auth.ts has no covered lines'
)
);
assert.equal(uncovered.results[0].status, 'fail');
});
test('requires changed executable statements themselves to be covered', () => {
const summary = { server: { 'server/src/middleware/auth.ts': fileCoverage(3, 4) } };
const details = {
server: {
'server/src/middleware/auth.ts': {
statementMap: {
0: { start: { line: 10 }, end: { line: 10 } },
1: { start: { line: 20 }, end: { line: 22 } },
},
s: { 0: 1, 1: 0 },
},
},
};
const changedLines = new Map([['server/src/middleware/auth.ts', new Set([21])]]);
const uncovered = evaluateCoverage(
policy,
summary,
'2026-08-23',
['server/src/middleware/auth.ts'],
details,
changedLines
);
assert.match(uncovered.failures.join('\n'), /uncovered executable statements on line\(s\) 20/);
assert.equal(uncovered.results[0].status, 'fail');
details.server['server/src/middleware/auth.ts'].s[1] = 1;
const covered = evaluateCoverage(
policy,
summary,
'2026-08-23',
['server/src/middleware/auth.ts'],
details,
changedLines
);
assert.deepEqual(covered.failures, []);
assert.equal(covered.results[0].status, 'pass');
});
test('does not require executable coverage for a type-only changed critical file', () => {
const summary = { server: { 'server/src/middleware/auth.ts': fileCoverage(3, 4) } };
const covered = evaluateCoverage(
policy,
summary,
'2026-08-23',
['server/src/middleware/types.ts'],
{ server: {} },
new Map([['server/src/middleware/types.ts', new Set()]])
);
assert.deepEqual(covered.failures, []);
assert.equal(covered.results[0].status, 'pass');
});
test('rejects broad and untracked exceptions', () => {
const invalid = globalThis.structuredClone(policy);
invalid.packages[0].boundaries[0].exceptions = [
{
path: 'server/src/middleware/**',
reason: 'This reason is long enough for review.',
owner: 'BradGroux',
trackingIssue: '#1169',
reviewBy: '2026-09-01',
},
];
assert.throws(
() => evaluateCoverage(invalid, { server: {} }, '2026-08-23'),
/one exact repository-relative file/
);
});
test('validates selected coverage packages', () => {
assert.deepEqual(parseSelectedPackages([], ['server', 'web']), ['server', 'web']);
assert.deepEqual(parseSelectedPackages(['--packages=web'], ['server', 'web']), ['web']);
assert.throws(() => parseSelectedPackages(['--packages', 'unknown'], ['server']), /Unknown/);
});