openspec уехал в конвейер: заводит его пайплайн, канон только высказывается

Версия 7 объявила openspec/ слотом канона: init его заводил, adopt тоже, образец
config.yaml лежал в скелетах, отсутствие каталога docs.py считал отказом. Разрез
был проведён не там. По OpenSpec работает конвейер — без каталога не запускаются
ни opsx:propose, ни ревью дизайна, ни сверка требований, — а канон документов о
нём только высказывался. Проект, которому конвейер не нужен, получал отказ за
отсутствие того, чем не пользуется.

Появился скилл av-dev-pipeline:openspec: заводит каталог, заменяет
закомментированный пример в config.yaml настройкой, объясняет разрез между
ссылкой и пересказом — утверждение, опровергаемое открытием другого файла, это
пересказ; строка, говорящая какой файл открыть, это ссылка. Образец переехал туда
же, в references/config-skeleton.md, а в скелетах канона остался указатель.

init и canon adopt OpenSpec больше не заводят, а зовут скилл конвейера через
пространство имён. Вызов не разрешился — плагина конвейера нет, и это строка
доклада, а не поломка: docs.py о каталоге тогда тоже молчит. Отсутствие openspec/
стало неприменимостью вместо отказа, остальные четыре проверки формы идут только
при живом каталоге. На фикстуре без openspec дрейф упал с 10 пунктов до 9.

Что осталось на месте и названо честно: проверка формы config.yaml и сторож
версии (docs.py openspec-form) пока живут в скрипте канона. Перенести их значит
завести в конвейере свой скрипт, а этого у него нет ни одного. У файла сейчас два
плагина — один заводит, другой проверяет, — и это временное состояние, а не
задуманное; в журнале версий оно записано так же.

Канон повышен до версии 9. Запись не двигает ни одного файла проекта: меняется
только то, кто их заводит. Но в ней названа потеря, которую легко не заметить —
проект по OpenSpec без установленного пайплайна теперь не услышит от docs.py
ничего про свою настройку, и молчание это законное.

