fix(#1279): node-test prover fail-closes on missing violationFixture + honest projection docs

Addresses the #1314 maintainer review (trek-e):

- Major 1 (fail-OPEN): defaultProveFailFirst's node-test branch only guarded
  `if (!fixture)`. A missing/typo'd/stale violationFixture made GSD_PROHIB_SUBJECT
  point at a missing file; an honest negative test threw ENOENT *inside its
  callback* (a failing test named distinctly from the file), which
  isNonVacuousNodeTestRed accepted as proof -> a green forged from a setup crash.
  Now requires fs.existsSync(path.resolve(cwd, fixture)) before spawning, symmetric
  with the lint-rule path's file-result guard. Regression test pins it (RED without
  the guard); a second test pins cwd-relative fixture resolution.

- Major 2 (misleading prose): the #1278 projection carries no violationFixture, so
  the deterministic-locate path always hard-gates (fail-closed) until a
  check_violation_fixture scalar is threaded through. verify-phase.md and
  prohibition-probe.md no longer read as if the projected path produces greens;
  the ADR-550 addendum records both items. Tracked as follow-up #1346.

- Documented residual: existence is necessary but not sufficient (a red caused by
  the env being set vs the subject's content); recorded as a constraint, in #1346.

- Nit: stale 'NOT attested fail-first' comment -> 'NOT machine-proven fail-first'.

64 tests pass; eslint + tsc clean; changeset valid.
This commit is contained in:
Dave
2026-06-16 13:05:20 -04:00
parent ee9ef7a8e4
commit 33b6ee6f0c
6 changed files with 91 additions and 9 deletions

View File

@@ -169,15 +169,20 @@ nested object would flatten/mangle the round-trip (ADR-550 2026-06-15 addendum;
rewrite" precedent). `projectProhibitions` emits these keys **only for a well-formed descriptor**
(valid `check_kind` + non-empty `check_target`; `check_rule` only on the lint-rule path), and
verify-phase reads them back via `descriptorFromProjection` into the `CheckDescriptor` handed to
`check prohibition-enforcement`. A wired, passing test then closes the gap with **zero manual
descriptor authoring**.
`check prohibition-enforcement`. This closes the **locate** half with **zero manual descriptor
authoring**. Note the projection carries **no `violationFixture`** (`descriptorFromProjection`
reconstructs only `{ kind, target, rule? }`); because #1279 machine-proves fail-first against a
fixture, a prohibition wired purely through this projected path **hard-gates (fail-closed)** until a
`check_violation_fixture` scalar is threaded through — tracked as **#1346**. Until then green needs a
hand-supplied `violationFixture`.
**Fail-closed + backward-compat.** A partial descriptor (`lint-rule` missing `check_rule`), an
unknown `check_kind`, or an **absent** descriptor on a test-tier prohibition falls through to the
producer's existing fail-closed locate — never a silent green. A prohibition with no descriptor
parses and disposes byte-identically to today. `failFirst` is **not** sourced from the
descriptor — it stays a verify-time caller attestation (machine-proven fail-first is tracked in
#1279; the `dispositionForProhibition` policy is unchanged).
descriptor and is now **demoted** (machine-proven fail-first DELIVERED in #1279 — no path greens on
attestation alone, FF-08); the `dispositionForProhibition` policy is unchanged. The field that gates
green and is **not yet projected** is `violationFixture` (follow-up #1346).
## Output schema