diff --git a/plugins/voyage/tests/commands/trekexecute.test.mjs b/plugins/voyage/tests/commands/trekexecute.test.mjs index e848119..15a67c7 100644 --- a/plugins/voyage/tests/commands/trekexecute.test.mjs +++ b/plugins/voyage/tests/commands/trekexecute.test.mjs @@ -1,5 +1,5 @@ // tests/commands/trekexecute.test.mjs -// v5.1 — sequencing-gate surface + low-effort prose check for /trekexecute. +// v5.1 prose-pin tests + v5.1.1 runtime SC4 + SC7 tests for /trekexecute. // Plan Assumption 2 locks low-effort to --gates open + sequential-only. import { test } from 'node:test'; @@ -7,15 +7,24 @@ import { strict as assert } from 'node:assert'; import { readFileSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; +import { resolvePhaseSignal } from '../../lib/profiles/phase-signal-resolver.mjs'; +import { validateBriefContent } from '../../lib/validators/brief-validator.mjs'; +import { parseDocument } from '../../lib/util/frontmatter.mjs'; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = join(HERE, '..', '..'); const COMMAND_FILE = join(ROOT, 'commands', 'trekexecute.md'); +const PHASE = 'execute'; -function read() { - return readFileSync(COMMAND_FILE, 'utf8'); +function read() { return readFileSync(COMMAND_FILE, 'utf8'); } +function readFixture(name) { return readFileSync(join(ROOT, 'tests', 'fixtures', name), 'utf8'); } +function frontmatterOf(text) { + const doc = parseDocument(text); + return doc.parsed && doc.parsed.frontmatter; } +// --- Pattern D prose-pins --- + test('trekexecute — sequencing-gate surface mentions BRIEF_V51_MISSING_SIGNALS + phase_signals', () => { const text = read(); assert.ok(text.includes('BRIEF_V51_MISSING_SIGNALS'), @@ -32,3 +41,35 @@ test('trekexecute — low-effort path references --gates open + sequential', () assert.match(section, /--gates open/, 'Low-effort path must mention --gates open'); assert.match(section, /sequential/, 'Low-effort path must mention sequential-only execution'); }); + +// --- v5.1.1 runtime SC4 + SC7 --- + +test('trekexecute — SC4: low-effort fixture → resolver returns {effort: low, model: sonnet}', () => { + const fm = frontmatterOf(readFixture('brief-effort-low.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'low'); + assert.equal(r.model, 'sonnet'); +}); + +test('trekexecute — SC4: standard-effort fixture → resolver returns {effort: standard, model: undefined}', () => { + const fm = frontmatterOf(readFixture('brief-effort-standard.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'standard'); + assert.equal(r.model, undefined); +}); + +test('trekexecute — SC4: high-effort fixture → resolver returns {effort: high, model: opus}', () => { + const fm = frontmatterOf(readFixture('brief-effort-high.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'high'); + assert.equal(r.model, 'opus'); +}); + +test('trekexecute — SC7: brief_version 2.1 + no phase_signals + no partial → BRIEF_V51_MISSING_SIGNALS', () => { + const r = validateBriefContent(readFixture('brief-v21-no-signals.md'), { strict: true }); + assert.equal(r.valid, false); + assert.ok( + r.errors.find(e => e.code === 'BRIEF_V51_MISSING_SIGNALS'), + `sequencing gate must fire; errors=${JSON.stringify(r.errors)}`, + ); +}); diff --git a/plugins/voyage/tests/commands/trekplan.test.mjs b/plugins/voyage/tests/commands/trekplan.test.mjs index 901936d..1ab3ee0 100644 --- a/plugins/voyage/tests/commands/trekplan.test.mjs +++ b/plugins/voyage/tests/commands/trekplan.test.mjs @@ -1,20 +1,29 @@ // tests/commands/trekplan.test.mjs -// v5.1 — sequencing-gate surface + low-effort prose check for /trekplan. +// v5.1 prose-pin tests + v5.1.1 runtime SC4 + SC7 tests for /trekplan. 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 { resolvePhaseSignal } from '../../lib/profiles/phase-signal-resolver.mjs'; +import { validateBriefContent } from '../../lib/validators/brief-validator.mjs'; +import { parseDocument } from '../../lib/util/frontmatter.mjs'; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = join(HERE, '..', '..'); const COMMAND_FILE = join(ROOT, 'commands', 'trekplan.md'); +const PHASE = 'plan'; -function read() { - return readFileSync(COMMAND_FILE, 'utf8'); +function read() { return readFileSync(COMMAND_FILE, 'utf8'); } +function readFixture(name) { return readFileSync(join(ROOT, 'tests', 'fixtures', name), 'utf8'); } +function frontmatterOf(text) { + const doc = parseDocument(text); + return doc.parsed && doc.parsed.frontmatter; } +// --- Pattern D prose-pins (kept) --- + test('trekplan — sequencing-gate surface mentions BRIEF_V51_MISSING_SIGNALS + phase_signals', () => { const text = read(); assert.ok(text.includes('BRIEF_V51_MISSING_SIGNALS'), @@ -30,3 +39,35 @@ test('trekplan — low-effort path references --quick equivalent', () => { const section = text.slice(compIdx, compIdx + 2000); assert.match(section, /--quick/, 'Low-effort path must mention --quick equivalent'); }); + +// --- v5.1.1 runtime SC4 + SC7 tests --- + +test('trekplan — SC4: low-effort fixture → resolver returns {effort: low, model: sonnet}', () => { + const fm = frontmatterOf(readFixture('brief-effort-low.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'low'); + assert.equal(r.model, 'sonnet'); +}); + +test('trekplan — SC4: standard-effort fixture → resolver returns {effort: standard, model: undefined}', () => { + const fm = frontmatterOf(readFixture('brief-effort-standard.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'standard'); + assert.equal(r.model, undefined); +}); + +test('trekplan — SC4: high-effort fixture → resolver returns {effort: high, model: opus}', () => { + const fm = frontmatterOf(readFixture('brief-effort-high.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'high'); + assert.equal(r.model, 'opus'); +}); + +test('trekplan — SC7: brief_version 2.1 + no phase_signals + no partial → BRIEF_V51_MISSING_SIGNALS', () => { + const r = validateBriefContent(readFixture('brief-v21-no-signals.md'), { strict: true }); + assert.equal(r.valid, false); + assert.ok( + r.errors.find(e => e.code === 'BRIEF_V51_MISSING_SIGNALS'), + `sequencing gate must fire; errors=${JSON.stringify(r.errors)}`, + ); +}); diff --git a/plugins/voyage/tests/commands/trekresearch.test.mjs b/plugins/voyage/tests/commands/trekresearch.test.mjs index 4fd2a8c..0e10351 100644 --- a/plugins/voyage/tests/commands/trekresearch.test.mjs +++ b/plugins/voyage/tests/commands/trekresearch.test.mjs @@ -1,20 +1,29 @@ // tests/commands/trekresearch.test.mjs -// v5.1 — sequencing-gate surface + low-effort prose check for /trekresearch. +// v5.1 prose-pin tests + v5.1.1 runtime SC4 + SC7 tests for /trekresearch. 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 { resolvePhaseSignal } from '../../lib/profiles/phase-signal-resolver.mjs'; +import { validateBriefContent } from '../../lib/validators/brief-validator.mjs'; +import { parseDocument } from '../../lib/util/frontmatter.mjs'; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = join(HERE, '..', '..'); const COMMAND_FILE = join(ROOT, 'commands', 'trekresearch.md'); +const PHASE = 'research'; -function read() { - return readFileSync(COMMAND_FILE, 'utf8'); +function read() { return readFileSync(COMMAND_FILE, 'utf8'); } +function readFixture(name) { return readFileSync(join(ROOT, 'tests', 'fixtures', name), 'utf8'); } +function frontmatterOf(text) { + const doc = parseDocument(text); + return doc.parsed && doc.parsed.frontmatter; } +// --- Pattern D prose-pins --- + test('trekresearch — sequencing-gate surface mentions BRIEF_V51_MISSING_SIGNALS + phase_signals', () => { const text = read(); assert.ok(text.includes('BRIEF_V51_MISSING_SIGNALS'), @@ -30,3 +39,35 @@ test('trekresearch — low-effort path references --quick equivalent', () => { const section = text.slice(compIdx, compIdx + 2000); assert.match(section, /--quick/, 'Low-effort path must mention --quick equivalent'); }); + +// --- v5.1.1 runtime SC4 + SC7 --- + +test('trekresearch — SC4: low-effort fixture → resolver returns {effort: low, model: sonnet}', () => { + const fm = frontmatterOf(readFixture('brief-effort-low.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'low'); + assert.equal(r.model, 'sonnet'); +}); + +test('trekresearch — SC4: standard-effort fixture → resolver returns {effort: standard, model: undefined}', () => { + const fm = frontmatterOf(readFixture('brief-effort-standard.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'standard'); + assert.equal(r.model, undefined); +}); + +test('trekresearch — SC4: high-effort fixture → resolver returns {effort: high, model: opus}', () => { + const fm = frontmatterOf(readFixture('brief-effort-high.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'high'); + assert.equal(r.model, 'opus'); +}); + +test('trekresearch — SC7: brief_version 2.1 + no phase_signals + no partial → BRIEF_V51_MISSING_SIGNALS', () => { + const r = validateBriefContent(readFixture('brief-v21-no-signals.md'), { strict: true }); + assert.equal(r.valid, false); + assert.ok( + r.errors.find(e => e.code === 'BRIEF_V51_MISSING_SIGNALS'), + `sequencing gate must fire; errors=${JSON.stringify(r.errors)}`, + ); +}); diff --git a/plugins/voyage/tests/commands/trekreview.test.mjs b/plugins/voyage/tests/commands/trekreview.test.mjs index 9d1a53c..e66ef00 100644 --- a/plugins/voyage/tests/commands/trekreview.test.mjs +++ b/plugins/voyage/tests/commands/trekreview.test.mjs @@ -1,20 +1,29 @@ // tests/commands/trekreview.test.mjs -// v5.1 — sequencing-gate surface + low-effort prose check for /trekreview. +// v5.1 prose-pin tests + v5.1.1 runtime SC4 + SC7 tests for /trekreview. 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 { resolvePhaseSignal } from '../../lib/profiles/phase-signal-resolver.mjs'; +import { validateBriefContent } from '../../lib/validators/brief-validator.mjs'; +import { parseDocument } from '../../lib/util/frontmatter.mjs'; const HERE = dirname(fileURLToPath(import.meta.url)); const ROOT = join(HERE, '..', '..'); const COMMAND_FILE = join(ROOT, 'commands', 'trekreview.md'); +const PHASE = 'review'; -function read() { - return readFileSync(COMMAND_FILE, 'utf8'); +function read() { return readFileSync(COMMAND_FILE, 'utf8'); } +function readFixture(name) { return readFileSync(join(ROOT, 'tests', 'fixtures', name), 'utf8'); } +function frontmatterOf(text) { + const doc = parseDocument(text); + return doc.parsed && doc.parsed.frontmatter; } +// --- Pattern D prose-pins --- + test('trekreview — sequencing-gate surface mentions BRIEF_V51_MISSING_SIGNALS + phase_signals', () => { const text = read(); assert.ok(text.includes('BRIEF_V51_MISSING_SIGNALS'), @@ -30,3 +39,36 @@ test('trekreview — low-effort path references --quick equivalent', () => { const section = text.slice(compIdx, compIdx + 2000); assert.match(section, /--quick/, 'Low-effort path must mention --quick equivalent'); }); + +// --- v5.1.1 runtime SC4 + SC7 --- + +test('trekreview — SC4: low-effort fixture → resolver returns {effort: low, model: sonnet}', () => { + const fm = frontmatterOf(readFixture('brief-effort-low.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'low'); + assert.equal(r.model, 'sonnet'); +}); + +test('trekreview — SC4: standard-effort fixture → resolver returns {effort: standard, model: undefined}', () => { + const fm = frontmatterOf(readFixture('brief-effort-standard.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'standard'); + assert.equal(r.model, undefined); +}); + +test('trekreview — SC4: high-effort fixture → resolver returns {effort: high, model: opus}', () => { + const fm = frontmatterOf(readFixture('brief-effort-high.md')); + const r = resolvePhaseSignal(fm, PHASE); + assert.equal(r.effort, 'high'); + assert.equal(r.model, 'opus'); +}); + +test('trekreview — SC7: brief_version 2.1 + no phase_signals + no partial → BRIEF_V51_MISSING_SIGNALS', () => { + // Falsification via brief-v21-no-signals fixture: validator must catch missing signals. + const r = validateBriefContent(readFixture('brief-v21-no-signals.md'), { strict: true }); + assert.equal(r.valid, false); + assert.ok( + r.errors.find(e => e.code === 'BRIEF_V51_MISSING_SIGNALS'), + `sequencing gate must fire; errors=${JSON.stringify(r.errors)}`, + ); +});