fix(execute): one definition of the step's test files, read as decision 20 sets it

Review finding cf241526.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-13 19:00:09 +02:00
commit 0142034979
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
4 changed files with 135 additions and 18 deletions

View file

@ -35,14 +35,16 @@ and never touch a file the step does not list.
1. **Test first.** Read the step's `Test first:` and write that test (and only
that test) first. Follow the `Pattern:` file's style when one is named.
The step's test files are every file on the `Test first:` `File:` line
(below plan_version 1.9 every backticked span on that line with the shape
of a path; from 1.9 the backticked paths the line opens with).
The step's test files are every file on the `Test first:` `File:` line:
the backticked paths that stand right after `File:`, separated only by
commas or spaces; a path in the description after them is not a test file
(every plan_version; operator decision 20, 2026-10-12).
Then register every new file you created so the executor's diff sees it:
`git add --intent-to-add -- <path>` (this stages nothing).
2. **Prove it red before you build.** Run, from the repository root:
`node {voyage_root}/lib/verification/red-proof.mjs --red-only --base {start_sha} --cmd "<the step's Verify command>" --tests <test files as ONE comma-separated argument: a,b> --plan "{plan}" --step {step}`
(`--tests` lists every file on the `Test first:` `File:` line.)
(`--tests` lists the step's test files. Red proof refuses a list that
differs from the plan's and prints the plan's list as `plan_tests`.)
Exit 0 = the test fails at the start point: continue. Exit 1 = the test
already passes at the start point, so it proves nothing: rewrite the test
until it fails for the reason the step exists, and run the check again.
@ -51,10 +53,14 @@ and never touch a file the step does not list.
`Files:` alone decides this, not what you have changed: the behaviour
already exists at the start point, and no test can be red here. Do not rewrite the test and do not build; say so in
the report and stop. The executor sends the step up to the plan.
Exit 2 = it could not run (the Verify command is not one test-runner
invocation, or a file is missing): on `plan_version` ≥ 1.8 do not build;
say so in the report and stop. Below 1.8, write "red proof not run:
{reason}" in the report and go on to step 4 without a lock.
Exit 2 = it could not run. When its reason starts `tests-mismatch` (the
`--tests` you gave differs from the plan's list), run the gate once more
with `plan_tests` as `--tests`, whatever the plan_version; only a second
exit 2 goes on to the two branches that follow. Exit 2 otherwise (the
Verify command is not one test-runner invocation, or a file is missing):
on `plan_version` ≥ 1.8 do not build; say so in the report and stop.
Below 1.8, write "red proof not run: {reason}" in the report and go on to
step 4 without a lock.
**A step with no `Test first:`** (allowed only below plan_version 1.8):
skip steps 1–3, write "no Test first: no test written, no proof of red" in
@ -62,8 +68,8 @@ and never touch a file the step does not list.
3. **Lock the tests** (when the CLI exists):
`node {voyage_root}/lib/util/test-lock.mjs lock --files <test files> --step {step} --cmd "{Verify command}"`
(the lock stores the step's test command; only that command can later
mark the step green). `--files` lists every file on the `Test first:`
`File:` line, the same list as `--tests`.
mark the step green). `--files` is the list red proof accepted: the
`--tests` it ran without `tests-mismatch` (after a rerun, `plan_tests`).
If the file does not exist, write "not-locked (test-lock.mjs missing)" in the
report. Never silent. Once locked you cannot edit the tests, and that is the
point: the code changes to meet the test, never the reverse.