Files
brain/tools/enforce-coverage-verify.test.mjs

96 lines
3.2 KiB
JavaScript

import { describe, it, expect } from 'vitest';
import { decide } from './enforce-coverage-verify.mjs';
const TDD = 'superpowers:test-driven-development';
describe('enforce-coverage-verify / decide (журнал-факт K2)', () => {
it('allows turn with no mutating tools (pure conversational)', () => {
const r = decide({ toolUses: [{ name: 'Read', input: {} }], assistantText: 'just talking', journalSkillCalls: [] });
expect(r.block).toBe(false);
});
it('blocks mutating turn with no coverage line', () => {
const r = decide({
toolUses: [{ name: 'Edit', input: { file_path: 'foo.mjs' } }],
assistantText: 'just did some work',
journalSkillCalls: [],
});
expect(r.block).toBe(true);
expect(r.message).toMatch(/coverage/);
});
it('blocks skill:X when Skill tool_use present this turn but X NOT in journal (acceptance)', () => {
const r = decide({
toolUses: [
{ name: 'Skill', input: { skill: TDD } },
{ name: 'Edit', input: { file_path: 'foo.mjs' } },
],
assistantText: `coverage: skill:${TDD}\nок`,
journalSkillCalls: [],
});
expect(r.block).toBe(true);
expect(r.message).toMatch(/журнал/i);
});
it('blocks skill:X when X in journal but NOT in this turn tool_use (turn-scoping, no false-pass)', () => {
const r = decide({
toolUses: [{ name: 'Edit', input: { file_path: 'foo.mjs' } }],
assistantText: `coverage: skill:${TDD}`,
journalSkillCalls: [TDD],
});
expect(r.block).toBe(true);
});
it('allows skill:X when X in BOTH this-turn tool_use AND journal', () => {
const r = decide({
toolUses: [
{ name: 'Skill', input: { skill: TDD } },
{ name: 'Edit', input: { file_path: 'foo.mjs' } },
],
assistantText: `coverage: skill:${TDD}\nок`,
journalSkillCalls: [TDD],
});
expect(r.block).toBe(false);
});
it('matches skill name across superpowers: prefix (tool input bare, coverage prefixed, journal prefixed)', () => {
const r = decide({
toolUses: [
{ name: 'Skill', input: { skill: 'test-driven-development' } },
{ name: 'Edit', input: { file_path: 'foo.mjs' } },
],
assistantText: `coverage: skill:${TDD}`,
journalSkillCalls: [TDD],
});
expect(r.block).toBe(false);
});
it('allows direct coverage (journal cannot verify non-skill channels — §4.2)', () => {
const r = decide({
toolUses: [{ name: 'Edit', input: { file_path: 'memory/foo.md' } }],
assistantText: 'coverage: direct:memory-sync',
journalSkillCalls: [],
});
expect(r.block).toBe(false);
});
it('allows node coverage', () => {
const r = decide({
toolUses: [{ name: 'Edit', input: { file_path: 'foo.vue' } }],
assistantText: 'coverage: node:#19',
journalSkillCalls: [],
});
expect(r.block).toBe(false);
});
it('override phrase does NOT bypass (§12 escape≠override — vocab removed)', () => {
const r = decide({
toolUses: [{ name: 'Edit', input: { file_path: 'foo.mjs' } }],
assistantText: 'no coverage',
journalSkillCalls: [],
override: { phrase: 'без скилов' },
});
expect(r.block).toBe(true);
});
});