fix(execute): Phase 7 pins the criteria runner to the working tree, like Phase 4.5

/trekreview passed --cwd and trekexecute Phase 7 did not, so the same criterion
could resolve two ways in the two phases (PM checkpoint 2026-09-18, MINOR).

It stopped being cosmetic with the refusal list: --cwd is the boundary a write
is measured against, so leaving it unset silently moves that boundary to
whatever the process cwd happens to be. Both phases now resolve

  CRITERIA_CWD="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"

- one form, with a fallback, so a repo-less checkout falls back instead of
passing an empty --cwd. Pinned in tests/lib/doc-consistency.test.mjs.

Red first: the new pin failed on both phases before this change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-18 02:14:57 +02:00
commit e1e7bdfaf1
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
3 changed files with 29 additions and 2 deletions

View file

@ -1288,7 +1288,13 @@ if [ ! -f "$VOYAGE_ROOT/lib/verification/criteria-runner.mjs" ]; then
exit 2 exit 2
fi fi
node "$VOYAGE_ROOT/lib/verification/criteria-runner.mjs" --plan "{plan_path}" --json # The working tree the criteria run in. It is also the boundary the runner's
# refusal list measures a write against, so it is resolved, never left to the
# process cwd - and a repo-less checkout falls back rather than passing "".
CRITERIA_CWD="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
node "$VOYAGE_ROOT/lib/verification/criteria-runner.mjs" --plan "{plan_path}" \
--json --cwd "$CRITERIA_CWD"
``` ```
The exit code is the verdict, and it is not advisory: The exit code is the verdict, and it is not advisory:

View file

@ -220,8 +220,12 @@ fi
# refusal list (writes - push, recursive delete, pipe-to-shell, redirection # refusal list (writes - push, recursive delete, pipe-to-shell, redirection
# outside the working tree) reports REFUSED, and the executor denylist # outside the working tree) reports REFUSED, and the executor denylist
# (catastrophe) reports BLOCKED. Neither is ever run. Foreground only. # (catastrophe) reports BLOCKED. Neither is ever run. Foreground only.
# The working tree the criteria run in - the same resolution trekexecute
# Phase 7 uses, so one criterion cannot resolve two ways in the two phases.
CRITERIA_CWD="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
node "$VOYAGE_ROOT/lib/verification/criteria-runner.mjs" \ node "$VOYAGE_ROOT/lib/verification/criteria-runner.mjs" \
--brief "{brief_path}" --evidence --cwd "$(git rev-parse --show-toplevel)" --brief "{brief_path}" --evidence --cwd "$CRITERIA_CWD"
``` ```
Exit 0 means every criterion passed; exit 1 means at least one failed, was Exit 0 means every criterion passed; exit 1 means at least one failed, was

View file

@ -1857,6 +1857,23 @@ test('D-03: trekexecute Phase 7 runs the plan Verification on the single-session
// Success Criterion's verification command "exists and passes" — with Read/Glob/Grep. The // Success Criterion's verification command "exists and passes" — with Read/Glob/Grep. The
// command now runs the commands and hands over the result; the reviewer stays read-only. // command now runs the commands and hands over the result; the reviewer stays read-only.
// Fix the SOURCE. // Fix the SOURCE.
// PM checkpoint 2026-09-18, MINOR: /trekreview passed --cwd and Phase 7 did not,
// so the same criterion could resolve two ways in the two phases. It is no longer
// cosmetic - --cwd is the boundary the runner's refusal list measures a write
// against, so an unset one silently moves that boundary to the process cwd.
test('both phases pin the criteria runner to the working tree with --cwd', () => {
const phase7 = (read('commands/trekexecute.md').split('\n## Phase 7 — ')[1] || '').split('\n## ')[0];
const phase45 = (read('commands/trekreview.md').split('\n## Phase 4.5 — ')[1] || '').split('\n## ')[0];
for (const [label, phase] of [['trekexecute Phase 7', phase7], ['trekreview Phase 4.5', phase45]]) {
assert.ok(phase.length > 0, `${label} must still exist`);
assert.match(phase, /--cwd "\$CRITERIA_CWD"/, `${label} must pass --cwd, and the same resolved value`);
assert.match(
phase, /CRITERIA_CWD="\$\(git rev-parse --show-toplevel 2>\/dev\/null \|\| pwd\)"/,
`${label} must resolve the working tree with a fallback — an empty --cwd is a moved boundary, not an error`,
);
}
});
test('D-04: the conformance reviewer judges a supplied result, and never runs a command', () => { test('D-04: the conformance reviewer judges a supplied result, and never runs a command', () => {
const a = read('agents/brief-conformance-reviewer.md'); const a = read('agents/brief-conformance-reviewer.md');
assert.ok( assert.ok(