- DECISIONS.md (4040 строк, 65 тем) → decisions/, файл на тему плюс указатель; - буквенные метки решений заменены сквозными Р1–Р234, следствия получили префикс С при прежних номерах: схема букв выродилась до пятибуквенных и сломалась — `АЕАКЛ` была занята и темой 53, и темой 65; - 42 перекрёстные ссылки переписаны под новые номера и стали живыми; где номер означал тему, а слово стояло «решение», формулировка исправлена.
52 lines
5.1 KiB
Markdown
52 lines
5.1 KiB
Markdown
# 47. OpenSpec заводится скиллом, а его конфиг — часть канона (2026-08-07)
|
||
|
||
**Р186. `init` заводит OpenSpec сам, а не оставляет это человеку.** Каталог
|
||
`openspec/` был предпосылкой, о которой канон говорил, но за которой не следил:
|
||
`openspec/specs/` объявлен домом темы `requirements`, `config.yaml` описан
|
||
абзацем — а заводилось всё руками, и не проверялось ничего. Новый проект выходил
|
||
из `init` с полным каноном документов и без каталога, без которого не работают
|
||
ни `opsx:propose`, ни ревью дизайна, ни сверка требований. Команда названа
|
||
поимённо (`openspec init --tools claude`) в трёх местах — скилле, каноне и
|
||
отказе скрипта: отказ без команды заставляет искать её в другом месте.
|
||
|
||
**Р187. Файл из коробки хуже отсутствующего, и потому проверяется машиной.**
|
||
`openspec init` кладёт `config.yaml`, где `context` и `rules` —
|
||
закомментированный пример на английском. Такой файл читается как настроенный: он
|
||
есть, он валиден, имя правильное. Работает он как пустой, и узнаётся это по уже
|
||
написанному предложению — на другом языке, с capability по имени пакета, без
|
||
единого `SHALL`. `docs.py` проверяет четыре вещи, и каждая про молчащий пробел:
|
||
каталог есть; имя именно `config.yaml` (`config.yml` OpenSpec не читает и об
|
||
этом не сообщает); `context` и `rules.specs` не остались примером, а правила
|
||
называют `SHALL`; `context` называет `passport` и `CLAUDE.md`.
|
||
|
||
**Р188. Форма конфига — маршрутизатор, и это разрез, а не пожелание.**
|
||
Утверждение, которое можно опровергнуть, открыв другой файл проекта, — пересказ;
|
||
строка, которая говорит, какой файл открыть, — ссылка. `context` читается при
|
||
порождении **каждого** артефакта, туда удобно дописать «чтобы агент знал», и
|
||
именно поэтому в нём заводятся вторые дома инвариантов, конвенций, гейта и
|
||
правил ревью. Машина этот разрез не проверяет — отличить ссылку от пересказа она
|
||
не умеет, — и он отдан `doc-consistency` отдельным абзацем правила «один факт —
|
||
один дом», с `config.yaml`, добавленным ему во вход.
|
||
|
||
**Обязательными сделаны ровно два адреса — паспорт и `CLAUDE.md`.** Причина в
|
||
порядке работы: предложение пишется **до** того, как кто-либо откроет `docs/`, и
|
||
без этих двух строк его пишут, не зная ни границы домена, ни инвариантов.
|
||
Длинный список адресов превратил бы `context` во второй дом ровно тем способом,
|
||
против которого правило и заведено.
|
||
|
||
**Образец конфига лёг в канон, а не в конвейер**, как планировалось решением
|
||
[Р3](01-openspec-status.md). Форма документа принадлежит тому, кто владеет
|
||
каноном документов; конвейер её читатель. Иначе `av-dev-pipeline` завёл бы у
|
||
себя описание файла, который заводит и проверяет `av-dev-pm`, — тот же шов, что
|
||
разбирали, убирая имена проходов из канона.
|
||
|
||
## Что из этого следует
|
||
|
||
**С167. Предпосылка, за которой никто не следит, — не предпосылка, а
|
||
пожелание.** Если условие названо обязательным, его должен кто-то заводить и
|
||
кто-то проверять; иначе оно живёт ровно до первого проекта, где о нём забыли.
|
||
|
||
**С168. Заполненная форма и заполненный смысл — разные вещи, и первая маскирует
|
||
вторую.** Файл на месте, валиден, с правильным именем — и пуст по существу: это
|
||
худший вид пробела, потому что выглядит он как его отсутствие.
|