Files
portal/docs/superpowers/specs/2026-05-16-regression-skill-design.md
T
Дмитрий c327840407 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>
2026-05-16 07:25:10 +03:00

28 KiB
Raw Blame History

Скилл /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.86v2.1, audit-записи, sprint-closure-записи).

Сами команды свода разбросаны по четырём файлам и двум рабочим директориям:

  • корневой package.jsonlint:md, spell, links, a11y, sast;
  • app/package.jsonlint:vue, format:check, type-check, test:vue, build;
  • app/composer.jsontest, pint:test, test:parallel, stan;
  • lefthook.yml — gitleaks (staged + full-history), lychee.

Следствия отсутствия единого входа:

  1. Ручная оркестрация — Claude/человек запускает ~12 команд вручную, по одной, помня про смену cwd (app/ vs корень).
  2. Недетерминированность отчёта — итоговая каноническая строка собирается «на глаз»; формат и полнота зависят от исполнителя; возможен пропуск проверки.
  3. Нет жёсткого вердикта — «зелёно ли» определяется чтением вывода, а не машинно.
  4. Дублирование в 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 --parallel flake, 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):

  • PestPest <total>/<passed>/<skipped>sk/<failed> (напр. 742/739/3sk/0).
  • VitestVitest <files>f/<passed>/<skipped>sk/<failed> (напр. 92f/774/3sk/0).
  • Vite buildVite build <время>s.
  • gitleaksgitleaks <leaks>/<commits-scanned>.
  • lycheelychee <OK>/<errors>.
  • LarastanLarastan <число ошибок> (напр. 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).
  • full Claude сам не запускает — только по явному /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-код), сборка канонической строки, платформенная развилка бинаря (win32bin\*.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. Отклонённые альтернативы

Альтернатива Почему отклонена
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»). Текущий поток: brainstormingwriting-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).