fix(1259-01): close re-review NEW-BL-01 (ignored-target vacuous green) + no-throw hardening
Round-2 adversarial review found the lint-rule runner falsely greened an eslint-IGNORED target: eslint returns a length-1 "File ignored" result (ruleId null) that passed the >=1-file vacuity guard while nothing was linted — reopening the vacuous-green class. Fix: buildLintArgs now passes --no-warn-ignored so an ignored path returns [] -> fails closed (verified + E2E test on an ignored bin/lib artifact). Also: wrap runCheck() so even a (test-injected) throwing runner fails closed (NEW-WR-01, full no-throw contract); document the benign basename-naming constraint on wired node-test names (NEW-WR-02, fail-closed).
This commit is contained in:
@@ -105,9 +105,11 @@ export function buildNodeTestArgs(check: CheckDescriptor): string[] {
|
||||
}
|
||||
|
||||
/** eslint argv (the args AFTER `npx`). Runs the project flat config so plugin rules (e.g. `local/*`)
|
||||
* load — `--rule` CANNOT load a plugin, so we lint the TARGET path as JSON and filter by rule id. */
|
||||
* load — `--rule` CANNOT load a plugin, so we lint the TARGET path as JSON and filter by rule id.
|
||||
* `--no-warn-ignored` makes an eslint-IGNORED target return `[]` (not a length-1 "File ignored"
|
||||
* warning result) so an ignored path fails closed via the vacuity guard instead of falsely greening. */
|
||||
export function buildLintArgs(check: CheckDescriptor): string[] {
|
||||
return ['eslint', '--format', 'json', check.target];
|
||||
return ['eslint', '--no-warn-ignored', '--format', 'json', check.target];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,6 +147,11 @@ export function tapTestNames(out: string): string[] {
|
||||
* with ZERO `test()` calls as one passing "test" named after the file, so the counts alone cannot
|
||||
* tell an empty/deleted negative test from a real one (the #1259 BL-01 false-green). Requiring a
|
||||
* named test distinct from the file closes that hole.
|
||||
*
|
||||
* KNOWN CONSTRAINT (fail-closed, not a hole): a real test whose `test('...')` name is EXACTLY the
|
||||
* target file's basename emits TAP indistinguishable from an empty file and is conservatively
|
||||
* rejected (non-green). A wired negative test must carry a descriptive name, not be named after its
|
||||
* own file — a benign authoring constraint, and the safe direction if violated.
|
||||
*/
|
||||
export function isNonVacuousNodeTestPass(out: string, target: string): boolean {
|
||||
const s = parseNodeTestSummary(out);
|
||||
@@ -296,7 +303,14 @@ export function runProhibitionEnforcement(
|
||||
// fail-first (that needs a violation fixture — tracked follow-up, ADR-550 D5d). A non-attested or
|
||||
// non-passing check hard-gates (never green) in BOTH modes.
|
||||
const attestedFailFirst = c.failFirst === true;
|
||||
const run = runCheck(c);
|
||||
// No-throw contract end-to-end: even a (test-injected) runCheck that throws must fail closed,
|
||||
// never propagate. The default real runner already never throws.
|
||||
let run: CheckRunResult;
|
||||
try {
|
||||
run = runCheck(c);
|
||||
} catch {
|
||||
run = { passed: false };
|
||||
}
|
||||
const passed = attestedFailFirst && run.passed === true;
|
||||
|
||||
if (!passed) {
|
||||
|
||||
Reference in New Issue
Block a user