Гейт зелёный, скиллов стало десять.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-08-09 14:17:19 +03:00
co-authored by Claude Opus 5
parent 1f31ac6afd
commit f0dd8f70c1
11 changed files with 278 additions and 118 deletions
+16 -8
View File
@@ -114,7 +114,7 @@ openspec/
| `database.*` | источник | `operations` — схема и настройки с числами |
| `CLAUDE.md`, `AGENTS.md` | источник | `autotests` (семантика гейта); инварианты — сквозные |
| `openspec/specs/` | источник | `requirements` |
| `openspec/config.yaml` | процессный | — (настройка порождения артефактов, слой **до** тем) |
| `openspec/config.yaml` | процессный | — (настройка порождения артефактов, слой **до** тем; заводит конвейер) |
| `tasks/` | процессный | — (чужое владение: плагин `av-dev-tasks`) |
| `review.*` | процессный | — (настройка самого конвейера, слой **над** темами) |
| `adr.*` | процессный | — |
@@ -432,11 +432,18 @@ kebab-case.** Причина не эстетическая: имя файла с
пересказ конвенций и инварианты сюда не пишутся: у них есть свои дома, и второй
дом разойдётся на первой же правке.
**Каталог `openspec/` — часть канона, а не соседняя технология.** В нём дом темы
`requirements`, и заводится он командой: `openspec init --tools claude`. Её
выполняет `init` на новом проекте и `adopt` на переводимом; из канона она названа
поимённо потому, что её печатает отказ `docs.py`, а отказ без команды заставляет
искать её в другом месте.
**Каталог `openspec/` принадлежит конвейеру, а не канону.** В нём дом темы
`requirements`, и нужен он тому, кто по OpenSpec работает: без каталога не
работают ни `opsx:propose`, ни ревью дизайна, ни сверка требований. Заводит и
настраивает его скилл `av-dev-pipeline:openspec`; `init` и `adopt` его только
зовут. Команда (`openspec init --tools claude`) названа здесь поимённо потому,
что её печатает вывод `docs.py`, а адрес без команды заставляет искать её в
другом месте.
**Отсюда и односторонность: канон о файле высказывается, но его не требует.**
`docs.py check` проверяет форму, **если каталог есть**, и говорит
«неприменимо», если его нет. Проект без конвейера живёт без OpenSpec законно, и
отказом это быть не может.
**Файл из коробки настройкой не является.** `openspec init` кладёт `config.yaml`,
где и `context`, и `rules` лежат закомментированным примером. Такой файл читается
@@ -447,7 +454,8 @@ kebab-case.** Причина не эстетическая: имя файла с
Проверяется пять вещей, и каждая — про молчащий пробел, а не про вкус:
1. **`openspec/` есть.** Нет — нет и дома темы `requirements`.
1. **`openspec/` есть.** Нет — проверка неприменима, и это не отказ: каталог
нужен конвейеру, а не канону. Остальные четыре идут только при живом каталоге.
2. **Имя файла `config.yaml`.** `config.yml` OpenSpec не читает и об этом не
сообщает: настройка, написанная в файл с таким именем, пропадает целиком.
3. **`context` и `rules.specs` не остались примером.** Правила для `specs`
@@ -570,7 +578,7 @@ OpenSpec переименует артефакт или сменит схему
```json
{
"canon": 8,
"canon": 9,
"migrations": "internal/store/migrations"
}
```
@@ -13,6 +13,44 @@ upgrade` идёт по записям снизу вверх от версии п
---
## Версия 9 — 2026-08-09
OpenSpec уехал в конвейер. Каталог `openspec/` версией 7 был объявлен слотом
канона: `init` его заводил, `adopt` тоже, образец `config.yaml` лежал в скелетах,
а отсутствие каталога `docs.py` считал отказом. Разрез был проведён не там. По
OpenSpec работает конвейер — без каталога не запускаются ни `opsx:propose`, ни
ревью дизайна, ни сверка требований, — а канон документов о нём только
высказывался. Проект, которому конвейер не нужен, получал отказ за отсутствие
того, чем не пользуется.
**Что появилось.** Скилл `av-dev-pipeline:openspec`: заводит каталог, заменяет
закомментированный пример в `config.yaml` настройкой, объясняет разрез между
ссылкой и пересказом. Образец файла переехал туда же — в
`references/config-skeleton.md` того скилла.
**Что изменилось.** `init` и `canon adopt` OpenSpec больше не заводят, а **зовут
скилл конвейера**; вызов не разрешился — плагина конвейера нет, и это строка
доклада, а не поломка. Отсутствие `openspec/` для `docs.py check` стало
неприменимостью вместо отказа: остальные четыре проверки формы идут только при
живом каталоге.
**Что осталось на месте и почему.** Проверка формы `config.yaml` и сторож версии
(`docs.py openspec-form`) пока живут в скрипте канона — переносить их значит
заводить в конвейере свой скрипт, а этого у него нет ни одного. Разрез названного
это не отменяет, но и не завершает: **у файла сейчас два плагина — один заводит,
другой проверяет**, и это временное состояние, а не задуманное.
**Что сделать проекту.**
1. Ничего не переносить: файлы проекта эта версия не двигает. Меняется только то,
кто их заводит.
2. Проверить, что плагин `av-dev-pipeline` установлен, если проект работает по
OpenSpec. Без него `docs.py check` про каталог промолчит — и молчание это
законное, так что отсутствие настройки перестанет ловиться само.
3. Проект **не** работает по OpenSpec: убедиться, что `openspec/` нет, и
перестать держать его пустым ради проверки. Она больше не требует каталога.
4. `docs/.pm.json`: `"canon": 9`.
## Версия 8 — 2026-08-09
Канон отпустил каталог задач. Плагин `av-dev-pm` расколот на `av-dev-docs`
@@ -419,89 +419,19 @@ severity стоит здесь, а не выводится каждым прох
## `openspec/config.yaml`
Каталог `openspec/` заводится командой — `openspec init --tools claude`, — и она
кладёт `config.yaml` с закомментированным примером внутри. Пример **заменяется
целиком**: нетронутый файл выглядит настроенным, а работает как пустой.
**Это маршрутизатор, а не второй дом фактов.** Сюда пишут ровно то, что нужно
**в момент порождения артефакта** и чего в этот момент ещё никто не открыл:
язык, правила именования capability, придирки валидатора и **адреса** документов
канона. Пересказ паспорта, инвариантов, конвенций и правил ревью сюда не
переносится: расходится он молча, а замечают это в уже написанном предложении.
```yaml
schema: spec-driven
context: |
Language: Russian
Пиши на русском, но:
- Структурные заголовки оставляй на английском:
## ADDED/MODIFIED/REMOVED Requirements, ### Requirement:, #### Scenario:
- Ключевые слова GIVEN/WHEN/THEN и RFC 2119 (SHALL/MUST/SHOULD) — на английском
- Технические термины, пути и код — на английском
Имена capabilities:
- Capability — это ПОВЕДЕНИЕ или домен системы, а не пакет кода (совпадение с
именем пакета допустимо, но не критерий).
- Существительное, понятное без знания кода: ingest, parsing, storage,
read-api. НЕ store/httpapi — это реализация.
- Гранулярность по принципу «требования меняются вместе». Дробить, когда в
одной спеке смешиваются разные заботы. Переименовать дёшево (RENAMED
Requirements) — не дроби преждевременно в маленьком проекте.
RFC 2119 — требование валидатора, не стиль:
- Каждое ### Requirement ОБЯЗАНО содержать литерал SHALL или MUST, иначе
`openspec validate` падает. Поэтому эти слова и WHEN/THEN не русифицируем.
Что это за проект — читай перед предложением, а не отсюда:
- docs/passport.md — цель, её граница (чем проект НЕ является), потребители,
типовые сценарии, референсы;
- CLAUDE.md — инварианты с severity и семантика гейта;
- docs/architecture.md — устройство; docs/security.md — периметр;
docs/adr/ — почему решено так; docs/research/ — что уже измерено.
Пересказа этих документов здесь нет намеренно: второй дом факта расходится с
первым молча, и заметно это становится в предложении, которое уже написано.
Ревью: правило выбора метки и состав проходов здесь не пересказываем — их дом
скилл av-dev-pipeline:review-pipeline, проектная настройка — docs/review.md.
Конвенции кода: механизированное проверяет гейт, прозой остаётся
docs/conventions/. Ни состав шагов гейта, ни перечень конвенций здесь не
пересказываем: и то и другое растёт по ходу задач.
Развилка или блокер — сперва prior art. Готовые решения смотрим в референсах
паспорта, отвергаем — с названной причиной, и причина идёт в design.md этого
же изменения.
rules:
proposal:
- Capabilities называй по поведению или домену системы, не по пакету кода
specs:
# Кавычки обязательны: без них YAML обрежет строку на первом '#'.
- "Каждое ### Requirement обязано содержать SHALL или MUST (иначе валидация падает)"
- "Сценарий — ровно #### (четыре решётки); три или список молча теряются"
- "SHALL/MUST должно стоять в ПЕРВОМ абзаце требования: валидатор смотрит только его"
- "Заголовки и WHEN/THEN/GIVEN — на английском, остальной текст на русском"
```
**Четыре правила для `specs` сняты отказами валидатора, а не выведены из
документации** — потому и записаны дословно: без них каждое второе предложение
узнаёт их падением `openspec validate --strict`. Блок `context` проект
дополняет своим (стек, разведка, особенности домена), но **адреса паспорта и
`CLAUDE.md` обязательны** — их отсутствие `docs.py check` называет отказом.
**Ключи под `rules:` — имена артефактов схемы**, а не свободные слова:
`proposal`, `specs`, `design`, `tasks`. Правило под чужим именем не применяется
и об этом не сообщает, поэтому `rules.spec` вместо `rules.specs` даёт конфиг,
выглядящий написанным и не работающий; `docs.py check` такой ключ называет.
Перечень артефактов задаёт OpenSpec, а не канон, — за его актуальностью следит
`docs.py openspec-form`.
**Образец переехал.** Файл заводит и заполняет плагин конвейера — скилл
`av-dev-pipeline:openspec`, — потому что по OpenSpec работает он, а не канон
документов. Проект без конвейера каталога `openspec/` не имеет вовсе, и образец
файла, которого у него нет, в скелетах канона лежал бы мёртвым грузом.
Канон о нём всё ещё **высказывается**, но только в одну сторону: `docs.py check`
проверяет форму, **если каталог есть**, и молчит, если его нет. Что именно
проверяется — [canon.md](canon.md), раздел `openspec/config.yaml`.
## `docs/.pm.json`
```json
{
"canon": 8
"canon": 9
}
```