enhance(#1279): project check_violation_fixture scalar — #1278 locate + #1279 proof compose end-to-end (#1346)

Delivers option (a) from the #1314 maintainer review: thread a fourth flat
scalar check_violation_fixture through the projection so a prohibition authored
at spec-phase machine-proves fail-first and greens through the deterministic
path alone — zero hand-authoring at verify time.

- src/probe-core.cts: Prohibition gains check_violation_fixture?; projectProhibitions
  emits it (both kinds) ONLY for a well-formed descriptor and ONLY when non-empty
  (blank/absent -> projects absent -> producer hard-gates, never a partial green).
- src/prohibition-enforcement.cts: descriptorFromProjection reads it back into
  violationFixture via the same numeric-coercion-safe scalar() normalizer.
- Tests (RED-first, proven non-vacuous by reverting both src edits): CHK-02(#1346)
  projection emit, CHK-08(#1346) read-back, CHK-03(D) example round-trip, the
  fast-check round-trip property extended to the 4th scalar (the contract trek-e
  blocked #1301 on), and a real-subprocess COMPOSE capstone greening end-to-end
  through project -> descriptorFromProjection -> default prover+runner.
- Docs flipped from 'hard-gates until #1346' to 'composes end-to-end': verify-phase.md,
  prohibition-probe.md, spec-phase.md authoring, ADR-550 addendum, changeset.
  #1346 now tracks only the node-test causation residual.

190 affected-suite tests green; eslint + tsc clean; size baseline regenerated.
This commit is contained in:
Dave
2026-06-16 14:00:49 -04:00
parent 91bc49c9f1
commit 56d4a1bf39
12 changed files with 190 additions and 37 deletions

View File

@@ -193,6 +193,7 @@ function renderProhibitionsDoc(entries) {
if (e.check_kind !== undefined) lines.push(` check_kind: ${e.check_kind}`);
if (e.check_target !== undefined) lines.push(` check_target: ${e.check_target}`);
if (e.check_rule !== undefined) lines.push(` check_rule: ${e.check_rule}`);
if (e.check_violation_fixture !== undefined) lines.push(` check_violation_fixture: ${e.check_violation_fixture}`);
}
lines.push('---', '', 'Body.', '');
return lines.join('\n');
@@ -216,19 +217,20 @@ const pathScalarArb = fc.array(fc.constantFrom(...PATH_CHARS), { minLength: 1, m
const numericScalarArb = fc.nat({ max: 9999999 }).map(String);
const targetArb = fc.oneof(pathScalarArb, numericScalarArb);
// A fully well-formed descriptor item (resolved test-tier); node-test carries no rule.
// A fully well-formed descriptor item (resolved test-tier); node-test carries no rule. The
// violation fixture (#1346) rides BOTH kinds and exercises the numeric-coercion path too.
const wellFormedArb = KIND_ARB.chain((kind) =>
fc.record({ target: targetArb, rule: pathScalarArb }).map(({ target, rule }) => {
const item = { ...BASE_TIER, check_kind: kind, check_target: target };
fc.record({ target: targetArb, rule: pathScalarArb, fixture: targetArb }).map(({ target, rule, fixture }) => {
const item = { ...BASE_TIER, check_kind: kind, check_target: target, check_violation_fixture: fixture };
if (kind === 'lint-rule') item.check_rule = rule;
return { item, kind, target, rule: kind === 'lint-rule' ? rule : undefined };
return { item, kind, target, rule: kind === 'lint-rule' ? rule : undefined, fixture };
}),
);
describe('probe-core property: #1278 check-descriptor round-trip is deterministic across the full string domain', () => {
test('a well-formed descriptor survives project -> render -> parse -> descriptorFromProjection (incl. numeric coercion); target/rule reconstruct as strings', () => {
fc.assert(
fc.property(wellFormedArb, ({ item, kind, target, rule }) => {
fc.property(wellFormedArb, ({ item, kind, target, rule, fixture }) => {
const projected = pc.projectProhibitions([item]);
if (projected[0].check_kind !== kind) return false; // projector emits the descriptor
const reparsed = fm.parseMustHavesBlock(renderProhibitionsDoc(projected), 'prohibitions');
@@ -236,6 +238,8 @@ describe('probe-core property: #1278 check-descriptor round-trip is deterministi
if (!d || d.kind !== kind) return false;
// target is string-normalized even when parseMustHavesBlock numerically coerced it.
if (typeof d.target !== 'string' || d.target !== target) return false;
// violationFixture (#1346) survives the round-trip as a string (numeric-coercion normalized).
if (typeof d.violationFixture !== 'string' || d.violationFixture !== fixture) return false;
if (kind === 'lint-rule') {
return typeof d.rule === 'string' && d.rule === rule;
}