9ec5e1ee58
buildForgottenSkillCard формирует внятную карточку «ПЛАН ЗАБЫЛ вызвать навык(и) из skills-json: X → вызови Skill X» вместо общей прозы. decide() возвращает список uncalled; main() отдаёт карточку в exit-2. callCovers/нормализация/fail-CLOSE — без изменений. Хвост спеки роутера §6 (контроллеру — имя забытого навыка), эпик роутер-реестр этап 3, item 4. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
2.5 KiB
JavaScript
57 lines
2.5 KiB
JavaScript
import { describe, it, expect } from 'vitest';
|
|
import { decide, buildForgottenSkillCard } from './enforce-domain-skill-discipline.mjs';
|
|
|
|
describe('судья дисциплины: объявленный навык должен быть вызван', () => {
|
|
it('объявлен, не вызван → блок с перечнем', () => {
|
|
const r = decide({ frozenPlan: { skills: ['claude-md-management'] }, journalSkillCalls: [] });
|
|
expect(r.block).toBe(true);
|
|
expect(r.reason).toMatch(/claude-md-management/);
|
|
});
|
|
|
|
it('объявлен и вызван (плагин-префикс) → allow', () => {
|
|
const r = decide({ frozenPlan: { skills: ['claude-md-management'] }, journalSkillCalls: ['claude-md-management:revise-claude-md'] });
|
|
expect(r.block).toBe(false);
|
|
});
|
|
|
|
it('объявлен и вызван (совпадение суффиксов) → allow', () => {
|
|
const r = decide({ frozenPlan: { skills: ['test-driven-development'] }, journalSkillCalls: ['superpowers:test-driven-development'] });
|
|
expect(r.block).toBe(false);
|
|
});
|
|
|
|
it('пустой skills → allow', () => {
|
|
expect(decide({ frozenPlan: { skills: [] }, journalSkillCalls: [] }).block).toBe(false);
|
|
});
|
|
|
|
it('нет печати → allow', () => {
|
|
expect(decide({ frozenPlan: null, journalSkillCalls: [] }).block).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('exit-2 карточка забытого навыка (item 4)', () => {
|
|
it('одно имя → содержит имя и директиву вызвать', () => {
|
|
const m = buildForgottenSkillCard(['frontend-design']);
|
|
expect(m).toMatch(/frontend-design/);
|
|
expect(m).toMatch(/вызови/i);
|
|
});
|
|
|
|
it('несколько имён → все имена в карточке', () => {
|
|
const m = buildForgottenSkillCard(['alpha', 'beta']);
|
|
expect(m).toMatch(/alpha/);
|
|
expect(m).toMatch(/beta/);
|
|
});
|
|
|
|
it('пустой список → пустая строка', () => {
|
|
expect(buildForgottenSkillCard([])).toBe('');
|
|
});
|
|
|
|
it('decide возвращает uncalled при незваном навыке', () => {
|
|
const r = decide({ frozenPlan: { skills: ['frontend-design'] }, journalSkillCalls: [] });
|
|
expect(r.uncalled).toEqual(['frontend-design']);
|
|
});
|
|
|
|
it('decide: вызванный навык не попадает в uncalled', () => {
|
|
const r = decide({ frozenPlan: { skills: ['test-driven-development'] }, journalSkillCalls: ['superpowers:test-driven-development'] });
|
|
expect(r.uncalled).toEqual([]);
|
|
});
|
|
});
|