diff --git a/tools/judge-gate-floor.test.mjs b/tools/judge-gate-floor.test.mjs index 4614ff3e..4f3b1053 100644 --- a/tools/judge-gate-floor.test.mjs +++ b/tools/judge-gate-floor.test.mjs @@ -244,3 +244,34 @@ describe('greenSignaturesValid (5.4, Δ5): green засчитан только expect(greenSignaturesValid({ greenRuns: [run], key: undefined }).ok).toBe(false); }); }); + +import { extractSkillCalls as extractSkillCalls4b } from './enforce-skill-journaler.mjs'; + +// М7 Фаза 4b §5 coverage-map: decomposition (скрытое дробление) ловит Гейт-1 existenceCheck +// через ЖУРНАЛ (обещанные навыки ← extractSkillCalls), не текст. Proof покрытия ДО retire +// no-op enforce-decomposition-detector (Ф8); live-wiring «обещанные ← журнал» в judge-gate — Ф7. +describe('existenceCheck как decomposition look-ahead через журнал (М7 Фаза 4b §4.2)', () => { + const journal = [ + { payload: { op: 'Skill', object: 'superpowers:test-driven-development' } }, + { payload: { op: 'Edit', object: 'foo.mjs' } }, + ]; + it('promised planning skill НЕ вызван (по журналу) → existenceCheck ловит (missingSkills непуст)', () => { + const invoked = extractSkillCalls4b(journal); + const r = existenceCheck({ + questions: [{ id: 'q1', answered: true }], + skillsPromised: ['superpowers:writing-plans'], + skillsInvoked: invoked, + }); + expect(r.ok).toBe(false); + expect(r.missingSkills).toContain('superpowers:writing-plans'); + }); + it('promised skill вызван (в журнале) → existenceCheck ok', () => { + const invoked = extractSkillCalls4b(journal); + const r = existenceCheck({ + questions: [{ id: 'q1', answered: true }], + skillsPromised: ['superpowers:test-driven-development'], + skillsInvoked: invoked, + }); + expect(r.ok).toBe(true); + }); +});