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:
@@ -149,11 +149,12 @@ capability), `openspec/config.yaml`.
|
||||
1. `docs/.pm.json` с `{"canon": <текущая версия>}` и путём миграций, если БД есть;
|
||||
2. каталоги канона и скелет **по [references/skeletons.md](references/skeletons.md)**:
|
||||
незаполненное — одной честной информативной строкой, а не «TBD»;
|
||||
3. **OpenSpec, если его нет** — `openspec init --tools claude`, и `config.yaml`
|
||||
по тому же скелету. Каталог есть, а `config.yaml` из коробки — тот же случай,
|
||||
что отсутствие: закомментированный пример выглядит настройкой и не является
|
||||
ею. Пересказ инвариантов, конвенций и правил ревью из `context` вычисти
|
||||
ссылкой на дом — на переводимом проекте он там почти наверняка есть;
|
||||
3. **OpenSpec, если его нет или `config.yaml` остался примером** — **вызови
|
||||
Skill `av-dev-pipeline:openspec`**. Каталог принадлежит конвейеру, и команда
|
||||
заведения с формой файла живут там. Пересказ инвариантов, конвенций и правил
|
||||
ревью из `context` вычисти ссылкой на дом — на переводимом проекте он там
|
||||
почти наверняка есть. Вызов не разрешился — плагина конвейера нет, и это
|
||||
строка доклада, а не поломка: `docs.py` о каталоге тогда тоже молчит;
|
||||
4. переносы содержимого;
|
||||
5. каталог задач — **вызови скилл `av-dev-tasks:tasks`**, сценарий адаптации: он
|
||||
владеет форматом задач. Он же переименует транслитные слаги в английские и
|
||||
|
||||
@@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import NoReturn
|
||||
|
||||
CANON_VERSION = 8
|
||||
CANON_VERSION = 9
|
||||
|
||||
OK, DRIFT, USAGE, ENV, INTERNAL = 0, 1, 2, 3, 4
|
||||
|
||||
@@ -528,9 +528,15 @@ def check_openspec(root: Path, rep: Report) -> None:
|
||||
"""
|
||||
os_dir = root / "openspec"
|
||||
if not os_dir.is_dir():
|
||||
rep.error(
|
||||
"нет openspec/ — там дом темы requirements (openspec/specs/) и "
|
||||
f"настройка генерации артефактов; заводится `{OPENSPEC_INIT}`"
|
||||
# Каталог принадлежит конвейеру, а не канону: там дом темы requirements
|
||||
# и настройка генерации артефактов, и нужен он тому, кто по OpenSpec
|
||||
# работает. Проект без конвейера живёт без него законно, поэтому здесь
|
||||
# неприменимость, а не отказ. Заводит каталог скилл
|
||||
# av-dev-pipeline:openspec; команда названа на случай, если плагина нет.
|
||||
rep.skip(
|
||||
"нет openspec/ — проверка неприменима. Каталог заводит скилл "
|
||||
f"av-dev-pipeline:openspec (`{OPENSPEC_INIT}`); без конвейера "
|
||||
"он проекту не нужен"
|
||||
)
|
||||
return
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: init
|
||||
description: "Завести новый проект — сессия вопросов и ответов по свободному описанию замысла, из которой рождается первичная документация по канону av-dev: паспорт, CLAUDE.md с инвариантами и командами, модель угроз с периметром, первые цели в роадмапе и скелет остальных документов. Заводит и OpenSpec (openspec init) с настроенным openspec/config.yaml — дом темы requirements, без которого не работают ни propose, ни ревью. Использовать, когда начинают новый проект с нуля, когда есть только текст «что мне нужно и почему» и надо превратить его в рабочую документацию, когда просят провести стартовое интервью по брифу. Проект, где документация уже как-то ведётся, переводит скилл canon."
|
||||
description: "Завести новый проект — сессия вопросов и ответов по свободному описанию замысла, из которой рождается первичная документация по канону av-dev: паспорт, CLAUDE.md с инвариантами и командами, модель угроз с периметром, первые цели в роадмапе и скелет остальных документов. OpenSpec заводит не сам, а вызовом скилла av-dev-pipeline:openspec — каталог принадлежит конвейеру; плагина конвейера нет — шаг пропускается строкой доклада. Использовать, когда начинают новый проект с нуля, когда есть только текст «что мне нужно и почему» и надо превратить его в рабочую документацию, когда просят провести стартовое интервью по брифу. Проект, где документация уже как-то ведётся, переводит скилл canon."
|
||||
---
|
||||
|
||||
# Заведение нового проекта
|
||||
@@ -28,7 +28,6 @@ description: "Завести новый проект — сессия вопро
|
||||
| `security.md` | `conventions/` |
|
||||
| `docs/tasks/ROADMAP.md` — первые цели | `research/`, `adr/` |
|
||||
| `docs/.pm.json` | `review.md` — журнал пуст, настройка появится с первым ревью |
|
||||
| `openspec/config.yaml` | |
|
||||
|
||||
Честная строка информативна, а не «TBD»: «архитектуры пока нет: кода нет,
|
||||
заводится первой задачей». Проход читает её как факт.
|
||||
@@ -69,30 +68,28 @@ description: "Завести новый проект — сессия вопро
|
||||
|
||||
1. Прочитай бриф целиком. Выпиши, на какие блоки интервью ответ уже есть.
|
||||
2. Проведи интервью итерациями по ≤3 вопроса.
|
||||
3. **Заведи OpenSpec: `openspec init --tools claude`.** Каталог `openspec/` —
|
||||
часть канона, а не соседняя технология: в нём дом темы `requirements`, и без
|
||||
него не работают ни `opsx:propose`, ни ревью дизайна, ни сверка требований.
|
||||
Команда кладёт ещё `.claude/skills/openspec-*` и `.claude/commands/opsx/*` —
|
||||
это её нормальная работа, не трогай их.
|
||||
3. **OpenSpec — вызови Skill `av-dev-pipeline:openspec`.** Он заводит каталог и
|
||||
заменяет пример в `config.yaml` настройкой. Делается это **до первого
|
||||
документа**: без `openspec/` не работают ни `opsx:propose`, ни ревью дизайна,
|
||||
ни сверка требований. Каталог принадлежит конвейеру, а не канону, поэтому
|
||||
здесь только вызов — ни команды, ни формы файла `init` не знает.
|
||||
|
||||
**Вызов не разрешился — плагина конвейера в проекте нет.** Это законный исход,
|
||||
а не поломка: проект без конвейера живёт без OpenSpec. Скажи это строкой в
|
||||
докладе и иди дальше; `docs.py check` о каталоге тоже промолчит.
|
||||
4. Заведи `docs/.pm.json` с текущей версией канона.
|
||||
5. Напиши заполняемые документы. **Бриф переезжает в `passport.md`** и
|
||||
отдельным файлом не остаётся: два дома для одного замысла разойдутся на
|
||||
первом же уточнении.
|
||||
6. Заведи скелет остальных по [скелетам](../canon/references/skeletons.md) —
|
||||
каждый с честной строкой.
|
||||
7. **Заполни `openspec/config.yaml`** по тем же скелетам. Файл из коробки —
|
||||
закомментированный пример на английском; он **заменяется целиком**, потому что
|
||||
нетронутый выглядит настроенным, а работает как пустой. Пиши туда только то,
|
||||
что нужно **в момент порождения артефакта**: язык, правила именования
|
||||
capability, придирки валидатора и **адреса** `docs/passport.md` и `CLAUDE.md`.
|
||||
Инварианты, конвенции и правило ревью не пересказывай — у них есть дома, и
|
||||
второй дом разойдётся с первым молча.
|
||||
8. Каталог задач и первые цели — **вызови скилл `av-dev-tasks:tasks`**: он владеет
|
||||
форматом целей и задач.
|
||||
9. `docs.py check` из скилла `canon` — до отсутствия дрейфа. Замечания о
|
||||
7. Каталог задач и первые цели — **вызови скилл `av-dev-tasks:tasks`**: он владеет
|
||||
форматом целей и задач. Не разрешился — учёт задач остаётся владельцу, и это
|
||||
тоже строка доклада.
|
||||
8. `docs.py check` из скилла `canon` — до отсутствия дрейфа. Замечания о
|
||||
незаполненных плейсхолдерах остаются: их закрывает не `init`, а работа.
|
||||
10. Покажи человеку, что получилось, и **отдельным списком** — что выведено из
|
||||
брифа, что предположено, что осталось неизвестным. Правят по этим строкам.
|
||||
9. Покажи человеку, что получилось, и **отдельным списком** — что выведено из
|
||||
брифа, что предположено, что осталось неизвестным. Правят по этим строкам.
|
||||
|
||||
## Что дальше
|
||||
|
||||
|
||||
Reference in New Issue
Block a user