voyage/tests/lib/guards-prose-pins.test.mjs
Kjell Tore Guttormsen 32621dcb63
chore(cleanup): R-b R2 — STORM loop, cap hook and the --engine research choice removed
/trekresearch loses Phase 4.5, the bounded Phase 5 loop (Phase 5 keeps its
single pass of at most 2 follow-ups), the --engine flag, the deep-research
adapter and its output self-check. hooks.json loses the pre-agent-cap
PreToolUse entry (README: 9 hooks = 9 scripts). The STORM env vars leave the
docs; query-privacy-gate.mjs stays, called by no command, and says so.

Files removed: 13 (4 docs, 1 hook, 1 lib module, 1 script, 5 tests, 1 fixture).
Files edited: 17. Tests: 2600 (2598 pass / 0 fail / 2 skipped) before,
2467 (2466 pass / 0 fail / 1 skipped, R3 pending) after.
Durable check: group R2 green and no longer pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 20:32:38 +01:00

69 lines
3.3 KiB
JavaScript

// tests/lib/guards-prose-pins.test.mjs
// Prose pins owned by the guards process (wave-1 order 4).
//
// The mod precondition: a Claude Code mod that handles `tool.check` answers
// AFTER the rules and the PreToolUse hooks, and «its answer can replace
// theirs» — it can approve a call a plugin PreToolUse hook blocked
// (code.claude.com/docs/en/permissions § Extend permissions with hooks,
// verified verbatim 06.10). So Voyage's stop guards are deterministic only
// under a stated condition, and the condition is written where the guards are
// described: README § Security hardening, SECURITY.md, and the head of every
// PreToolUse stop guard.
import { test } from 'node:test';
import { strict as assert } from 'node:assert';
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
const read = (rel) => readFileSync(join(ROOT, rel), 'utf8');
export const MOD_PRECONDITION = "Voyage's guards are deterministic only when no installed mod handles `tool.check`.";
const STOP_GUARDS = [
'hooks/scripts/pre-bash-executor.mjs',
'hooks/scripts/pre-write-executor.mjs',
'hooks/scripts/pre-plan-gate.mjs',
];
test('mod precondition: README § Security hardening states it', () => {
const md = read('README.md');
const start = md.indexOf('### Security hardening');
assert.ok(start !== -1);
const end = md.indexOf('\n### ', start + 1);
assert.ok(md.slice(start, end).includes(MOD_PRECONDITION), 'README § Security hardening must state the mod precondition');
});
test('mod precondition: SECURITY.md states it', () => {
assert.ok(read('SECURITY.md').includes(MOD_PRECONDITION));
});
test('mod precondition: the head of every PreToolUse stop guard states it', () => {
for (const rel of STOP_GUARDS) {
const head = read(rel).split('\n').slice(0, 40).join('\n').replace(/^\/\/ ?/gm, '').replace(/\n/g, ' ');
assert.ok(head.replace(/\s+/g, ' ').includes(MOD_PRECONDITION), `${rel}: the first 40 lines must state the mod precondition`);
}
});
test('mod precondition: the guards cannot see a mod; the docs say so where it is stated', () => {
// Looked up 06.10: no hook input field names installed mods; the documented
// ways to see them are `/plugin` and a CLI subcommand, both for a person.
assert.match(read('SECURITY.md'), /cannot tell whether such a mod is installed/);
});
test('P12 guard: README names the classes it asks about and that it holds in auto mode', () => {
const md = read('README.md');
const sec = md.slice(md.indexOf('### Security hardening'), md.indexOf('#### Recommended: disable Skill shell execution'));
for (const w of ['merge into `main`', 'push', 'tag', 'destructive git', 'auto mode']) {
assert.ok(sec.includes(w), `README § Security hardening must mention ${w}`);
}
});
test('borrowings are credited where the guards are described (PLAN fixed limit 3)', () => {
const md = read('README.md');
const sec = md.slice(md.indexOf('### Security hardening'), md.indexOf('#### Recommended: disable Skill shell execution'));
for (const src of ['Superpowers', 'agent-skills', 'ai-native-sdlc', 'Pocock', 'Kiro', 'Cherny', 'Claude Code']) {
assert.ok(sec.includes(src), `credit missing for ${src}`);
}
});