// tests/lib/executor-prose-pins.test.mjs // Wave 1, process 1 (the executor): prose pins for P8 (fresh helper per step, // one controller with two verdicts, fix rounds that go up), P9 on the executor // side (proof of red, the floor guard, the done line, end to end, back to the // architecture after three failed fixes) and P4 (the closed stop list and the // decision log). The mechanisms themselves are tested as code in // tests/lib/{red-proof,test-integrity,done-line}.test.mjs; these pins hold the // command prose to them. Fix the SOURCE a pin guards, not the pin. import { test } from 'node:test'; import { strict as assert } from 'node:assert'; import { existsSync, readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = join(HERE, '..', '..'); const read = (rel) => readFileSync(join(ROOT, rel), 'utf8'); const CMD = 'commands/trekexecute.md'; const AGENT = 'agents/step-implementer.md'; function frontmatter(text) { const m = text.match(/^---\n([\s\S]*?)\n---/); assert.ok(m, 'frontmatter missing'); return m[1]; } const fmValue = (fm, key) => (fm.match(new RegExp(`^${key}:\\s*(.+)$`, 'm')) || [])[1]; /** The text between `## {start}` (or `#### {start}`) and the next heading of the same or higher level. */ function section(text, heading) { const at = text.indexOf(heading); assert.ok(at >= 0, `${CMD} must have "${heading}"`); const level = heading.match(/^#+/)[0].length; const rest = text.slice(at + heading.length); const next = rest.search(new RegExp(`\\n#{1,${level}} `)); return heading + (next >= 0 ? rest.slice(0, next) : rest); } // --- P8: the Agent tool is back, for one purpose ------------------------------- test('P8: /trekexecute may spawn - Agent is allowed and no longer disallowed', () => { const fm = frontmatter(read(CMD)); assert.match(fmValue(fm, 'allowed-tools'), /\bAgent\b/, 'allowed-tools must list Agent'); const disallowed = fmValue(fm, 'disallowed-tools') || ''; assert.doesNotMatch(disallowed, /\bAgent\b/, 'disallowed-tools must no longer remove Agent'); assert.match(disallowed, /\bTeamCreate\b/, 'TeamCreate stays removed - helpers, never a team'); }); test('P8: Hard rule 10 is rewritten - one fresh helper per plan step, and helpers never start helpers', () => { const text = read(CMD); assert.doesNotMatch(text, /\*\*No sub-agents\.\*\*/, 'the old "No sub-agents" rule must be gone'); const rule = text.slice(text.indexOf('10. **'), text.indexOf('11. **')); assert.match(rule, /fresh helper per plan step/i); assert.match(rule, /voyage:step-implementer/); assert.match(rule, /helpers never start helpers/i); assert.match(rule, /controller/i); }); test('P8: the step agent exists, is opus at effort >= high, and cannot spawn', () => { assert.ok(existsSync(join(ROOT, AGENT)), `${AGENT} must exist`); const fm = frontmatter(read(AGENT)); assert.equal(fmValue(fm, 'name'), 'step-implementer'); assert.equal(fmValue(fm, 'model'), 'opus'); assert.ok(['high', 'xhigh', 'max'].includes(fmValue(fm, 'effort')), 'effort must be >= high'); assert.doesNotMatch(fmValue(fm, 'tools') || '', /\bAgent\b/, 'a helper must not hold the Agent tool'); // Measured 2026-10-06 (CC 2.1.291): a worktree-isolated helper branched from // the default branch (02f320f), not from the executor's HEAD (2c89a6b), and so // did not see the earlier steps. A plugin cannot set worktree.baseRef. So no // isolation: the helper works in the executor's tree, from a recorded start_sha. assert.doesNotMatch(fm, /^isolation:/m, 'no isolation: worktree on the step agent (measured: wrong base)'); }); test('P8: the helper report contract is ran / saw / did NOT check', () => { const body = read(AGENT); for (const h of ['### Ran', '### Saw', '### Did NOT check']) assert.ok(body.includes(h), `${AGENT} report must have "${h}"`); assert.ok(read(CMD).includes('Did NOT check'), 'the command must name the report contract too'); }); test('P8: hand-over is in files, from a recorded start point', () => { const text = read(CMD); assert.match(text, /start_sha/); assert.match(text, /report_path/); assert.match(text, /git diff \{start_sha\}/, 'the review package is the diff from the recorded start point'); }); test('P8: one controller, two verdicts, reads the diff not the summary, re-checks only what was fixed', () => { const ctl = section(read(CMD), '#### Sub-step E — Control'); assert.match(ctl, /one controller/i); assert.match(ctl, /two verdicts/i); assert.match(ctl, /"spec"/); assert.match(ctl, /"quality"/); assert.match(ctl, /reads the diff, not the helper's (summary|report)/i); assert.match(ctl, /only what (was|the round) fixed/i); assert.match(ctl, /general-purpose/, 'the controller is a general helper with a prompt from the command, not agent no. 2'); }); test('P8: fix rounds go up - maximum 5, plan then operator, never a cheaper-model ladder', () => { const fix = section(read(CMD), '#### Sub-step F — Fix rounds'); assert.match(fix, /maximum 5 fix rounds[^\n]*upward/i); assert.match(fix, /back to (the )?planning/i); assert.match(fix, /operator/i); assert.match(fix, /does not improvise/i); assert.match(fix, /no ladder of cheaper models/i); // P9 (7): after three failed fixes the question is the architecture, not a fourth fix. assert.match(fix, /three failed fix(es| rounds)[^\n]*architecture/i); }); test('P8: the no-name rule covers the step helper and the controller', () => { const text = read(CMD); assert.ok(text.includes('in_process_teammate')); assert.match(text, /never pass .*`name`/i); assert.match(text, /^Launch\b/m, 'the spawn site starts with "Launch" (the S85 detector reads it)'); }); // --- P9 (executor side) --------------------------------------------------------- test('P9 (1): proof of red is a command and it blocks - the old "do not block" sentence is gone', () => { const text = read(CMD); assert.doesNotMatch(text, /Do not block on test-first failures/); assert.match(text, /lib\/verification\/red-proof\.mjs/); const red = section(text, '#### Sub-step B — Test first and proof of red'); assert.match(red, /must FAIL/); assert.match(red, /must PASS/); assert.match(red, /not-run/); assert.match(red, /never (a pass|green|proven)/i); }); test('K4: Test first is required from plan_version 1.8; Interface in/out and Review focus are read, not required', () => { const text = read(CMD); assert.match(text, /plan_version ≥ 1\.8[^\n]*`Test first:`|`Test first:`[^\n]*plan_version ≥ 1\.8/); for (const f of ['Interface in:', 'Interface out:', 'Review focus:']) assert.ok(text.includes(f), `${CMD} must read ${f}`); assert.match(text, /tolerat(e|es) (their|its) absence|never required/i); }); test('K8: the test lock is used through its CLI, and a missing CLI is said out loud', () => { const text = read(CMD); assert.match(text, /lib\/util\/test-lock\.mjs lock --files/); assert.match(text, /test-lock\.mjs unlock/); assert.match(text, /"not-locked"/); assert.match(text, /never silent/i); }); test('P9 (2): the floor guard runs on the step diff and exit 2 is never green', () => { const d3 = section(read(CMD), '#### Sub-step D3 — Floor guard'); assert.match(d3, /lib\/verification\/test-integrity\.mjs --base \{start_sha\}/); assert.match(d3, /exit 2 is never green/i); assert.match(d3, /justified/); }); test('P9 (4): the done line is written by a script, only when the test command exits 0, at the step commit', () => { const g = section(read(CMD), '#### Sub-step G — Checkpoint, done line, unlock'); assert.match(g, /lib\/verification\/done-line\.mjs --step \{N\}/); assert.match(g, /done-line\.mjs --check --step \{N\} --report \{report_path\} --commit \{hash\}/); assert.match(g, /writes its line only when the test command\s+exits 0/i); // The checkpoint comes first, so the line names the step's own commit. assert.ok(g.indexOf('**Checkpoint.**') < g.indexOf('**The done line**'), 'checkpoint before the done line'); }); // --- the independent review of 2026-10-06 (15 findings): what the fixes must keep test('review: the step test files are part of the scope and committed at the checkpoint', () => { const text = read(CMD); assert.match(section(text, '#### Sub-step B — Test first and proof of red'), /scope = its `Files:` \+ its test files/); assert.match(section(text, '#### Sub-step G — Checkpoint, done line, unlock'), /its `Files:` and its test files/); }); test('review: every new file is registered (not only listed ones), so no check is blind to it', () => { const c = section(read(CMD), '#### Sub-step C — Implement through one fresh helper'); assert.match(c, /git ls-files --others --exclude-standard/); assert.match(c, /git add --intent-to-add -- \{path\}/); }); test('review: proof of red has a control run and a real git checkout as its start point', () => { const b = section(read(CMD), '#### Sub-step B — Test first and proof of red'); assert.match(b, /control run/); assert.match(b, /git clone --shared/); }); test('review: Phase 7.5 audits the run from session_start_sha, never a step start_sha', () => { const text = read(CMD); const audit = text.slice(text.indexOf('## Phase 7.5'), text.indexOf('### Machine-verifiable completion gate')); assert.match(audit, /\{session_start_sha\}\.\.HEAD/); assert.doesNotMatch(audit, /\{start_sha\}/); }); test('review: no sixth round, attempts never reset, a step at 5 is never built again', () => { const text = read(CMD); assert.match(section(text, '#### Sub-step F — Fix rounds'), /no sixth round/); const c = section(text, '#### Sub-step C — Implement through one fresh helper'); assert.match(c, /never\s+reset/); assert.match(c, /A step at `fix_rounds` 5 is never built again/); }); test('review: the helper appends its report, and gives red proof no --tests', () => { const agent = read(AGENT); assert.match(agent, /APPEND it to `report_path`/); const gate = agent.split('\n').find((l) => l.includes('red-proof.mjs --red-only')); assert.ok(gate, 'the helper has its red-proof --red-only line'); assert.ok(!gate.includes('--tests'), `the helper's red-proof line passes --tests: ${gate}`); assert.match(agent, /A step with no `Test first:`/); }); test('P9 (6): without a run-the-thing check the result is "not verified end to end", never green', () => { const text = read(CMD); assert.match(text, /not verified end to end/); assert.match(text, /end_to_end/); }); test('P9: the three new CLIs the prose names exist', () => { for (const f of ['red-proof.mjs', 'test-integrity.mjs', 'done-line.mjs']) { assert.ok(existsSync(join(ROOT, 'lib', 'verification', f)), `lib/verification/${f}`); } }); // --- P4: the closed stop list and the decision log ------------------------------ test('P4: the run stops only on the closed list of four, and the final report shows it', () => { const text = read(CMD); const list = section(text, '### Closed stop list'); for (const cls of [/cannot be undone/i, /security-sensitive/i, /outside the working copy/i, /so broken that (every|any)thing (after it )?is guesswork/i]) { assert.match(list, cls); } assert.match(list, /closed/i); // Phase 8's report template is a fence that holds its own "## " heading, so // the phase is read up to Phase 9, not up to the next heading. const report = text.slice(text.indexOf('## Phase 8 — Final report'), text.indexOf('## Phase 9')); assert.match(report, /### Stops/); assert.match(report, /### Decisions taken/); }); test('P4: every decision the executor took is logged with what it costs if it is wrong', () => { const text = read(CMD); assert.match(text, /cost_if_wrong/); assert.match(text, /"decisions"/); }); // --- Credits: every borrowing is named, never silent ---------------------------- test('every borrowing in the executor is credited', () => { const text = read(CMD); const credits = section(text, '## Credits'); for (const src of [/Superpowers/, /subagent-driven-development/, /ai-native-sdlc/, /Kiro/, /Spec Kit/, /agent-skills/, /Cherny/]) { assert.match(credits, src); } assert.match(credits, /MIT/); });