test(intent): M3–M7 — halt pinned where it acts, allowlist guarded, header claims pinned
M4: the halt regex matched any **halt** in a 2500-char window, so the PM's mutant (first **halt** → "continue anyway") survived. Two new tests pin the sentence right after the gate command and the could-not-run halt. Mutant run: old test ok, both new tests not ok. M5: nothing guarded 2045432's allowlist line. New test: trekbrief keeps intent_approved, drops task/project_dir. Mutant (line removed): not ok. M3 (red): the header claims a reflow keeps the approval; joining lines is STALE. Pins the honest wording + the STALE behaviour. M7 (red): the trekreview exemption is not documented as a bypass of the same trust class as self-stamping (header, HANDOVER-CONTRACTS, trekplan). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
20f32bb06b
commit
097bae8a02
2 changed files with 62 additions and 0 deletions
|
|
@ -440,3 +440,47 @@ test('M2: the gate names a remedy that works for --brief too (/trekbrief --appro
|
|||
} finally { rmSync(dir, { recursive: true, force: true }); }
|
||||
assert.match(read('docs/HANDOVER-CONTRACTS.md'), /--approve <project-dir \| brief-file>/);
|
||||
});
|
||||
|
||||
// ---- M4: the halt sentence is pinned where it acts, not anywhere in a 2500-char window ----
|
||||
// (PM mutant: the first "**halt**" → "continue anyway" survived the window regex above)
|
||||
|
||||
test('M4: the sentence right after the gate command halts on any non-zero exit', () => {
|
||||
const text = read('commands/trekplan.md');
|
||||
const gateIdx = text.indexOf(commandLine('commands/trekplan.md', '--check'));
|
||||
const fenceEnd = text.indexOf('```', gateIdx);
|
||||
const after = text.slice(fenceEnd + 3).replace(/^\s+/, '');
|
||||
assert.match(after,
|
||||
/^Exit 0 → continue\. Any other exit → \*\*halt\*\* — do not read further, spawn no\s+agent, write no plan\./,
|
||||
'the first sentence after the gate command must be the halt rule, verbatim');
|
||||
});
|
||||
|
||||
test('M4: a check that could not run halts too (never a pass)', () => {
|
||||
const text = read('commands/trekplan.md');
|
||||
const section = text.slice(text.indexOf('### Read the brief'), text.indexOf('Read the brief file and parse'));
|
||||
assert.match(section,
|
||||
/does not print the JSON report[\s\S]{0,120}\*\*halt\*\* as well[\s\S]{0,60}approval check that could not run is never a pass/);
|
||||
assert.doesNotMatch(section, /continue anyway/i);
|
||||
});
|
||||
|
||||
// ---- M3 + M7: the header says only what is true ----
|
||||
|
||||
test('M3: the header does not claim a reflow keeps the approval; joining lines is STALE (fails safe)', async () => {
|
||||
const src = readFileSync(MODULE, 'utf8');
|
||||
const header = src.slice(0, src.indexOf('\nimport '));
|
||||
assert.doesNotMatch(header, /Reflowing a paragraph keeps the approval/);
|
||||
assert.match(header, /joining or splitting lines[\s\S]{0,80}stale/i);
|
||||
const { stampIntentApproval, checkIntentApprovalContent } = await load();
|
||||
const stamped = stampIntentApproval(BRIEF, STAMP_AT).text;
|
||||
const joined = stamped.replace('glares.\nThey want', 'glares. They want');
|
||||
assert.deepEqual(checkIntentApprovalContent(joined).errors.map((e) => e.code), ['BRIEF_INTENT_APPROVAL_STALE']);
|
||||
});
|
||||
|
||||
test('M7: the trekreview exemption is documented as the same trust class as self-stamping', () => {
|
||||
const src = readFileSync(MODULE, 'utf8');
|
||||
const header = src.slice(0, src.indexOf('\nimport '));
|
||||
assert.match(header, /type: trekreview[\s\S]{0,400}same trust class as self-stamping/);
|
||||
assert.match(read('docs/HANDOVER-CONTRACTS.md'), /`trekreview` briefs are exempt[^.]*\.[^.]*same trust class as self-stamping/);
|
||||
const plan = read('commands/trekplan.md');
|
||||
const section = plan.slice(plan.indexOf('### Read the brief'), plan.indexOf('Read the brief file and parse'));
|
||||
assert.match(section, /same trust class as self-stamping/);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue