Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
120 lines
5.6 KiB
JavaScript
120 lines
5.6 KiB
JavaScript
// tests/commands/trekexecute.test.mjs
|
|
// 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';
|
|
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 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'),
|
|
'/trekexecute must surface the BRIEF_V51_MISSING_SIGNALS sequencing gate');
|
|
assert.ok(text.includes('phase_signals'),
|
|
'/trekexecute must reference phase_signals (v5.1 composition rule)');
|
|
});
|
|
|
|
test('trekexecute — low-effort path references --gates open + sequential', () => {
|
|
const text = read();
|
|
const compIdx = text.indexOf('## Composition rule (v5.1)');
|
|
assert.ok(compIdx >= 0, 'Composition rule (v5.1) section missing');
|
|
const section = text.slice(compIdx, compIdx + 2000);
|
|
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)}`,
|
|
);
|
|
});
|
|
|
|
// --- S38 loop-discipline hardening: completion gate (Step 2) ---
|
|
|
|
test('trekexecute — machine-verifiable completion gate + stop-signal contract literals present (SC a)', () => {
|
|
const text = read();
|
|
assert.ok(text.includes('machine-verifiable completion gate'),
|
|
'completion-gate literal must be grep-able');
|
|
assert.ok(text.includes('stop-signal contract'),
|
|
'stop-signal contract literal must be grep-able');
|
|
});
|
|
|
|
test('trekexecute — completion gate anchors result:completed to Phase 7.5 audit + DONE-after-check (SC a)', () => {
|
|
const text = read();
|
|
const gateIdx = text.indexOf('machine-verifiable completion gate');
|
|
assert.ok(gateIdx >= 0, 'gate literal missing');
|
|
const section = text.slice(gateIdx, gateIdx + 1400);
|
|
assert.match(section, /Phase 7\.5/, 'gate must name Phase 7.5 as the objective predicate');
|
|
assert.match(section, /DONE/, 'gate must reference the DONE stop-signal token');
|
|
assert.match(section, /emitted AFTER/, 'gate must require DONE emitted AFTER the audit ran');
|
|
});
|
|
|
|
// --- S38 loop-discipline hardening: caps + global recovery budget (Step 3) ---
|
|
|
|
test('trekexecute — global recovery/retry budget TREKEXECUTE_MAX_RECOVERY_ITERATIONS default 25 (SC b)', () => {
|
|
const text = read();
|
|
assert.ok(text.includes('TREKEXECUTE_MAX_RECOVERY_ITERATIONS'),
|
|
'global recovery/retry budget constant must be documented');
|
|
assert.match(
|
|
text,
|
|
/TREKEXECUTE_MAX_RECOVERY_ITERATIONS[^\n]{0,40}\b25\b|default[^\n]{0,20}\b25\b[^\n]{0,40}aggregate/i,
|
|
'global budget must document numeric default 25 adjacent to the constant',
|
|
);
|
|
});
|
|
|
|
test('trekexecute — every recovery/retry loop bounded + 3-axis cap hierarchy (SC b)', () => {
|
|
const text = read();
|
|
assert.match(text, /maximum 2 retries|Retry cap = 3 attempts/, 'per-step retry cap must be explicit');
|
|
assert.match(text, /recovery_depth < 2/, 'recovery-dispatch cap must be explicit');
|
|
const capIdx = text.indexOf('Iteration caps');
|
|
assert.ok(capIdx >= 0, 'cap-hierarchy section ("Iteration caps") must exist');
|
|
const section = text.slice(capIdx, capIdx + 1500);
|
|
assert.match(section, /attempts/, 'hierarchy must name per-step attempts axis');
|
|
assert.match(section, /recovery_depth/, 'hierarchy must name per-session recovery_depth axis');
|
|
assert.match(section, /TREKEXECUTE_MAX_RECOVERY_ITERATIONS/, 'hierarchy must name the global budget axis');
|
|
});
|