import { describe, it, expect } from 'vitest'; import { decide } from './enforce-criterion-gate.mjs'; import { signGreen } from './floor-signer.mjs'; const KEY = 'signer-key'; const FP = 'a'.repeat(64); const CID = 'c1'; const green = (occ = 1, fp = FP) => ({ ...signGreen({ criterion_id: CID, code_fingerprint: fp, occurrence: occ }, KEY), green: true }); const base = () => ({ toolName: 'Bash', command: 'git push origin main', gate: { active: true }, key: KEY, codeChanged: true, frozenPlanValid: true, criteria: [{ id: CID }], sealedCriterionIds: [CID], greenRuns: [green()], currentFingerprints: { [CID]: FP }, escapeOpen: false, changedPaths: ['tools/x.mjs'], }); describe('enforce-criterion-gate / decide', () => { it('не git commit/push → allow', () => { expect(decide({ ...base(), command: 'git status' }).block).toBe(false); }); it('docs-only → allow', () => { expect(decide({ ...base(), changedPaths: ['a.md'], codeChanged: false }).block).toBe(false); }); it('флаг OFF (inert) → allow $0', () => { expect(decide({ ...base(), gate: { active: false, keyMissing: false }, greenRuns: [] }).block).toBe(false); }); it('флаг ON но ключ пропал → fail-CLOSE block', () => { expect(decide({ ...base(), gate: { active: false, keyMissing: true } }).block).toBe(true); }); it('код меняется, но нет валидного запечатанного плана → block (SE-LB-5)', () => { expect(decide({ ...base(), frozenPlanValid: false }).block).toBe(true); }); it('все критерии доказаны (green+свежесть+подпись) → allow', () => { expect(decide(base()).block).toBe(false); }); it('критерий без green → block', () => { expect(decide({ ...base(), greenRuns: [] }).block).toBe(true); }); it('отпечаток устарел (код изменился после green) → block', () => { expect(decide({ ...base(), currentFingerprints: { [CID]: 'c'.repeat(64) } }).block).toBe(true); }); it('подпись битая → block', () => { const bad = { ...green(), sig: 'd'.repeat(64) }; expect(decide({ ...base(), greenRuns: [bad] }).block).toBe(true); }); it('критерий вне запечатанного набора → block', () => { expect(decide({ ...base(), sealedCriterionIds: [] }).block).toBe(true); }); it('escape владельца открыт → allow (M6)', () => { expect(decide({ ...base(), greenRuns: [], escapeOpen: true }).block).toBe(false); }); });