fix(trekbrief): the review stamp covers only text the reviewer saw
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e6755bd886
commit
94de23ca3b
2 changed files with 61 additions and 4 deletions
56
tests/validators/brief-review-stamp-order.test.mjs
Normal file
56
tests/validators/brief-review-stamp-order.test.mjs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// tests/validators/brief-review-stamp-order.test.mjs
|
||||
// /trekbrief stamps only text the reviewer saw. A `small` brief gets one
|
||||
// review; its gaps are written as assumptions. When that writing came before
|
||||
// the stamp, the stamp covered text no reviewer read and /trekplan skipped its
|
||||
// own review. The gaps are now written after the stamp, on purpose, so the
|
||||
// stamp reads stale and /trekplan reviews the brief once more.
|
||||
|
||||
import { test } from 'node:test';
|
||||
import { strict as assert } from 'node:assert';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { stampBriefReview, checkBriefReview } from '../../lib/validators/brief-review-stamp.mjs';
|
||||
|
||||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||||
const ROOT = join(HERE, '..', '..');
|
||||
const brief = readFileSync(join(ROOT, 'commands', 'trekbrief.md'), 'utf8');
|
||||
|
||||
const STAMP = 'brief-review-stamp.mjs --stamp';
|
||||
const GAPS = "Class `small` only: now write the reviewer's gaps";
|
||||
const PASS_START = '**If gate passes:**';
|
||||
const PASS_END = '**If gate fails AND iteration count < the class cap:**';
|
||||
|
||||
function unique(text, needle) {
|
||||
const at = text.indexOf(needle);
|
||||
assert.ok(at >= 0, `found: ${needle}`);
|
||||
assert.equal(text.lastIndexOf(needle), at, `unique in commands/trekbrief.md: ${needle}`);
|
||||
return at;
|
||||
}
|
||||
|
||||
test('trekbrief: the stamp comes before the small-class gaps are written, both in the passed-gate branch', () => {
|
||||
const start = unique(brief, PASS_START);
|
||||
const end = unique(brief, PASS_END);
|
||||
const stamp = unique(brief, STAMP);
|
||||
const gaps = unique(brief, GAPS);
|
||||
assert.ok(start < end, 'passed-gate branch precedes the failed-gate branch');
|
||||
assert.ok(start < stamp && stamp < end, 'the stamp sits in the passed-gate branch');
|
||||
assert.ok(start < gaps && gaps < end, 'the gaps instruction sits in the passed-gate branch');
|
||||
assert.ok(stamp < gaps, 'order: stamp, then the small-class gaps');
|
||||
const after = brief.slice(gaps, end);
|
||||
assert.match(after, /They come after the stamp on purpose/);
|
||||
assert.match(after, /## Open Questions \/ Assumptions/);
|
||||
});
|
||||
|
||||
test('guard: stamping a brief and then appending an assumption reads as stale', () => {
|
||||
const text = [
|
||||
'---', 'type: trekbrief', 'brief_version: "2.2"', 'task: t', 'slug: s', 'ceremony: small', '---', '',
|
||||
'## TL;DR', '', 'A toy.', '', '## Intent', '', 'Why it matters.', '', '## Goal', '', 'What.', '',
|
||||
'## Open Questions / Assumptions', '', '- None.', '',
|
||||
].join('\n');
|
||||
const s = stampBriefReview(text);
|
||||
assert.equal(s.stamped, true);
|
||||
assert.equal(checkBriefReview(s.text).state, 'current');
|
||||
const withGap = s.text + '- Assumed, not asked: the setting defaults to off (reviewer gap).\n';
|
||||
assert.equal(checkBriefReview(withGap).state, 'stale');
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue