Files
brain/tools/enforce-decomposition-detector.test.mjs
T

87 lines
3.8 KiB
JavaScript

// tools/enforce-decomposition-detector.test.mjs
// Stream H Task 5 (H6) — wrapper tests around the pure decomposition-detector module.
import { describe, it, expect } from 'vitest';
import { decide } from './enforce-decomposition-detector.mjs';
describe('enforce-decomposition-detector wrapper (Stream H Task 5)', () => {
it('allows when history is empty', () => {
const r = decide({
history: [],
currentEntry: { primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 1 },
llmVerdict: 'NO',
});
expect(r.action).toBe('allow');
});
it('allows when overlap below threshold (only 2 prompts share keywords)', () => {
const history = [
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 1 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 2 },
];
const r = decide({
history,
currentEntry: { primary_keywords: ['unrelated', 'topic', 'words'], skill_invoked_this_prompt: false, prompt_idx: 3 },
llmVerdict: 'YES',
});
expect(r.action).toBe('allow');
});
it('hard_block_mutating when 3+ overlap, no skill, LLM YES (v4.1)', () => {
const history = [
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 1 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 2 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 3 },
];
const r = decide({
history,
currentEntry: { primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 4 },
llmVerdict: 'YES',
});
expect(r.action).toBe('hard_block_mutating');
expect(r.reason).toMatch(/decomp/i);
});
it('soft_flag when threshold met but LLM verdict NO (legit-distinct)', () => {
const history = [
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 1 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 2 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 3 },
];
const r = decide({
history,
currentEntry: { primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 4 },
llmVerdict: 'NO',
});
expect(r.action).toBe('soft_flag');
});
it('allows when threshold met but a writing-plans skill was invoked', () => {
const history = [
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: true, prompt_idx: 1 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 2 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 3 },
];
const r = decide({
history,
currentEntry: { primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 4 },
llmVerdict: 'YES',
});
expect(r.action).toBe('allow');
});
it('degraded allow when LLM verdict is missing/null (fail-open on LLM layer)', () => {
const history = [
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 1 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 2 },
{ primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 3 },
];
const r = decide({
history,
currentEntry: { primary_keywords: ['feature', 'login', 'form'], skill_invoked_this_prompt: false, prompt_idx: 4 },
llmVerdict: null,
});
expect(r.action).toBe('soft_flag');
expect(r.degraded).toBe(true);
});
});