feat(contracts): карточки phase-0 (#2-#9) + m3a form-инвариант всех карточек
8 карточек-контрактов phase-0: playwright-mcp, github-mcp, markdownlint, cspell, lychee, stylelint, gitleaks, pa11y (все external, zero-hash + path"" → G4 инертен). m3a расширен: «ВСЕ файлы contracts/ form-валидны + нет дрейфа» (loadRegistry errors + driftFlags пусты) — per-батч валидация прогоном vitest. m3a 3/3 GREEN. coverage: skill:executing-plans
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"skill": "cspell",
|
||||
"kind": "external",
|
||||
"needs": ["Markdown-текст для проверки орфографии", "пользовательский словарь проекта"],
|
||||
"produces": ["отчёт о неизвестных словах"],
|
||||
"constraints": ["ru/en орфография .md с пользовательским словарём", "НЕ стиль (markdownlint)", "НЕ грамматика"],
|
||||
"preview-form": "none",
|
||||
"defaults": ["учитывать cspell-words.txt"],
|
||||
"key-decisions": ["новый валидный термин → в словарь, а не подавлять находку"],
|
||||
"acceptance-criteria": ["0 неизвестных слов вне словаря"],
|
||||
"source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"skill": "github-mcp",
|
||||
"kind": "external",
|
||||
"needs": ["ссылка на repo/issue/PR", "намерение операции"],
|
||||
"produces": ["результат чтения или записи issue/PR/комментария"],
|
||||
"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": "" }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"skill": "gitleaks",
|
||||
"kind": "external",
|
||||
"needs": ["git diff или история репозитория"],
|
||||
"produces": ["находки утечек секретов (ключи/токены/пароли/DSN)"],
|
||||
"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": "" }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"skill": "lychee",
|
||||
"kind": "external",
|
||||
"needs": ["Markdown-файлы со ссылками"],
|
||||
"produces": ["отчёт о битых URL и якорях"],
|
||||
"constraints": ["внутренние + внешние ссылки и якоря .md", "НЕ стиль/орфография"],
|
||||
"preview-form": "none",
|
||||
"defaults": ["проверять и внутренние якоря, и внешние URL"],
|
||||
"key-decisions": ["внешний временно недоступный vs реально битый — различать"],
|
||||
"acceptance-criteria": ["0 битых ссылок/якорей"],
|
||||
"source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"skill": "markdownlint",
|
||||
"kind": "external",
|
||||
"needs": ["Markdown-файлы для линта"],
|
||||
"produces": ["отчёт о нарушениях стиля Markdown"],
|
||||
"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": "" }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"skill": "pa11y",
|
||||
"kind": "external",
|
||||
"needs": ["отрендеренная веб-страница / URL"],
|
||||
"produces": ["отчёт о нарушениях доступности WCAG 2.1 AA"],
|
||||
"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": "" }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"skill": "playwright-mcp",
|
||||
"kind": "external",
|
||||
"needs": ["URL или HTML-файл для управления", "намерение: скриншот / взаимодействие / сетевой трейс"],
|
||||
"produces": ["скриншот / результат взаимодействия / снимок console+network"],
|
||||
"constraints": ["внешний MCP — управляет headless-браузером", "НЕ a11y-проверка (это Pa11y)", "НЕ замена unit/e2e-тестам"],
|
||||
"preview-form": "sample",
|
||||
"defaults": ["read-first: снять снимок/состояние страницы до действия"],
|
||||
"key-decisions": ["что проверяем: визуал, взаимодействие или сетевой трейс"],
|
||||
"acceptance-criteria": ["ожидаемое состояние страницы подтверждено снимком/снапшотом"],
|
||||
"source": { "version": "n/a", "hash": "0000000000000000000000000000000000000000000000000000000000000000", "path": "" }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"skill": "stylelint",
|
||||
"kind": "external",
|
||||
"needs": ["CSS-код в .vue SFC или .css-файлах"],
|
||||
"produces": ["отчёт о нарушениях стиля CSS"],
|
||||
"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": "" }
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { validateContract } from './skill-contract.mjs';
|
||||
import { loadRegistry } from './skill-contract-registry.mjs';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const contractsDir = join(here, '..', 'docs', 'registry', 'contracts');
|
||||
@@ -16,4 +17,9 @@ describe('Машина 3-A — инварианты контрактов', () =>
|
||||
const c = JSON.parse(readFileSync(join(contractsDir, 'operations-process-doc.contract.json'), 'utf8'));
|
||||
expect(validateContract(c).ok).toBe(true);
|
||||
});
|
||||
it('ВСЕ файлы contracts/ form-валидны (нет ошибок формы/дублей/дрейфа)', () => {
|
||||
const reg = loadRegistry({ dir: contractsDir });
|
||||
expect(reg.errors).toEqual([]);
|
||||
expect(reg.driftFlags).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user