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:
parent
734b4a23ae
commit
0142034979
4 changed files with 135 additions and 18 deletions
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
# tests/e2e-files-trial4.sh
|
||||
# End to end for the trial-4 plan (step 13): the three CLIs run the way a
|
||||
# command runs them.
|
||||
# End to end for the trial-4 plan (steps 11 and 13): the four CLIs run the
|
||||
# way a command runs them.
|
||||
# 1. lib/validators/plan-validator.mjs --strict --json on three plans built
|
||||
# with tests/helpers/plan-v18-builder.mjs: a valid 1.9 plan (exit 0), a
|
||||
# 1.9 plan with an unticked Files entry (exit 1, PLAN_STEP_PATH_NOT_FIRST),
|
||||
|
|
@ -10,6 +10,13 @@
|
|||
# the trailer is the message's last line), without (exit 1, HEAD unchanged).
|
||||
# 3. lib/review/verdict-gate.mjs on the legal (exit 0) and the illegal
|
||||
# (exit 2) brief-conflict review fixtures.
|
||||
# 4. plan-validator on a 1.8 plan whose Test first File line names a source
|
||||
# path in its description (exit 0, no PLAN_STEP_TESTS_ONLY: decision 20).
|
||||
# 5. plan-validator on a 1.9 plan whose Files is a backticked None (exit 1,
|
||||
# PLAN_STEP_PATH_NOT_A_PATH).
|
||||
# 6. lib/verification/red-proof.mjs with --plan/--step and a --tests that
|
||||
# differs from the plan's list (exit 2, tests-mismatch).
|
||||
# 7. artifact-commit with an empty-model trailer (exit 1, HEAD unchanged).
|
||||
# Prints "e2e: ok" and exits 0, or names the failed check and exits 1.
|
||||
# bash 3.2 compatible, ASCII only.
|
||||
|
||||
|
|
@ -104,5 +111,51 @@ out="$(node lib/review/verdict-gate.mjs tests/fixtures/review-brief-conflict-ill
|
|||
rc=$?
|
||||
[ "$rc" -eq 2 ] || fail "verdict-gate on review-brief-conflict-illegal.md: exit $rc, expected 2: $out"
|
||||
|
||||
# ---- 4. and 5. the plan validator on decision 20 and on a placeholder ----
|
||||
|
||||
node --input-type=module -e '
|
||||
import { writeFileSync } from "node:fs";
|
||||
import { buildPlan } from "./tests/helpers/plan-v18-builder.mjs";
|
||||
const dir = process.argv[1];
|
||||
const e2e = { endToEnd: "bash tests/e2e.sh" };
|
||||
writeFileSync(dir + "/plan-1-8-description.md", buildPlan({ steps: [{
|
||||
file: "src/parser.mjs", test: "tests/parser.test.mjs",
|
||||
filesRaw: "`src/parser.mjs`, `tests/parser.test.mjs`",
|
||||
testFirstRaw: " - File: `tests/parser.test.mjs` (new) - covers `parse()` in `src/parser.mjs`",
|
||||
}, e2e] }));
|
||||
writeFileSync(dir + "/plan-1-9-none.md",
|
||||
buildPlan({ version: "1.9", steps: [{ filesRaw: "`None`" }, e2e] }));
|
||||
' "$TMP" || fail "could not write the plans for checks 4 and 5"
|
||||
|
||||
out="$(node lib/validators/plan-validator.mjs --strict --json "$TMP/plan-1-8-description.md" 2>&1)"
|
||||
rc=$?
|
||||
[ "$rc" -eq 0 ] || fail "1.8 plan with a source path in the File line description: plan-validator exit $rc, expected 0: $out"
|
||||
if echo "$out" | grep -q 'PLAN_STEP_TESTS_ONLY'; then
|
||||
fail "1.8 plan with a source path in the File line description: PLAN_STEP_TESTS_ONLY in: $out"
|
||||
fi
|
||||
|
||||
out="$(node lib/validators/plan-validator.mjs --strict --json "$TMP/plan-1-9-none.md" 2>&1)"
|
||||
rc=$?
|
||||
[ "$rc" -eq 1 ] || fail "1.9 plan whose Files is a backticked None: plan-validator exit $rc, expected 1: $out"
|
||||
echo "$out" | grep -q 'PLAN_STEP_PATH_NOT_A_PATH' \
|
||||
|| fail "1.9 plan whose Files is a backticked None: no PLAN_STEP_PATH_NOT_A_PATH in: $out"
|
||||
|
||||
# ---- 6. red proof refuses a --tests that differs from the plan ----
|
||||
|
||||
out="$(node lib/verification/red-proof.mjs --red-only --base HEAD --cwd "$REPO" --cmd 'node --test tests/parser.test.mjs' --tests tests/other.test.mjs --plan "$TMP/plan-1-8-description.md" --step 1 --json 2>&1)"
|
||||
rc=$?
|
||||
[ "$rc" -eq 2 ] || fail "red-proof with a --tests that differs from the plan: exit $rc, expected 2: $out"
|
||||
echo "$out" | grep -q 'tests-mismatch' \
|
||||
|| fail "red-proof with a --tests that differs from the plan: no tests-mismatch in: $out"
|
||||
|
||||
# ---- 7. the approval commit refuses an empty-model trailer ----
|
||||
|
||||
before="$(git -C "$REPO" rev-parse HEAD)"
|
||||
out="$(node lib/util/artifact-commit.mjs --repo "$REPO" --store local --message 'docs(voyage): approve intent e2e' --trailer 'Co-Authored-By: Claude <noreply@anthropic.com>' 2>&1)"
|
||||
rc=$?
|
||||
[ "$rc" -eq 1 ] || fail "artifact-commit with an empty-model trailer: exit $rc, expected 1: $out"
|
||||
after="$(git -C "$REPO" rev-parse HEAD)"
|
||||
[ "$before" = "$after" ] || fail "artifact-commit with an empty-model trailer: HEAD moved from $before to $after"
|
||||
|
||||
echo 'e2e: ok'
|
||||
exit 0
|
||||
|
|
|
|||
|
|
@ -194,3 +194,61 @@ test('decision 20: a 1.8 line with two File: markers, each followed by a test, g
|
|||
assert.deepEqual(testFirstFiles(body, '1.8'), ['tests/a.test.mjs', 'tests/b.test.mjs']);
|
||||
assert.deepEqual(testFirstFiles(body, null), ['tests/a.test.mjs', 'tests/b.test.mjs']);
|
||||
});
|
||||
|
||||
// ---- one definition in the prose (plan step 11, review cf241526) -----------
|
||||
// The executor and the step helper define the step's test files once, as
|
||||
// decision 20 reads them; every other place points at that definition. Red
|
||||
// proof refuses a --tests that differs from the plan (`tests-mismatch`) and
|
||||
// prints the plan's list (`plan_tests`): the executor and the helper run it
|
||||
// once more with that list, and the lock follows the list red proof accepted.
|
||||
|
||||
const EXEC = ['commands', 'trekexecute.md'];
|
||||
const HELPER = ['agents', 'step-implementer.md'];
|
||||
const readRel = (rel) => readFileSync(join(ROOT, ...rel), 'utf8');
|
||||
const count = (text, s) => text.split(s).length - 1;
|
||||
|
||||
test('prose: neither file reads every backticked span on the File: line any more', () => {
|
||||
for (const rel of [EXEC, HELPER]) {
|
||||
const text = readRel(rel);
|
||||
assert.equal(count(text, 'every backticked span on that line'), 0, `${rel.join('/')} still says "every backticked span on that line"`);
|
||||
}
|
||||
});
|
||||
|
||||
test('prose: the decision-20 definition stands exactly once in each file and keeps the pinned phrase', () => {
|
||||
for (const rel of [EXEC, HELPER]) {
|
||||
const text = readRel(rel);
|
||||
assert.equal((text.match(/operator decision 20(?!\d)/g) || []).length, 1, `${rel.join('/')} holds the decision-20 definition once`);
|
||||
assert.ok(text.includes('every file on the `Test first:` `File:` line'), `${rel.join('/')} keeps the pinned phrase`);
|
||||
}
|
||||
});
|
||||
|
||||
test('prose: the executor definition names tests-mismatch and plan_tests and keeps its line shape', () => {
|
||||
const lines = readRel(EXEC).split('\n');
|
||||
const i = lines.findIndex((l) => l.startsWith("**The step's test files** are"));
|
||||
assert.ok(i >= 0, 'the definition line is there');
|
||||
const def = lines[i];
|
||||
assert.ok(def.includes('operator decision 20'), 'the definition line carries decision 20');
|
||||
assert.ok(def.includes('`tests-mismatch`'), 'the definition names tests-mismatch');
|
||||
assert.ok(def.includes('`plan_tests`'), 'the definition names plan_tests');
|
||||
assert.ok(def.includes('`--files` is the list red proof accepted'), 'the definition says the lock follows the accepted list');
|
||||
assert.ok(def.endsWith(' The'), `the definition line still ends with " The": ${def.slice(-40)}`);
|
||||
assert.ok(lines[i + 1].startsWith('plan template lists them'), `the next line: ${lines[i + 1]}`);
|
||||
});
|
||||
|
||||
test('prose: the executor exit-2 row names tests-mismatch and the rerun with plan_tests', () => {
|
||||
const row = readRel(EXEC).split('\n').find((l) => l.startsWith('| 2 | `"not-run"`'));
|
||||
assert.ok(row, 'the exit-2 row is there');
|
||||
assert.ok(row.includes('`tests-mismatch`'), 'the exit-2 row names tests-mismatch');
|
||||
assert.ok(row.includes('`plan_tests`'), 'the exit-2 row names plan_tests');
|
||||
});
|
||||
|
||||
test('prose: the helper reruns once with plan_tests on tests-mismatch, before the 1.8 branches, and locks the accepted list', () => {
|
||||
const text = readRel(HELPER);
|
||||
const mm = text.match(/tests-mismatch[^.]*once\s+more[^.]*plan_tests/);
|
||||
assert.ok(mm, 'the helper runs the gate once more with plan_tests on tests-mismatch');
|
||||
assert.match(text, /whatever\s+the\s+plan_version/);
|
||||
const below = text.indexOf('Below 1.8');
|
||||
assert.ok(below > 0, 'the helper still has its Below 1.8 branch');
|
||||
assert.ok(mm.index < below, 'the mismatch sentence stands before "Below 1.8"');
|
||||
assert.match(text, /`--files` is the list red proof accepted/);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue