fix(execute): the completion gate says which checks are commands and which are executor judgement

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-22 16:25:23 +02:00
commit a9f5f6251a
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
3 changed files with 60 additions and 8 deletions

View file

@ -785,3 +785,48 @@ test('[#33] no gates_mode = \'closed\', "strictest" or --event gates_mode_flag_o
'### High-effort behavior (v5.1.1) High effort changes nothing in `/trekexecute`: the step helper and the controller '
+ 'already run opus, and every gate already runs. No `gates_mode` is set from the effort.');
});
// --- #28 ---------------------------------------------------------------------------
/** The completion gate's text with its blockquote markers removed, flattened. */
function completionGate() {
return flat(section(read(EXEC), '### Machine-verifiable completion gate (stop-signal contract)').replace(/^> ?/gm, ''));
}
test('[#28] the completion gate calls nothing deterministic that is executor judgement, and cites no line number', () => {
const gate = completionGate();
assert.ok(!gate.includes('Counter liveness (deterministic'), 'clause 3 still calls the counter check deterministic');
assert.ok(!gate.includes('deterministic audit'), 'the gate still says termination rests on a deterministic audit');
assert.ok(!gate.includes('`:1221`'), 'the gate still cites `:1221`');
assert.doesNotMatch(gate, /`:\d+`/, 'the gate cites a line number; line numbers rot');
assert.ok(gate.includes('Counter liveness (checked by the executor against the audit\'s counts, defeats "never decremented")'),
'clause 3 does not say the executor checks the counter against the audit\'s counts');
assert.ok(gate.includes('rests on the audit and an objective stop-signal, never on the model\'s narrative'),
'the termination sentence does not rest on the audit and an objective stop-signal');
});
test('[#28] the completion gate names its commands and its executor judgement, and each command is in Phase 7.5', () => {
const gate = completionGate();
const c = gate.indexOf('Commands:');
const j = gate.indexOf('Executor judgement:');
assert.ok(c !== -1, 'the gate does not say which checks are commands');
assert.ok(j > c, 'the gate does not say which checks are executor judgement, after its commands');
const commands = gate.slice(c, j);
const judgement = gate.slice(j);
// Phase 7.5's own steps only: the gate subsection after them holds the Commands part under test.
const phase75 = section(read(EXEC), '## Phase 7.5 — Manifest audit (independent)');
const gateAt = phase75.indexOf('\n### Machine-verifiable completion gate');
assert.ok(gateAt !== -1, 'Phase 7.5 no longer holds the completion gate subsection');
const audit = flat(phase75.slice(0, gateAt));
assert.ok(!audit.includes('Commands:'), 'the audit slice still holds the gate\'s Commands part');
for (const cmd of ['git rev-list --count', 'bash -n', 'git diff --name-only', 'done-line.mjs --check']) {
assert.ok(commands.includes(cmd), `the Commands part does not name ${cmd}`);
assert.ok(audit.includes(cmd), `Phase 7.5 does not run ${cmd}, so the gate cannot call it a command`);
}
for (const s of ['criteria runner', 'arch-rules.mjs', 'plan-scope-sweep.mjs']) {
assert.ok(commands.includes(s), `the Commands part does not name ${s}`);
}
for (const s of ['steps 1, 2 and 4', 'the expected count in step 3', 'clause 3\'s formula']) {
assert.ok(judgement.includes(s), `the Executor judgement part does not name ${s}`);
}
});