Files
dev-skills/av-dev-pm/skills/canon/references/changelog.md
T
avandClaude Opus 5 6ff12fedd5 форма config.yaml сверяется с живым openspec, а не с памятью
Проверка формы знала имя схемы и перечень артефактов константами — и это не наше
решение, а состояние чужого инструмента. OpenSpec переименует артефакт: правила
под прежним именем перестанут применяться, конфиг останется выглядеть
написанным, канон продолжит требовать прежнее. Молчат при этом все три стороны,
и заметить расхождение было некому.

Сторожем поставлено сравнение версий. check спрашивает openspec --version —
десятые доли секунды — и сравнивает major.minor с той, на которой форма
сверялась. Разошлось — замечание, не отказ, с именем команды, которая
перепроверяет. Патч-версия в сравнение не берётся намеренно: формы она не меняет,
а нагоняй на каждый багфикс приучает пролистывать весь блок.

Перепроверяет docs.py openspec-form: берёт openspec templates --json, то есть
перечень артефактов текущей схемы, и печатает, что разошлось с константами.
Дорогой вызов вынесен из check сознательно — он стоит втрое дороже опроса версии,
а ответ меняется только вместе с версией. Дешёвая проверка служит воротами
дорогой, и дорогая не ржавеет, потому что зовут её не по памяти. Чинится
расхождение в плагине, а не в проекте, и команда печатает три адреса правки
списком: константы скрипта, скелет, журнал версий канона.

Пятой проверкой формы стали ключи под rules: — это имена артефактов, и правило,
адресованное несуществующему, не применяется молча. rules.spec вместо
rules.specs даёт конфиг, выглядящий написанным и не работающий.

Первый вариант этой проверки искал ключи отступом по всему файлу и нашёл их
внутри литерального блока context: строки «Language: Russian» и
«av-dev-pm:review-pipeline» выглядят ключами. Оба живых проекта из-за этого
покраснели на правде. Теперь разбор идёт от строки rules: до следующего ключа
нулевой колонки; на тех же проектах чисто, а опечатка в имени артефакта
по-прежнему находится.

Решение — 48.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-07 12:07:46 +03:00

