docs(spec): /regression — amend §10, add run.test.mjs (writing-plans)

Spec §10 claimed run.mjs needs no unit harness, on the false premise that tools/*.mjs have no tests. In fact all 3 tools/*.mjs have a co-located .test.mjs (node:test). Amended §2/§3/§4/§10 + header note: run.mjs is split into exported pure functions (parsers, verdict, canonical-line, platform fork) + orchestrator, with a co-located run.test.mjs (node:test, ruflo-queen-hook.test.mjs pattern) — pure functions unit-tested, main subprocess-tested.

Aligns the spec with the economy-0% TDD mandate and the project tools/*.mjs convention before writing the implementation plan.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-05-16 07:25:10 +03:00
parent f0e347e76a
commit c327840407
@@ -3,9 +3,10 @@
**Дата:** 2026-05-16
**Статус:** дизайн одобрен заказчиком (через `superpowers:brainstorming`, Q1–Q4 + полное согласование дизайна)
**Экономия:** 0% (максимальное качество, без скипов)
**Связанные артефакты:** `.claude/skills/regression/SKILL.md` (создаётся), `.claude/skills/regression/run.mjs` (создаётся), `.claude/skills/q-item-add/SKILL.md` (образец), `.claude/skills/rls-check/SKILL.md` (образец), `package.json`, `app/package.json`, `app/composer.json`, `lefthook.yml`
**Связанные артефакты:** `.claude/skills/regression/SKILL.md` (создаётся), `.claude/skills/regression/run.mjs` (создаётся), `.claude/skills/regression/run.test.mjs` (создаётся), `.claude/skills/q-item-add/SKILL.md` (образец), `.claude/skills/rls-check/SKILL.md` (образец), `tools/ruflo-queen-hook.test.mjs` (образец теста), `package.json`, `app/package.json`, `app/composer.json`, `lefthook.yml`
**Источник:** рекомендация №1 из `/claude-code-setup:claude-automation-recommender` (16.05.2026)
**Следующий шаг:** `superpowers:writing-plans` → план реализации.
**Правка 1 (2026-05-16, при `writing-plans`):** §2/§3/§4/§10 — добавлен co-located `run.test.mjs` (`node:test`). Прежняя формулировка §10 (об отсутствии отдельных unit-тестов для `run.mjs`) опиралась на ложную предпосылку («`tools/*.mjs` тестов не имеют»); фактически все 3 `tools/*.mjs` имеют co-located `.test.mjs`. Скорректировано под economy-0% TDD-мандат + конвенцию проекта.
---
@@ -39,7 +40,8 @@
- bundled-скрипт-оркестратор на Node ESM;
- каноническая строка + per-check таблица + вердикт GREEN/RED;
- правила инвокации (Both с self-restraint);
- caveats по проектным квиркам (Pest `--parallel` flake, ruflo daemon).
- caveats по проектным квиркам (Pest `--parallel` flake, ruflo daemon);
- co-located `run.test.mjs` (`node:test`) — unit-тесты pure-функций `run.mjs` + subprocess-тест `main`.
**Не-цели (сознательно вне scope v1):**
@@ -63,6 +65,7 @@
| U1 | Дефолт без аргумента | `/regression``/regression full` | Headline use-case — свод перед закрытием. |
| U2 | Состав `quick` | `quick` НЕ включает Larastan | Чистая граница «линт/формат/тип» vs «статанализ/прогон»; Larastan уже в `lefthook` pre-commit. |
| U3 | Язык скрипта | Node `.mjs` | House-style проекта: `tools/ruflo-*.mjs`, `app/scripts/dev-indices-lookup.mjs`, `node -e` в хуках `.claude/settings.json`; кросс-платформенно для Linux/Mac CI. |
| P1 | Тестирование `run.mjs` | Co-located `run.test.mjs` (`node:test`): unit-тесты pure-функций + subprocess-тест `main` | Правка 1 — economy-0% TDD-мандат + конвенция проекта (все `tools/*.mjs` имеют `.test.mjs`, паттерн `tools/ruflo-queen-hook.test.mjs`). |
## 4. Компоненты
@@ -71,7 +74,8 @@
| Файл | Назначение |
|---|---|
| `.claude/skills/regression/SKILL.md` | frontmatter (`name`, `description`, инвокация) + «Когда использовать» + «Workflow» + «Правила инвокации (self-restraint)» + «Caveats» + «Не использовать когда». Структура повторяет `q-item-add`/`rls-check`. |
| `.claude/skills/regression/run.mjs` | Оркестратор. Аргумент `quick` \| `full` (дефолт `full`). Чистый Node ESM — только `node:child_process`, `node:process`, `node:path`; без npm-зависимостей. |
| `.claude/skills/regression/run.mjs` | Оркестратор. Аргумент `quick` \| `full` (дефолт `full`). Чистый Node ESM — только `node:child_process`, `node:process`, `node:path`; без npm-зависимостей. Экспортирует pure-функции (`parse`-функции проверок, логика вердикта, сборка канонической строки, платформенная развилка) для unit-тестирования. |
| `.claude/skills/regression/run.test.mjs` | Co-located тесты (`node:test` + `node:assert/strict`), паттерн `tools/ruflo-queen-hook.test.mjs`: unit-тесты экспортированных pure-функций + subprocess-тесты `main` через `execFileSync`. |
`SKILL.md` frontmatter (Both с self-restraint — `disable-model-invocation` НЕ ставится, в отличие от `q-item-add`/`rls-check`):
@@ -199,14 +203,29 @@ Frontmatter разрешает инвокацию и Claude, и пользова
## 10. Тестирование скилла
Дисциплина `superpowers:writing-skills` — верифицировать скилл до объявления «готово»:
Проект тестирует `tools/*.mjs` co-located файлами `<name>.test.mjs` на встроенном `node:test` (паттерн `tools/ruflo-queen-hook.test.mjs`: unit-тесты экспортированных pure-функций + subprocess-тест `main` через `execFileSync`). `run.mjs` следует той же конвенции — TDD по `superpowers:test-driven-development`.
1. **Happy path.** Прогон `/regression quick` и `/regression full` на чистом дереве — убедиться, что печатается каноническая строка и вердикт GREEN, exit-код 0.
2. **RED path.** Временно внести lint-ошибку (напр. в `.ts`-файл) → `/regression quick` обязан дать RED, exit 1, перечислить ESLint; откатить лом.
3. **RED-INCOMPLETE path.** Временно сделать недоступным один бинарь (напр. переименовать `bin\gitleaks.exe`) → `full` обязан дать `[⚠] SKIPPED` + вердикт RED-INCOMPLETE; вернуть бинарь.
4. **Парсеры.** Сверить count-токены канонической строки с реальным выводом каждой команды (Pest/Vitest/gitleaks/lychee/Vite build) — числа должны совпадать с тем, что печатают сами инструменты.
**`run.mjs` структурируется на два слоя:**
Отдельного unit-харнесса для `run.mjs` нет — сознательное решение, согласованное с тем, что существующие `tools/*.mjs` проекта unit-тестов не имеют. Верификация — функциональная, по пунктам 1–4 выше.
- **Pure-функции** (экспортируются, детерминированы, без I/O): `parse`-функция каждой проверки (вывод инструмента → count-токен), логика вердикта (массив результатов → GREEN/RED/RED-INCOMPLETE + exit-код), сборка канонической строки, платформенная развилка бинаря (`win32``bin\*.exe`).
- **Orchestrator** (`main`): парсинг аргумента, последовательный запуск проверок через `child_process`, печать таблицы/строки/вердикта.
**`run.test.mjs`** (co-located, `node:test` + `node:assert/strict`):
- unit-тест каждой `parse`-функции — на реальных фрагментах вывода Pest / Vitest / gitleaks / lychee / Vite build / Larastan (фикстуры-строки в тесте);
- unit-тест логики вердикта — GREEN (все exit 0), RED (≥1 ненулевой), RED-INCOMPLETE (≥1 SKIPPED) + сверка возвращаемого exit-кода;
- unit-тест сборки канонической строки (порядок токенов, число токенов = числу проверок уровня) и платформенной развилки бинаря;
- subprocess-тесты `main` через `execFileSync`: неизвестный аргумент → ошибка + ненулевой exit; `run.mjs quick` стартует и печатает заголовок уровня.
Прогон: `node --test .claude/skills/regression/run.test.mjs` (Node ≥20, нулевые зависимости).
**Дополнительная функциональная верификация** (внешние инструменты — вне unit-покрытия):
1. **Happy path.** `/regression quick` и `/regression full` на чистом дереве → каноническая строка + вердикт GREEN, exit 0.
2. **RED path.** Временный lint-лом в `.ts``/regression quick` даёт RED, exit 1, перечисляет ESLint; откатить лом.
3. **RED-INCOMPLETE path.** Временно недоступный бинарь (переименовать `bin\gitleaks.exe`) → `full` даёт `[⚠] SKIPPED` + RED-INCOMPLETE; вернуть бинарь.
Дисциплина `superpowers:writing-skills` — верификация скилла (unit `run.test.mjs` + функциональная 1–3) до объявления «готово».
## 11. Отклонённые альтернативы