Files
dev-skills/av-dev/skills/doc-canon/references/changelog.md
T
av de12a4d8a3 слияние: три плагина стали одним av-dev, скиллы получили префиксы
Каталоги, агенты и общие дома переехали в av-dev/; скиллы названы по прежнему
плагину — doc-*, task-*, code-*, с двумя смысловыми именами вместо тавтологии:
doc-sync вместо docs, task-track вместо tasks. Манифесты сведены к двум
плагинам. Пространства имён вызовов и пути внутри дерева переписаны машинно;
проза, которая называет прежние плагины отдельными, идёт следующим шагом.
2026-08-13 10:10:51 +03:00

71 KiB
Raw Blame History

Журнал версий канона

Одна запись на версию. Проект знает свою версию из docs/.docs.json; canon upgrade идёт по записям снизу вверх от версии проекта до текущей и делает то, что в них названо. Записи ниже версии 13 зовут этот файл прежним именем, docs/.pm.json, — так и было на день записи, и переписывать историю мы не станем; переименование делает запись 13.

Каталог задач этим журналом не повышается. У него своя версия формата и свой журнал — references/changelog.md скилла av-dev-tasks:tasks. Записи 8, 11 и 12 трогали его в те времена, когда своего числа у него не было; впредь запись канона вправе позвать соседа, но не двигать его версию.

Правило записи: что добавилось, что переехало, что удалено, что сделать проекту. Без последнего пункта запись бесполезна — по ней и работает upgrade.

Версия — целое число. Обратной совместимости у канона нет: есть «приведён» и «не приведён».


Версия 14 — 2026-08-11

У ADR стало два законных источника. Прежде запись цитировала только архивный design.md, то есть решение, принятое по ходу изменения. Решение, принятое разведкой — намеренный отказ, выбор подхода, «проверили и не делаем», — не имеет design.md по построению: change по нему не заводится никогда. Триггер канона такое решение ловит («намеренный отказ от очевидного подхода»), а дома у него не было, и оно оседало в записке разведки или в переписке.

Что изменилось. adr/ принимает второй источник — записку разведки. Правило «промоут, а не второе сочинение» не тронуто: запись по-прежнему цитирует уже написанное и называет источник, изменилось только то, что источников два. Следом сказали то же самое: карта домов, разрез проверки doc-consistency, вход и устав самого агента, скелеты docs/adr/README.md и docs/adr/template.md.

Почему это версия, а не правка текста. Два следствия уезжают в репозиторий проекта. По карте домов судит агент согласованности — прежняя редакция читала ADR со ссылкой на записку разведки как нарушение; а скелеты adr/ лежат в проекте файлами и говорят там от имени канона.

Что сделать проекту.

  1. Ничего с существующими записями: прежние ADR ссылаются на design.md, и это по-прежнему верно.
  2. Поднять шапку docs/adr/README.md: «промоут поверх архивного design.md» → «промоут поверх уже написанного», с обоими источниками. Точный текст — в skeletons.md, раздел docs/adr/README.md.
  3. Поднять docs/adr/template.md: строка - **Источник:** называет два возможных источника.
  4. docs/.docs.json: "canon": 14.

Чего делать не надо. Заводить ADR задним числом по старым разведкам. Запись заводится, когда решение принимается, а не когда о нём вспомнили: сочинённое через полгода обоснование — ровно то «второе сочинение», против которого правило и написано.


Версия 13 — 2026-08-11

Служебный файл канона переименован: docs/.pm.jsondocs/.docs.json. Имя досталось от плагина av-dev-pm, который распался на четыре и которого больше нет: файл пережил владельца и указывал в пустоту. Правило простое и теперь соблюдается всеми тремя: имя служебного файла — имя плагина, который его завёл, .docs.json — канон, .tasks.json — задачи, openspec/config.yaml — конвейер.

