fix(#3309): make the lint guard's W024 exemption explicit, not accidental
W024's committed rule (state-consistency.cts) is a documented permanent no-op — its real check runs in cmdValidateHealth itself, outside the rule table, since readStateHeadFreshness needs a git-log shell-out no Rule.check may perform. The guard's §8.5 fixture-proof check previously "passed" for W024 only because some test file's title happened to contain the string "W024" — not because any fixture actually proves it fires, which it structurally never can. Found by the Spec-axis orthogonal review. Adds an explicit PERMANENTLY_INERT_CODES map (currently just W024, with its reason recorded) that checkFixtureProofInvariant reports separately from real coverage. The guard's PASS output now says "30 covered by a real fixture, 1 exempted" instead of implying uniform proof — a code with no coverage and no exemption entry still fails.
This commit is contained in:
@@ -23,6 +23,19 @@
|
||||
* `tests/health-diagnostic.test.cjs`). A mere comment/string mention
|
||||
* outside a titled block does not count as coverage.
|
||||
*
|
||||
* EXCEPTION — `PERMANENTLY_INERT_CODES` (below): a rule whose `check`
|
||||
* always returns `[]` BY DESIGN (the real check lives outside the rule
|
||||
* table entirely, because it needs ambient I/O `Rule.check` cannot
|
||||
* perform — §8.1 rule 1) can never satisfy a real fixture-proof, no
|
||||
* matter how many tests reference its code. Before this exception
|
||||
* existed, W024 "passed" this guard only because an unrelated test title
|
||||
* (the RULES-array shape assertion, "exports exactly 5 rules: W024, ...")
|
||||
* happened to contain the string "W024" — accidental coverage, not proof
|
||||
* the rule can fire. `PERMANENTLY_INERT_CODES` makes that exemption
|
||||
* explicit and auditable instead of relying on a coincidental title
|
||||
* match, and the PASS output now reports exempted codes SEPARATELY from
|
||||
* genuinely fixture-covered ones rather than folding them together.
|
||||
*
|
||||
* Design: .gsd/phase/refactor-3309-health-diagnostic-rule-table/40-design.md
|
||||
* ("The lint guard (§8.2 1:1 invariant + §8.5 fixture proof)").
|
||||
*
|
||||
@@ -57,6 +70,22 @@ const SKELETON_TEST_FILE = path.join(REPO_ROOT, 'tests', 'health-diagnostic.test
|
||||
// (scripts/lint-planning-snapshot-bypass-drift.cjs's scanCode precedent).
|
||||
const TITLED_BLOCK_RE = /\b(describe|test|it)\(\s*(['"`])((?:\\.|(?!\2)[^\\])*)\2/g;
|
||||
|
||||
// Rule codes whose `check` is a documented PERMANENT no-op (always returns
|
||||
// `[]`) because the real check requires ambient I/O forbidden inside a
|
||||
// `Rule.check(snapshot)` (§8.1 rule 1) — the real check runs elsewhere,
|
||||
// outside the rule table. These can never be proven via a real
|
||||
// diagnostic-firing fixture, so they are exempted from the §8.5 fixture-proof
|
||||
// invariant explicitly here rather than via an accidental test-title match.
|
||||
// Adding an entry is a deliberate, reviewed decision — see each reason.
|
||||
const PERMANENTLY_INERT_CODES = new Map([
|
||||
[
|
||||
'W024',
|
||||
'readStateHeadFreshness requires a git-log shell-out, forbidden ambient I/O for Rule.check ' +
|
||||
'(§8.1 rule 1) — the real check runs in cmdValidateHealth itself, outside the rule table ' +
|
||||
'(src/verify.cts). This rule-table entry is a permanent no-op by design, not a fixture gap.',
|
||||
],
|
||||
]);
|
||||
|
||||
/**
|
||||
* Load the compiled health-diagnostic module. Throws a clear ExitError
|
||||
* (not a raw MODULE_NOT_FOUND) if `npm run build:lib` has not run.
|
||||
@@ -155,13 +184,17 @@ function findHealthDiagnosticTestFiles(repoRoot = REPO_ROOT) {
|
||||
/**
|
||||
* §8.5 — fixture-proof invariant: for every code in `rules`, confirm at
|
||||
* least one test file in `testFiles` has a `describe(`/`test(`/`it(` block
|
||||
* whose title names that exact code.
|
||||
* whose title names that exact code — UNLESS the code is listed in
|
||||
* `PERMANENTLY_INERT_CODES`, in which case it is reported separately as
|
||||
* `exempted` (visibly, not folded into "covered") and never fails the guard
|
||||
* regardless of test coverage.
|
||||
*
|
||||
* @param {Array<{code: string}>} rules
|
||||
* @param {string[]} testFiles absolute paths to *.test.cjs files to scan
|
||||
* @returns {{uncovered: string[], testFilesScanned: string[]}}
|
||||
* @param {Map<string, string>} inertCodes PERMANENTLY_INERT_CODES (injectable for tests)
|
||||
* @returns {{uncovered: string[], exempted: string[], testFilesScanned: string[]}}
|
||||
*/
|
||||
function checkFixtureProofInvariant(rules, testFiles) {
|
||||
function checkFixtureProofInvariant(rules, testFiles, inertCodes = PERMANENTLY_INERT_CODES) {
|
||||
const allTitles = [];
|
||||
for (const file of testFiles) {
|
||||
const text = fs.readFileSync(file, 'utf8');
|
||||
@@ -169,13 +202,18 @@ function checkFixtureProofInvariant(rules, testFiles) {
|
||||
}
|
||||
|
||||
const uncovered = [];
|
||||
const exempted = [];
|
||||
for (const rule of rules) {
|
||||
if (inertCodes.has(rule.code)) {
|
||||
exempted.push(rule.code);
|
||||
continue;
|
||||
}
|
||||
if (!codeAppearsInTitle(rule.code, allTitles)) {
|
||||
uncovered.push(rule.code);
|
||||
}
|
||||
}
|
||||
|
||||
return { uncovered, testFilesScanned: testFiles };
|
||||
return { uncovered, exempted, testFilesScanned: testFiles };
|
||||
}
|
||||
|
||||
function formatRepoRelative(absPath) {
|
||||
@@ -188,7 +226,7 @@ function main() {
|
||||
const { duplicates, badSeverities } = checkOneToOneInvariant(RULES, SEVERITY);
|
||||
|
||||
const testFiles = findHealthDiagnosticTestFiles(REPO_ROOT);
|
||||
const { uncovered } = checkFixtureProofInvariant(RULES, testFiles);
|
||||
const { uncovered, exempted } = checkFixtureProofInvariant(RULES, testFiles);
|
||||
|
||||
const problems = [];
|
||||
|
||||
@@ -229,9 +267,15 @@ function main() {
|
||||
throw new ExitError(1, `${problems.join('\n\n')}\n`);
|
||||
}
|
||||
|
||||
const coveredCount = RULES.length - exempted.length;
|
||||
const exemptedDetail = exempted
|
||||
.map((code) => `${code} (${PERMANENTLY_INERT_CODES.get(code)})`)
|
||||
.join('; ');
|
||||
|
||||
console.log(
|
||||
`lint-health-diagnostic-rule-table: PASS — ${RULES.length} rule code(s), all unique, ` +
|
||||
`all severities valid, all covered by a titled test block across ${testFiles.length} test file(s).`,
|
||||
`lint-health-diagnostic-rule-table: PASS — ${RULES.length} rule code(s): ${coveredCount} covered by a ` +
|
||||
`real fixture, ${exempted.length} exempted across ${testFiles.length} test file(s).` +
|
||||
(exempted.length > 0 ? `\n Exempted: ${exemptedDetail}` : ''),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -244,6 +288,7 @@ module.exports = {
|
||||
codeAppearsInTitle,
|
||||
findHealthDiagnosticTestFiles,
|
||||
checkFixtureProofInvariant,
|
||||
PERMANENTLY_INERT_CODES,
|
||||
COMPILED_MODULE_PATH,
|
||||
TEST_GROUP_DIR,
|
||||
SKELETON_TEST_FILE,
|
||||
|
||||
@@ -21,6 +21,7 @@ const {
|
||||
checkOneToOneInvariant,
|
||||
checkFixtureProofInvariant,
|
||||
findHealthDiagnosticTestFiles,
|
||||
PERMANENTLY_INERT_CODES,
|
||||
} = guard;
|
||||
|
||||
const FAKE_SEVERITY = Object.freeze({ ERROR: 'error', WARNING: 'warning', INFO: 'info' });
|
||||
@@ -151,6 +152,75 @@ describe('checkFixtureProofInvariant (§8.5)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Check 2b — §8.5 EXCEPTION: PERMANENTLY_INERT_CODES ────────────────────
|
||||
//
|
||||
// A code whose `check` is a documented permanent no-op (W024 — see
|
||||
// `scripts/lint-health-diagnostic-rule-table.cjs`'s own `PERMANENTLY_INERT_CODES`
|
||||
// comment) can never satisfy a real fixture-proof. It must be reported as
|
||||
// `exempted`, separately from genuinely-covered codes, and must NEVER land in
|
||||
// `uncovered` — regardless of whether any test file happens to mention it.
|
||||
|
||||
describe('checkFixtureProofInvariant — PERMANENTLY_INERT_CODES exemption (§8.5 exception)', () => {
|
||||
test('an exempted code with ZERO test coverage anywhere still passes (not uncovered), and is reported as exempted', (t) => {
|
||||
const dir = createTempDir('gsd-lint-hd-rt-exempt-nomention-');
|
||||
t.after(() => cleanup(dir));
|
||||
const file = writeTempTestFile(dir, 'fake.test.cjs', "describe('unrelated', () => {});\n");
|
||||
|
||||
const rules = [{ code: 'W024' }];
|
||||
const inertCodes = new Map([['W024', 'permanent no-op, real check lives outside the rule table']]);
|
||||
const { uncovered, exempted } = checkFixtureProofInvariant(rules, [file], inertCodes);
|
||||
|
||||
assert.deepEqual(uncovered, [], 'an exempted code must never be reported as uncovered');
|
||||
assert.deepEqual(exempted, ['W024']);
|
||||
});
|
||||
|
||||
test('a code NOT in the exemption map, with zero test coverage, still fails as uncovered', (t) => {
|
||||
const dir = createTempDir('gsd-lint-hd-rt-not-exempt-');
|
||||
t.after(() => cleanup(dir));
|
||||
const file = writeTempTestFile(dir, 'fake.test.cjs', "describe('unrelated', () => {});\n");
|
||||
|
||||
const rules = [{ code: 'W998' }];
|
||||
const inertCodes = new Map([['W024', 'permanent no-op']]); // W998 is NOT in this map
|
||||
const { uncovered, exempted } = checkFixtureProofInvariant(rules, [file], inertCodes);
|
||||
|
||||
assert.deepEqual(uncovered, ['W998'], 'a non-exempted, uncovered code must still fail the guard');
|
||||
assert.deepEqual(exempted, []);
|
||||
});
|
||||
|
||||
test('an exempted code is reported as exempted even when a test file DOES happen to mention it in a titled block', (t) => {
|
||||
const dir = createTempDir('gsd-lint-hd-rt-exempt-mentioned-');
|
||||
t.after(() => cleanup(dir));
|
||||
const file = writeTempTestFile(
|
||||
dir,
|
||||
'fake.test.cjs',
|
||||
"test('exports exactly 1 rule: W024', () => {});\n",
|
||||
);
|
||||
|
||||
const rules = [{ code: 'W024' }];
|
||||
const inertCodes = new Map([['W024', 'permanent no-op']]);
|
||||
const { uncovered, exempted } = checkFixtureProofInvariant(rules, [file], inertCodes);
|
||||
|
||||
assert.deepEqual(uncovered, []);
|
||||
assert.deepEqual(exempted, ['W024'], 'must be classified as exempted, not folded into ordinary coverage');
|
||||
});
|
||||
|
||||
test('W024 is exempted (not uncovered, not silently "covered") against the real tests/ tree and the real PERMANENTLY_INERT_CODES map', () => {
|
||||
const testFiles = findHealthDiagnosticTestFiles();
|
||||
const { uncovered, exempted } = checkFixtureProofInvariant([{ code: 'W024' }], testFiles);
|
||||
|
||||
assert.deepEqual(uncovered, []);
|
||||
assert.deepEqual(exempted, ['W024']);
|
||||
});
|
||||
|
||||
test('PERMANENTLY_INERT_CODES locks exactly W024 with a non-empty, auditable reason', () => {
|
||||
assert.deepEqual([...PERMANENTLY_INERT_CODES.keys()], ['W024']);
|
||||
const reason = PERMANENTLY_INERT_CODES.get('W024');
|
||||
assert.equal(typeof reason, 'string');
|
||||
assert.ok(reason.length > 0);
|
||||
assert.ok(/ambient I\/O|§8\.1/i.test(reason), 'reason should explain the §8.1 rule 1 constraint');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── findHealthDiagnosticTestFiles ─────────────────────────────────────────
|
||||
|
||||
describe('findHealthDiagnosticTestFiles', () => {
|
||||
|
||||
Reference in New Issue
Block a user