fix(end-state): D-03 and D-04 measure behaviour, and the frozen denominator moves with them

The operator decided on 2026-09-18 that the two checks must stop measuring a
phrase and start measuring behaviour. The reason is the gate's own caveat: a
phrase probe closes on rewording, so "Phase 7 no longer says 'Skip for
trekplans'" and "the rubric no longer says 'exists and passes'" could both have
been satisfied by an edit that changed no behaviour at all. Both entries now
point at code a test exercises:

  D-03  lib/**/*.mjs exports runPlanVerification
  D-04  lib/**/*.mjs exports formatCriteriaEvidence

Verified open against the pre-fix tree (8d1669e) and closed against this one —
a check that cannot be seen to fire is not evidence.

What the probes can and cannot prove is now stated by the gate itself rather
than left to the reader. `PROBE_NOTES` carries one note per kind, the detail
line prints a note for every kind PRESENT in the row (and none for a kind no
entry declares), and the open/closed tags name the kind instead of labelling
`phrase` alone and leaving every other kind unlabelled. A behaviour probe
proves the capability exists; it does not prove a prose phase calls it — the
wiring is pinned by tests/lib/doc-consistency.test.mjs, and the gate says so.

THE DENOMINATOR MOVED ON PURPOSE. `tests/fixtures/end-state-frozen.json` and
the `FROZEN` literal in `tests/scripts/end-state-gate.test.mjs` carry new
signatures for D-03 and D-04, amended together and dated in both places. That
is the freeze mechanism working, not a bypass: the integrity check went
VIOLATED the moment the checks changed and stayed red until the amendment was
written down. The list may change — only as a decision said out loud. Nothing
else about the denominator moved: seven defect ids, three experiment ids, and
the agents/decisions/freeze configuration are unchanged, and no entry was
removed.

Gate after: defects 0 of 7, registry intact, still RED and exit 1 on the other
four rows — which is correct.

Suite: 1120 (1118/0/2), up 3.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-18 01:36:44 +02:00
commit 6cafb4c04c
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
4 changed files with 90 additions and 27 deletions

View file

@ -160,14 +160,27 @@ export function verifyIntegrity(registry, frozen) {
const notMeasured = (detail) => ({ open: null, total: null, items: [], detail });
// What each probe kind can and cannot prove. An entry declares its kind; the
// gate states the limit out loud, because a closed check is only ever as strong
// as the thing it reads. Every kind a registry entry may declare belongs here —
// the entry-shape test rejects a kind the gate cannot explain.
export const PROBE_NOTES = {
phrase:
'a phrase probe closes on rewording: a closed phrase probe is evidence, not proof of behaviour',
behaviour:
'a behaviour probe reads code a test exercises: it proves the capability exists, not that a prose phase calls it (the wiring is pinned by the suite, not by this probe)',
byte:
"a byte probe reads the file's bytes, so it closes only on a real change to them",
};
function tallyEntries(root, entries) {
const items = entries.map((e) => ({ id: e.id, summary: e.summary, probe: e.probe, ...evaluateCheck(root, e.check) }));
const phrase = items.some((i) => i.probe === 'phrase');
const kinds = Object.keys(PROBE_NOTES).filter((k) => items.some((i) => i.probe === k));
return {
open: items.filter((i) => i.status !== 'closed').length,
total: items.length,
items,
detail: phrase ? 'a phrase probe closes on rewording: a closed phrase probe is evidence, not proof of behaviour' : '',
detail: kinds.map((k) => PROBE_NOTES[k]).join('; '),
};
}
@ -377,12 +390,12 @@ export function render(result) {
for (const i of r.items) {
if (i.status === 'closed') continue;
let tag = i.status === 'not-fellable' ? 'NOT FELLABLE, counted open' : 'open';
if (i.probe === 'phrase') tag += ' · phrase probe';
if (i.probe) tag += ` · ${i.probe} probe`;
out.push(` [${tag}] ${i.id}: ${i.summary}${i.detail ? ` — ${i.detail}` : ''}`);
}
const closed = r.items.filter((i) => i.status === 'closed' && i.probe);
if (closed.length > 0) {
out.push(` closed: ${closed.map((i) => (i.probe === 'phrase' ? `${i.id} (phrase probe)` : i.id)).join(', ')}`);
out.push(` closed: ${closed.map((i) => `${i.id} (${i.probe} probe)`).join(', ')}`);
}
}
return out.join('\n');

View file

@ -35,33 +35,25 @@
{
"id": "D-03",
"summary": "commands/trekexecute.md never runs a trekplan's `## Verification` (where the brief's success criteria land) on the single-session path: Phase 7 says 'Skip for trekplans', and only the multi-session wave path runs master verification",
"closesWhen": "Phase 7 no longer skips trekplans (proxy: the fix must also make that path run the plan's Verification; Phase 4's entry-condition skip is legitimate and out of scope)",
"probe": "phrase",
"closesWhen": "a runnable plan-verification runner exists in lib/ (behaviour probe: it proves the capability exists and is exercised by a test, not that Phase 7 calls it — the wiring is pinned by tests/lib/doc-consistency.test.mjs)",
"probe": "behaviour",
"check": [
{
"path": "commands/trekexecute.md",
"section": "## Phase 7 —",
"pattern": "^\\*\\*Skip for trekplans\\.\\*\\*",
"flags": "m",
"expect": "match"
"path": "lib/**/*.mjs",
"pattern": "export function runPlanVerification",
"expect": "no-match"
}
]
},
{
"id": "D-04",
"summary": "agents/brief-conformance-reviewer.md must judge whether a success criterion's verification command 'exists and passes', but its tools are Read/Glob/Grep, so it cannot run anything",
"closesWhen": "the rubric no longer asks it to judge 'passes', or the reviewer can execute the command",
"probe": "phrase",
"closesWhen": "the evidence block the conformance reviewer judges is BUILT IN CODE (behaviour probe: it proves /trekreview can hand over a real exit code instead of asking a Read/Glob/Grep agent whether a command passes; the rubric rewrite and the hand-over are pinned by tests/lib/doc-consistency.test.mjs)",
"probe": "behaviour",
"check": [
{
"path": "agents/brief-conformance-reviewer.md",
"pattern": "exists and passes",
"expect": "match"
},
{
"path": "agents/brief-conformance-reviewer.md",
"pattern": "^tools:.*\"Bash\"",
"flags": "m",
"path": "lib/**/*.mjs",
"pattern": "export function formatCriteriaEvidence",
"expect": "no-match"
}
]