Что изменилось. docs.py читает только новое имя. Прежнее он не читает намеренно: два дома для одной версии канона расходятся молча, а тут расхождение стоило бы дорого — по этому числу upgrade решает, какие записи применять. Файл под старым именем check узнаёт и называет отдельной строкой с готовой командой, а не жалуется на пропажу.

Что появилось у соседа. У каталога задач теперь есть своя версия формата — ключ tasks в <каталог задач>/.tasks.json, — и свой журнал версий в скилле av-dev-tasks:tasks. До сих пор её не было вовсе: формат задач менялся записями этого журнала (8, 11, 12), хотя каталог принадлежит другому плагину и ставится без канона документов. Канон это число не двигает.

Что сделать проекту.

  1. git mv docs/.pm.json docs/.docs.json — одним коммитом с шагом 2. Содержимое не меняется: ключи те же.
  2. Поправить упоминания прежнего имени в своих файлах — CLAUDE.md, гейт, README.md, docs/**. Битой ссылкой это чаще всего не выглядит (файл служебный, на него ссылаются прозой), поэтому docs.py check таких упоминаний не ловит: ищи grep -rn '\.pm\.json' по репозиторию.
  3. Объявить версию формата задач, если каталог задач в проекте есть: <каталог задач>/.tasks.json с ключом "tasks": <версия>. Файла нет вовсе — заведи, он теперь обязателен: версия не настройка, от которой можно отказаться. Какое число ставить и что сделать перед этим, говорит журнал владельца — позови скилл av-dev-tasks:tasks, здесь этих шагов нет намеренно: второй перечень чужих шагов разошёлся бы с первым.
  4. Гейт не меняется: шаги те же, версию задач сторожит tasks.py check, который в нём уже стоит.
  5. docs/.docs.json: "canon": 13.

Чего делать не надо. Ключи в файле не трогаются, документы не переезжают, записи задач не меняются: версия 13 — про имена служебных файлов и про то, кто чью версию двигает.


Версия 12 — 2026-08-09

Спринты отменены. Работа идёт задача за задачей, и замороженный набор перестал что-либо удерживать: он отвечал на вопрос «что делать дальше», а между наборами на этот вопрос не отвечал никто.

Что изменилось. Индексов задач два вместо трёх: SPRINT.md упразднён. Приоритет стал тем, чем он и является, — порядком строк в BACKLOG.md: первая строка секции это то, что делают следующим. Назначает порядок человек, машина его не выводит; двигают его move --after и move --first с причиной.

Гейт готовности записи стоял на взятии задачи в спринт — единственном месте, где её судили целиком. Момент нужен и без спринта: теперь это команда tasks.py ready <слаг>, и зовёт её тот, кто берёт задачу в работу.

Ритуал между спринтами (av-dev-tasks:session) стал скиллом груминга (av-dev-tasks:groom): два вопроса — что сейчас самое важное и что перестало быть важным.

Что сделать проекту.

  1. Вернуть задачи из набора в беклог и снести SPRINT.md. Порядок такой: git rm tasks/SPRINT.md, затем tasks.py check --dir tasks --fix. Строки набора после удаления файла становятся бездомными, и --fix возвращает их в беклог в конец своей секции — с пометкой, что позицию назначает человек. Наоборот делать нельзя: check без удалённого файла увидит третий индекс и станет ругаться на него, а не чинить.
  2. Снять теги sprint:<слаг> с записей — tasks.py edit <слаг> --rm-tag sprint:<слаг>. Тег больше никем не читается, а check о нём молчит: он законный свободный тег. Пропущенный вреда не сделает, но и пользы не несёт.
  3. Расставить порядок — первый груминг: av-dev-tasks:groom. После шага 1 очередь состоит из того, что машина поставила в конец, то есть очереди нет вовсе. Пока порядок не назначен, «что делать дальше» по-прежнему без ответа.
  4. Поправить упоминания спринта в CLAUDE.md проекта, если они были: слот «общий станок» переехал в груминг под именем «что считается сломанным», ориентир «5–8 задач в спринте» стал ориентиром размера порции разбора.
  5. docs/.pm.json: "canon": 12.

Чего делать не надо. REJECTED.md, ROADMAP.md и файлы items/ не меняются: спринт жил только в собственном индексе и в тегах.


Версия 11 — 2026-08-09

Каталог задач уехал из docs/ в корень репозитория. Версия 8 отпустила его из канона — перестала требовать, перестала проверять, — но место он занимал всё то же, docs/tasks/. Полдела: каталог, принадлежащий одному плагину, лежал внутри дерева, которым владеет другой. Проекту, поставившему учёт работ без канона документов, приходилось заводить docs/ ради одной вложенной папки.

Что изменилось. Дом задач — tasks/ в корне репозитория. tasks.py ищет его там первым; docs/tasks/ и doc/tasks/ остаются в списке поиска для непереехавших проектов, а init заводит только в корне. Настройки — там же, tasks/.tasks.json.

Что осталось терпимым. docs.py по-прежнему не считает docs/tasks/ файлом вне канона: непереехавший проект не должен получать выдуманную ошибку вдобавок к этой записи, которая и так велит ему переехать.

Что сделать проекту.

  1. git mv docs/tasks tasks — одним коммитом вместе с шагом 2, чтобы ссылки не жили битыми между коммитами.
  2. Починить относительные ссылки внутри записей. Файл tasks/items/x.md стал на уровень ближе к корню: ../../passport.md в теле записи теперь ../docs/passport.md. Тот же сдвиг у ссылок из индексов. Это самая тихая часть переезда: битая относительная ссылка не мешает tasks.py check, её ловит только docs.py check и только у документов канона.
  3. Проверить ссылки на задачи снаружи: CLAUDE.md, README.md, гейт, docs/review.md. Путь docs/tasks/... в них теперь ведёт в никуда.
  4. Поправить путь в гейте: tasks.py check --dir tasks.
  5. docs/.pm.json: "canon": 11.

Версия 10 — 2026-08-09

Проверка формы config.yaml ушла к тому, кто файл заводит. Версия 9 перенесла в конвейер настройку OpenSpec и честно назвала остаток: форма и сторож версии остались в docs.py, то есть у файла было два плагина — один заводит, другой проверяет. Остаток закрыт.

Что появилось. Скрипт openspec.py в скилле av-dev-code:openspec, две команды: check --dir <корень> — форма в проекте, form — сверка слепка с живым OpenSpec. Коды выхода те же, что у docs.py и tasks.py.

Что удалено из docs.py. Константы OPENSPEC_*, проверка формы, сторож версии и подкоманда openspec-form — 252 строки. Скрипт канона про openspec/config.yaml не говорит теперь ничего; openspec/specs/ он по-прежнему знает, потому что это дом темы requirements и часть карты тем.

Что стало лучше по дороге. Адреса docs/passport.md и CLAUDE.md требуются теперь только к тем документам, которые в проекте есть. Прежняя проверка требовала их безусловно, то есть на проекте без канона документов требовала битую ссылку. Теперь отсутствие документа — строка «не проверялось» с указанием, что без канона конвейер работает вслепую.

Что осталось за каноном. Один вопрос, и это не форма: не пересказан ли в context документ, у которого есть свой дом. Разрез — утверждение, опровергаемое открытием другого файла, против строки «открой такой-то файл»; машине он не виден, судит агент doc-consistency, и config.yaml у него во входе.

Что сделать проекту.

  1. Заменить в гейте и в скриптах docs.py openspec-form на openspec.py form. Подкоманды больше нет: прежний вызов упадёт ошибкой употребления (код 2), а не промолчит.
  2. Добавить в гейт шаг openspec.py check, если проект работает по OpenSpec. Форму раньше проверял docs.py check заодно; теперь он о ней молчит, и без отдельного шага незаменённый пример в config.yaml перестанет ловиться. Это главная потеря этого повышения, и она тихая.
  3. Проект по OpenSpec без установленного av-dev-code — форму не проверяет никто. Либо поставить плагин, либо назвать это принятым риском вслух.
  4. docs/.pm.json: "canon": 10.

Версия 9 — 2026-08-09

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

Что появилось. Скилл av-dev-code: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-code установлен, если проект работает по OpenSpec. Без него docs.py check про каталог промолчит — и молчание это законное, так что отсутствие настройки перестанет ловиться само.
  3. Проект не работает по OpenSpec: убедиться, что openspec/ нет, и перестать держать его пустым ради проверки. Она больше не требует каталога.
  4. docs/.pm.json: "canon": 9.

Версия 8 — 2026-08-09

Канон отпустил каталог задач. Плагин av-dev-pm расколот на av-dev-docs (документы) и av-dev-tasks (учёт работ), и каждый теперь ставится сам по себе. Пока владелец был один, docs/tasks/ числился слотом канона: docs.py требовал каталог, звал внутрь чужой скрипт и выдавал его дрейф за свой, а настройки задач жили ключом tasks в docs/.pm.json. Для проекта, поставившего только документы, всё это — отказ на ровном месте: задач он не ведёт, и требовать их не за что.

Что изменилось. Каталог задач канону не принадлежит; канон резервирует ему место в docs/ и внутрь не смотрит. docs.py больше не проверяет согласованность задач вовсе — это делает tasks.py сам, командой своего плагина. Дом настроек каталога задач — <каталог задач>/.tasks.json; ключ tasks в docs/.pm.json читается, только пока своего файла нет, и об этом говорится замечанием.

Что удалено. Проверка check_tasks из docs.py и ключ "tasks" из скелета docs/.pm.json.

Что сделать проекту.

  1. Перенести настройки задач: содержимое ключа "tasks" из docs/.pm.json — в docs/tasks/.tasks.json тем же объектом. Ключа в проекте нет (имена файлов и заголовков умолчательные) — переносить нечего, шаг пропускается.
  2. Удалить ключ "tasks" из docs/.pm.json после переноса. Оставленный он не читается, и tasks.py скажет об этом замечанием на каждом прогоне.
  3. Проверить, что согласованность задач по-прежнему кто-то гоняет: раньше её тянул за собой docs.py check, теперь — только tasks.py check. Если в гейте проекта стоял один docs.py, добавить туда второй шаг — иначе дрейф индексов перестанет ловиться молча, и это самая вероятная потеря на этом повышении.
  4. Установить оба плагина, если нужны оба: av-dev-docs и av-dev-tasks вместо прежнего av-dev-pm. Прежний из enabledPlugins убрать.
  5. docs/.pm.json: "canon": 8.

Версия 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: блок 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.mdautotests, 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. Переименовать метки прогона везде, где проект их называет — в «Триггерах метки», в «Недоступно проверке», в журнале дефектов: quicksmall, standardmedium, widelarge. Метка это итог классификации задачи, и три её значения — часть общего словаря канона и конвейера. Слово «ступень» из документов уходит: у одной вещи одно имя.
  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

Две правки, обе про то, как читается каталог задач. Первая — секция роадмапа переименована, и вместе с именем расширен её смысл; достигнутое переехало вниз. Вторая — у каждой записи появился тип, и тип определяет, что с записью можно делать. Раскладка не меняется, файлов канона не прибавляется.

Что переехало:

  • секция роадмапа РазработкаСопровождение (англ. ToolingOperations). Прежнее имя называло слишком много: роадмап весь про разработку, и секция с таким именем не отличалась от остальных ничем;
  • тип записи — из префикса заголовка ([goal]/[idea]) и тега kind:<род> в поле меты Тип первой строкой. Эмодзи в заголовке от него производна;
  • поле места у задачи: СекцияКатегория. У цели остаётся Секция: у задачи поле называет полку домена, в которую она вернётся из спринта, у цели — часть роадмапа, то есть состояние очереди. Одно имя на два смысла их и смешивало.

Что добавилось:

  1. Смысл секции расширен. Было «инструмент и процесс», стало «чем держат проект: инструмент, процесс, эксплуатация». Метрики, логи, инфраструктура, выкладка и дежурство — сюда же. Расширение не косметическое: английское Operations при узком смысле обещало бы эксплуатацию, а внутри лежал бы линтер.
  2. Общий словарь трёх мест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. Там же проверить журнал дефектов и «Недоступно проверке» на упоминания независимой реализации: класс «форма решения, где спека выбора не сделала» переезжает в подраздел «перестали проверять сознательно», а рядом с ним встаёт вторая честная строка — на 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, раздел 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, общий дом для документов канона, задач, решений ADR и записок разведки: информационный стиль (глагол вместо отглагольного существительного, активный залог, факт вместо оценки, стоп-слова, параллельность), таблицы англицизмов и жаргона и то, что из стиля отброшено намеренно. Проектных файлов не добавляет и раскладку не меняет — это правила письма, а не новый слот.
  7. Умолчание профиля ревью сменилось — это не раскладка, но проектный текст под него уже написан. standard стал рабочим умолчанием: миграция схемы, публичный контракт и инвариант ступень больше не поднимают, wide означает новое понятие или структурную единицу. Подраздел «Триггеры профиля» в docs/review.md остаётся на месте, но его содержимое надо перечитать.

Что переехало: docs/tasks/PLAN.mddocs/tasks/ROADMAP.md; достигнутая цель — из небытия в секцию Готово: close <цель> --implemented удаляет файл, но оставляет строку с датой. Прежде роадмап отвечал только «что осталось», и половину его вопроса вели прозой руками. Вместе с файлом переименован ключ конфига tasks.plantasks.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 — и ничего не переписывать задним числом. Правила языка применяются к тому, что пишется и правится сейчас; сплошная вычитка старых документов стоит дороже, чем даёт.
  13. docs/.pm.json: "canon": 3.

Версия 2 — 2026-08-03

Шапка записи ADR — мета-блоком общей формы, и у статуса появился объявленный дом. Раскладка не менялась: правка касается одного шаблона.

Что добавилось: поле - **Статус:** в шапке docs/adr/template.mdзаменено на ADR-… либо устарело, у активной записи поля нет. Правило «старая запись получает статус» было и раньше (canon.md, adr/), но места под него шаблон не отводил: каждая запись изобретала своё, а колонка «Статус» таблицы adr/README.md брала его оттуда, где он у каждого свой.

Что переехало: поля Дата и Источник в шаблоне стали жирными (- **Дата:**, - **Источник:**) — та же форма, что у меты задачи и у записи журнала дефектов: поле на строку, имя жирным.

Что удалено: ничего.

Что сделать проекту:

  1. Привести docs/adr/template.md к скелету версии 2 (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.

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

  1. docs/.pm.json с {"canon": 1} и путём миграций, если БД есть.
  2. Скелет канона целиком; незаполненное — одной честной строкой.
  3. docs/specs/ разобрать: поведение — в openspec/specs/, обзор — в docs/architecture.md, знание о чужих системах — в docs/research/. Дубли capability удалить, сверив поимённо.
  4. docs/plan.mddocs/tasks/PLAN.md, шаги плана — целями в «порядок».
  5. BRIEF.mddocs/passport.md.
  6. docs/backlog/docs/tasks/.
  7. docs/review-journal.md или docs/review/journal.mddocs/review.md, плюс раздел настройки конвейера.
  8. docs/drafts/ растворить: идея → задача [idea], намеренный отказ → ADR, порядок работ → PLAN.md.
  9. docs/review-brief.md, если заводился, удалить: его разделы разошлись по документам канона.
  10. conventions.mdconventions/, local-research.mdresearch/.
  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-code/skills/review/references/review-journal.md
правило заведения ADR в docs/adr/README.md canon.md, раздел adr/