Files
brain/tools/plan-skills.test.mjs
T
Дмитрий bbc053e0a6 feat: D1 — благословлённый ops-runbook (деплой выполняет агент под ревью)
Деплой, помеченный **Kind:** deploy и опечатанный (наставник+судья GO,
judge_mode=live-block), агент выполняет по белому списку шагов под ОДНИМ
согласием владельца `FLOOR-ESCAPE: ops-runbook:<plan-hash>` — без аварийного
выхода на каждую команду. «Ядерный» набор (rm -rf/force-push/migrate:fresh/
db:wipe) остаётся на per-command escape.

- plan-lock: freezePlan принимает kind (в подписанную базу + хеш, как delivery);
  не-'normal' добавляет поле, обычные планы байт-идентичны старым печатям.
- plan-skills: parsePlanKind (**Kind:** deploy|normal, default normal).
- seal-orchestration: sealablePlan/sealPlan прокидывают kind в печать.
- escape-grant: loadOpsRunbookGrants (окно = существование плана, БЕЗ 5-мин
  фильтра) + opsRunbookGrantOpen (точный матч на plan_id).
- floor-decide: floorDecide получает инъектируемый blessedOps(cmd); content-block
  команда из набора пропускается, ЯДЕРНЫЙ набор (bashIsFloor) исключён из послабления.
- blessed-ops (новый модуль-мост): buildBlessedOps + loadBlessedOpsForSession —
  знает план+пол, чтобы СОХРАНИТЬ Δ9 (enforce-floor не зависит от модуля печати плана).
  Предикат пускает команду только дословно из Bash-листов опечатанного deploy-плана.
- enforce-floor: gated — blessed-ops грузит план/гранты ТОЛЬКО при открытом
  ops-runbook-гранте; без согласия владельца пол плана не касается (Δ9 цел).

План: docs/superpowers/plans/2026-06-18-blessed-ops-runbook-plan.md
Спека: docs/superpowers/specs/2026-06-18-blessed-ops-runbook-design.md §3.1-3.7.
+33 теста, свод 4299 passed / 2 skipped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:19:22 +03:00

57 lines
2.8 KiB
JavaScript

// tools/plan-skills.test.mjs
import { describe, it, expect } from 'vitest';
import { parsePlanSkills, extractPlanGoal, parsePlanDelivery, parsePlanKind } from './plan-skills.mjs';
describe('parsePlanKind (D1)', () => {
it('**Kind:** deploy → "deploy"', () => {
expect(parsePlanKind('# План\n**Kind:** deploy\n')).toBe('deploy');
});
it('нет пометки / мусор → "normal" (fail-safe)', () => {
expect(parsePlanKind('# План без пометки')).toBe('normal');
expect(parsePlanKind('**Kind:** wat')).toBe('normal');
});
});
describe('parsePlanDelivery', () => {
it('читает user-result из маркера', () => {
expect(parsePlanDelivery('текст\n**Delivery:** user-result\nещё')).toBe('user-result');
});
it('читает internal', () => {
expect(parsePlanDelivery('**Delivery:** internal')).toBe('internal');
});
it('по умолчанию internal (нет маркера)', () => {
expect(parsePlanDelivery('план без пометки')).toBe('internal');
});
it('мусорное значение → internal (fail-safe)', () => {
expect(parsePlanDelivery('**Delivery:** whatever')).toBe('internal');
});
});
describe('parsePlanSkills', () => {
const md = ['# План', '```skills-json', '["executing-plans","test-driven-development"]', '```', '## Цель', 'x'].join('\n');
it('достаёт список скилов из ```skills-json блока', () => {
expect(parsePlanSkills(md)).toEqual(['executing-plans', 'test-driven-development']);
});
it('нет блока → пустой массив', () => { expect(parsePlanSkills('# План\nтекст')).toEqual([]); });
it('битый JSON → пустой массив (fail-safe)', () => {
expect(parsePlanSkills('```skills-json\n[не json\n```')).toEqual([]);
});
it('не-массив / не-строки отфильтрованы', () => {
expect(parsePlanSkills('```skills-json\n["ok", 5, null, "two"]\n```')).toEqual(['ok', 'two']);
});
});
describe('extractPlanGoal (зеркало extractGoal судьи)', () => {
it('секция ## Цель → её текст до след. заголовка', () => {
const md = ['# План', '## Цель', 'починить парсер X', '', '## Шаги', 'шаг 1'].join('\n');
expect(extractPlanGoal(md)).toBe('починить парсер X');
});
it('секция ## Goal → её текст', () => {
expect(extractPlanGoal('## Goal\nfix the bug\n## Steps')).toBe('fix the bug');
});
it('нет секции цели → первый непустой не-заголовок абзац', () => {
expect(extractPlanGoal('# План\n\nделаем фичу\n')).toBe('делаем фичу');
});
it('пусто → пустая строка', () => { expect(extractPlanGoal('')).toBe(''); });
});