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>
28 KiB
Скилл /regression — канонический регрессионный свод — Design Spec
Дата: 2026-05-16
Статус: дизайн одобрен заказчиком (через superpowers:brainstorming, Q1–Q4 + полное согласование дизайна)
Экономия: 0% (максимальное качество, без скипов)
Связанные артефакты: .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-мандат + конвенцию проекта.
1. Контекст и проблема
Перед каждым закрытием задачи/спринта проект «Лидерра» прогоняет один и тот же регрессионный свод и записывает его результат в CLAUDE.md канонической строкой вида Pest 742/739/3sk/0 / Vitest 92f/774/3sk/0 / Vite build 2.03s / gitleaks 0/442 / lychee 325/0. Эта строка повторяется в CLAUDE.md и memory десятки раз (v1.86–v2.1, audit-записи, sprint-closure-записи).
Сами команды свода разбросаны по четырём файлам и двум рабочим директориям:
- корневой
package.json—lint:md,spell,links,a11y,sast; app/package.json—lint:vue,format:check,type-check,test:vue,build;app/composer.json—test,pint:test,test:parallel,stan;lefthook.yml— gitleaks (staged + full-history), lychee.
Следствия отсутствия единого входа:
- Ручная оркестрация — Claude/человек запускает ~12 команд вручную, по одной, помня про смену
cwd(app/vs корень). - Недетерминированность отчёта — итоговая каноническая строка собирается «на глаз»; формат и полнота зависят от исполнителя; возможен пропуск проверки.
- Нет жёсткого вердикта — «зелёно ли» определяется чтением вывода, а не машинно.
- Дублирование в
verification-before-completion— дисциплина «проверь перед claimготово» каждый раз заново перечисляет тот же свод.
Скилл /regression устраняет всё перечисленное: один вызов запускает свод, печатает каноническую строку детерминированно и даёт машинный вердикт GREEN/RED.
2. Цель и границы
Цель. Упаковать регрессионный свод в один скилл Claude Code с двумя уровнями объёма, детерминированным bundled-оркестратором и exit-code-вердиктом.
В scope v1:
- два уровня —
quick(линт/формат/тип) иfull(весь свод с прогоном тестов); - bundled-скрипт-оркестратор на Node ESM;
- каноническая строка + per-check таблица + вердикт GREEN/RED;
- правила инвокации (Both с self-restraint);
- caveats по проектным квиркам (Pest
--parallelflake, ruflo daemon); - co-located
run.test.mjs(node:test) — unit-тесты pure-функцийrun.mjs+ subprocess-тестmain.
Не-цели (сознательно вне scope v1):
- сравнение с хранимым baseline и авто-флаг регрессий по числам (отклонено в Q4 — дрейф baseline, ручной ре-синк);
- автоматическая правка
CLAUDE.mdканонической строкой (нарушило быCLAUDE.md§5 п.10 — каналclaude-md-management); - параллельный запуск проверок (возможная поздняя оптимизация, YAGNI для v1);
- Pa11y / Semgrep SAST / knip / infection (CI-tier или слишком медленные — см. §5);
- интеграция в CI (скрипт пригоден к вызову из CI, но workflow-файлы — вне scope);
- формализация скилла в
Tooling_v8_3.mdПрил. Н (возможный follow-up — см. §13).
3. Архитектурные решения
Четыре развилки согласованы заказчиком через AskUserQuestion (Q1–Q4); три детали приняты Claude единолично и одобрены при согласовании дизайна.
| # | Развилка | Решение | Обоснование |
|---|---|---|---|
| Q1 | Объём | Два уровня: quick + full |
quick — быстрый фидбэк по ходу работы; full — полный свод перед закрытием. Соответствует реальному workflow. |
| Q2 | Реализация | Bundled-скрипт-оркестратор | Детерминизм канонической строки и полнота прогона — ядро ценности скилла; instruction-only их не гарантирует. |
| Q3 | Инвокация | Both с self-restraint | Синергия с verification-before-completion (Claude авто-quick) + контроль дорогого full-прогона. |
| Q4 | Вердикт | Run + report + exit-code, без baseline | Exit-коды уже отвечают на «зелёно?»; хранимый baseline дрейфует и требует ручного ре-синка. YAGNI. |
| 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. Компоненты
Скилл — самодостаточный каталог .claude/skills/regression/ рядом с существующими q-item-add и rls-check.
| Файл | Назначение |
|---|---|
.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-зависимостей. Экспортирует 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):
---
name: regression
description: |
Run the project regression sweep and report a canonical status line + GREEN/RED verdict.
Two tiers: `quick` (lint/format/type-check — seconds) and `full` (everything incl.
Pest --parallel, Larastan, Vitest, Vite build, lychee, gitleaks — minutes).
Claude auto-runs only `quick` (e.g. during verification-before-completion);
`full` runs only on explicit `/regression full` or with user confirmation.
---
description — на английском (конвенция frontmatter скиллов Claude Code; тело SKILL.md — на русском по Pravila §3.6). Self-restraint выражен в description и подробно — в теле «Правила инвокации».
5. Матрица проверок
quick — строгое подмножество full. full опирается на существующие npm/composer-скрипты; прямой вызов бинаря — только у gitleaks и lychee (их npm-скрипт links хардкодит bin\lychee.exe, что ломается на POSIX, поэтому оркестратор вызывает оба бинаря сам с платформенной развилкой).
| # | Проверка | quick | full | cwd | команда |
|---|---|---|---|---|---|
| 1 | Pint (PHP style) | ✅ | ✅ | app/ |
composer pint:test |
| 2 | ESLint | ✅ | ✅ | app/ |
npm run lint:vue |
| 3 | Prettier --check |
✅ | ✅ | app/ |
npm run format:check |
| 4 | vue-tsc (type-check) | ✅ | ✅ | app/ |
npm run type-check |
| 5 | markdownlint | ✅ | ✅ | корень | npm run lint:md |
| 6 | cspell | ✅ | ✅ | корень | npm run spell |
| 7 | Larastan | — | ✅ | app/ |
composer stan |
| 8 | Pest --parallel |
— | ✅ | app/ |
composer test:parallel |
| 9 | Vitest | — | ✅ | app/ |
npm run test:vue |
| 10 | Vite build | — | ✅ | app/ |
npm run build |
| 11 | lychee (links) | — | ✅ | корень | win32: bin\lychee.exe --config .lychee.toml "docs/**/*.md" "db/**/*.md" "*.md"; POSIX: lychee + те же аргументы |
| 12 | gitleaks | — | ✅ | корень | win32: bin\gitleaks.exe detect --source . --no-banner --config .gitleaks.toml --redact; POSIX: gitleaks + те же аргументы |
Итого: quick — 6 проверок, full — 12.
Сознательно исключены (заказчик может попросить добавить):
- Pa11y — CI-only, требует Chromium;
CLAUDE.md§5 п.3 иlefthook.ymlявно держат его только в CI. - Semgrep SAST (
npm run sast) — CI-tier; не входит в каноническую строку. - knip (dead-code) — не входит в каноническую строку; разовый P3-инструмент.
- infection (мутационное тестирование) — слишком медленно для регрессионного свода.
6. Модель исполнения
- Запускать ВСЕ проверки уровня; не останавливаться на первом провале. Оркестратор прогоняет каждую проверку до конца и агрегирует результаты — нужна полная картина, а не первый failure.
- Последовательно в v1. Pest
--parallelуже сатурирует ядра; параллельный Vitest рядом дал бы CPU-трешинг и contention тестовых БД. Порядок: сначала быстрые (1–6), затем тяжёлые (7–12) — ранний фидбэк по дешёвым проверкам. - Для каждой проверки оркестратор фиксирует:
id, exit-код, wall-time, и распарсенный count-токен для канонической строки. - Платформенная развилка:
process.platform === 'win32'→bin\*.exeдля gitleaks/lychee, иначе бинарь наPATH(CLAUDE.md§4 — на Linux/Mac CI gitleaks/lychee ставятся через brew/apt). - Смена
cwd— оркестратор резолвит корень репозитория от расположенияrun.mjs(../../..от.claude/skills/regression/) и запускает app-проверки в<root>/app.
Структура данных проверки (концептуально, детали — в плане реализации):
{ id: 'pest', label: 'Pest', tiers: ['full'], cwd: 'app',
cmd: ['composer', 'test:parallel'],
parse: (stdout, stderr, code) => 'Pest 742/739/3sk/0' }
Каждая проверка несёт собственный parse — мелкую функцию, извлекающую count-токен из вывода. Токены проверок 1–6 (линт/формат/тип) сводятся к exit-коду (Pint 0, vue-tsc 0); проверки 7–12 несут содержательный count (Larastan 2, Pest 742/739/3sk/0, Vite build 2.0s, lychee 325/0, gitleaks 0/442 — см. §7).
7. Формат вывода
Оркестратор печатает в stdout три блока: заголовок + per-check таблица, каноническая строка, вердикт.
─ /regression full ──────────────────────────
[✅] Pint 0 1.8s
[✅] ESLint 0 3.1s
[✅] Prettier 0 1.9s
[✅] vue-tsc 0 3.4s
[✅] markdownlint 0 2.0s
[✅] cspell 0 3.2s
[❌] Larastan 1 8.4s
[✅] Pest 0 71.2s
[✅] Vitest 0 12.6s
[✅] Vite build 0 2.0s
[✅] lychee 0 9.1s
[✅] gitleaks 0 4.3s
──────────────────────────────────────────────
Canonical: Pest 742/739/3sk/0 / Vitest 92f/774/3sk/0 / Vite build 2.0s / Larastan 2 /
vue-tsc 0 / ESLint 0 / Prettier 0 / Pint 0 / markdownlint 0 / cspell 0 /
lychee 325/0 / gitleaks 0/442
VERDICT: 🔴 RED — 1/12 failed: Larastan (см. вывод выше)
Каноническая строка содержит токен каждой проверки прогнанного уровня (full — 12 токенов, quick — 6) — это обеспечивает прозрачность «все проверки прогнаны». Формат count-токенов (по образцам из CLAUDE.md):
- Pest —
Pest <total>/<passed>/<skipped>sk/<failed>(напр.742/739/3sk/0). - Vitest —
Vitest <files>f/<passed>/<skipped>sk/<failed>(напр.92f/774/3sk/0). - Vite build —
Vite build <время>s. - gitleaks —
gitleaks <leaks>/<commits-scanned>. - lychee —
lychee <OK>/<errors>. - Larastan —
Larastan <число ошибок>(напр.Larastan 2). - Pint / ESLint / Prettier / vue-tsc / markdownlint / cspell —
<tool> <exit-код>(напр.Pint 0); для линт/формат/тип exit-код0= чисто.
Вердикт:
- 🟢 GREEN — все проверки уровня завершились exit 0; оркестратор выходит с кодом
0. - 🔴 RED — ≥1 проверка с ненулевым exit; оркестратор выходит с кодом
1; в строке вердикта перечислены все упавшие проверки. - 🟠 RED-INCOMPLETE — ≥1 проверка не прогналась (отсутствует бинарь — см. §8); exit-код
1; свод нельзя признать зелёным.
Полный вывод каждой упавшей проверки оркестратор не подавляет — печатает её stdout/stderr выше таблицы, чтобы failure'ы были видны с file:line.
8. Обработка ошибок и caveats
Отсутствие бинаря. Если composer/php/npm/bin\gitleaks.exe/bin\lychee.exe не найдены — проверка помечается [⚠] <check> SKIPPED — binary not found, не считается провалом, но общий вердикт деградирует до RED-INCOMPLETE: свод неполон, зелёным признать нельзя (economy-0% — «не верифицировал X» фиксируется явно).
Pest --parallel flake (квирки 72/73/77). Известный intermittent-flake: Redis supplier:session race в subdir-only прогонах, cumulative state в долгих сессиях, unique-key collision в bulk-action тестах. SKILL.md несёт caveat: если Pest показал 1–3 ошибки, похожие на эти паттерны, — перепрогнать composer test:parallel один раз ИЛИ свериться с агентом pest-parallel-debugger до объявления реального RED. Оркестратор сам ретраи не делает (v1) — он лишь честно репортит exit-код; интерпретация flake — на человеке/Claude по caveat.
ruflo daemon (квирк 93). ruflo daemon worker-jitter усиливает частоту Pest-flake. SKILL.md несёт caveat: перед baseline-критичным full-прогоном рассмотреть pm2 stop ruflo-daemon (ruflo не трогает Redis, лишь timing-amplifier).
Падение самого оркестратора. Непойманное исключение в run.mjs → ненулевой exit + сообщение об ошибке; не выдавать за вердикт регрессии.
9. Инвокация и self-restraint
Frontmatter разрешает инвокацию и Claude, и пользователю (Both — Q3). Тело SKILL.md, раздел «Правила инвокации», фиксирует self-restraint:
- Claude авто-запускает только
quick— в частности, в рамкахsuperpowers:verification-before-completionперед claim «готово»/«passed»/«closed». Для этого Claude вызывает/regression quick(илиrun.mjs quick). fullClaude сам не запускает — только по явному/regression fullот пользователя ИЛИ запросив подтверждение («запускаю полный свод, ~5–10 мин — ок?»).- Дефолт без аргумента —
/regression≡/regression full(U1). - Self-restraint — поведенческое правило в теле
SKILL.md, не frontmatter-флаг (frontmatter не умеет различать аргументы); опирается на skill-дисциплину проекта.
10. Тестирование скилла
Проект тестирует 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.
run.mjs структурируется на два слоя:
- 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-покрытия):
- Happy path.
/regression quickи/regression fullна чистом дереве → каноническая строка + вердикт GREEN, exit 0. - RED path. Временный lint-лом в
.ts→/regression quickдаёт RED, exit 1, перечисляет ESLint; откатить лом. - RED-INCOMPLETE path. Временно недоступный бинарь (переименовать
bin\gitleaks.exe) →fullдаёт[⚠] SKIPPED+ RED-INCOMPLETE; вернуть бинарь.
Дисциплина superpowers:writing-skills — верификация скилла (unit run.test.mjs + функциональная 1–3) до объявления «готово».
11. Отклонённые альтернативы
| Альтернатива | Почему отклонена |
|---|---|
Instruction-only SKILL.md (как q-item-add/rls-check) |
Q2 — нет детерминизма канонической строки и гарантии полноты прогона; Claude может пропустить проверку или собрать строку в разном формате. |
baseline.json со сравнением чисел |
Q4 — baseline дрейфует при каждом закрытии, требует ручного /regression baseline ре-синка; exit-code-вердикт уже отвечает на «зелёно?». |
Per-domain split (/regression backend/frontend/docs) |
Q1 — нет единой «всё сразу» канонической строки без трёх отдельных вызовов. |
| Один полный прогон без уровней | Q1 — 5–10 мин на каждый вызов; нет быстрого режима для фидбэка по ходу работы. |
PowerShell .ps1 |
U3 — проект стандартизировал tool-скрипты на Node ESM; .ps1 не кросс-платформенный для Linux/Mac CI. |
| Параллельный запуск всех проверок | CPU-трешинг (Pest --parallel уже сатурирует ядра) + contention тестовых БД; YAGNI для v1. |
12. Нормативное соответствие
- Создание скилла. Реализация — терминал
superpowers:writing-skills(Pravila§12.2 «Создание / правка пользовательских skills»). Текущий поток:brainstorming→writing-plans→ реализация подwriting-skills. CLAUDE.md§5 п.10. Скилл не правитCLAUDE.md. Он только печатает каноническую строку в stdout; вставка строки вCLAUDE.md— отдельное действие через каналclaude-md-management.- Нормативный sync не требуется.
.claude/skills/regression/— не нормативный документ; создание скилла не требует правокPravila/CLAUDE.md/Tooling/PSR_v1. (Опциональный follow-up — см. §13.) - Schema / Q-items. Скилл не трогает
db/schema.sqlи не закрывает открытые вопросы реестра. - §14 ruflo Queen. Триггер
queen/королевав задаче отсутствовал; §14 не активирован. Задача (одинSKILL.md+ один скрипт) — не эпик; проактивное ruflo-предложение §14.3 неприменимо. - ПДн (
Pravila§5). Скилл запускает только проверки; gitleaks в своде сам ловит секреты. Скрипт не логирует и не персистит вывод проверок никуда, кроме stdout.
13. Follow-ups (вне scope v1)
- Tooling Прил. Н. Опционально — упомянуть
/regressionв реестре инструментовTooling_v8_3.mdкак infrastructure/off-phase позицию. Решение — за заказчиком; вне scope v1. - CI-интеграция.
run.mjsпригоден к вызову из GitHub Actions (node .claude/skills/regression/run.mjs full); отдельный workflow-файл — возможный follow-up. --concurrent-режим. Параллельный запуск независимых doc-проверок (markdownlint/cspell/lychee) — поздняя оптимизация при необходимости.- Расширение свода. Pa11y/Semgrep/knip могут быть добавлены отдельным уровнем (напр.
/regression ci) по запросу заказчика.
Истинно-открытых вопросов в этом дизайне: 0. Все развилки согласованы (Q1–Q4) либо приняты с обоснованием и одобрены (U1–U3).