diff --git a/docs/registry/capability-vocabulary.json b/docs/registry/capability-vocabulary.json index 3b8d11d..9507d3e 100644 --- a/docs/registry/capability-vocabulary.json +++ b/docs/registry/capability-vocabulary.json @@ -1,5 +1,5 @@ { - "version": "0.5.0", + "version": "0.6.0", "tokens": [ { "token": "running-portal", @@ -1002,6 +1002,594 @@ "category": "given", "label": "промпт + тест-кейсы", "description": "LLM-промпт + кейсы для eval. Вход promptfoo." + }, + { + "token": "ui-template-draft", + "category": "produced", + "label": "стартовый UI-шаблон", + "description": "LLM-сгенерированный UI-шаблон. Выход 21st-magic." + }, + { + "token": "db-or-docs-result", + "category": "produced", + "label": "результат SQL/Eloquent или docs", + "description": "Результат запроса к dev-БД или релевантная докуменация Laravel. Выход boost." + }, + { + "token": "library-docs", + "category": "produced", + "label": "документация библиотеки", + "description": "Актуальная документация библиотеки/SDK. Выход context7." + }, + { + "token": "ru-seo-data", + "category": "produced", + "label": "SEO-данные РФ", + "description": "SERP/бэклинки/конкурентный анализ РФ. Выход dataforseo-mcp." + }, + { + "token": "semantic-web-results", + "category": "produced", + "label": "семантический веб-поиск", + "description": "Результаты по смыслу + страница по URL. Выход exa-mcp." + }, + { + "token": "figma-tokens", + "category": "produced", + "label": "дизайн-токены Figma", + "description": "Извлечённые токены/компоненты/стили. Выход figma-mcp." + }, + { + "token": "web-page-content", + "category": "produced", + "label": "содержимое страниц", + "description": "Scrape/crawl/map/extract + web-research. Выход firecrawl-mcp." + }, + { + "token": "github-op-result", + "category": "produced", + "label": "результат GitHub-операции", + "description": "Чтение/запись issue/PR/комментария. Выход github-mcp." + }, + { + "token": "notebook-result", + "category": "produced", + "label": "результат ноутбука", + "description": "Результат исполнения ячеек. Выход jupyter-mcp." + }, + { + "token": "n8n-automation", + "category": "produced", + "label": "автоматизация n8n", + "description": "Автоматизация процесса через n8n. Выход n8n-mcp." + }, + { + "token": "api-resources", + "category": "produced", + "label": "API-ресурсы (чтение)", + "description": "Эндпоинты/схемы/параметры как MCP-ресурсы. Выход openapi-mcp." + }, + { + "token": "web-answer-cited", + "category": "produced", + "label": "web-ответ с цитатами", + "description": "Ранжированный ответ sonar (search/ask/research/reason). Выход perplexity-mcp." + }, + { + "token": "browser-interaction-result", + "category": "produced", + "label": "результат браузера", + "description": "Скриншот/взаимодействие/console+network. Выход playwright-mcp." + }, + { + "token": "sql-result", + "category": "produced", + "label": "результат SQL", + "description": "Результат исторического SQL к dev-БД. Выход postgres-mcp." + }, + { + "token": "scheduled-social-posts", + "category": "produced", + "label": "запланированные публикации", + "description": "Публикации в 30+ соцсетях (VK/Telegram). Выход postiz." + }, + { + "token": "redis-state", + "category": "produced", + "label": "состояние Redis", + "description": "Ключи/очереди/TTL/паттерны (чтение). Выход redis-mcp." + }, + { + "token": "sentry-events", + "category": "produced", + "label": "события Sentry", + "description": "События/ошибки/трассировки (чтение). Выход sentry-mcp." + }, + { + "token": "telegram-result", + "category": "produced", + "label": "результат Telegram", + "description": "Публикация/редактирование/аналитика канала. Выход telegram-mcp." + }, + { + "token": "email-blast-sent", + "category": "produced", + "label": "email-рассылка отправлена", + "description": "Отправка маркетинговой рассылки. Выход unisender-go-mcp." + }, + { + "token": "svg-icon", + "category": "produced", + "label": "SVG-иконка", + "description": "Иконка из не-Lucide коллекции (Material/Tabler/Phosphor). Выход universal-icons-mcp." + }, + { + "token": "metrika-data", + "category": "produced", + "label": "данные Яндекс.Метрики", + "description": "Визиты/источники/гео/поведение. Выход yandex-metrika-mcp." + }, + { + "token": "wordstat-frequency", + "category": "produced", + "label": "частотность Wordstat", + "description": "Частотность РФ-запросов: сезонность/связанные. Выход yandex-wordstat-mcp." + }, + { + "token": "spelling-report", + "category": "produced", + "label": "отчёт орфографии", + "description": "Отчёт о неизвестных словах. Выход cspell." + }, + { + "token": "cve-dependency-pr", + "category": "produced", + "label": "auto-PR на CVE зависимости", + "description": "Auto-PR при CVE в зависимости. Выход dependabot." + }, + { + "token": "layer-violation-report", + "category": "produced", + "label": "отчёт нарушений слоёв", + "description": "Нарушения границ слоёв. Выход deptrac." + }, + { + "token": "linted-js-vue", + "category": "produced", + "label": "пролинченный JS/Vue", + "description": "Исправленный/проверенный JS/Vue (ESLint+Prettier). Выход eslint-prettier." + }, + { + "token": "secret-leak-findings", + "category": "produced", + "label": "находки утечек секретов", + "description": "Ключи/токены/пароли/DSN. Выход gitleaks." + }, + { + "token": "stories-catalog", + "category": "produced", + "label": "каталог stories", + "description": "Визуальный каталог stories/variants. Выход histoire." + }, + { + "token": "ide-stubs", + "category": "produced", + "label": "IDE-заглушки", + "description": "@mixin IdeHelper* для autocomplete. Выход ide-helper." + }, + { + "token": "php-type-report", + "category": "produced", + "label": "отчёт типов PHP", + "description": "Ошибки типов/сигнатур/undefined. Выход larastan." + }, + { + "token": "broken-link-report", + "category": "produced", + "label": "отчёт битых ссылок", + "description": "Битые URL и якоря. Выход lychee." + }, + { + "token": "markdown-style-report", + "category": "produced", + "label": "отчёт стиля Markdown", + "description": "Нарушения стиля Markdown. Выход markdownlint." + }, + { + "token": "mermaid-diagram", + "category": "produced", + "label": "диаграмма Mermaid", + "description": "Диаграмма в нотации Mermaid/C4. Выход mermaid." + }, + { + "token": "runtime-trace", + "category": "produced", + "label": "runtime-трейс", + "description": "Коррелированный request/job/query трейс. Выход nightowl." + }, + { + "token": "a11y-violations-report", + "category": "produced", + "label": "отчёт a11y (рантайм)", + "description": "Нарушения WCAG 2.1 AA на странице. Выход pa11y." + }, + { + "token": "php-test-result", + "category": "produced", + "label": "результат Pest", + "description": "Pass/fail/assertions PHP-тестов. Выход pest." + }, + { + "token": "masked-dump", + "category": "produced", + "label": "маскированный дамп", + "description": "Дамп с маской ПДн (телефоны/имена/email). Выход pg-anonymizer." + }, + { + "token": "db-audit-log", + "category": "produced", + "label": "аудит-журнал БД", + "description": "Журнал DDL/DML/DCL операций. Выход pg-audit." + }, + { + "token": "formatted-sql", + "category": "produced", + "label": "отформатированный SQL", + "description": "Отступы/регистр/выравнивание. Выход pg-formatter." + }, + { + "token": "auto-partitions", + "category": "produced", + "label": "авто-партиции", + "description": "Создание/удаление partition по расписанию. Выход pg-partman." + }, + { + "token": "php-quality-metrics", + "category": "produced", + "label": "метрики качества PHP", + "description": "Сложность/архитектура/code style. Выход php-insights." + }, + { + "token": "formatted-php", + "category": "produced", + "label": "отформатированный PHP", + "description": "PSR-12 + Laravel style. Выход pint." + }, + { + "token": "refactored-php", + "category": "produced", + "label": "рефакторенный PHP", + "description": "Upgrade/dead-code/modernization. Выход rector." + }, + { + "token": "composer-cve-block", + "category": "produced", + "label": "блок CVE-пакета", + "description": "Блок установки пакета с известным CVE. Выход roave-security." + }, + { + "token": "sast-report", + "category": "produced", + "label": "SAST-отчёт", + "description": "Уязвимости кода (инъекции/XSS/конфиг). Выход semgrep." + }, + { + "token": "migration-danger-report", + "category": "produced", + "label": "отчёт опасной миграции", + "description": "Блокировки/без CONCURRENTLY/ненадёжный DEFAULT. Выход squawk." + }, + { + "token": "css-style-report", + "category": "produced", + "label": "отчёт стиля CSS", + "description": "Нарушения стиля CSS. Выход stylelint." + }, + { + "token": "image-cve-report", + "category": "produced", + "label": "отчёт CVE образа", + "description": "CVE в OS-пакетах и зависимостях образа. Выход trivy." + }, + { + "token": "vitest-result", + "category": "produced", + "label": "результат Vitest", + "description": "Pass/fail unit/component. Выход vitest." + }, + { + "token": "editor-type-diagnostics", + "category": "produced", + "label": "диагностика в редакторе", + "description": "IntelliSense/go-to-def/hover/типы. Выход volar." + }, + { + "token": "vue-type-report", + "category": "produced", + "label": "отчёт типов Vue", + "description": "Несоответствия типов в шаблонах/script. Выход vue-tsc." + }, + { + "token": "ui-template-intent", + "category": "given", + "label": "намерение UI-шаблона", + "description": "Компонент/лейаут/форма. Вход 21st-magic." + }, + { + "token": "db-or-docs-query", + "category": "given", + "label": "запрос к БД или docs", + "description": "SQL/Eloquent к dev-БД или вопрос по docs Laravel. Вход boost." + }, + { + "token": "library-api-question", + "category": "given", + "label": "вопрос по API библиотеки", + "description": "Вопрос по API/доке библиотеки/SDK. Вход context7." + }, + { + "token": "ru-seo-question", + "category": "given", + "label": "SEO-вопрос РФ", + "description": "SERP/ключевые/бэклинки РФ. Вход dataforseo-mcp." + }, + { + "token": "semantic-search-need", + "category": "given", + "label": "нужен семантический поиск", + "description": "Найти источники по смыслу. Вход exa-mcp." + }, + { + "token": "figma-file", + "category": "given", + "label": "Figma-файл", + "description": "Файл с дизайн-токенами/компонентами. Вход figma-mcp." + }, + { + "token": "web-read-need", + "category": "given", + "label": "нужно прочитать страницу/сайт", + "description": "Прочитать/обойти/извлечь со страниц. Вход firecrawl-mcp." + }, + { + "token": "repo-ref", + "category": "given", + "label": "ссылка на repo/issue/PR", + "description": "Ссылка на repo/issue/PR. Вход github-mcp." + }, + { + "token": "github-operation-intent", + "category": "given", + "label": "намерение GitHub-операции", + "description": "Операция чтения/записи. Вход github-mcp." + }, + { + "token": "jupyter-notebook", + "category": "given", + "label": "Jupyter-ноутбук", + "description": "Ноутбук для исполнения. Вход jupyter-mcp." + }, + { + "token": "n8n-workflow", + "category": "given", + "label": "workflow n8n", + "description": "Workflow для движка n8n. Вход n8n-mcp." + }, + { + "token": "openapi-spec", + "category": "given", + "label": "OpenAPI-спецификация", + "description": "OpenAPI/REST-спека интеграции. Вход openapi-mcp." + }, + { + "token": "web-research-question", + "category": "given", + "label": "вопрос веб-разведки", + "description": "Актуальные практики/нормы/конкуренты с источниками. Вход perplexity-mcp." + }, + { + "token": "browser-target", + "category": "given", + "label": "URL/HTML для браузера", + "description": "URL или HTML-файл для управления. Вход playwright-mcp." + }, + { + "token": "browser-action-intent", + "category": "given", + "label": "намерение действия браузера", + "description": "Скриншот/взаимодействие/сетевой трейс. Вход playwright-mcp." + }, + { + "token": "historical-sql-query", + "category": "given", + "label": "исторический SQL-запрос", + "description": "Исторический SQL к dev-БД. Вход postgres-mcp." + }, + { + "token": "social-content-plan", + "category": "given", + "label": "план публикаций", + "description": "Контент-календарь/план соцсетей. Вход postiz." + }, + { + "token": "redis-state-question", + "category": "given", + "label": "вопрос о состоянии Redis", + "description": "Ключи/очереди/TTL. Вход redis-mcp." + }, + { + "token": "prod-runtime-error", + "category": "given", + "label": "production runtime ошибка", + "description": "Ошибка для диагностики. Вход sentry-mcp." + }, + { + "token": "telegram-action", + "category": "given", + "label": "действие в Telegram", + "description": "Пост/действие в канале. Вход telegram-mcp." + }, + { + "token": "email-blast-task", + "category": "given", + "label": "массовая email-рассылка", + "description": "Рассылка через Unisender Go. Вход unisender-go-mcp." + }, + { + "token": "svg-icon-need", + "category": "given", + "label": "нужна SVG-иконка", + "description": "Иконка не-Lucide коллекции. Вход universal-icons-mcp." + }, + { + "token": "web-analytics-question", + "category": "given", + "label": "вопрос веб-аналитики", + "description": "Аналитика лендинга. Вход yandex-metrika-mcp." + }, + { + "token": "keyword-topic", + "category": "given", + "label": "тема для ключевых слов", + "description": "Тема для подбора ключевых. Вход yandex-wordstat-mcp." + }, + { + "token": "markdown-files", + "category": "given", + "label": "Markdown-файлы", + "description": "Markdown для проверки. Вход cspell/lychee/markdownlint." + }, + { + "token": "project-dictionary", + "category": "given", + "label": "словарь проекта", + "description": "Пользовательский словарь орфографии. Вход cspell." + }, + { + "token": "project-dependencies", + "category": "given", + "label": "зависимости проекта", + "description": "Composer/npm зависимости. Вход dependabot." + }, + { + "token": "php-layers", + "category": "given", + "label": "PHP-слои", + "description": "Слои для проверки направления зависимостей. Вход deptrac." + }, + { + "token": "js-vue-source", + "category": "given", + "label": "JS/Vue-код", + "description": "JS/Vue для линта/тестов. Вход eslint-prettier/vitest." + }, + { + "token": "git-diff-or-history", + "category": "given", + "label": "git diff/история", + "description": "Diff или история репозитория. Вход gitleaks." + }, + { + "token": "vue-component", + "category": "given", + "label": "Vue-компонент", + "description": "Vue-компонент(ы) для каталога/проверки типов. Вход histoire/vue-tsc." + }, + { + "token": "laravel-project", + "category": "given", + "label": "Laravel-проект", + "description": "Facades/модели/хелперы. Вход ide-helper." + }, + { + "token": "php-source", + "category": "given", + "label": "PHP-код", + "description": "PHP-код для анализа/форматирования/рефакторинга. Вход larastan/pint/php-insights/rector." + }, + { + "token": "diagram-requirement", + "category": "given", + "label": "требование к диаграмме", + "description": "C4/flow/sequence. Вход mermaid." + }, + { + "token": "trace-correlation-need", + "category": "given", + "label": "нужна корреляция трасс", + "description": "Сквозная request/job/query корреляция. Вход nightowl." + }, + { + "token": "rendered-page", + "category": "given", + "label": "отрендеренная страница", + "description": "Страница/URL для a11y. Вход pa11y." + }, + { + "token": "php-tests", + "category": "given", + "label": "PHP-тесты", + "description": "Unit/feature/RLS тесты. Вход pest." + }, + { + "token": "db-dump-with-pii", + "category": "given", + "label": "дамп с ПДн", + "description": "Дамп БД с персональными данными. Вход pg-anonymizer." + }, + { + "token": "db-operations", + "category": "given", + "label": "операции БД", + "description": "DDL/DML/DCL операции. Вход pg-audit." + }, + { + "token": "sql-file", + "category": "given", + "label": "SQL-файл", + "description": "SQL для форматирования. Вход pg-formatter." + }, + { + "token": "partition-schedule", + "category": "given", + "label": "расписание партиций", + "description": "Расписание партиционирования таблиц. Вход pg-partman." + }, + { + "token": "composer-install", + "category": "given", + "label": "composer install/update", + "description": "Установка/обновление пакетов. Вход roave-security." + }, + { + "token": "code-for-sast", + "category": "given", + "label": "код для SAST", + "description": "PHP/JS/Vue для SAST. Вход semgrep." + }, + { + "token": "sql-migration", + "category": "given", + "label": "SQL-миграция", + "description": "Миграция PostgreSQL. Вход squawk." + }, + { + "token": "css-source", + "category": "given", + "label": "CSS-код", + "description": "CSS в .vue SFC или .css. Вход stylelint." + }, + { + "token": "docker-image", + "category": "given", + "label": "Docker-образ", + "description": "Образ для скана. Вход trivy." + }, + { + "token": "open-vue-file", + "category": "given", + "label": "открытый .vue в VSCode", + "description": "Открытый .vue для IntelliSense. Вход volar." } ] } diff --git a/docs/registry/contracts/21st-magic.contract.json b/docs/registry/contracts/21st-magic.contract.json index 338163a..26cd31e 100644 --- a/docs/registry/contracts/21st-magic.contract.json +++ b/docs/registry/contracts/21st-magic.contract.json @@ -1,12 +1,30 @@ { "skill": "21st-magic", "kind": "external", - "needs": ["намерение UI-шаблона (компонент / лейаут / форма)"], - "produces": ["стартовый UI-шаблон (LLM-сгенерированный)"], - "constraints": ["генератор шаблонов через PSR_v1 R14.4 pipeline", "Pa11y проверка обязательна после генерации", "стек-фильтр R6.0"], + "needs": [ + "ui-template-intent" + ], + "produces": [ + "ui-template-draft" + ], + "constraints": [ + "генератор шаблонов через PSR_v1 R14.4 pipeline", + "Pa11y проверка обязательна после генерации", + "стек-фильтр R6.0" + ], "preview-form": "mockup", - "defaults": ["после генерации — обязательный Pa11y"], - "key-decisions": ["какой шаблон; адаптация под Vue+Vuetify"], - "acceptance-criteria": ["шаблон в стеке Vue+Vuetify, Pa11y 0 нарушений"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "после генерации — обязательный Pa11y" + ], + "key-decisions": [ + "какой шаблон; адаптация под Vue+Vuetify" + ], + "acceptance-criteria": [ + "шаблон в стеке Vue+Vuetify, Pa11y 0 нарушений" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/boost.contract.json b/docs/registry/contracts/boost.contract.json index 9129169..fed6cf1 100644 --- a/docs/registry/contracts/boost.contract.json +++ b/docs/registry/contracts/boost.contract.json @@ -1,12 +1,30 @@ { "skill": "boost", "kind": "external", - "needs": ["SQL/Eloquent-запрос к dev-БД или вопрос по docs Laravel/пакета"], - "produces": ["результат SQL/Eloquent или релевантная документация Laravel"], - "constraints": ["MCP к dev-БД через Roster auto-detect", "НЕ подключать к production DB", "заменил PostgreSQL MCP (#1)"], + "needs": [ + "db-or-docs-query" + ], + "produces": [ + "db-or-docs-result" + ], + "constraints": [ + "MCP к dev-БД через Roster auto-detect", + "НЕ подключать к production DB", + "заменил PostgreSQL MCP (#1)" + ], "preview-form": "none", - "defaults": ["read-first; serverить только установленные пакеты (Roster)"], - "key-decisions": ["источник: только dev-БД, не прод"], - "acceptance-criteria": ["запрос/доки отданы из правильного (dev) источника"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "read-first; serverить только установленные пакеты (Roster)" + ], + "key-decisions": [ + "источник: только dev-БД, не прод" + ], + "acceptance-criteria": [ + "запрос/доки отданы из правильного (dev) источника" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/context7.contract.json b/docs/registry/contracts/context7.contract.json index 63221bb..3eb9167 100644 --- a/docs/registry/contracts/context7.contract.json +++ b/docs/registry/contracts/context7.contract.json @@ -1,12 +1,29 @@ { "skill": "context7", "kind": "external", - "needs": ["вопрос по API/доке конкретной библиотеки/SDK"], - "produces": ["актуальная документация библиотеки/SDK"], - "constraints": ["первый выбор для доков известной библиотеки", "WebFetch — fallback на URL; WebSearch — без знания библиотеки"], + "needs": [ + "library-api-question" + ], + "produces": [ + "library-docs" + ], + "constraints": [ + "первый выбор для доков известной библиотеки", + "WebFetch — fallback на URL; WebSearch — без знания библиотеки" + ], "preview-form": "none", - "defaults": ["resolve-library-id → query-docs"], - "key-decisions": ["какая библиотека/тема"], - "acceptance-criteria": ["актуальная дока по API получена"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "resolve-library-id → query-docs" + ], + "key-decisions": [ + "какая библиотека/тема" + ], + "acceptance-criteria": [ + "актуальная дока по API получена" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/cspell.contract.json b/docs/registry/contracts/cspell.contract.json index 3e76e9c..68f17d1 100644 --- a/docs/registry/contracts/cspell.contract.json +++ b/docs/registry/contracts/cspell.contract.json @@ -1,12 +1,31 @@ { "skill": "cspell", "kind": "external", - "needs": ["Markdown-текст для проверки орфографии", "пользовательский словарь проекта"], - "produces": ["отчёт о неизвестных словах"], - "constraints": ["ru/en орфография .md с пользовательским словарём", "НЕ стиль (markdownlint)", "НЕ грамматика"], + "needs": [ + "markdown-files", + "project-dictionary" + ], + "produces": [ + "spelling-report" + ], + "constraints": [ + "ru/en орфография .md с пользовательским словарём", + "НЕ стиль (markdownlint)", + "НЕ грамматика" + ], "preview-form": "none", - "defaults": ["учитывать cspell-words.txt"], - "key-decisions": ["новый валидный термин → в словарь, а не подавлять находку"], - "acceptance-criteria": ["0 неизвестных слов вне словаря"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "учитывать cspell-words.txt" + ], + "key-decisions": [ + "новый валидный термин → в словарь, а не подавлять находку" + ], + "acceptance-criteria": [ + "0 неизвестных слов вне словаря" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/dataforseo-mcp.contract.json b/docs/registry/contracts/dataforseo-mcp.contract.json index e040cff..e82fa8a 100644 --- a/docs/registry/contracts/dataforseo-mcp.contract.json +++ b/docs/registry/contracts/dataforseo-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "dataforseo-mcp", "kind": "external", - "needs": ["SEO-вопрос по РФ (SERP/ключевые/бэклинки)"], - "produces": ["SEO-данные РФ: SERP-позиции, бэклинки, конкурентный анализ"], - "constraints": ["DEFERRED — платный, pending Б-1", "комплементарен Wordstat #79"], + "needs": [ + "ru-seo-question" + ], + "produces": [ + "ru-seo-data" + ], + "constraints": [ + "DEFERRED — платный, pending Б-1", + "комплементарен Wordstat #79" + ], "preview-form": "none", - "defaults": ["при платном аккаунте"], - "key-decisions": ["какие SEO-данные нужны"], - "acceptance-criteria": ["SEO-данные РФ получены (при доступе)"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "при платном аккаунте" + ], + "key-decisions": [ + "какие SEO-данные нужны" + ], + "acceptance-criteria": [ + "SEO-данные РФ получены (при доступе)" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/dependabot.contract.json b/docs/registry/contracts/dependabot.contract.json index 92f3c62..41aa5a0 100644 --- a/docs/registry/contracts/dependabot.contract.json +++ b/docs/registry/contracts/dependabot.contract.json @@ -1,12 +1,29 @@ { "skill": "dependabot", "kind": "external", - "needs": ["Composer/npm-зависимости"], - "produces": ["auto-PR при обнаружении CVE в зависимости"], - "constraints": ["авто-PR через .github/dependabot.yml", "НЕ блок install (Roave)"], + "needs": [ + "project-dependencies" + ], + "produces": [ + "cve-dependency-pr" + ], + "constraints": [ + "авто-PR через .github/dependabot.yml", + "НЕ блок install (Roave)" + ], "preview-form": "none", - "defaults": ["настройка через .github/dependabot.yml"], - "key-decisions": ["принять/отклонить предложенное обновление"], - "acceptance-criteria": ["CVE-зависимости имеют открытый update-PR"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "настройка через .github/dependabot.yml" + ], + "key-decisions": [ + "принять/отклонить предложенное обновление" + ], + "acceptance-criteria": [ + "CVE-зависимости имеют открытый update-PR" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/deptrac.contract.json b/docs/registry/contracts/deptrac.contract.json index 7abb7fd..03c2ad1 100644 --- a/docs/registry/contracts/deptrac.contract.json +++ b/docs/registry/contracts/deptrac.contract.json @@ -1,12 +1,30 @@ { "skill": "deptrac", "kind": "external", - "needs": ["PHP-слои для проверки направления зависимостей"], - "produces": ["отчёт о нарушениях границ слоёв"], - "constraints": ["граф слоёв по app/deptrac.yaml; lefthook job 10", "НЕ типовой анализ (Larastan)", "НЕ декларативный ADR (adr-judge)"], + "needs": [ + "php-layers" + ], + "produces": [ + "layer-violation-report" + ], + "constraints": [ + "граф слоёв по app/deptrac.yaml; lefthook job 10", + "НЕ типовой анализ (Larastan)", + "НЕ декларативный ADR (adr-judge)" + ], "preview-form": "none", - "defaults": ["конфиг 13 слоёв, консервативный ruleset"], - "key-decisions": ["допустимые направления зависимостей"], - "acceptance-criteria": ["0 нарушений границ слоёв"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "конфиг 13 слоёв, консервативный ruleset" + ], + "key-decisions": [ + "допустимые направления зависимостей" + ], + "acceptance-criteria": [ + "0 нарушений границ слоёв" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/eslint-prettier.contract.json b/docs/registry/contracts/eslint-prettier.contract.json index 6924f38..c038aad 100644 --- a/docs/registry/contracts/eslint-prettier.contract.json +++ b/docs/registry/contracts/eslint-prettier.contract.json @@ -1,12 +1,30 @@ { "skill": "eslint-prettier", "kind": "external", - "needs": ["JS/Vue-код для линта+форматирования"], - "produces": ["исправленный/проверенный JS/Vue по ESLint+Prettier"], - "constraints": ["связка lint+format JS/Vue", "НЕ CSS (Stylelint)", "НЕ типы (vue-tsc)"], + "needs": [ + "js-vue-source" + ], + "produces": [ + "linted-js-vue" + ], + "constraints": [ + "связка lint+format JS/Vue", + "НЕ CSS (Stylelint)", + "НЕ типы (vue-tsc)" + ], "preview-form": "none", - "defaults": ["flat-config + plugin-vue; config-prettier разводит конфликты"], - "key-decisions": ["scope: staged-файлы vs весь js/vue"], - "acceptance-criteria": ["0 ESLint-ошибок, формат единообразен"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "flat-config + plugin-vue; config-prettier разводит конфликты" + ], + "key-decisions": [ + "scope: staged-файлы vs весь js/vue" + ], + "acceptance-criteria": [ + "0 ESLint-ошибок, формат единообразен" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/exa-mcp.contract.json b/docs/registry/contracts/exa-mcp.contract.json index 4774d73..e9e191e 100644 --- a/docs/registry/contracts/exa-mcp.contract.json +++ b/docs/registry/contracts/exa-mcp.contract.json @@ -1,12 +1,30 @@ { "skill": "exa-mcp", "kind": "external", - "needs": ["нужно найти источники по смыслу, которые keyword-поиск пропускает"], - "produces": ["семантически близкие результаты веб-поиска (web_search_exa) + страница по URL (web_fetch_exa)"], - "constraints": ["READ-ONLY MCP, живой веб", "платный API, ключ EXA_API_KEY только в env", "обнаружение источников, НЕ ранжированный ответ (perplexity #87) и НЕ глубокое чтение (firecrawl #89)"], + "needs": [ + "semantic-search-need" + ], + "produces": [ + "semantic-web-results" + ], + "constraints": [ + "READ-ONLY MCP, живой веб", + "платный API, ключ EXA_API_KEY только в env", + "обнаружение источников, НЕ ранжированный ответ (perplexity #87) и НЕ глубокое чтение (firecrawl #89)" + ], "preview-form": "none", - "defaults": ["семантическое обнаружение источников по смыслу"], - "key-decisions": ["web_search_exa vs web_fetch_exa; глубина выдачи"], - "acceptance-criteria": ["найдены концептуально релевантные источники по смыслу запроса"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "семантическое обнаружение источников по смыслу" + ], + "key-decisions": [ + "web_search_exa vs web_fetch_exa; глубина выдачи" + ], + "acceptance-criteria": [ + "найдены концептуально релевантные источники по смыслу запроса" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/figma-mcp.contract.json b/docs/registry/contracts/figma-mcp.contract.json index f692bd0..100289e 100644 --- a/docs/registry/contracts/figma-mcp.contract.json +++ b/docs/registry/contracts/figma-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "figma-mcp", "kind": "external", - "needs": ["Figma-файл с дизайн-токенами/компонентами"], - "produces": ["извлечённые дизайн-токены/компоненты/стили"], - "constraints": ["DEFERRED — нет Figma-аккаунта; источник — статический handoff Платона", "extract-only, code-gen за Frontend Design (#30)"], + "needs": [ + "figma-file" + ], + "produces": [ + "figma-tokens" + ], + "constraints": [ + "DEFERRED — нет Figma-аккаунта; источник — статический handoff Платона", + "extract-only, code-gen за Frontend Design (#30)" + ], "preview-form": "none", - "defaults": ["на поддерживаемом источнике: extract-only"], - "key-decisions": ["какие токены извлекать"], - "acceptance-criteria": ["токены извлечены из Figma-источника (когда доступен)"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "на поддерживаемом источнике: extract-only" + ], + "key-decisions": [ + "какие токены извлекать" + ], + "acceptance-criteria": [ + "токены извлечены из Figma-источника (когда доступен)" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/firecrawl-mcp.contract.json b/docs/registry/contracts/firecrawl-mcp.contract.json index 182e93d..6de1095 100644 --- a/docs/registry/contracts/firecrawl-mcp.contract.json +++ b/docs/registry/contracts/firecrawl-mcp.contract.json @@ -1,12 +1,30 @@ { "skill": "firecrawl-mcp", "kind": "external", - "needs": ["нужно прочитать страницу целиком / обойти сайт / извлечь структурированное со страниц"], - "produces": ["содержимое страниц и обхода (scrape/batch_scrape/map/search/crawl/extract) + автономный web-research (firecrawl_agent)"], - "constraints": ["READ-ONLY (read-тяжёлый) MCP, живой веб", "платный API, ключ FIRECRAWL_API_KEY только в env", "глубокое чтение/обход, НЕ ранжированный ответ (perplexity #87) и НЕ наш REST-спек (openapi #47)"], + "needs": [ + "web-read-need" + ], + "produces": [ + "web-page-content" + ], + "constraints": [ + "READ-ONLY (read-тяжёлый) MCP, живой веб", + "платный API, ключ FIRECRAWL_API_KEY только в env", + "глубокое чтение/обход, НЕ ранжированный ответ (perplexity #87) и НЕ наш REST-спек (openapi #47)" + ], "preview-form": "none", - "defaults": ["scrape одной страницы целиком в markdown"], - "key-decisions": ["scrape vs crawl vs extract vs agent; глубина обхода"], - "acceptance-criteria": ["получено полное/структурированное содержимое целевой страницы или обхода"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "scrape одной страницы целиком в markdown" + ], + "key-decisions": [ + "scrape vs crawl vs extract vs agent; глубина обхода" + ], + "acceptance-criteria": [ + "получено полное/структурированное содержимое целевой страницы или обхода" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/github-mcp.contract.json b/docs/registry/contracts/github-mcp.contract.json index 5c08d74..baceaa5 100644 --- a/docs/registry/contracts/github-mcp.contract.json +++ b/docs/registry/contracts/github-mcp.contract.json @@ -1,12 +1,30 @@ { "skill": "github-mcp", "kind": "external", - "needs": ["ссылка на repo/issue/PR", "намерение операции"], - "produces": ["результат чтения или записи issue/PR/комментария"], - "constraints": ["внешний MCP — операции через GitHub API", "НЕ локальный git-флоу (это git/PowerShell)"], + "needs": [ + "repo-ref", + "github-operation-intent" + ], + "produces": [ + "github-op-result" + ], + "constraints": [ + "внешний MCP — операции через GitHub API", + "НЕ локальный git-флоу (это git/PowerShell)" + ], "preview-form": "none", - "defaults": ["read-first перед мутацией"], - "key-decisions": ["scope операции: чтение или запись"], - "acceptance-criteria": ["операция отражена в GitHub и подтверждена ответом API"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "read-first перед мутацией" + ], + "key-decisions": [ + "scope операции: чтение или запись" + ], + "acceptance-criteria": [ + "операция отражена в GitHub и подтверждена ответом API" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/gitleaks.contract.json b/docs/registry/contracts/gitleaks.contract.json index b347289..5027507 100644 --- a/docs/registry/contracts/gitleaks.contract.json +++ b/docs/registry/contracts/gitleaks.contract.json @@ -1,12 +1,29 @@ { "skill": "gitleaks", "kind": "external", - "needs": ["git diff или история репозитория"], - "produces": ["находки утечек секретов (ключи/токены/пароли/DSN)"], - "constraints": ["сканирует секреты в diff/истории через lefthook pre-commit/pre-push", "НЕ SAST-уязвимости кода (Semgrep)"], + "needs": [ + "git-diff-or-history" + ], + "produces": [ + "secret-leak-findings" + ], + "constraints": [ + "сканирует секреты в diff/истории через lefthook pre-commit/pre-push", + "НЕ SAST-уязвимости кода (Semgrep)" + ], "preview-form": "none", - "defaults": ["protect --staged на pre-commit; полная история на pre-push"], - "key-decisions": ["реальный секрет vs тестовая фикстура (false-positive)"], - "acceptance-criteria": ["0 утечек секретов в diff/истории"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "protect --staged на pre-commit; полная история на pre-push" + ], + "key-decisions": [ + "реальный секрет vs тестовая фикстура (false-positive)" + ], + "acceptance-criteria": [ + "0 утечек секретов в diff/истории" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/histoire.contract.json b/docs/registry/contracts/histoire.contract.json index 8f5eaa3..93320a6 100644 --- a/docs/registry/contracts/histoire.contract.json +++ b/docs/registry/contracts/histoire.contract.json @@ -1,12 +1,29 @@ { "skill": "histoire", "kind": "external", - "needs": ["Vue-компонент для каталога stories"], - "produces": ["визуальный каталог stories/variants"], - "constraints": ["каталог компонентов (не Storybook)", "Vuetify через setupFile"], + "needs": [ + "vue-component" + ], + "produces": [ + "stories-catalog" + ], + "constraints": [ + "каталог компонентов (не Storybook)", + "Vuetify через setupFile" + ], "preview-form": "sample", - "defaults": ["npm run story"], - "key-decisions": ["какие компоненты/variants в каталоге"], - "acceptance-criteria": ["stories собираются и рендерятся"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "npm run story" + ], + "key-decisions": [ + "какие компоненты/variants в каталоге" + ], + "acceptance-criteria": [ + "stories собираются и рендерятся" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/ide-helper.contract.json b/docs/registry/contracts/ide-helper.contract.json index c55993a..57ee8a8 100644 --- a/docs/registry/contracts/ide-helper.contract.json +++ b/docs/registry/contracts/ide-helper.contract.json @@ -1,12 +1,29 @@ { "skill": "ide-helper", "kind": "external", - "needs": ["Laravel-проект (facades/модели/хелперы)"], - "produces": ["IDE-заглушки (@mixin IdeHelper*) для autocomplete/type-inference"], - "constraints": ["генерация stubs для IDE", "НЕ влияет на рантайм"], + "needs": [ + "laravel-project" + ], + "produces": [ + "ide-stubs" + ], + "constraints": [ + "генерация stubs для IDE", + "НЕ влияет на рантайм" + ], "preview-form": "none", - "defaults": ["ide-helper:generate + models -W -M -N"], - "key-decisions": ["когда перегенерировать (после изменения моделей)"], - "acceptance-criteria": ["autocomplete/type-inference покрывают facades+модели"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "ide-helper:generate + models -W -M -N" + ], + "key-decisions": [ + "когда перегенерировать (после изменения моделей)" + ], + "acceptance-criteria": [ + "autocomplete/type-inference покрывают facades+модели" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/jupyter-mcp.contract.json b/docs/registry/contracts/jupyter-mcp.contract.json index 51c2db9..f03f5ba 100644 --- a/docs/registry/contracts/jupyter-mcp.contract.json +++ b/docs/registry/contracts/jupyter-mcp.contract.json @@ -1,12 +1,28 @@ { "skill": "jupyter-mcp", "kind": "external", - "needs": ["Jupyter-ноутбук для исполнения"], - "produces": ["результат исполнения ячеек ноутбука"], - "constraints": ["DEFERRED — нет Python ML-окружения на native-Windows"], + "needs": [ + "jupyter-notebook" + ], + "produces": [ + "notebook-result" + ], + "constraints": [ + "DEFERRED — нет Python ML-окружения на native-Windows" + ], "preview-form": "none", - "defaults": ["на поддерживаемой среде с Python ML"], - "key-decisions": ["какие ячейки исполнять"], - "acceptance-criteria": ["ноутбук исполнен, результаты получены (на поддерживаемой среде)"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "на поддерживаемой среде с Python ML" + ], + "key-decisions": [ + "какие ячейки исполнять" + ], + "acceptance-criteria": [ + "ноутбук исполнен, результаты получены (на поддерживаемой среде)" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/larastan.contract.json b/docs/registry/contracts/larastan.contract.json index d8c9c2a..ede344c 100644 --- a/docs/registry/contracts/larastan.contract.json +++ b/docs/registry/contracts/larastan.contract.json @@ -1,12 +1,30 @@ { "skill": "larastan", "kind": "external", - "needs": ["PHP-код для статанализа типов"], - "produces": ["отчёт об ошибках типов/сигнатур/undefined-переменных"], - "constraints": ["типовой анализ PHPStan+Laravel", "НЕ стиль (Pint)", "НЕ граф слоёв (deptrac)"], + "needs": [ + "php-source" + ], + "produces": [ + "php-type-report" + ], + "constraints": [ + "типовой анализ PHPStan+Laravel", + "НЕ стиль (Pint)", + "НЕ граф слоёв (deptrac)" + ], "preview-form": "none", - "defaults": ["уровень + baseline проекта"], - "key-decisions": ["новая ошибка vs baseline-долг"], - "acceptance-criteria": ["0 новых ошибок типов сверх baseline"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "уровень + baseline проекта" + ], + "key-decisions": [ + "новая ошибка vs baseline-долг" + ], + "acceptance-criteria": [ + "0 новых ошибок типов сверх baseline" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/lychee.contract.json b/docs/registry/contracts/lychee.contract.json index 4af3a37..8e44cc1 100644 --- a/docs/registry/contracts/lychee.contract.json +++ b/docs/registry/contracts/lychee.contract.json @@ -1,12 +1,29 @@ { "skill": "lychee", "kind": "external", - "needs": ["Markdown-файлы со ссылками"], - "produces": ["отчёт о битых URL и якорях"], - "constraints": ["внутренние + внешние ссылки и якоря .md", "НЕ стиль/орфография"], + "needs": [ + "markdown-files" + ], + "produces": [ + "broken-link-report" + ], + "constraints": [ + "внутренние + внешние ссылки и якоря .md", + "НЕ стиль/орфография" + ], "preview-form": "none", - "defaults": ["проверять и внутренние якоря, и внешние URL"], - "key-decisions": ["внешний временно недоступный vs реально битый — различать"], - "acceptance-criteria": ["0 битых ссылок/якорей"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "проверять и внутренние якоря, и внешние URL" + ], + "key-decisions": [ + "внешний временно недоступный vs реально битый — различать" + ], + "acceptance-criteria": [ + "0 битых ссылок/якорей" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/markdownlint.contract.json b/docs/registry/contracts/markdownlint.contract.json index 6ebc4bb..f369809 100644 --- a/docs/registry/contracts/markdownlint.contract.json +++ b/docs/registry/contracts/markdownlint.contract.json @@ -1,12 +1,30 @@ { "skill": "markdownlint", "kind": "external", - "needs": ["Markdown-файлы для линта"], - "produces": ["отчёт о нарушениях стиля Markdown"], - "constraints": ["внешний CLI — стиль .md (заголовки/таблицы/пробелы/переносы)", "НЕ орфография (cspell)", "НЕ ссылки (lychee)"], + "needs": [ + "markdown-files" + ], + "produces": [ + "markdown-style-report" + ], + "constraints": [ + "внешний CLI — стиль .md (заголовки/таблицы/пробелы/переносы)", + "НЕ орфография (cspell)", + "НЕ ссылки (lychee)" + ], "preview-form": "none", - "defaults": ["авто-fix где возможно (--fix), кроме корневого CLAUDE.md"], - "key-decisions": ["scope: какие .md в проверке"], - "acceptance-criteria": ["0 нарушений стиля по правилам markdownlint"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "авто-fix где возможно (--fix), кроме корневого CLAUDE.md" + ], + "key-decisions": [ + "scope: какие .md в проверке" + ], + "acceptance-criteria": [ + "0 нарушений стиля по правилам markdownlint" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/mermaid.contract.json b/docs/registry/contracts/mermaid.contract.json index c2e1c44..d3fcd05 100644 --- a/docs/registry/contracts/mermaid.contract.json +++ b/docs/registry/contracts/mermaid.contract.json @@ -1,12 +1,29 @@ { "skill": "mermaid", "kind": "external", - "needs": ["требование к диаграмме (C4 / flow / sequence / ...)"], - "produces": ["диаграмма в нотации Mermaid/C4"], - "constraints": ["вендоренный скил; диаграммы в docs/architecture/", "НЕ фиксация решения (adr-kit)"], + "needs": [ + "diagram-requirement" + ], + "produces": [ + "mermaid-diagram" + ], + "constraints": [ + "вендоренный скил; диаграммы в docs/architecture/", + "НЕ фиксация решения (adr-kit)" + ], "preview-form": "diagram", - "defaults": ["C4: context/container/component"], - "key-decisions": ["тип и уровень диаграммы"], - "acceptance-criteria": ["диаграмма рендерится и отражает систему"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "C4: context/container/component" + ], + "key-decisions": [ + "тип и уровень диаграммы" + ], + "acceptance-criteria": [ + "диаграмма рендерится и отражает систему" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/n8n-mcp.contract.json b/docs/registry/contracts/n8n-mcp.contract.json index 57c8ee6..0209270 100644 --- a/docs/registry/contracts/n8n-mcp.contract.json +++ b/docs/registry/contracts/n8n-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "n8n-mcp", "kind": "external", - "needs": ["workflow для движка n8n"], - "produces": ["автоматизация процесса через n8n"], - "constraints": ["DEFERRED — n8n не в стеке; движок процессов = очередь Laravel", "принятие n8n — отдельное архитектурное решение"], + "needs": [ + "n8n-workflow" + ], + "produces": [ + "n8n-automation" + ], + "constraints": [ + "DEFERRED — n8n не в стеке; движок процессов = очередь Laravel", + "принятие n8n — отдельное архитектурное решение" + ], "preview-form": "none", - "defaults": ["на среде с n8n"], - "key-decisions": ["принятие n8n как движка — отдельный ADR"], - "acceptance-criteria": ["workflow исполняется в n8n (когда принят)"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "на среде с n8n" + ], + "key-decisions": [ + "принятие n8n как движка — отдельный ADR" + ], + "acceptance-criteria": [ + "workflow исполняется в n8n (когда принят)" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/nightowl.contract.json b/docs/registry/contracts/nightowl.contract.json index 089183a..f1f9d43 100644 --- a/docs/registry/contracts/nightowl.contract.json +++ b/docs/registry/contracts/nightowl.contract.json @@ -1,12 +1,29 @@ { "skill": "nightowl", "kind": "external", - "needs": ["сквозная корреляция request/job/query трассировок"], - "produces": ["коррелированный runtime-трейс (self-hosted)"], - "constraints": ["DEFERRED — нет pcntl/posix на native-Windows; pending Б-1/Linux", "ADR-013 BT7 НЕ Sentry #34 (трейс vs ошибки), BT8 НЕ Pail/Boost"], + "needs": [ + "trace-correlation-need" + ], + "produces": [ + "runtime-trace" + ], + "constraints": [ + "DEFERRED — нет pcntl/posix на native-Windows; pending Б-1/Linux", + "ADR-013 BT7 НЕ Sentry #34 (трейс vs ошибки), BT8 НЕ Pail/Boost" + ], "preview-form": "none", - "defaults": ["на Linux-среде с pcntl/posix"], - "key-decisions": ["scope корреляции трассировок"], - "acceptance-criteria": ["request/job/query скоррелированы в трейс (на поддерживаемой среде)"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "на Linux-среде с pcntl/posix" + ], + "key-decisions": [ + "scope корреляции трассировок" + ], + "acceptance-criteria": [ + "request/job/query скоррелированы в трейс (на поддерживаемой среде)" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/openapi-mcp.contract.json b/docs/registry/contracts/openapi-mcp.contract.json index a0c99e0..35e61cb 100644 --- a/docs/registry/contracts/openapi-mcp.contract.json +++ b/docs/registry/contracts/openapi-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "openapi-mcp", "kind": "external", - "needs": ["OpenAPI/REST-спецификация интеграции"], - "produces": ["эндпоинты/схемы/параметры как MCP-ресурсы (чтение)"], - "constraints": ["READ-ONLY интроспекция спеки", "НЕ генерация кода"], + "needs": [ + "openapi-spec" + ], + "produces": [ + "api-resources" + ], + "constraints": [ + "READ-ONLY интроспекция спеки", + "НЕ генерация кода" + ], "preview-form": "none", - "defaults": ["read-only через .mcp.json"], - "key-decisions": ["какой эндпоинт/схему смотреть"], - "acceptance-criteria": ["структура API понята из спеки"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "read-only через .mcp.json" + ], + "key-decisions": [ + "какой эндпоинт/схему смотреть" + ], + "acceptance-criteria": [ + "структура API понята из спеки" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/pa11y.contract.json b/docs/registry/contracts/pa11y.contract.json index 5ac28dc..9567c6e 100644 --- a/docs/registry/contracts/pa11y.contract.json +++ b/docs/registry/contracts/pa11y.contract.json @@ -1,12 +1,30 @@ { "skill": "pa11y", "kind": "external", - "needs": ["отрендеренная веб-страница / URL"], - "produces": ["отчёт о нарушениях доступности WCAG 2.1 AA"], - "constraints": ["единственный технический SoT a11y в проекте", "НЕ через Lighthouse", "НЕ визуальный смок (Playwright)"], + "needs": [ + "rendered-page" + ], + "produces": [ + "a11y-violations-report" + ], + "constraints": [ + "единственный технический SoT a11y в проекте", + "НЕ через Lighthouse", + "НЕ визуальный смок (Playwright)" + ], "preview-form": "none", - "defaults": ["проверять контраст / alt / роли / фокус-порядок по WCAG 2.1 AA"], - "key-decisions": ["какие страницы/URL в a11y-прогоне"], - "acceptance-criteria": ["0 нарушений WCAG 2.1 AA на проверяемых страницах"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "проверять контраст / alt / роли / фокус-порядок по WCAG 2.1 AA" + ], + "key-decisions": [ + "какие страницы/URL в a11y-прогоне" + ], + "acceptance-criteria": [ + "0 нарушений WCAG 2.1 AA на проверяемых страницах" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/perplexity-mcp.contract.json b/docs/registry/contracts/perplexity-mcp.contract.json index 5b1ff97..538ec61 100644 --- a/docs/registry/contracts/perplexity-mcp.contract.json +++ b/docs/registry/contracts/perplexity-mcp.contract.json @@ -1,12 +1,30 @@ { "skill": "perplexity-mcp", "kind": "external", - "needs": ["вопрос веб-разведки: актуальные практики/нормы/конкуренты — нужен ответ-с-источниками"], - "produces": ["ранжированный web-ответ с цитатами (sonar): search/ask/research/reason"], - "constraints": ["READ-ONLY MCP, живой веб", "платный API (sonar-*), ключ PERPLEXITY_API_KEY только в env — без авто-расхода без нужды", "НЕ SDK-доки (context7 #60); НЕ внутренний граф проекта (graphify #86)"], + "needs": [ + "web-research-question" + ], + "produces": [ + "web-answer-cited" + ], + "constraints": [ + "READ-ONLY MCP, живой веб", + "платный API (sonar-*), ключ PERPLEXITY_API_KEY только в env — без авто-расхода без нужды", + "НЕ SDK-доки (context7 #60); НЕ внутренний граф проекта (graphify #86)" + ], "preview-form": "none", - "defaults": ["ранжированный ответ-с-источниками, не сырой список ссылок"], - "key-decisions": ["search vs ask vs research vs reason; глубина (reasoning_effort)"], - "acceptance-criteria": ["получен ответ с цитируемыми источниками по запросу веб-разведки"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "ранжированный ответ-с-источниками, не сырой список ссылок" + ], + "key-decisions": [ + "search vs ask vs research vs reason; глубина (reasoning_effort)" + ], + "acceptance-criteria": [ + "получен ответ с цитируемыми источниками по запросу веб-разведки" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/pest.contract.json b/docs/registry/contracts/pest.contract.json index 6dd6fdb..7f768ec 100644 --- a/docs/registry/contracts/pest.contract.json +++ b/docs/registry/contracts/pest.contract.json @@ -1,12 +1,29 @@ { "skill": "pest", "kind": "external", - "needs": ["PHP-тесты (unit/feature/RLS)"], - "produces": ["результат прогона тестов (pass/fail/assertions)"], - "constraints": ["Pest 4: unit/feature/RLS/parallel/browser/stress/mutation", "НЕ Vue-тесты (Vitest)"], + "needs": [ + "php-tests" + ], + "produces": [ + "php-test-result" + ], + "constraints": [ + "Pest 4: unit/feature/RLS/parallel/browser/stress/mutation", + "НЕ Vue-тесты (Vitest)" + ], "preview-form": "none", - "defaults": ["composer test; --parallel в CI"], - "key-decisions": ["scope: какие тесты, parallel vs serial"], - "acceptance-criteria": ["все тесты зелёные, без регрессий"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "composer test; --parallel в CI" + ], + "key-decisions": [ + "scope: какие тесты, parallel vs serial" + ], + "acceptance-criteria": [ + "все тесты зелёные, без регрессий" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/pg-anonymizer.contract.json b/docs/registry/contracts/pg-anonymizer.contract.json index ca2e4c3..ebfab93 100644 --- a/docs/registry/contracts/pg-anonymizer.contract.json +++ b/docs/registry/contracts/pg-anonymizer.contract.json @@ -1,12 +1,29 @@ { "skill": "pg-anonymizer", "kind": "external", - "needs": ["дамп БД с персональными данными"], - "produces": ["маскированный дамп (телефоны/имена/email)"], - "constraints": ["загрузка по требованию LOAD 'anon' (не db-wide preload)", "на проде liderra.ru"], + "needs": [ + "db-dump-with-pii" + ], + "produces": [ + "masked-dump" + ], + "constraints": [ + "загрузка по требованию LOAD 'anon' (не db-wide preload)", + "на проде liderra.ru" + ], "preview-form": "sample", - "defaults": ["маски по требованию для выгрузок"], - "key-decisions": ["какие поля маскировать"], - "acceptance-criteria": ["ПДн в выгрузке замаскированы"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "маски по требованию для выгрузок" + ], + "key-decisions": [ + "какие поля маскировать" + ], + "acceptance-criteria": [ + "ПДн в выгрузке замаскированы" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/pg-audit.contract.json b/docs/registry/contracts/pg-audit.contract.json index 93e9810..e034225 100644 --- a/docs/registry/contracts/pg-audit.contract.json +++ b/docs/registry/contracts/pg-audit.contract.json @@ -1,12 +1,29 @@ { "skill": "pg-audit", "kind": "external", - "needs": ["DDL/DML/DCL операции БД"], - "produces": ["аудит-журнал операций на уровне БД"], - "constraints": ["pgaudit.log=ddl,role,write; log_parameter=off (ПДн не логируются)", "на проде liderra.ru; закрывает 152-ФЗ"], + "needs": [ + "db-operations" + ], + "produces": [ + "db-audit-log" + ], + "constraints": [ + "pgaudit.log=ddl,role,write; log_parameter=off (ПДн не логируются)", + "на проде liderra.ru; закрывает 152-ФЗ" + ], "preview-form": "none", - "defaults": ["журнал в /var/log/postgresql"], - "key-decisions": ["scope логируемых операций"], - "acceptance-criteria": ["аудит-журнал БД ведётся, ПДн не в логах"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "журнал в /var/log/postgresql" + ], + "key-decisions": [ + "scope логируемых операций" + ], + "acceptance-criteria": [ + "аудит-журнал БД ведётся, ПДн не в логах" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/pg-formatter.contract.json b/docs/registry/contracts/pg-formatter.contract.json index dbbfcf5..aaf3ae3 100644 --- a/docs/registry/contracts/pg-formatter.contract.json +++ b/docs/registry/contracts/pg-formatter.contract.json @@ -1,12 +1,29 @@ { "skill": "pg-formatter", "kind": "external", - "needs": ["SQL-файл для форматирования"], - "produces": ["отформатированный SQL (отступы/регистр/выравнивание)"], - "constraints": ["форматирование SQL по хуку на db/schema.sql", "НЕ линт опасных паттернов (squawk)"], + "needs": [ + "sql-file" + ], + "produces": [ + "formatted-sql" + ], + "constraints": [ + "форматирование SQL по хуку на db/schema.sql", + "НЕ линт опасных паттернов (squawk)" + ], "preview-form": "none", - "defaults": ["стандарт pgFormatter"], - "key-decisions": ["scope: какой SQL форматировать"], - "acceptance-criteria": ["SQL приведён к стандарту pgFormatter"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "стандарт pgFormatter" + ], + "key-decisions": [ + "scope: какой SQL форматировать" + ], + "acceptance-criteria": [ + "SQL приведён к стандарту pgFormatter" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/pg-partman.contract.json b/docs/registry/contracts/pg-partman.contract.json index b02f880..bd3fb89 100644 --- a/docs/registry/contracts/pg-partman.contract.json +++ b/docs/registry/contracts/pg-partman.contract.json @@ -1,12 +1,29 @@ { "skill": "pg-partman", "kind": "external", - "needs": ["расписание партиционирования таблиц"], - "produces": ["авто-создание/удаление partition-таблиц по расписанию"], - "constraints": ["dormant — недоступно на native-Windows PG", "заменён Artisan partitions:create-months"], + "needs": [ + "partition-schedule" + ], + "produces": [ + "auto-partitions" + ], + "constraints": [ + "dormant — недоступно на native-Windows PG", + "заменён Artisan partitions:create-months" + ], "preview-form": "none", - "defaults": ["на поддерживаемой среде — по расписанию; на dev заменён ручным cron'ом"], - "key-decisions": ["окно/гранулярность партиций"], - "acceptance-criteria": ["партиции созданы/удалены по расписанию (на поддерживаемой среде)"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "на поддерживаемой среде — по расписанию; на dev заменён ручным cron'ом" + ], + "key-decisions": [ + "окно/гранулярность партиций" + ], + "acceptance-criteria": [ + "партиции созданы/удалены по расписанию (на поддерживаемой среде)" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/php-insights.contract.json b/docs/registry/contracts/php-insights.contract.json index dd0566a..ccf9758 100644 --- a/docs/registry/contracts/php-insights.contract.json +++ b/docs/registry/contracts/php-insights.contract.json @@ -1,12 +1,29 @@ { "skill": "php-insights", "kind": "external", - "needs": ["PHP-код для метрик качества"], - "produces": ["метрики: сложность, архитектура, code style score"], - "constraints": ["on-demand/CI, не блокирует; пороги 78/79/73", "ADR-013 BT4 НЕ Pint/Larastan; уникум — оси complexity+architecture"], + "needs": [ + "php-source" + ], + "produces": [ + "php-quality-metrics" + ], + "constraints": [ + "on-demand/CI, не блокирует; пороги 78/79/73", + "ADR-013 BT4 НЕ Pint/Larastan; уникум — оси complexity+architecture" + ], "preview-form": "none", - "defaults": ["composer insights; baseline-пороги"], - "key-decisions": ["какие оси/пороги важны"], - "acceptance-criteria": ["метрики не ниже baseline-порогов"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "composer insights; baseline-пороги" + ], + "key-decisions": [ + "какие оси/пороги важны" + ], + "acceptance-criteria": [ + "метрики не ниже baseline-порогов" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/pint.contract.json b/docs/registry/contracts/pint.contract.json index 102097b..9ad3cdc 100644 --- a/docs/registry/contracts/pint.contract.json +++ b/docs/registry/contracts/pint.contract.json @@ -1,12 +1,29 @@ { "skill": "pint", "kind": "external", - "needs": ["PHP-код для форматирования"], - "produces": ["отформатированный PHP по PSR-12 + Laravel style"], - "constraints": ["только форматирование стиля", "НЕ статанализ типов (Larastan)"], + "needs": [ + "php-source" + ], + "produces": [ + "formatted-php" + ], + "constraints": [ + "только форматирование стиля", + "НЕ статанализ типов (Larastan)" + ], "preview-form": "none", - "defaults": ["применять Laravel preset"], - "key-decisions": ["scope: staged-файлы vs весь php"], - "acceptance-criteria": ["0 расхождений со стилем Pint"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "применять Laravel preset" + ], + "key-decisions": [ + "scope: staged-файлы vs весь php" + ], + "acceptance-criteria": [ + "0 расхождений со стилем Pint" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/playwright-mcp.contract.json b/docs/registry/contracts/playwright-mcp.contract.json index d9155b8..3aee10d 100644 --- a/docs/registry/contracts/playwright-mcp.contract.json +++ b/docs/registry/contracts/playwright-mcp.contract.json @@ -1,12 +1,31 @@ { "skill": "playwright-mcp", "kind": "external", - "needs": ["URL или HTML-файл для управления", "намерение: скриншот / взаимодействие / сетевой трейс"], - "produces": ["скриншот / результат взаимодействия / снимок console+network"], - "constraints": ["внешний MCP — управляет headless-браузером", "НЕ a11y-проверка (это Pa11y)", "НЕ замена unit/e2e-тестам"], + "needs": [ + "browser-target", + "browser-action-intent" + ], + "produces": [ + "browser-interaction-result" + ], + "constraints": [ + "внешний MCP — управляет headless-браузером", + "НЕ a11y-проверка (это Pa11y)", + "НЕ замена unit/e2e-тестам" + ], "preview-form": "sample", - "defaults": ["read-first: снять снимок/состояние страницы до действия"], - "key-decisions": ["что проверяем: визуал, взаимодействие или сетевой трейс"], - "acceptance-criteria": ["ожидаемое состояние страницы подтверждено снимком/снапшотом"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "read-first: снять снимок/состояние страницы до действия" + ], + "key-decisions": [ + "что проверяем: визуал, взаимодействие или сетевой трейс" + ], + "acceptance-criteria": [ + "ожидаемое состояние страницы подтверждено снимком/снапшотом" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/postgres-mcp.contract.json b/docs/registry/contracts/postgres-mcp.contract.json index b8e289b..1fe37db 100644 --- a/docs/registry/contracts/postgres-mcp.contract.json +++ b/docs/registry/contracts/postgres-mcp.contract.json @@ -1,12 +1,28 @@ { "skill": "postgres-mcp", "kind": "external", - "needs": ["исторический SQL-запрос к dev-БД"], - "produces": ["результат SQL (исторически)"], - "constraints": ["historic — заменён Laravel Boost (#10); не используется"], + "needs": [ + "historical-sql-query" + ], + "produces": [ + "sql-result" + ], + "constraints": [ + "historic — заменён Laravel Boost (#10); не используется" + ], "preview-form": "none", - "defaults": ["заменён Boost #10"], - "key-decisions": ["использовать Boost #10 вместо этого узла"], - "acceptance-criteria": ["SQL-запросы идут через Boost #10, не через этот узел"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "заменён Boost #10" + ], + "key-decisions": [ + "использовать Boost #10 вместо этого узла" + ], + "acceptance-criteria": [ + "SQL-запросы идут через Boost #10, не через этот узел" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/postiz.contract.json b/docs/registry/contracts/postiz.contract.json index b903bf6..6afe639 100644 --- a/docs/registry/contracts/postiz.contract.json +++ b/docs/registry/contracts/postiz.contract.json @@ -1,12 +1,29 @@ { "skill": "postiz", "kind": "external", - "needs": ["контент-календарь / план публикаций в соцсети"], - "produces": ["запланированные публикации в 30+ соцсетях (VK/Telegram)"], - "constraints": ["self-host AGPL-3.0 без дистрибуции (ADR-015 MKT7)", "покрывает VK-постинг"], + "needs": [ + "social-content-plan" + ], + "produces": [ + "scheduled-social-posts" + ], + "constraints": [ + "self-host AGPL-3.0 без дистрибуции (ADR-015 MKT7)", + "покрывает VK-постинг" + ], "preview-form": "outline", - "defaults": ["контент-календарь, self-host"], - "key-decisions": ["каналы и расписание публикаций"], - "acceptance-criteria": ["публикации запланированы по календарю"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "контент-календарь, self-host" + ], + "key-decisions": [ + "каналы и расписание публикаций" + ], + "acceptance-criteria": [ + "публикации запланированы по календарю" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/rector.contract.json b/docs/registry/contracts/rector.contract.json index efb90ca..e074271 100644 --- a/docs/registry/contracts/rector.contract.json +++ b/docs/registry/contracts/rector.contract.json @@ -1,12 +1,29 @@ { "skill": "rector", "kind": "external", - "needs": ["PHP-код для авто-рефакторинга/version-upgrade"], - "produces": ["трансформированный PHP (upgrade/dead-code/modernization)"], - "constraints": ["вручную/CI, не блокирует коммит", "ADR-013: BT1 НЕ Pint (трансформация vs формат), BT2 комплементарен Larastan, BT3 НЕ deptrac"], + "needs": [ + "php-source" + ], + "produces": [ + "refactored-php" + ], + "constraints": [ + "вручную/CI, не блокирует коммит", + "ADR-013: BT1 НЕ Pint (трансформация vs формат), BT2 комплементарен Larastan, BT3 НЕ deptrac" + ], "preview-form": "dry-run", - "defaults": ["dry-run baseline; conservative ruleset"], - "key-decisions": ["какие правила трансформации"], - "acceptance-criteria": ["код трансформирован, тесты зелёные"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "dry-run baseline; conservative ruleset" + ], + "key-decisions": [ + "какие правила трансформации" + ], + "acceptance-criteria": [ + "код трансформирован, тесты зелёные" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/redis-mcp.contract.json b/docs/registry/contracts/redis-mcp.contract.json index 8dd3428..e4bf588 100644 --- a/docs/registry/contracts/redis-mcp.contract.json +++ b/docs/registry/contracts/redis-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "redis-mcp", "kind": "external", - "needs": ["вопрос о состоянии Redis/Memurai (ключи/очереди/TTL)"], - "produces": ["состояние Redis (чтение): ключи, очереди, TTL, паттерны"], - "constraints": ["READ-ONLY MCP к Redis/Memurai", "НЕ prod-ошибки (Sentry MCP)"], + "needs": [ + "redis-state-question" + ], + "produces": [ + "redis-state" + ], + "constraints": [ + "READ-ONLY MCP к Redis/Memurai", + "НЕ prod-ошибки (Sentry MCP)" + ], "preview-form": "none", - "defaults": ["read-only инспекция кэша/очередей"], - "key-decisions": ["что инспектировать: кэш, очередь, race"], - "acceptance-criteria": ["состояние кэша/очереди/race локализовано"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "read-only инспекция кэша/очередей" + ], + "key-decisions": [ + "что инспектировать: кэш, очередь, race" + ], + "acceptance-criteria": [ + "состояние кэша/очереди/race локализовано" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/roave-security.contract.json b/docs/registry/contracts/roave-security.contract.json index ca32d11..0771b84 100644 --- a/docs/registry/contracts/roave-security.contract.json +++ b/docs/registry/contracts/roave-security.contract.json @@ -1,12 +1,29 @@ { "skill": "roave-security", "kind": "external", - "needs": ["composer install/update"], - "produces": ["блок установки пакета с известным CVE"], - "constraints": ["conflict-список CVE на install/update", "НЕ SAST кода (Semgrep)"], + "needs": [ + "composer-install" + ], + "produces": [ + "composer-cve-block" + ], + "constraints": [ + "conflict-список CVE на install/update", + "НЕ SAST кода (Semgrep)" + ], "preview-form": "none", - "defaults": ["срабатывает автоматически на composer"], - "key-decisions": ["нет ручного выбора — автоматический conflict-гейт"], - "acceptance-criteria": ["установка с известным CVE заблокирована"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "срабатывает автоматически на composer" + ], + "key-decisions": [ + "нет ручного выбора — автоматический conflict-гейт" + ], + "acceptance-criteria": [ + "установка с известным CVE заблокирована" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/semgrep.contract.json b/docs/registry/contracts/semgrep.contract.json index d6f1534..1cfbf59 100644 --- a/docs/registry/contracts/semgrep.contract.json +++ b/docs/registry/contracts/semgrep.contract.json @@ -1,12 +1,30 @@ { "skill": "semgrep", "kind": "external", - "needs": ["PHP/JS/Vue-код для SAST"], - "produces": ["отчёт об уязвимостях кода (инъекции, небезопасная конфигурация, XSS)"], - "constraints": ["SAST бинарь + MCP", "НЕ секреты в diff (gitleaks)", "НЕ глубокий on-demand аудит (Trail of Bits)"], + "needs": [ + "code-for-sast" + ], + "produces": [ + "sast-report" + ], + "constraints": [ + "SAST бинарь + MCP", + "НЕ секреты в diff (gitleaks)", + "НЕ глубокий on-demand аудит (Trail of Bits)" + ], "preview-form": "none", - "defaults": ["npm run sast"], - "key-decisions": ["scope скана; реальная уязвимость vs false-positive"], - "acceptance-criteria": ["0 уязвимостей высокого риска"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "npm run sast" + ], + "key-decisions": [ + "scope скана; реальная уязвимость vs false-positive" + ], + "acceptance-criteria": [ + "0 уязвимостей высокого риска" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/sentry-mcp.contract.json b/docs/registry/contracts/sentry-mcp.contract.json index d3cbd41..559f381 100644 --- a/docs/registry/contracts/sentry-mcp.contract.json +++ b/docs/registry/contracts/sentry-mcp.contract.json @@ -1,12 +1,30 @@ { "skill": "sentry-mcp", "kind": "external", - "needs": ["production runtime ошибка для диагностики"], - "produces": ["события/ошибки/трассировки из Sentry (чтение)"], - "constraints": ["READ-ONLY MCP к self-hosted Sentry", "pending активации Б-1", "НЕ Redis-состояние (Redis MCP)"], + "needs": [ + "prod-runtime-error" + ], + "produces": [ + "sentry-events" + ], + "constraints": [ + "READ-ONLY MCP к self-hosted Sentry", + "pending активации Б-1", + "НЕ Redis-состояние (Redis MCP)" + ], "preview-form": "none", - "defaults": ["read-only диагностика"], - "key-decisions": ["какое событие/трассировку смотреть"], - "acceptance-criteria": ["причина prod-ошибки локализована по событию Sentry"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "read-only диагностика" + ], + "key-decisions": [ + "какое событие/трассировку смотреть" + ], + "acceptance-criteria": [ + "причина prod-ошибки локализована по событию Sentry" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/squawk.contract.json b/docs/registry/contracts/squawk.contract.json index d210f4a..8fb196b 100644 --- a/docs/registry/contracts/squawk.contract.json +++ b/docs/registry/contracts/squawk.contract.json @@ -1,12 +1,29 @@ { "skill": "squawk", "kind": "external", - "needs": ["SQL-миграция PostgreSQL"], - "produces": ["отчёт об опасных паттернах миграции (блокировки, без CONCURRENTLY, ненадёжный DEFAULT)"], - "constraints": ["линт миграций в pre-commit для database/migrations", "НЕ форматирование (pgFormatter)"], + "needs": [ + "sql-migration" + ], + "produces": [ + "migration-danger-report" + ], + "constraints": [ + "линт миграций в pre-commit для database/migrations", + "НЕ форматирование (pgFormatter)" + ], "preview-form": "none", - "defaults": ["прогон на staged миграциях"], - "key-decisions": ["блокирующая операция vs допустимая"], - "acceptance-criteria": ["0 опасных паттернов в миграции"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "прогон на staged миграциях" + ], + "key-decisions": [ + "блокирующая операция vs допустимая" + ], + "acceptance-criteria": [ + "0 опасных паттернов в миграции" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/stylelint.contract.json b/docs/registry/contracts/stylelint.contract.json index 554e807..54a8b53 100644 --- a/docs/registry/contracts/stylelint.contract.json +++ b/docs/registry/contracts/stylelint.contract.json @@ -1,12 +1,30 @@ { "skill": "stylelint", "kind": "external", - "needs": ["CSS-код в .vue SFC или .css-файлах"], - "produces": ["отчёт о нарушениях стиля CSS"], - "constraints": ["CSS в .vue SFC + css-файлы", "НЕ JS/TS (ESLint)", "НЕ a11y (Pa11y)"], + "needs": [ + "css-source" + ], + "produces": [ + "css-style-report" + ], + "constraints": [ + "CSS в .vue SFC + css-файлы", + "НЕ JS/TS (ESLint)", + "НЕ a11y (Pa11y)" + ], "preview-form": "none", - "defaults": ["порядок свойств + именование по конфигу проекта"], - "key-decisions": ["scope: staged-файлы vs весь css"], - "acceptance-criteria": ["0 нарушений стиля CSS"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "порядок свойств + именование по конфигу проекта" + ], + "key-decisions": [ + "scope: staged-файлы vs весь css" + ], + "acceptance-criteria": [ + "0 нарушений стиля CSS" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/telegram-mcp.contract.json b/docs/registry/contracts/telegram-mcp.contract.json index b8cd1d9..5eaf838 100644 --- a/docs/registry/contracts/telegram-mcp.contract.json +++ b/docs/registry/contracts/telegram-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "telegram-mcp", "kind": "external", - "needs": ["пост/действие в Telegram-канале"], - "produces": ["публикация/редактирование/аналитика Telegram-канала"], - "constraints": ["выделенный аккаунт через SESSION_STRING (только .env)", "ADR-015 MKT8"], + "needs": [ + "telegram-action" + ], + "produces": [ + "telegram-result" + ], + "constraints": [ + "выделенный аккаунт через SESSION_STRING (только .env)", + "ADR-015 MKT8" + ], "preview-form": "none", - "defaults": ["выделенный аккаунт, SESSION_STRING в .env"], - "key-decisions": ["канал и контент поста"], - "acceptance-criteria": ["пост опубликован / аналитика получена"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "выделенный аккаунт, SESSION_STRING в .env" + ], + "key-decisions": [ + "канал и контент поста" + ], + "acceptance-criteria": [ + "пост опубликован / аналитика получена" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/trivy.contract.json b/docs/registry/contracts/trivy.contract.json index 45744ff..307c682 100644 --- a/docs/registry/contracts/trivy.contract.json +++ b/docs/registry/contracts/trivy.contract.json @@ -1,12 +1,29 @@ { "skill": "trivy", "kind": "external", - "needs": ["Docker-образ для скана"], - "produces": ["отчёт о CVE в OS-пакетах и зависимостях образа"], - "constraints": ["скан Docker-образов в CI перед push в registry", "НЕ скан кода (Semgrep)"], + "needs": [ + "docker-image" + ], + "produces": [ + "image-cve-report" + ], + "constraints": [ + "скан Docker-образов в CI перед push в registry", + "НЕ скан кода (Semgrep)" + ], "preview-form": "none", - "defaults": ["trivy image перед push в Yandex Container Registry"], - "key-decisions": ["порог severity для блока"], - "acceptance-criteria": ["0 критичных CVE в образе"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "trivy image перед push в Yandex Container Registry" + ], + "key-decisions": [ + "порог severity для блока" + ], + "acceptance-criteria": [ + "0 критичных CVE в образе" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/unisender-go-mcp.contract.json b/docs/registry/contracts/unisender-go-mcp.contract.json index 1f8e8b5..5ce338c 100644 --- a/docs/registry/contracts/unisender-go-mcp.contract.json +++ b/docs/registry/contracts/unisender-go-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "unisender-go-mcp", "kind": "external", - "needs": ["массовая email-рассылка через Unisender Go"], - "produces": ["отправка маркетинговой email-рассылки"], - "constraints": ["DEFERRED — нет upstream MCP, нужна своя обёртка", "ADR-015 MKT5: маркетинговые рассылки НЕ транзакционный email; 152-ФЗ согласия cross-ref #77/#71"], + "needs": [ + "email-blast-task" + ], + "produces": [ + "email-blast-sent" + ], + "constraints": [ + "DEFERRED — нет upstream MCP, нужна своя обёртка", + "ADR-015 MKT5: маркетинговые рассылки НЕ транзакционный email; 152-ФЗ согласия cross-ref #77/#71" + ], "preview-form": "none", - "defaults": ["при наличии обёртки"], - "key-decisions": ["сегмент и согласия рассылки"], - "acceptance-criteria": ["рассылка отправлена с соблюдением 152-ФЗ согласий (при наличии обёртки)"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "при наличии обёртки" + ], + "key-decisions": [ + "сегмент и согласия рассылки" + ], + "acceptance-criteria": [ + "рассылка отправлена с соблюдением 152-ФЗ согласий (при наличии обёртки)" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/universal-icons-mcp.contract.json b/docs/registry/contracts/universal-icons-mcp.contract.json index 9ad054b..c1f2ea8 100644 --- a/docs/registry/contracts/universal-icons-mcp.contract.json +++ b/docs/registry/contracts/universal-icons-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "universal-icons-mcp", "kind": "external", - "needs": ["потребность в SVG-иконке (не-Lucide коллекция)"], - "produces": ["SVG-иконка из коллекции (Material/Tabler/Phosphor/...)"], - "constraints": ["только не-Lucide коллекции (ADR-006: Lucide → lucide-vue-next)", "raw-SVG, не компонент"], + "needs": [ + "svg-icon-need" + ], + "produces": [ + "svg-icon" + ], + "constraints": [ + "только не-Lucide коллекции (ADR-006: Lucide → lucide-vue-next)", + "raw-SVG, не компонент" + ], "preview-form": "sample", - "defaults": ["для Lucide использовать lucide-vue-next, не этот MCP"], - "key-decisions": ["коллекция и конкретная иконка"], - "acceptance-criteria": ["иконка вставлена из не-Lucide коллекции корректно"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "для Lucide использовать lucide-vue-next, не этот MCP" + ], + "key-decisions": [ + "коллекция и конкретная иконка" + ], + "acceptance-criteria": [ + "иконка вставлена из не-Lucide коллекции корректно" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/vitest.contract.json b/docs/registry/contracts/vitest.contract.json index 4fe439e..df629a6 100644 --- a/docs/registry/contracts/vitest.contract.json +++ b/docs/registry/contracts/vitest.contract.json @@ -1,12 +1,29 @@ { "skill": "vitest", "kind": "external", - "needs": ["Vue-компоненты/модули для unit/component-тестов"], - "produces": ["результат прогона Vitest (pass/fail)"], - "constraints": ["тесты Vue (jsdom, @vue/test-utils, Pinia)", "НЕ PHP-тесты (Pest)"], + "needs": [ + "js-vue-source" + ], + "produces": [ + "vitest-result" + ], + "constraints": [ + "тесты Vue (jsdom, @vue/test-utils, Pinia)", + "НЕ PHP-тесты (Pest)" + ], "preview-form": "none", - "defaults": ["npm run test:vue"], - "key-decisions": ["scope тестов"], - "acceptance-criteria": ["все Vue-тесты зелёные"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "npm run test:vue" + ], + "key-decisions": [ + "scope тестов" + ], + "acceptance-criteria": [ + "все Vue-тесты зелёные" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/volar.contract.json b/docs/registry/contracts/volar.contract.json index 1cb6682..7cac97f 100644 --- a/docs/registry/contracts/volar.contract.json +++ b/docs/registry/contracts/volar.contract.json @@ -1,12 +1,29 @@ { "skill": "volar", "kind": "external", - "needs": ["открытый .vue-файл в VSCode"], - "produces": ["IntelliSense / go-to-definition / hover / диагностика типов в редакторе"], - "constraints": ["VSCode-расширение (редактор-only)", "НЕ CI type-check (vue-tsc)"], + "needs": [ + "open-vue-file" + ], + "produces": [ + "editor-type-diagnostics" + ], + "constraints": [ + "VSCode-расширение (редактор-only)", + "НЕ CI type-check (vue-tsc)" + ], "preview-form": "none", - "defaults": ["работает в редакторе автоматически"], - "key-decisions": ["нет ручного выбора — редакторная служба"], - "acceptance-criteria": ["навигация/диагностика по .vue работают в редакторе"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "работает в редакторе автоматически" + ], + "key-decisions": [ + "нет ручного выбора — редакторная служба" + ], + "acceptance-criteria": [ + "навигация/диагностика по .vue работают в редакторе" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/vue-tsc.contract.json b/docs/registry/contracts/vue-tsc.contract.json index 145690e..bb7465f 100644 --- a/docs/registry/contracts/vue-tsc.contract.json +++ b/docs/registry/contracts/vue-tsc.contract.json @@ -1,12 +1,29 @@ { "skill": "vue-tsc", "kind": "external", - "needs": [".vue-компоненты для проверки типов"], - "produces": ["отчёт о несоответствиях типов в шаблонах/script"], - "constraints": ["полный type-check только в CI", "НЕ редакторная служба (Volar)"], + "needs": [ + "vue-component" + ], + "produces": [ + "vue-type-report" + ], + "constraints": [ + "полный type-check только в CI", + "НЕ редакторная служба (Volar)" + ], "preview-form": "none", - "defaults": ["прогон в CI"], - "key-decisions": ["scope проверки типов"], - "acceptance-criteria": ["0 ошибок типов vue-tsc"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "прогон в CI" + ], + "key-decisions": [ + "scope проверки типов" + ], + "acceptance-criteria": [ + "0 ошибок типов vue-tsc" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/yandex-metrika-mcp.contract.json b/docs/registry/contracts/yandex-metrika-mcp.contract.json index ded435b..b3f859e 100644 --- a/docs/registry/contracts/yandex-metrika-mcp.contract.json +++ b/docs/registry/contracts/yandex-metrika-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "yandex-metrika-mcp", "kind": "external", - "needs": ["вопрос веб-аналитики лендинга"], - "produces": ["данные Яндекс.Метрики (визиты/источники/гео/демография/поведение)"], - "constraints": ["READ-ONLY MCP; активен при живом лендинге (Б-1)", "НЕ подбор ключевых слов (Wordstat #79)"], + "needs": [ + "web-analytics-question" + ], + "produces": [ + "metrika-data" + ], + "constraints": [ + "READ-ONLY MCP; активен при живом лендинге (Б-1)", + "НЕ подбор ключевых слов (Wordstat #79)" + ], "preview-form": "none", - "defaults": ["read-only чтение метрик"], - "key-decisions": ["какие метрики смотреть"], - "acceptance-criteria": ["аналитика лендинга получена из Метрики"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "read-only чтение метрик" + ], + "key-decisions": [ + "какие метрики смотреть" + ], + "acceptance-criteria": [ + "аналитика лендинга получена из Метрики" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/docs/registry/contracts/yandex-wordstat-mcp.contract.json b/docs/registry/contracts/yandex-wordstat-mcp.contract.json index 544a9e8..0eddf30 100644 --- a/docs/registry/contracts/yandex-wordstat-mcp.contract.json +++ b/docs/registry/contracts/yandex-wordstat-mcp.contract.json @@ -1,12 +1,29 @@ { "skill": "yandex-wordstat-mcp", "kind": "external", - "needs": ["тема для подбора ключевых слов"], - "produces": ["частотность запросов РФ (Wordstat): сезонность, связанные фразы"], - "constraints": ["только Wordstat (5 read-only tools); Direct-мутации отключены (ADR-015)", "НЕ веб-аналитика (Метрика #78)"], + "needs": [ + "keyword-topic" + ], + "produces": [ + "wordstat-frequency" + ], + "constraints": [ + "только Wordstat (5 read-only tools); Direct-мутации отключены (ADR-015)", + "НЕ веб-аналитика (Метрика #78)" + ], "preview-form": "none", - "defaults": ["только Wordstat-модуль"], - "key-decisions": ["набор ключевых фраз"], - "acceptance-criteria": ["ключевые слова подобраны с частотностью РФ"], - "source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" } + "defaults": [ + "только Wordstat-модуль" + ], + "key-decisions": [ + "набор ключевых фраз" + ], + "acceptance-criteria": [ + "ключевые слова подобраны с частотностью РФ" + ], + "source": { + "version": "n/a", + "hash": "0000000000000000000000000000000000000000000000000000000000000000", + "path": "" + } } diff --git a/tools/vocab-rollout-full.test.mjs b/tools/vocab-rollout-full.test.mjs new file mode 100644 index 0000000..947d6e6 --- /dev/null +++ b/tools/vocab-rollout-full.test.mjs @@ -0,0 +1,40 @@ +import { describe, it, expect } from 'vitest'; +import { readFileSync, readdirSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; +import { buildRegistry } from './skill-contract-registry.mjs'; +import { loadVocabulary } from './capability-vocabulary.mjs'; +import { buildDependencyGraph } from './coverage-machine.mjs'; + +const here = dirname(fileURLToPath(import.meta.url)); +const cdir = join(here, '..', 'docs', 'registry', 'contracts'); +const vocabPath = join(here, '..', 'docs', 'registry', 'capability-vocabulary.json'); + +const FILES = readdirSync(cdir).filter((f) => f.endsWith('.contract.json')); +const entries = FILES.map((f) => ({ contract: JSON.parse(readFileSync(join(cdir, f), 'utf8')), currentContent: '' })); + +describe('Phase 2b ИТОГ — весь реестр проходит замок словаря (готовность к 2d)', () => { + const { tokens } = loadVocabulary({ path: vocabPath }); + + it('ВСЕ контракты needs/produces — только токены словаря (0 unknown)', () => { + const { contracts, errors } = buildRegistry(entries, { vocabTokens: tokens }); + expect(errors).toEqual([]); + expect(contracts.length).toBe(FILES.length); + expect(FILES.length).toBe(153); + }); + + it('граф непуст: рёбра рабочих цепочек существуют на полном наборе', () => { + const { contracts } = buildRegistry(entries, { vocabTokens: tokens }); + const { edges } = buildDependencyGraph(contracts); + expect(edges.length).toBeGreaterThan(0); + const has = (from, to) => edges.some((e) => e.from === from && e.to === to); + // A8-цепочка (нужды security-go-live кормятся пятью проверками) + expect(has('owasp-zap', 'security-go-live')).toBe(true); + expect(has('nuclei', 'security-go-live')).toBe(true); + // superpowers + expect(has('superpowers:writing-plans', 'superpowers:executing-plans')).toBe(true); + // кросс-плагинный мост + expect(has('frontend-design', 'design-plugin:design-handoff')).toBe(true); + expect(has('product-management:write-spec', 'superpowers:writing-plans')).toBe(true); + }); +});