Решение 51 отдало OpenSpec конвейеру и честно оставило хвост: проверка формы и сторож версии остались в docs.py, потому что своего скрипта у пайплайна не было ни одного. Хвост не косметический — это ровно то состояние, против которого написан весь канон: у файла два владельца, один заводит, другой проверяет, и разойтись они могут молча. 252 строки переехали в av-dev-pipeline/skills/openspec/scripts/openspec.py: пять проверок формы, сторож версии, сверка слепка с живым инструментом. Команды две — check --dir <корень> и form; коды выхода общие со всеми скриптами av-dev. Из docs.py удалены константы OPENSPEC_*, check_openspec, openspec_cli, check_openspec_fresh, rules_keys и подкоманда openspec-form; про config.yaml он больше не говорит ничего, кроме строки границы механизируемого — что форму смотрит чужой скрипт. openspec/specs/ он по-прежнему знает: это дом темы requirements и часть карты тем. Переезд оплатился сразу, и не тем, чего ждали. Прежняя проверка требовала, чтобы context называл docs/passport.md и CLAUDE.md, безусловно — то есть на проекте без канона документов требовала ссылку на несуществующий файл. Пока код жил в скрипте канона, допущение «канон есть» было незаметным: скрипт канона запускают там, где канон есть. В скрипте конвейера то же допущение стало видно на первом прогоне. Теперь адрес требуется только к существующему документу, отсутствие идёт строкой «не проверялось» с названной ценой — без канона конвейер работает вслепую. Заодно починен хвост от раскола плагинов: pyrefly project-includes в pyproject всё ещё указывали на av-dev-pm. Линтер на явных файлах работал, а на обходе проекта не проверял ничего. Проверено пятью случаями: нет openspec (1), годный конфиг (0), опечатка в имени артефакта под rules (1), проект без канона (0, с двумя строками «не проверялось»), неизвестная команда (2). Канон повышен до версии 10. Главное в записи — тихая потеря: форму раньше проверял docs.py check заодно, теперь нужен отдельный шаг openspec.py check в гейте, иначе незаменённый пример в config.yaml перестанет ловиться. Решение — 52. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
11 KiB
name, description
| name | description |
|---|---|
| openspec | Завести и настроить OpenSpec в проекте — openspec init --tools claude, замена закомментированного примера в openspec/config.yaml на настройку канонической формы (язык, правила именования capability, придирки валидатора, адреса паспорта и CLAUDE.md), проверка формы своим скриптом openspec.py (имя файла, схема, незаменённый пример, адреса документов, ключи rules против артефактов схемы) и сверка слепка с живой версией инструмента. Использовать, когда в проекте нет каталога openspec/, когда config.yaml остался примером из коробки, когда заводят новый проект или переводят чужой и дошли до шага OpenSpec, а также когда конвейер отказался работать без источника требований. Каталог openspec нужен именно конвейеру: без него не работают ни opsx:propose, ни ревью дизайна, ни сверка требований. |
OpenSpec в проекте
Каталог openspec/ — предпосылка конвейера, а не канона документов. Без него
не работают ни opsx:propose, ни ревью дизайна, ни review-specs: у требований
не остаётся дома. Поэтому заводит и настраивает его этот плагин — тот, кто по
OpenSpec и работает.
Канон документов о файле не высказывается вовсе: docs.py его не открывает и об
его отсутствии молчит. Проект без конвейера живёт без OpenSpec законно, и
проверять там нечего. За каноном остаётся одно — единственный дом: не
пересказан ли в context документ, у которого есть свой файл. Это суждение, а не
форма, и смотрит его агент.
Два шага, и второй важнее первого
1. Завести.
openspec init --tools claude
Команда кладёт ещё .claude/skills/openspec-* и .claude/commands/opsx/* — это
её нормальная работа, не трогай их.
2. Заменить пример. openspec init кладёт config.yaml, где context и
rules — закомментированный пример на английском. Файл из коробки хуже
отсутствующего: он есть, он валиден, имя правильное, — и читается как
настроенный, работая как пустой. Узнаётся это по уже написанному предложению: на
другом языке, с capability по имени пакета, без единого SHALL.
Пример заменяется целиком по образцу: references/config-skeleton.md.
Что туда пишут, а что нет
Это маршрутизатор, а не второй дом фактов. Внутрь идёт ровно то, что нужно в момент порождения артефакта и чего в этот момент ещё никто не открыл: язык, правила именования capability, придирки валидатора и адреса документов проекта.
Пересказ паспорта, инвариантов, конвенций и правил ревью сюда не переносится.
Место для второго дома здесь самое частое: context читается при порождении
каждого артефакта, туда удобно дописать «чтобы агент знал», и так заводятся копии
инвариантов, состава гейта и правил выбора метки. Расходятся они молча, а
замечают это в уже написанном предложении.
Разрез, по которому отличают одно от другого: утверждение, которое можно
опровергнуть, открыв другой файл проекта, — пересказ; строка, которая говорит,
какой файл открыть, — ссылка. Машина этот разрез не проверяет; его смотрит
агент doc-consistency из плагина канона, когда тот подключён.
Два адреса обязательны — docs/passport.md и CLAUDE.md: предложение пишется до
того, как кто-либо откроет docs/, и без них его пишут, не зная ни границы
домена, ни инвариантов. Отсутствие адреса к существующему документу
openspec.py check называет отказом; документа нет в проекте — нет и требования.
Инструмент
os="$CLAUDE_PLUGIN_ROOT/skills/openspec/scripts/openspec.py"
python3 $os check --dir <корень> # форма config.yaml в проекте
python3 $os form # слепок формы против живого OpenSpec
Коды выхода — общий словарь скриптов av-dev: 0 сошлось, 1 дрейф, 2 ошибка употребления, 3 окружение, 4 внутренний сбой. Ветвись на коде, а не на тексте. Различать 1 и 3 обязательно: «форма разошлась» — рабочая ситуация, «openspec не отвечает» — нерабочая.
check проверяет пять вещей, и каждая — про молчащий пробел, а не про вкус:
каталог есть; имя именно config.yaml (config.yml OpenSpec не читает и об этом
не сообщает); context и rules.specs не остались примером, а правила называют
SHALL; context называет паспорт и CLAUDE.md; ключи под rules: — имена
артефактов схемы, а не свободные слова.
Адреса требуются только к тем документам, которые в проекте есть. Канон
документов ставится отдельным плагином и может быть не подключён; требовать
ссылку на несуществующий файл значит требовать битую ссылку. Нет
docs/passport.md — проверка по нему идёт строкой «не проверялось», и там же
сказано, что без канона конвейер работает вслепую.
Форма сверяется с живым инструментом
Схема (spec-driven) и перечень артефактов (proposal, specs, design,
tasks) — состояние чужого инструмента, а не наше решение. OpenSpec
переименует артефакт: правила под прежним именем перестанут применяться, конфиг
останется выглядеть написанным, и молчат при этом все три стороны.
Сторож — сравнение версий. check каждым прогоном спрашивает openspec --version (десятые доли секунды) и сравнивает major.minor с той версией, на
которой форма сверялась; разошлось — замечание, не отказ, с именем команды.
Патч-версия в сравнение не берётся намеренно: формы она не меняет, а нагоняй на
каждый багфикс приучает пролистывать весь блок.
Перепроверяет openspec.py form: он спрашивает openspec templates --json, то
есть перечень артефактов текущей схемы, и печатает, что разошлось с константами.
Дорогой вызов вынесен из check сознательно — он стоит втрое дороже опроса
версии, а ответ меняется только вместе с версией. Чинится расхождение в
плагине, а не в проекте: константы скрипта, образец
references/config-skeleton.md и запись в журнал
версий канона.
Кто зовёт этот скилл
av-dev-docs:init— шагом заведения нового проекта, до первого документа;av-dev-docs:canonв режимеadopt— если на переводимом проекте каталога нет илиconfig.yamlостался примером;- человек — когда конвейер отказался работать без источника требований.
Вызов идёт через пространство имён, а не путём в дерево плагина. Не разрешился — плагина конвейера в проекте нет, и тогда OpenSpec заводит человек командой выше; скажи это строкой, а путь не выдумывай.
Чего этот скилл не делает
- Не пишет спеки и предложения. Это
opsx:proposeи пайплайн задачи. - Не ведёт документы канона — их дом плагин
av-dev-docs, и адреса вcontextтолько на них ссылаются. - Не чинит расхождение формы с версией OpenSpec в проекте. Оно чинится в плагине: константы скрипта, образец здесь, запись в журнал версий канона.
- Не судит, ссылается
contextна документы или пересказывает их. Машине этот разрез не виден; его смотрит агентdoc-consistencyиз плагина канона. Плагина нет — эту проверку не делает никто, и так и скажи.