voyage-lekerepo trial (2026-10-06) point 14, operator decision 2026-10-08
(«alle agenter, ny briefsjekk bare ved endring»):
- trekplan: the "Adaptive" hard rule (a 10-file project does not need 7
agents) contradicted Phase 5 ("All agents run for all codebase sizes");
it is gone, in line with quality before cost.
- brief-review-stamp.mjs: /trekbrief stamps the brief body when its
brief-reviewer gate passes; /trekplan Phase 4b skips its own review only
while the stamp is current. Stale (edited) or absent (another producer,
or a gate that did not pass) reviews as before. Additive optional
frontmatter fields, documented in Handover 1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
92 lines
4.3 KiB
JavaScript
92 lines
4.3 KiB
JavaScript
// tests/validators/brief-review-stamp.test.mjs
|
|
// Operator decision 2026-10-08 (voyage-lekerepo trial point 14): /trekplan
|
|
// Phase 4b re-ran brief-reviewer right after /trekbrief had run it on the same
|
|
// text. Now /trekbrief stamps the body it reviewed (on a passed gate), and
|
|
// /trekplan reviews again only when the stamp is absent or the body changed —
|
|
// a brief from any other producer has no stamp and is always reviewed.
|
|
// Same decision: every exploration agent runs at every codebase size; the
|
|
// contradicting "Adaptive" rule is gone.
|
|
|
|
import { test } from 'node:test';
|
|
import { strict as assert } from 'node:assert';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
import { dirname, join } from 'node:path';
|
|
import { tmpdir } from 'node:os';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { stampBriefReview, checkBriefReview } from '../../lib/validators/brief-review-stamp.mjs';
|
|
import { stampIntentApproval } from '../../lib/validators/intent-approval.mjs';
|
|
|
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
const ROOT = join(HERE, '..', '..');
|
|
const CLI = join(ROOT, 'lib', 'validators', 'brief-review-stamp.mjs');
|
|
|
|
const BRIEF = [
|
|
'---', 'type: trekbrief', 'brief_version: "2.2"', 'task: t', 'slug: s', '---', '',
|
|
'## TL;DR', '', 'A toy.', '', '## Intent', '', 'Why it matters.', '', '## Goal', '', 'What.', '',
|
|
'## Success Criteria', '', '- `npm test` exits 0.', '',
|
|
].join('\n');
|
|
|
|
test('stamp, then check: current', () => {
|
|
const s = stampBriefReview(BRIEF);
|
|
assert.equal(s.stamped, true);
|
|
assert.match(s.text, /^brief_reviewed_hash: "sha256:[0-9a-f]{64}"$/m);
|
|
assert.equal(checkBriefReview(s.text).state, 'current');
|
|
});
|
|
|
|
test('no stamp: absent (another producer\'s brief is always reviewed)', () => {
|
|
assert.equal(checkBriefReview(BRIEF).state, 'absent');
|
|
});
|
|
|
|
test('a changed body after the stamp: stale', () => {
|
|
const s = stampBriefReview(BRIEF).text;
|
|
assert.equal(checkBriefReview(s.replace('Why it matters.', 'Why it matters a lot.')).state, 'stale');
|
|
assert.equal(checkBriefReview(s + '\n## Non-Goals\n\n- none\n').state, 'stale');
|
|
});
|
|
|
|
test('frontmatter changes (the intent approval stamp) and CRLF keep the review current', () => {
|
|
const s = stampBriefReview(BRIEF).text;
|
|
const approved = stampIntentApproval(s).text;
|
|
assert.notEqual(approved, s);
|
|
assert.equal(checkBriefReview(approved).state, 'current');
|
|
assert.equal(checkBriefReview(s.replace(/\n/g, '\r\n')).state, 'current');
|
|
});
|
|
|
|
test('re-stamping replaces the old stamp, never adds a second', () => {
|
|
const twice = stampBriefReview(stampBriefReview(BRIEF).text).text;
|
|
assert.equal(twice.match(/^brief_reviewed_hash:/gm).length, 1);
|
|
});
|
|
|
|
test('CLI: --stamp writes the file, --check exits 0 current / 1 stale or absent / 2 usage', () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'voyage-brief-stamp-'));
|
|
try {
|
|
const p = join(dir, 'brief.md');
|
|
writeFileSync(p, BRIEF);
|
|
const run = (...a) => spawnSync(process.execPath, [CLI, ...a], { encoding: 'utf8' });
|
|
assert.equal(run('--check', p).status, 1);
|
|
assert.equal(run('--stamp', p).status, 0);
|
|
assert.equal(run('--check', p).status, 0);
|
|
writeFileSync(p, readFileSync(p, 'utf8').replace('What.', 'What else.'));
|
|
const c = run('--check', '--json', p);
|
|
assert.equal(c.status, 1);
|
|
assert.equal(JSON.parse(c.stdout).state, 'stale');
|
|
assert.equal(run('--check').status, 2);
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test('prose: /trekbrief stamps after a passed gate; /trekplan Phase 4b checks before it reviews again', () => {
|
|
const brief = readFileSync(join(ROOT, 'commands', 'trekbrief.md'), 'utf8');
|
|
const plan = readFileSync(join(ROOT, 'commands', 'trekplan.md'), 'utf8');
|
|
assert.match(brief, /brief-review-stamp\.mjs --stamp/);
|
|
const p4b = plan.slice(plan.indexOf('## Phase 4b'), plan.indexOf('## Phase 5'));
|
|
assert.match(p4b, /brief-review-stamp\.mjs --check/);
|
|
});
|
|
|
|
test('prose: every exploration agent runs at every codebase size; no "Adaptive" rule contradicts it', () => {
|
|
const plan = readFileSync(join(ROOT, 'commands', 'trekplan.md'), 'utf8');
|
|
assert.match(plan, /All agents run for all codebase sizes/);
|
|
assert.doesNotMatch(plan, /\*\*Adaptive\*\*/);
|
|
assert.doesNotMatch(plan, /does not need 7 exploration agents/);
|
|
});
|