// 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'); });