515 lines
48 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Журнал версий канона
Одна запись на версию. Проект знает свою версию из `docs/.pm.json`; `canon
upgrade` идёт по записям снизу вверх от версии проекта до текущей и делает то,
что в них названо.
Правило записи: **что добавилось, что переехало, что удалено, что сделать
проекту**. Без последнего пункта запись бесполезна — по ней и работает
`upgrade`.
Версия — целое число. Обратной совместимости у канона нет: есть «приведён» и «не
приведён».
---
## Версия 7 — 2026-08-07
`openspec/` был предпосылкой, о которой канон говорил, но за которой не следил.
Каталог назван в раскладке, `openspec/specs/` объявлен домом темы `requirements`,
`config.yaml` описан абзацем — а заводил всё это человек руками, и проверялось
из перечисленного ничего. Заведение нового проекта проходило мимо: `init`
собирал документы канона и оставлял проект без каталога, без которого не работают
ни `opsx:propose`, ни ревью дизайна, ни сверка требований.
Хуже отсутствия оказался файл из коробки. `openspec init` кладёт `config.yaml`,
где `context` и `rules` — закомментированный пример на английском. Такой файл
читается как настроенный: он есть, он валиден, имя правильное. Работает он как
пустой, и узнаётся это по предложению, написанному на другом языке, с
capability по имени пакета и без единого `SHALL`.
**Что изменилось:**
1. **`init` заводит OpenSpec сам** — `openspec init --tools claude`, до первого
документа канона. Команда названа в каноне поимённо, потому что её печатает
отказ `docs.py`.
2. **У `openspec/config.yaml` появилась каноническая форма** и скелет в
`skeletons.md`. Содержание — только то, что нужно **в момент порождения
артефакта**: язык, правила именования capability, придирки валидатора и
**адреса** документов канона. Пересказ паспорта, инвариантов, конвенций и
правил ревью в него не переносится.
3. **`docs.py check` проверяет пять вещей:** каталог `openspec/` есть; файл
называется `config.yaml` (`config.yml` OpenSpec читать не станет и об этом не
сообщит); `context` и `rules.specs` не остались примером, а правила для
`specs` называют `SHALL`; `context` называет `passport` и `CLAUDE.md`; ключи
под `rules:` — имена артефактов схемы, а не опечатки.
4. **За свежестью формы следит машина, а не память.** Схема и перечень
артефактов — слепок чужого инструмента; `check` сравнивает `major.minor`
установленного OpenSpec с версией, на которой форма сверялась, и при
расхождении даёт замечание. Перепроверяет `docs.py openspec-form`, и чинится
расхождение **в плагине, а не в проекте**.
5. **Шестое проверяет агент.** Отличить ссылку на документ от пересказа документа
машина не умеет — это работа `doc-consistency`, и в таблице «Что проверяет
машина, а что человек» она стоит строкой.
**Что переехало:** ничего в раскладке `docs/`. Ни один файл не переименовывается
и не перемещается.
**Что сделать проекту:**
1. Нет `openspec/` — завести: `openspec init --tools claude`. Команда кладёт ещё
и `.claude/skills/openspec-*` с `.claude/commands/opsx/*`; это её нормальная
работа, удалять их не надо.
2. Открыть `openspec/config.yaml` и привести к скелету из
[skeletons.md](skeletons.md): блок `context` с языком, правилами именования
capability, требованием `SHALL` и **адресами** `docs/passport.md` и
`CLAUDE.md`; блок `rules` с четырьмя правилами для `specs`.
3. **Вычистить из `context` пересказ.** Инварианты, перечень конвенций, состав
шагов гейта, правило выбора метки и состав проходов ревью — заменить ссылкой
на дом. Признак пересказа простой: строку можно опровергнуть, открыв другой
файл проекта.
4. Проверить имя файла: `config.yml` переименовать в `config.yaml`. Если жили оба
— содержимое `.yml` до сих пор не читалось никем, и переносить из него нужно
именно то, чего нет в `.yaml`.
5. `docs/.pm.json`: `"canon": 7`.
---
## Версия 6 — 2026-08-07
Версия 5 объявила: **каждый документ `docs/` — тема ревью**. Правило оказалось
верным ровно наполовину и потому вредным целиком. Паспорт и схему хранилища
ревью читает, но темами они не являются — они задают границу, по которой судит
чужая тема. Журнал решений и журнал наблюдений ревью изменения не нужны вовсе:
ADR объясняет прошлое решение, а не предъявляет требование к изменению.
Разметчик, применявший плоское правило буквально, обязан был либо завести
фантомные темы `passport`, `adr`, `database`, `research` и продублировать ими
работу тем `architecture` и `operations`, либо потерять четыре документа молча —
а молчащая потеря и есть то, против чего канон написан.
**Что изменилось:**
1. **Три категории документов вместо одной.** Разрез проверяемый: можно ли по
документу сказать «в этом изменении сделано не так»? **Тема** — да, прямо
(`conventions`, `security`, `architecture`, свои документы проекта).
**Источник темы** — нет, но он задаёт границу для чужой темы (`passport.*`
`architecture`, `database.*``operations`, `CLAUDE.md``autotests`,
`openspec/specs/``requirements`). **Процессный документ** — нет, он про то,
как мы работаем (`tasks/`, `review.*`, `adr.*`, `research.*`, `.pm.json`).
2. **Категории `источник` и `процессный` закрыты, категория `тема` открыта.**
Прежде открытым был весь список, и «не темы ровно две» противоречило
собственной раскладке канона. Теперь пополняется только одно множество, и
документ, которого нет в раскладке, — однозначно своя тема проекта.
3. **`adr/` и `research/` уходят из входа ревью изменения.** Прогон их больше не
открывает. Проверяться они не перестали: ADR без ссылки на архивный
`design.md`, замена без парного статуса, число без провенанса — это по-прежнему
работа `doc-consistency` и `doc-code-drift`, на сессии между спринтами.
4. **`docs.py` печатает категорию в отказе.** «Нет источника passport» читается
иначе, чем «нет темы security». Обязательность при этом не изменилась:
заводятся все документы одинаково и с первого дня.
5. **У задачи появилась метка — `small`, `medium` или `large`.** Это итог
классификации и **единственный вход, по которому конвейер выбирает
исполнителей** на обеих стадиях ревью. Прежние имена `quick`, `standard` и
`wide` описывали глубину прогона, то есть свойство ревью; метка описывает
**задачу** — а выбирают по ней одно и то же. Слово «ступень» уходит:
у одной вещи одно имя.
6. **Метка выводится из двух осей и не равна ни одной из них.** Размер (малое,
среднее, крупное) и сложность (знакомое, незнакомое); метка — максимум по
ним. Малое **незнакомое** изменение получает `large`, трогая один узел, —
поэтому размер и метка пишутся отдельными строками, и выводить одно из
другого нельзя.
**Цена, записанная явно:** расхождение изменения с записанным решением прогоном
больше не ловится. Раньше архитектурный проход мог сказать «здесь отменено
решение ADR-2026-03-11, парного статуса нет»; теперь это скажет только сверка
документации. Сделка сознательная: чтение всего каталога решений оплачивалось на
каждой задаче, а срабатывало на единицах.
**Что переехало:** ничего в раскладке. Ни один файл не переименовывается и не
перемещается.
**Что сделать проекту:**
1. `docs/review.*`, подраздел «Вопросы по темам»: убрать вопросы, адресованные
`passport`, `database`, `adr`, `research` и `review` — **ни одно из этих имён
больше не тема**. Под каноном 5 темой был каждый документ `docs/`, поэтому
такие вопросы там законны и почти наверняка есть. Переадресовать:
про границу домена и про решение → `architecture`; про хранилище, настройку и
измеренное число → `operations`. Вопрос, который никуда не переадресовывается,
удалить, а не оставить висеть: адресованный несуществующей теме, он не
задаётся никем и молча.
2. Там же, «Недоступно проверке»: те же пять имён убрать из разнесения по темам,
переразнеся содержимое по оставшимся.
3. Там же: подраздел **«Триггеры профиля» → «Триггеры метки»**, и разнести его
на **три** списка вместо двух — «крупное здесь» (про объём), «незнакомое
здесь» (про форму решения) и «мелкое здесь» (опускает до `small`). Раньше
первые две оси были склеены в один список, и потому объём в правило по факту
не входил.
4. **Переименовать метки прогона везде, где проект их называет** — в «Триггерах
метки», в «Недоступно проверке», в журнале дефектов: `quick`**`small`**,
`standard`**`medium`**, `wide`**`large`**. Метка это итог классификации
задачи, и три её значения — часть общего словаря канона и конвейера. Слово
«ступень» из документов уходит: у одной вещи одно имя.
5. Проверить, что свои темы проекта не совпадают именем с закрытыми категориями:
`docs/passport/`, `docs/adr/`, `docs/research/`, `docs/database/`,
`docs/review/` — это слоты канона, а не свои темы, и своим смыслом их
наполнять нельзя.
6. Ничего не заводить и не удалять: раскладка канона 6 совпадает с раскладкой
канона 5 файл в файл.
7. `docs/.pm.json`: `"canon": 6`.
---
## Версия 5 — 2026-08-06
Канон перестал быть списком файлов и стал **списком тем ревью**. Раскладка та же,
но читается иначе: документ в `docs/` — это направление проверки, а не просто
текст. Отсюда три правки, и все три развязывают то, что раньше было жёстко
сцеплено.
**Что изменилось:**
1. **Тема живёт файлом или каталогом, на выбор проекта.** `docs/security.md` и
`docs/security/` — одно и то же; тема разрослась, стала каталогом с
`README.md` — канон не сменился и версия не двинулась. Прежде форма была
задана поимённо: `conventions`, `research` и `adr` обязаны были быть
каталогами, остальные — файлами, и обосновать это было нечем. Обе формы сразу
— ошибка: два дома для одного факта расходятся молча.
2. **Список тем открытый.** Всё, что проект кладёт в `docs/`, становится темой
ревью и попадает в план каждого прогона; именной оптики у такой темы нет, её
разбирает общий проход конвейера, заведённый ровно за этим.
Прежде `docs.py` называл незнакомый файл «вне канона» — теперь называет своей
темой проекта и перечисляет их в отчёте. Не темы ровно две: `docs/tasks/` и
`docs/review.*`.
3. **`AGENTS.md` рядом с `CLAUDE.md` — законно.** Он почти стандарт; обязателен
по-прежнему только `CLAUDE.md`, но если лежат оба, читаются оба, и проверки
канона смотрят на второй так же, как на первый.
**Что переехало:**
- в `docs/review.*`: **«Вопросы к проходам» → «Вопросы по темам»**, форма
`<тема>: <вопрос> (<провенанс>)`. Причина не косметическая: вопрос,
адресованный проходу, перестал задаваться молча в тот день, когда тот уехал в
верхнюю ступень ревью. Тема переезд прохода переживает, имя прохода — нет;
- там же **«Недоступно проверке» — по темам**, оба подраздела.
**Что сделать проекту:**
1. Ничего не переименовывать, если всё уже разложено по канону 4: обе формы
дома законны, и текущая — одна из них.
2. `docs/review.*`, подраздел «Вопросы к проходам»: переименовать в «Вопросы по
темам» и переадресовать каждый вопрос теме вместо имени прохода. Темы ядра —
`requirements`, `autotests`, `conventions`, `architecture`, `security`,
`operations`.
3. Там же «Недоступно проверке»: разнести обе половины по темам.
4. Проверить, не лежит ли в `docs/` документ, который раньше считался лишним и
потому не заводился. Теперь он законен и станет темой ревью — это и есть
способ добавить проверку, которой в конвейере нет.
5. `docs/.pm.json`: `"canon": 5`.
6. Позвать судей `doc-consistency` и `doc-code-drift` — шагом 6 `upgrade`.
## Версия 4 — 2026-08-05
Две правки, обе про то, как читается каталог задач. Первая — секция роадмапа
переименована, и вместе с именем расширен её смысл; достигнутое переехало вниз.
Вторая — **у каждой записи появился тип, и тип определяет, что с записью можно
делать**. Раскладка не меняется, файлов канона не прибавляется.
**Что переехало:**
- секция роадмапа `Разработка`**`Сопровождение`** (англ. `Tooling`
**`Operations`**). Прежнее имя называло слишком много: роадмап **весь** про
разработку, и секция с таким именем не отличалась от остальных ничем;
- **тип записи** — из префикса заголовка (`[goal]`/`[idea]`) и тега
`kind:<род>` в **поле меты `Тип`** первой строкой. Эмодзи в заголовке от него
производна;
- **поле места** у задачи: `Секция`**`Категория`**. У цели остаётся `Секция`:
у задачи поле называет полку домена, в которую она вернётся из спринта, у цели
— часть роадмапа, то есть состояние очереди. Одно имя на два смысла их и
смешивало.
**Что добавилось:**
1. **Смысл секции расширен.** Было «инструмент и процесс», стало «чем держат
проект: инструмент, процесс, эксплуатация». Метрики, логи, инфраструктура,
выкладка и дежурство — сюда же. Расширение не косметическое: английское
`Operations` при узком смысле обещало бы эксплуатацию, а внутри лежал бы
линтер.
2. **Общий словарь трёх мест** — [canon.md](canon.md), раздел «Сопровождение и
эксплуатация». Сопровождение — всё, чем держат проект; эксплуатация — его
часть, работа системы на проде. `ROADMAP.md`, секция `Сопровождение` — план
работ; `architecture.md`, раздел «Эксплуатация» — как устроено сейчас;
эксплуатационный проход ревью — оптика проверки. Слить их в одно слово
нельзя: они отвечают на разные вопросы. Слово **«поддержка» не употребляется
вовсе** — в нём слышится помощь пользователю.
3. **Граница с возможностями проходит по тому, кто наблюдает.** «Приложение
сообщает о своём состоянии» — возможность приложения, её место среди прочих
целей. «Дежурный видит состояние на одном экране» — сопровождение. Одни и те
же метрики попадают в разные секции роадмапа, и это верно.
4. **Порядок секций стал каноническим**, и `Готово` переехало **вниз**:
`Запланировано` | `Направления` | `Сопровождение` | `Готово`. Достигнутое
копится — через год этой секции больше, чем всех остальных вместе, — и стоя
первой она отодвигает за экран то, ради чего роадмап открывают чаще всего.
Порядок проверяет `tasks.py check`, переставляет `check --fix`.
5. **Заголовок секции отбивается пустой строкой с обеих сторон.** Прежде
проверялась только строка после заголовка; перестановка секций двигает целые
блоки, и два заголовка оказываются вплотную. Правит `check --fix`.
6. **Тип — единственная ось записи, закрытый словарь из пяти значений:**
`goal` | `feature` | `fix` | `chore` | `research`. Осей было две — тип записи
(`goal`/`idea`/`task`) и род работы (`kind:` тегом), — но из двенадцати
клеток произведения законны были шесть, а алгоритм работы крепится к роду, а
не к типу. Оси схлопнуты.
7. **Тип задаёт схему тела:** какие разделы обязательны, какие допустимы, нужна
ли цель, берётся ли запись в спринт. Проверяет `sprint take`, замечания даёт
`check`. Два раздела новые: **`Воспроизведение`** у `fix` (не
воспроизводится — это `research`, а не `fix`; правило было записано и не
проверялось) и **`Вопрос` + `Куда ляжет ответ`** у `research` вместо
критериев приёмки (приёмка разведки — записанный ответ, и критерии в форме
«оракул: тест» ей натянуты).
8. **Тип `idea` упразднён.** Он значил не род работы, а состояние
незаполненности, а состояние типом быть не может. Теперь оно называется
честно: `research` без раздела «Вопрос» — **сырьё**. В спринт не берётся, как
и прежняя идея, лежит **в конце своей категории** (проверяет `check`,
переставляет `--fix`) и отбирается `list --raw`. Порядка «по важности» в
беклоге по-прежнему нет: этот порядок производен от типа, а не назначен
человеком.
9. **Алгоритм работы над каждым типом** — отдельным файлом,
`skills/tasks/references/task-<тип>.md`: схема, что проверяет машина, что
человек, и порядок шагов.
10. **Имена файлов проверяются.** Правило «текст русский, имена английские»
стояло в каноне и не было подкреплено ничем: `docs.py` имён не смотрел вовсе.
Теперь смотрит — кириллица и не-kebab-case **жёстко**, форма имени
`ADR-ГГГГ-ММ-ДД-slug.md` жёстко, транслит **эвристикой**, то есть
замечанием. Заодно из раскладки канона убраны плейсхолдеры `<тема>.md`,
приглашавшие называть файлы по-русски.
11. **Два агента вместо обещания.** В каноне была таблица «Что проверяет машина,
а что человек», и её правая колонка три версии описывала судью, которого не
существовало. Судьи заведены и разведены по глубине: **`doc-consistency`**
(документ ↔ документ ↔ openspec: факт в двух домах, прямое противоречие,
поведение в `architecture.md` вместо спек, ADR без ссылки и парного статуса,
число без провенанса, заглушка вместо честной строки); **`doc-code-drift`**
(документ ↔ код по закрытому перечню фактов). Оба зовутся раз в спринт на
сессии, а также после adopt и после upgrade, на весь канон разом.
**Что сделать проекту:**
1. Переименовать заголовок секции в `docs/tasks/ROADMAP.md`: `## Разработка`
`## Сопровождение` (или `## Tooling``## Operations`, если индекс
английский). **`check --fix` этого не сделает**: регистр канонической секции
он правит сам, а чужую секцию только называет ошибкой — смысл за человеком.
2. Поправить поле `- **Секция:**` в файлах целей, которые в ней лежат. Порядок
именно такой: сперва заголовок, потом `python3 tasks.py check --dir
docs/tasks` покажет расхождение поимённо.
3. Перечитать состав секции: цели про выкладку, метрики, логи и инфраструктуру,
если они лежали в `Направлениях` за неимением места, переезжают сюда.
4. Прогнать `python3 tasks.py check --dir docs/tasks --fix`. За один проход он
переставит секции роадмапа в канонический порядок (`Готово` уедет вниз вместе
со всем содержимым), поправит отбивку заголовков и **переведёт записи на
типы**: перенесёт значение из тега `kind:` и префикса `[goal]`/`[idea]` в поле
`Тип`, снимет тег, поставит эмодзи в заголовок, переименует `Секция`
`Категория` у задач и снесёт сырьё в конец категорий.
5. Разобрать то, что `--fix` вернул пометкой `НЕОДНОЗНАЧНО`. Главный случай —
**записи без типа**: заведённые до появления рода работы, они не несут ни
тега, ни префикса, и машина их не угадывает (`feature` от `chore` не
отличает). Проставить руками: `edit <слаг> --type …`.
6. Дописать новые обязательные разделы у задач, которые собираются в спринт:
`Воспроизведение` у каждого `fix`, `Вопрос` и `Куда ляжет ответ` у каждого
`research`. Не «заодно по всему беклогу», а порциями переоценки: `check`
ошибкой это не считает, отказывает только `sprint take`. Сколько задач готово
к взятию, печатает блок здоровья `check`.
7. Прогнать `python3 docs.py check`: он назовёт имена файлов не по правилу.
Кириллицу и не-kebab-case править обязательно, транслит — по решению
человека. **Переименование ADR это перенос ссылок**: слаг стоит в
`adr/README.md`, в `architecture.md` и в чужих документах, и делается одним
проходом, иначе останутся битые ссылки (их `docs.py` потом и покажет).
8. `docs/review.md`, подраздел «Триггеры профиля» — переписать целиком, он
отстал дважды. Снести перечень мест для `deep`: профиль упразднён вместе с
проходом независимой реализации, и перечень стал указателем в пустоту.
Оставшийся перечень перевести на новое правило: `wide` теперь означает не
«новое понятие», а **крупное или незнакомое** изменение и рассчитан на 5–10%
задач; отдельным списком назвать, что здесь считается **мелким** (это `quick`).
Форма подраздела — в [skeletons.md](skeletons.md). Там же проверить журнал
дефектов и «Недоступно проверке» на упоминания независимой реализации: класс
«форма решения, где спека выбора не сделала» переезжает в подраздел «перестали
проверять сознательно», а рядом с ним встаёт вторая честная строка — на
`quick` и `standard` не проверяется ничего, что требует запуска.
9. `docs/.pm.json`: `"canon": 4`.
10. Позвать **обоих судей**`doc-consistency` и `doc-code-drift`, шагом 6
`upgrade`. Пунктов выше десять, половина из них ручная, и именно здесь видно,
какие сделаны только наполовину: переименования секций и полей разводят
документы, а `check` сверяет число версии, а не существо. Первый прогон на
живом проекте вдобавок самый урожайный — правило единственного дома до сих пор
никто не проверял. Разбирать порциями, а не одним заходом.
## Версия 3 — 2026-08-04
Роадмап стал **состоянием проекта**, а не очередью работ: цель — возможность
приложения, задача — шаг к ней, достигнутое из роадмапа не исчезает. Плюс род
работы, раздел «Затрагивает» и новое умолчание профиля ревью. Раскладка меняется
в одном файле, но переименование и смена секций тянут за собой ссылки, поэтому
шаги делаются одним заходом.
**Что добавилось:**
1. **Род работы** — тег `kind:<род>` в мете задачи, словарь закрыт:
`feature` | `fix` | `chore` | `research`. Обязателен у задачи, у цели
запрещён. `sprint take` без него отказывает, `check` о пропаже напоминает
замечанием. Определение — [canon.md](canon.md), раздел `tasks/`; смысл и
причина, почему тегом, — в SKILL.md скилла `tasks`, раздел «Род работы».
2. **Раздел «Затрагивает»** в теле задачи — перечень границ, которых изменение
касается (эндпоинт, таблица и миграция, формат на диске, публичный тип). Как
и критерии приёмки, требуется к взятию в спринт, а не к заведению.
3. **Секции роадмапа** — четыре вместо двух и **канонические**, в отличие от
секций беклога: `Готово` (достигнутые цели строкой с датой, без ссылки на
файл), `Запланировано` (очередь значима), `Направления` (очереди нет),
`Разработка` (инструмент и процесс, не возможности приложения). Английский
вариант — `Done` | `Planned` | `Directions` | `Tooling`, один язык на весь
индекс. Переименованию проектом не подлежат: у каждой свой смысл, и в первую
пишет сам `close`; `tasks.py check` проверяет состав.
4. **Форма заголовка записи** — по типу: задача отвечает на «что нужно сделать»
и пишется глаголом в неопределённой форме («Не отбрасывать молча лишние
символы»), цель — на «что приложение будет уметь», идея просто называет, о
чём она. `check` считает заголовки не в форме действия и печатает число в
блоке здоровья. Годность формулировки — не машине: её смотрит новый агент
`task-form` (форма записи, только чтение), а язык текста — `doc-wording`.
5. **Заголовки секций — с прописной, после заголовка пустая строка**, во всех
индексах. Написание канонических секций и отбивку правит `check --fix`; он
же сводит написание секции в мете файла с заголовком индекса.
6. **Язык проектных текстов** — [language.md](language.md), общий дом для
документов канона, задач, решений ADR и записок разведки: информационный
стиль (глагол вместо отглагольного существительного, активный залог, факт
вместо оценки, стоп-слова, параллельность), таблицы англицизмов и жаргона и
то, что из стиля отброшено намеренно. Проектных файлов не добавляет и
раскладку не меняет — это правила письма, а не новый слот.
7. **Умолчание профиля ревью сменилось** — это не раскладка, но проектный текст
под него уже написан. `standard` стал рабочим умолчанием: миграция схемы,
публичный контракт и инвариант ступень больше **не** поднимают, `wide`
означает новое понятие или структурную единицу. Подраздел «Триггеры профиля»
в `docs/review.md` остаётся на месте, но его содержимое надо перечитать.
**Что переехало:** `docs/tasks/PLAN.md``docs/tasks/ROADMAP.md`; достигнутая
цель — из небытия в секцию `Готово`: `close <цель> --implemented` удаляет файл, но
**оставляет строку с датой**. Прежде роадмап отвечал только «что осталось», и
половину его вопроса вели прозой руками. Вместе с
файлом переименован ключ конфига `tasks.plan``tasks.roadmap` и токены
команд: `--index plan``--index roadmap`, `init --plan-sections`
`--roadmap-sections`, `init --plan``--roadmap`. Старый ключ в
`docs/.pm.json` не игнорируется молча — `tasks.py` останавливается и называет
переименование.
**Что удалено:** тип `[epic]`. Он был зонтиком между целью и задачами; зонтиком
стала цель, а слишком крупный шаг дробится на шаги помельче под ней. Ноль
употреблений на 97 записей двух живых проектов.
**Что сделать проекту:**
1. `git mv docs/tasks/PLAN.md docs/tasks/ROADMAP.md`.
2. Починить ссылки на прежнее имя: `grep -rn 'PLAN\.md' docs/ CLAUDE.md`
заголовок самого файла («# План» → «# Роадмап»), строка в `docs/tasks/BACKLOG.md`,
упоминания в `docs/passport.md` и в телах задач.
3. `docs/.pm.json`: ключ `tasks.plan`, если он там был, — в `tasks.roadmap`.
4. Проставить род работы живым задачам: `python3 tasks.py check --dir docs/tasks`
перечислит те, у кого его нет. Задним числом весь беклог не переоформляется —
род нужен к взятию, так что порядок такой: сперва то, что берётся в ближайший
спринт, остальное по ходу переоценки.
5. Дописать раздел «Затрагивает» — тем же порядком и по той же причине: сперва
набор спринта, остальное по мере того, как задача попадает в работу.
6. Перечитать «Триггеры профиля» в `docs/review.md`: строки вида «миграция →
`deep`» теперь дублируют умолчание с обратным знаком. Оставить там только то,
что для этого проекта считается **новым понятием** и **правилом
идентичности**, — и убрать остальное, иначе проект возвращает себе прежнюю
частоту полного набора уточнением.
7. Переименовать секции роадмапа: `порядок``Запланировано`, `темы`
`Направления`; завести `Готово` **первой** и `Разработка` последней
(порядок секций поменялся в версии 4 — если едешь сразу на неё, заводи
`Готово` последней и не переставляй дважды).
Прозаические разделы вроде «Что уже пройдено», которые велись руками,
разложить: звенья — строками в `Готово` (дата, слаг, что стало возможно),
обоснование очереди оставить прозой в `Запланировано`. Любой `##` в индексе
проверка считает секцией, и теперь `check` называет чужую секцию ошибкой.
8. Переформулировать цели ответом на **«что приложение будет уметь»**: не
«Работа со слиянием», а «Исход слияния не зависит от порядка доставки».
Свойство поведения — законная цель. Цель, которая не про приложение
(процесс, инструмент), переезжает в `Разработка`.
9. `[epic]`, если он в проекте заводился: это либо цель, либо набор задач под
общей целью. `check` назовёт его неизвестным типом.
10. Прогнать `python3 tasks.py check --dir docs/tasks --fix`: он поднимет
написание канонических секций, поставит отбивку после заголовков и сведёт
секцию в мете файлов с заголовками индексов. Секции беклога проект
переименовывает сам — их имена он выбирал, и трогать их скрипт не вправе.
11. Переписать заголовки задач в форму действия — по мере того, как задача
попадает в работу, а не «заодно»: `check` печатает их число, а `task-form`
предложит формулировки на замену пачкой.
12. Прочитать [language.md](language.md) — и **ничего не переписывать задним
числом**. Правила языка применяются к тому, что пишется и правится сейчас;
сплошная вычитка старых документов стоит дороже, чем даёт.
13. `docs/.pm.json`: `"canon": 3`.
## Версия 2 — 2026-08-03
Шапка записи ADR — мета-блоком общей формы, и у статуса появился объявленный
дом. Раскладка не менялась: правка касается одного шаблона.
**Что добавилось:** поле `- **Статус:**` в шапке `docs/adr/template.md`
`заменено на ADR-…` либо `устарело`, у активной записи поля нет. Правило
«старая запись получает статус» было и раньше ([canon.md](canon.md), `adr/`),
но места под него шаблон не отводил: каждая запись изобретала своё, а колонка
«Статус» таблицы `adr/README.md` брала его оттуда, где он у каждого свой.
**Что переехало:** поля `Дата` и `Источник` в шаблоне стали жирными
(`- **Дата:**`, `- **Источник:**`) — та же форма, что у меты задачи и у записи
журнала дефектов: поле на строку, имя жирным.
**Что удалено:** ничего.
**Что сделать проекту:**
1. Привести `docs/adr/template.md` к скелету версии 2
([skeletons.md](skeletons.md), раздел `docs/adr/template.md`).
2. В существующих записях `docs/adr/ADR-*.md`: жирным поля шапки; если статус
записан прозой или заголовком — перенести его полем `- **Статус:**` в шапку
и сверить с колонкой «Статус» таблицы в `docs/adr/README.md`.
3. `docs/.pm.json`: `"canon": 2`.
## Версия 1 — 2026-08-03
Первая версия. Проект любой прежней раскладки приводится к ней скиллом `canon`
в режиме `adopt`, а не `upgrade`.
**Что вводится:** раскладка целиком — см. [canon.md](canon.md).
**Что сделать проекту, который приходит из свободной раскладки:**
1. `docs/.pm.json` с `{"canon": 1}` и путём миграций, если БД есть.
2. Скелет канона целиком; незаполненное — одной честной строкой.
3. `docs/specs/` разобрать: поведение — в `openspec/specs/`, обзор — в
`docs/architecture.md`, знание о чужих системах — в `docs/research/`.
Дубли capability удалить, сверив поимённо.
4. `docs/plan.md``docs/tasks/PLAN.md`, шаги плана — целями в «порядок».
5. `BRIEF.md``docs/passport.md`.
6. `docs/backlog/``docs/tasks/`.
7. `docs/review-journal.md` или `docs/review/journal.md``docs/review.md`,
плюс раздел настройки конвейера.
8. `docs/drafts/` растворить: идея → задача `[idea]`, намеренный отказ → ADR,
порядок работ → `PLAN.md`.
9. `docs/review-brief.md`, если заводился, удалить: его разделы разошлись по
документам канона.
10. `conventions.md``conventions/`, `local-research.md``research/`.
11. Завести `docs/security.md` с периметром первой строкой и `docs/adr/`.
12. В `CLAUDE.md`: severity рядом с каждым инвариантом; семантика гейта (чем
краснеет безусловно, где логи, чего в нём нет и кто тогда гоняет дорогое);
**имя основной ветки**; запреты с путями; где `testdata` и куда писать
временное; **что считается необратимым**; общий станок; ориентир по размеру
спринта. Убрать раздел «Процесс», если он пересказывает пайплайн.
13. В `openspec/config.yaml` оставить только нужды генерации и ссылки.
14. Добавить шаг `docs.py check` в гейт проекта.
**Копии правил в шаблонах, которые версия 1 уносит в проект** — их правка в
каноне обязана появляться здесь отдельной версией:
| Что копируется | Дом определения |
| --- | --- |
| форма записи журнала дефектов в `docs/review.md` | `av-dev-pipeline/skills/review-pipeline/references/review-journal.md` |
| правило заведения ADR в `docs/adr/README.md` | [canon.md](canon.md), раздел `adr/` |