fix(execute): below 1.8 a plan that names no test file gets the files the helper wrote

Operator decision 41 (14.10); review finding 7b3b59ed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-14 18:17:24 +02:00
commit 829da487ec
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
6 changed files with 90 additions and 9 deletions

View file

@ -346,6 +346,60 @@ test('prose: no red-proof call line in either file passes --tests (operator deci
}
});
test('prose: below 1.8 a plan that names no test file gets --tests from the files the helper wrote (operator decision 41, review 7b3b59ed)', () => {
const esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const phrase = (s) => new RegExp(s.split(/\s+/).map(esc).join('\\s+'));
const d41 = /\boperator\s+decision\s+41(?!\d)/;
const NTFG = '`no test files given`';
const has = (text, s, where) => assert.match(text, phrase(s), `${where} holds "${s}"`);
// The helper: the sentence that holds `no test files given`.
const h = readRel(HELPER);
const at = h.search(phrase(NTFG));
assert.ok(at >= 0, 'the helper names `no test files given`');
const before = h.slice(0, at);
const ends = [...before.matchAll(/\.\s/g)];
const start = ends.length ? ends[ends.length - 1].index + 1 : 0;
const rest = h.slice(at);
const stop = rest.search(/\.(\s|$)/);
const sentence = h.slice(start, stop < 0 ? undefined : at + stop + 1);
has(sentence, 'below 1.8', 'the helper sentence');
has(sentence, '`--tests <the test files you wrote', 'the helper sentence');
assert.match(sentence, d41, 'the helper sentence names operator decision 41');
const pu = h.match(/plan-unreadable[^.]*do not build/);
assert.ok(pu && pu.index < at, 'the helper sentence stands after the plan-unreadable sentence');
// The executor: the definition line and the exit-2 row.
const lines = readRel(EXEC).split('\n');
const def = lines.find((l) => l.startsWith("**The step's test files** are"));
assert.ok(def, 'the executor definition line is there');
for (const s of [NTFG, 'naming the test files it wrote', 'the `tests:` line the helper copied into its report']) {
has(def, s, 'the executor definition line');
}
assert.match(def, d41, 'the executor definition line names operator decision 41');
assert.ok(def.endsWith(' The'), `the definition line still ends with " The": ${def.slice(-40)}`);
const row = lines.find((l) => l.startsWith('| 2 | `"not-run"`'));
assert.ok(row, 'the exit-2 row is there');
const r = row.search(phrase(NTFG));
assert.ok(r >= 0, 'the exit-2 row names `no test files given`');
const after = row.slice(r);
for (const s of ['is not a finding', 'the `tests:` line in the helper\'s report', 'tolerated as `"not-run"`']) {
has(after, s, 'the exit-2 row after `no test files given`');
}
assert.match(after, d41, 'the exit-2 row names operator decision 41');
// Handover 4, invariant 7.
const ho = readRel(['docs', 'HANDOVER-CONTRACTS.md']);
const a7 = ho.indexOf('7. **Every plan_version');
const a8 = ho.indexOf('8. **', a7);
assert.ok(a7 >= 0 && a8 > a7, 'Handover 4 invariants 7 and 8 are there');
const inv7 = ho.slice(a7, a8);
for (const s of [NTFG, 'naming the test files it wrote', 'the `tests:` line in the helper\'s report']) {
has(inv7, s, 'Handover 4 invariant 7');
}
assert.match(inv7, d41, 'Handover 4 invariant 7 names operator decision 41');
});
test('prose: the helper stops on plan-unreadable before the 1.8 branches and locks the printed list', () => {
const text = readRel(HELPER);
const pu = text.match(/plan-unreadable[^.]*do not build/);