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:
@@ -27,7 +27,10 @@
|
|||||||
вычитывают их два отдельных прохода: `task-form` (форма записи) и
|
вычитывают их два отдельных прохода: `task-form` (форма записи) и
|
||||||
`task-wording` (язык записей);
|
`task-wording` (язык записей);
|
||||||
- `session` — ритуал между спринтами и ведение спринта.
|
- `session` — ритуал между спринтами и ведение спринта.
|
||||||
- **av-dev-pipeline** — исполнение. **Требует OpenSpec.**
|
- **av-dev-pipeline** — исполнение. **Требует OpenSpec и сам его заводит.**
|
||||||
|
- `openspec` — завести и настроить `openspec/` в проекте: `openspec init`,
|
||||||
|
замена примера в `config.yaml` настройкой канонической формы. Каталог
|
||||||
|
принадлежит конвейеру, а не канону: без конвейера он проекту не нужен;
|
||||||
- `task-pipeline` — задача через полный цикл SDD, от постановки до коммита;
|
- `task-pipeline` — задача через полный цикл SDD, от постановки до коммита;
|
||||||
- `task-batch` — несколько задач разом, каждая в своём worktree;
|
- `task-batch` — несколько задач разом, каждая в своём worktree;
|
||||||
- `review-pipeline` — конвейер ревью **по темам**: документ проекта либо
|
- `review-pipeline` — конвейер ревью **по темам**: документ проекта либо
|
||||||
|
|||||||
@@ -149,11 +149,12 @@ capability), `openspec/config.yaml`.
|
|||||||
1. `docs/.pm.json` с `{"canon": <текущая версия>}` и путём миграций, если БД есть;
|
1. `docs/.pm.json` с `{"canon": <текущая версия>}` и путём миграций, если БД есть;
|
||||||
2. каталоги канона и скелет **по [references/skeletons.md](references/skeletons.md)**:
|
2. каталоги канона и скелет **по [references/skeletons.md](references/skeletons.md)**:
|
||||||
незаполненное — одной честной информативной строкой, а не «TBD»;
|
незаполненное — одной честной информативной строкой, а не «TBD»;
|
||||||
3. **OpenSpec, если его нет** — `openspec init --tools claude`, и `config.yaml`
|
3. **OpenSpec, если его нет или `config.yaml` остался примером** — **вызови
|
||||||
по тому же скелету. Каталог есть, а `config.yaml` из коробки — тот же случай,
|
Skill `av-dev-pipeline:openspec`**. Каталог принадлежит конвейеру, и команда
|
||||||
что отсутствие: закомментированный пример выглядит настройкой и не является
|
заведения с формой файла живут там. Пересказ инвариантов, конвенций и правил
|
||||||
ею. Пересказ инвариантов, конвенций и правил ревью из `context` вычисти
|
ревью из `context` вычисти ссылкой на дом — на переводимом проекте он там
|
||||||
ссылкой на дом — на переводимом проекте он там почти наверняка есть;
|
почти наверняка есть. Вызов не разрешился — плагина конвейера нет, и это
|
||||||
|
строка доклада, а не поломка: `docs.py` о каталоге тогда тоже молчит;
|
||||||
4. переносы содержимого;
|
4. переносы содержимого;
|
||||||
5. каталог задач — **вызови скилл `av-dev-tasks:tasks`**, сценарий адаптации: он
|
5. каталог задач — **вызови скилл `av-dev-tasks:tasks`**, сценарий адаптации: он
|
||||||
владеет форматом задач. Он же переименует транслитные слаги в английские и
|
владеет форматом задач. Он же переименует транслитные слаги в английские и
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ openspec/
|
|||||||
| `database.*` | источник | `operations` — схема и настройки с числами |
|
| `database.*` | источник | `operations` — схема и настройки с числами |
|
||||||
| `CLAUDE.md`, `AGENTS.md` | источник | `autotests` (семантика гейта); инварианты — сквозные |
|
| `CLAUDE.md`, `AGENTS.md` | источник | `autotests` (семантика гейта); инварианты — сквозные |
|
||||||
| `openspec/specs/` | источник | `requirements` |
|
| `openspec/specs/` | источник | `requirements` |
|
||||||
| `openspec/config.yaml` | процессный | — (настройка порождения артефактов, слой **до** тем) |
|
| `openspec/config.yaml` | процессный | — (настройка порождения артефактов, слой **до** тем; заводит конвейер) |
|
||||||
| `tasks/` | процессный | — (чужое владение: плагин `av-dev-tasks`) |
|
| `tasks/` | процессный | — (чужое владение: плагин `av-dev-tasks`) |
|
||||||
| `review.*` | процессный | — (настройка самого конвейера, слой **над** темами) |
|
| `review.*` | процессный | — (настройка самого конвейера, слой **над** темами) |
|
||||||
| `adr.*` | процессный | — |
|
| `adr.*` | процессный | — |
|
||||||
@@ -432,11 +432,18 @@ kebab-case.** Причина не эстетическая: имя файла с
|
|||||||
пересказ конвенций и инварианты сюда не пишутся: у них есть свои дома, и второй
|
пересказ конвенций и инварианты сюда не пишутся: у них есть свои дома, и второй
|
||||||
дом разойдётся на первой же правке.
|
дом разойдётся на первой же правке.
|
||||||
|
|
||||||
**Каталог `openspec/` — часть канона, а не соседняя технология.** В нём дом темы
|
**Каталог `openspec/` принадлежит конвейеру, а не канону.** В нём дом темы
|
||||||
`requirements`, и заводится он командой: `openspec init --tools claude`. Её
|
`requirements`, и нужен он тому, кто по OpenSpec работает: без каталога не
|
||||||
выполняет `init` на новом проекте и `adopt` на переводимом; из канона она названа
|
работают ни `opsx:propose`, ни ревью дизайна, ни сверка требований. Заводит и
|
||||||
поимённо потому, что её печатает отказ `docs.py`, а отказ без команды заставляет
|
настраивает его скилл `av-dev-pipeline:openspec`; `init` и `adopt` его только
|
||||||
искать её в другом месте.
|
зовут. Команда (`openspec init --tools claude`) названа здесь поимённо потому,
|
||||||
|
что её печатает вывод `docs.py`, а адрес без команды заставляет искать её в
|
||||||
|
другом месте.
|
||||||
|
|
||||||
|
**Отсюда и односторонность: канон о файле высказывается, но его не требует.**
|
||||||
|
`docs.py check` проверяет форму, **если каталог есть**, и говорит
|
||||||
|
«неприменимо», если его нет. Проект без конвейера живёт без OpenSpec законно, и
|
||||||
|
отказом это быть не может.
|
||||||
|
|
||||||
**Файл из коробки настройкой не является.** `openspec init` кладёт `config.yaml`,
|
**Файл из коробки настройкой не является.** `openspec init` кладёт `config.yaml`,
|
||||||
где и `context`, и `rules` лежат закомментированным примером. Такой файл читается
|
где и `context`, и `rules` лежат закомментированным примером. Такой файл читается
|
||||||
@@ -447,7 +454,8 @@ kebab-case.** Причина не эстетическая: имя файла с
|
|||||||
|
|
||||||
Проверяется пять вещей, и каждая — про молчащий пробел, а не про вкус:
|
Проверяется пять вещей, и каждая — про молчащий пробел, а не про вкус:
|
||||||
|
|
||||||
1. **`openspec/` есть.** Нет — нет и дома темы `requirements`.
|
1. **`openspec/` есть.** Нет — проверка неприменима, и это не отказ: каталог
|
||||||
|
нужен конвейеру, а не канону. Остальные четыре идут только при живом каталоге.
|
||||||
2. **Имя файла `config.yaml`.** `config.yml` OpenSpec не читает и об этом не
|
2. **Имя файла `config.yaml`.** `config.yml` OpenSpec не читает и об этом не
|
||||||
сообщает: настройка, написанная в файл с таким именем, пропадает целиком.
|
сообщает: настройка, написанная в файл с таким именем, пропадает целиком.
|
||||||
3. **`context` и `rules.specs` не остались примером.** Правила для `specs`
|
3. **`context` и `rules.specs` не остались примером.** Правила для `specs`
|
||||||
@@ -570,7 +578,7 @@ OpenSpec переименует артефакт или сменит схему
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"canon": 8,
|
"canon": 9,
|
||||||
"migrations": "internal/store/migrations"
|
"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
|
## Версия 8 — 2026-08-09
|
||||||
|
|
||||||
Канон отпустил каталог задач. Плагин `av-dev-pm` расколот на `av-dev-docs`
|
Канон отпустил каталог задач. Плагин `av-dev-pm` расколот на `av-dev-docs`
|
||||||
|
|||||||
@@ -419,89 +419,19 @@ severity стоит здесь, а не выводится каждым прох
|
|||||||
|
|
||||||
## `openspec/config.yaml`
|
## `openspec/config.yaml`
|
||||||
|
|
||||||
Каталог `openspec/` заводится командой — `openspec init --tools claude`, — и она
|
**Образец переехал.** Файл заводит и заполняет плагин конвейера — скилл
|
||||||
кладёт `config.yaml` с закомментированным примером внутри. Пример **заменяется
|
`av-dev-pipeline:openspec`, — потому что по OpenSpec работает он, а не канон
|
||||||
целиком**: нетронутый файл выглядит настроенным, а работает как пустой.
|
документов. Проект без конвейера каталога `openspec/` не имеет вовсе, и образец
|
||||||
|
файла, которого у него нет, в скелетах канона лежал бы мёртвым грузом.
|
||||||
**Это маршрутизатор, а не второй дом фактов.** Сюда пишут ровно то, что нужно
|
|
||||||
**в момент порождения артефакта** и чего в этот момент ещё никто не открыл:
|
|
||||||
язык, правила именования 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`.
|
|
||||||
|
|
||||||
|
Канон о нём всё ещё **высказывается**, но только в одну сторону: `docs.py check`
|
||||||
|
проверяет форму, **если каталог есть**, и молчит, если его нет. Что именно
|
||||||
|
проверяется — [canon.md](canon.md), раздел `openspec/config.yaml`.
|
||||||
## `docs/.pm.json`
|
## `docs/.pm.json`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"canon": 8
|
"canon": 9
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from dataclasses import dataclass, field
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import NoReturn
|
from typing import NoReturn
|
||||||
|
|
||||||
CANON_VERSION = 8
|
CANON_VERSION = 9
|
||||||
|
|
||||||
OK, DRIFT, USAGE, ENV, INTERNAL = 0, 1, 2, 3, 4
|
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"
|
os_dir = root / "openspec"
|
||||||
if not os_dir.is_dir():
|
if not os_dir.is_dir():
|
||||||
rep.error(
|
# Каталог принадлежит конвейеру, а не канону: там дом темы requirements
|
||||||
"нет openspec/ — там дом темы requirements (openspec/specs/) и "
|
# и настройка генерации артефактов, и нужен он тому, кто по OpenSpec
|
||||||
f"настройка генерации артефактов; заводится `{OPENSPEC_INIT}`"
|
# работает. Проект без конвейера живёт без него законно, поэтому здесь
|
||||||
|
# неприменимость, а не отказ. Заводит каталог скилл
|
||||||
|
# av-dev-pipeline:openspec; команда названа на случай, если плагина нет.
|
||||||
|
rep.skip(
|
||||||
|
"нет openspec/ — проверка неприменима. Каталог заводит скилл "
|
||||||
|
f"av-dev-pipeline:openspec (`{OPENSPEC_INIT}`); без конвейера "
|
||||||
|
"он проекту не нужен"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: init
|
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/` |
|
| `security.md` | `conventions/` |
|
||||||
| `docs/tasks/ROADMAP.md` — первые цели | `research/`, `adr/` |
|
| `docs/tasks/ROADMAP.md` — первые цели | `research/`, `adr/` |
|
||||||
| `docs/.pm.json` | `review.md` — журнал пуст, настройка появится с первым ревью |
|
| `docs/.pm.json` | `review.md` — журнал пуст, настройка появится с первым ревью |
|
||||||
| `openspec/config.yaml` | |
|
|
||||||
|
|
||||||
Честная строка информативна, а не «TBD»: «архитектуры пока нет: кода нет,
|
Честная строка информативна, а не «TBD»: «архитектуры пока нет: кода нет,
|
||||||
заводится первой задачей». Проход читает её как факт.
|
заводится первой задачей». Проход читает её как факт.
|
||||||
@@ -69,29 +68,27 @@ description: "Завести новый проект — сессия вопро
|
|||||||
|
|
||||||
1. Прочитай бриф целиком. Выпиши, на какие блоки интервью ответ уже есть.
|
1. Прочитай бриф целиком. Выпиши, на какие блоки интервью ответ уже есть.
|
||||||
2. Проведи интервью итерациями по ≤3 вопроса.
|
2. Проведи интервью итерациями по ≤3 вопроса.
|
||||||
3. **Заведи OpenSpec: `openspec init --tools claude`.** Каталог `openspec/` —
|
3. **OpenSpec — вызови Skill `av-dev-pipeline:openspec`.** Он заводит каталог и
|
||||||
часть канона, а не соседняя технология: в нём дом темы `requirements`, и без
|
заменяет пример в `config.yaml` настройкой. Делается это **до первого
|
||||||
него не работают ни `opsx:propose`, ни ревью дизайна, ни сверка требований.
|
документа**: без `openspec/` не работают ни `opsx:propose`, ни ревью дизайна,
|
||||||
Команда кладёт ещё `.claude/skills/openspec-*` и `.claude/commands/opsx/*` —
|
ни сверка требований. Каталог принадлежит конвейеру, а не канону, поэтому
|
||||||
это её нормальная работа, не трогай их.
|
здесь только вызов — ни команды, ни формы файла `init` не знает.
|
||||||
|
|
||||||
|
**Вызов не разрешился — плагина конвейера в проекте нет.** Это законный исход,
|
||||||
|
а не поломка: проект без конвейера живёт без OpenSpec. Скажи это строкой в
|
||||||
|
докладе и иди дальше; `docs.py check` о каталоге тоже промолчит.
|
||||||
4. Заведи `docs/.pm.json` с текущей версией канона.
|
4. Заведи `docs/.pm.json` с текущей версией канона.
|
||||||
5. Напиши заполняемые документы. **Бриф переезжает в `passport.md`** и
|
5. Напиши заполняемые документы. **Бриф переезжает в `passport.md`** и
|
||||||
отдельным файлом не остаётся: два дома для одного замысла разойдутся на
|
отдельным файлом не остаётся: два дома для одного замысла разойдутся на
|
||||||
первом же уточнении.
|
первом же уточнении.
|
||||||
6. Заведи скелет остальных по [скелетам](../canon/references/skeletons.md) —
|
6. Заведи скелет остальных по [скелетам](../canon/references/skeletons.md) —
|
||||||
каждый с честной строкой.
|
каждый с честной строкой.
|
||||||
7. **Заполни `openspec/config.yaml`** по тем же скелетам. Файл из коробки —
|
7. Каталог задач и первые цели — **вызови скилл `av-dev-tasks:tasks`**: он владеет
|
||||||
закомментированный пример на английском; он **заменяется целиком**, потому что
|
форматом целей и задач. Не разрешился — учёт задач остаётся владельцу, и это
|
||||||
нетронутый выглядит настроенным, а работает как пустой. Пиши туда только то,
|
тоже строка доклада.
|
||||||
что нужно **в момент порождения артефакта**: язык, правила именования
|
8. `docs.py check` из скилла `canon` — до отсутствия дрейфа. Замечания о
|
||||||
capability, придирки валидатора и **адреса** `docs/passport.md` и `CLAUDE.md`.
|
|
||||||
Инварианты, конвенции и правило ревью не пересказывай — у них есть дома, и
|
|
||||||
второй дом разойдётся с первым молча.
|
|
||||||
8. Каталог задач и первые цели — **вызови скилл `av-dev-tasks:tasks`**: он владеет
|
|
||||||
форматом целей и задач.
|
|
||||||
9. `docs.py check` из скилла `canon` — до отсутствия дрейфа. Замечания о
|
|
||||||
незаполненных плейсхолдерах остаются: их закрывает не `init`, а работа.
|
незаполненных плейсхолдерах остаются: их закрывает не `init`, а работа.
|
||||||
10. Покажи человеку, что получилось, и **отдельным списком** — что выведено из
|
9. Покажи человеку, что получилось, и **отдельным списком** — что выведено из
|
||||||
брифа, что предположено, что осталось неизвестным. Правят по этим строкам.
|
брифа, что предположено, что осталось неизвестным. Правят по этим строкам.
|
||||||
|
|
||||||
## Что дальше
|
## Что дальше
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "av-dev-pipeline",
|
"name": "av-dev-pipeline",
|
||||||
"description": "Проведение задачи через полный цикл Spec Driven Development и конвейер ревью с детерминированным гейтом, сверкой со спеками, враждебными постановками, эксплуатационным постмортемом, независимой реализацией и обязательным триажем; плюс прогон нескольких задач разом по одной в изолированном worktree. Требует OpenSpec. Задача принимается и обычным текстом. Плагины av-dev-docs и av-dev-tasks опциональны: первый даёт документы канона, из которых проходы читают проектную конкретику, второй — учёт задач; без них прогон деградирует поразрядно и называет это строкой.",
|
"description": "Проведение задачи через полный цикл Spec Driven Development и конвейер ревью с детерминированным гейтом, сверкой со спеками, враждебными постановками, эксплуатационным постмортемом, независимой реализацией и обязательным триажем; плюс прогон нескольких задач разом по одной в изолированном worktree. Требует OpenSpec и сам его заводит скиллом openspec. Задача принимается и обычным текстом. Плагины av-dev-docs и av-dev-tasks опциональны: первый даёт документы канона, из которых проходы читают проектную конкретику, второй — учёт задач; без них прогон деградирует поразрядно и называет это строкой.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Anton Vakhrushev",
|
"name": "Anton Vakhrushev",
|
||||||
"email": "anwinged@gmail.com"
|
"email": "anwinged@gmail.com"
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
---
|
||||||
|
name: openspec
|
||||||
|
description: "Завести и настроить OpenSpec в проекте — openspec init --tools claude, замена закомментированного примера в openspec/config.yaml на настройку канонической формы (язык, правила именования capability, придирки валидатора, адреса паспорта и CLAUDE.md), проверка, что форма не разошлась с живой версией инструмента. Использовать, когда в проекте нет каталога openspec/, когда config.yaml остался примером из коробки, когда заводят новый проект или переводят чужой и дошли до шага OpenSpec, а также когда конвейер отказался работать без источника требований. Каталог openspec нужен именно конвейеру: без него не работают ни opsx:propose, ни ревью дизайна, ни сверка требований."
|
||||||
|
---
|
||||||
|
|
||||||
|
# OpenSpec в проекте
|
||||||
|
|
||||||
|
Каталог `openspec/` — **предпосылка конвейера**, а не канона документов. Без него
|
||||||
|
не работают ни `opsx:propose`, ни ревью дизайна, ни `review-specs`: у требований
|
||||||
|
не остаётся дома. Поэтому заводит и настраивает его этот плагин — тот, кто по
|
||||||
|
OpenSpec и работает.
|
||||||
|
|
||||||
|
Канон документов о файле всё ещё высказывается, но односторонне: `docs.py check`
|
||||||
|
проверяет форму `config.yaml`, **если каталог есть**, и молчит, если его нет.
|
||||||
|
Проект без конвейера живёт без OpenSpec законно.
|
||||||
|
|
||||||
|
## Два шага, и второй важнее первого
|
||||||
|
|
||||||
|
**1. Завести.**
|
||||||
|
|
||||||
|
```
|
||||||
|
openspec init --tools claude
|
||||||
|
```
|
||||||
|
|
||||||
|
Команда кладёт ещё `.claude/skills/openspec-*` и `.claude/commands/opsx/*` — это
|
||||||
|
её нормальная работа, не трогай их.
|
||||||
|
|
||||||
|
**2. Заменить пример.** `openspec init` кладёт `config.yaml`, где `context` и
|
||||||
|
`rules` — закомментированный пример на английском. **Файл из коробки хуже
|
||||||
|
отсутствующего:** он есть, он валиден, имя правильное, — и читается как
|
||||||
|
настроенный, работая как пустой. Узнаётся это по уже написанному предложению: на
|
||||||
|
другом языке, с capability по имени пакета, без единого `SHALL`.
|
||||||
|
|
||||||
|
Пример **заменяется целиком** по образцу:
|
||||||
|
[references/config-skeleton.md](references/config-skeleton.md).
|
||||||
|
|
||||||
|
## Что туда пишут, а что нет
|
||||||
|
|
||||||
|
**Это маршрутизатор, а не второй дом фактов.** Внутрь идёт ровно то, что нужно
|
||||||
|
**в момент порождения артефакта** и чего в этот момент ещё никто не открыл: язык,
|
||||||
|
правила именования capability, придирки валидатора и **адреса** документов
|
||||||
|
проекта.
|
||||||
|
|
||||||
|
Пересказ паспорта, инвариантов, конвенций и правил ревью сюда **не переносится**.
|
||||||
|
Место для второго дома здесь самое частое: `context` читается при порождении
|
||||||
|
каждого артефакта, туда удобно дописать «чтобы агент знал», и так заводятся копии
|
||||||
|
инвариантов, состава гейта и правил выбора метки. Расходятся они молча, а
|
||||||
|
замечают это в уже написанном предложении.
|
||||||
|
|
||||||
|
Разрез, по которому отличают одно от другого: **утверждение, которое можно
|
||||||
|
опровергнуть, открыв другой файл проекта, — пересказ; строка, которая говорит,
|
||||||
|
какой файл открыть, — ссылка.** Машина этот разрез не проверяет; его смотрит
|
||||||
|
агент `doc-consistency` из плагина канона, когда тот подключён.
|
||||||
|
|
||||||
|
Два адреса обязательны — `docs/passport.md` и `CLAUDE.md`: предложение пишется до
|
||||||
|
того, как кто-либо откроет `docs/`, и без них его пишут, не зная ни границы
|
||||||
|
домена, ни инвариантов. Их отсутствие `docs.py check` называет отказом.
|
||||||
|
|
||||||
|
## Форма сверяется с живым инструментом
|
||||||
|
|
||||||
|
Схема (`spec-driven`) и перечень артефактов (`proposal`, `specs`, `design`,
|
||||||
|
`tasks`) — **состояние чужого инструмента**, а не наше решение. OpenSpec
|
||||||
|
переименует артефакт: правила под прежним именем перестанут применяться, конфиг
|
||||||
|
останется выглядеть написанным, и молчат при этом все три стороны.
|
||||||
|
|
||||||
|
Сторож — сравнение версий, и живёт он пока в `docs.py` плагина канона:
|
||||||
|
|
||||||
|
```
|
||||||
|
python3 <канон>/skills/canon/scripts/docs.py openspec-form
|
||||||
|
```
|
||||||
|
|
||||||
|
`check` каждым прогоном сравнивает `major.minor` установленного OpenSpec с той
|
||||||
|
версией, на которой форма сверялась, и при расхождении просит эту команду. Она
|
||||||
|
ничего не правит — спрашивает инструмент и печатает, что разошлось. **Чинится
|
||||||
|
расхождение в плагине, а не в проекте.**
|
||||||
|
|
||||||
|
Плагина канона в проекте нет — сторожа тоже нет, и это надо назвать строкой, а не
|
||||||
|
считать, что форма верна.
|
||||||
|
|
||||||
|
## Кто зовёт этот скилл
|
||||||
|
|
||||||
|
- `av-dev-docs:init` — шагом заведения нового проекта, до первого документа;
|
||||||
|
- `av-dev-docs:canon` в режиме `adopt` — если на переводимом проекте каталога нет
|
||||||
|
или `config.yaml` остался примером;
|
||||||
|
- человек — когда конвейер отказался работать без источника требований.
|
||||||
|
|
||||||
|
Вызов идёт **через пространство имён**, а не путём в дерево плагина. Не
|
||||||
|
разрешился — плагина конвейера в проекте нет, и тогда OpenSpec заводит человек
|
||||||
|
командой выше; скажи это строкой, а путь не выдумывай.
|
||||||
|
|
||||||
|
## Чего этот скилл не делает
|
||||||
|
|
||||||
|
- **Не пишет спеки и предложения.** Это `opsx:propose` и пайплайн задачи.
|
||||||
|
- **Не ведёт документы канона** — их дом плагин `av-dev-docs`, и адреса в
|
||||||
|
`context` только на них ссылаются.
|
||||||
|
- **Не чинит расхождение формы с версией OpenSpec в проекте.** Оно чинится в
|
||||||
|
плагине: константы скрипта, образец здесь, запись в журнал версий канона.
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
# Образец `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`.
|
||||||
@@ -52,8 +52,9 @@ description: "Конвейер ревью изменения, устроенны
|
|||||||
требований. **Проект без OpenSpec этим конвейером не проверяется** — подключай
|
требований. **Проект без OpenSpec этим конвейером не проверяется** — подключай
|
||||||
OpenSpec, а не понижай прогон: ветка деградации здесь не пишется, потому что
|
OpenSpec, а не понижай прогон: ветка деградации здесь не пишется, потому что
|
||||||
непроверенная ветка деградации хуже честного отказа. Заводить руками не надо:
|
непроверенная ветка деградации хуже честного отказа. Заводить руками не надо:
|
||||||
`av-dev-docs:init` делает `openspec init` на новом проекте, `canon adopt` — на
|
этим владеет скилл `av-dev-pipeline:openspec` — он заводит каталог и заменяет
|
||||||
переводимом, и оба кладут `openspec/config.yaml` канонической формы.
|
пример в `config.yaml` настройкой. Его же зовут `av-dev-docs:init` на новом
|
||||||
|
проекте и `canon adopt` на переводимом.
|
||||||
- **Документы канона** — см. следующий раздел.
|
- **Документы канона** — см. следующий раздел.
|
||||||
- **Проектные копии этих скиллов и агентов удаляются при установке.** Если в
|
- **Проектные копии этих скиллов и агентов удаляются при установке.** Если в
|
||||||
проекте уже лежат свои `.claude/skills/review-pipeline`,
|
проекте уже лежат свои `.claude/skills/review-pipeline`,
|
||||||
|
|||||||
Reference in New Issue
Block a user