Команда stage была дефектна по шести пунктам, и все шесть подтверждены прогоном: не звала raw_last (переход оставлял каталог красным), не переписывала шапку беклога (индекс продолжал объявлять прежнюю стадию), шла в обход write_config, молча пропускала файлы с непересобираемой метой, ломалась на беклоге без заголовков и схлопывала полки при первом объявлении стадии. Объявление и смена разведены: объявление беклога не трогает вовсе, смена трогает состав секций только по явному --sections, а слить полки скрипт не берётся ни в одном случае. Абзац шапки размечен парой «стадия», и расхождение с конфигом стало обычным дрейфом. Отказ по недостающей строке индекса запирал запись, пережившую упразднение роадмапа: edit, close и reopen теперь заводят или пропускают строку сами. Прочее: регистр stage нормализуется при чтении; --fix снимает мёртвые теги и у неразобранных записей; move отказывает переставлять сырьё; adopt держит место сырья; docs.py bump двигает одну запись журнала за раз; tasks.py получил перечень упразднённых адресов, и гейт наконец видит собственное упразднение ROADMAP.md. Запись «Версия 3» переписана по прогону на игрушечном проекте: прежний порядок шагов был неисполним. Закрыты дыры модели стадий (пересмотр плана стройки стал сценарием, приёмка отвязана от груминга, from-review, research и adopt получили развилку по стадии, перечень осей пересчитан) и находки, старшие этой сессии: review-triage получил режим без метки, три списка проектных копий сведены к дому с проверяемыми копиями, пять пересказов правил стали помеченными копиями или ссылками, language.md перестал объявлять юрисдикцию над чужим плагином.
17 KiB
Журнал версий раскладки
Одна запись на версию. Проект знает свою версию из ключа version в
.av-dev.toml; операция upgrade скилла av-dev:canon идёт по записям
снизу вверх от версии проекта до текущей и делает то, что в них названо.
Правило записи: что добавилось, что переехало, что удалено, что сделать
проекту. Без последнего пункта запись бесполезна — по ней и работает
upgrade.
Версия — целое число. Обратной совместимости нет: есть «приведён» и «не приведён». Версия одна на всю раскладку — и на документы канона, и на каталог задач: ведёт их один плагин, и второе число означало бы только вопрос, по какому журналу повышать.
До слияния журналов было два, и нумерация в них своя: changelog-before-merge.md — канон документов, версии 1–14; changelog-tasks-before-merge.md — формат задач, версия 1. Оба закрыты и не переписаны: адрес, верный на день записи, там и остался. Проект, отставший от канона 14, идёт сперва по ним, а потом по этому журналу — порядок назван в записи 1.
Версия 3 — 2026-08-13
Тип записи goal и индекс ROADMAP.md упразднены; у проекта появилась
стадия — build (беклог это план стройки, порядок строк значит зависимость)
или support (очередь правок, порядок значит важность).
Цель была зонтиком над параллельными направлениями — она нужна там, где список
работ нельзя выстроить в один порядок. У проекта, который ведёт один человек,
такого не бывает, и роадмап при этом наполовину дублировал беклог («чего ещё не
умеет» = «что осталось в списке»), а вторую половину («что уже умеет») отвечают
openspec/specs/ и git log индекса.
Что переехало. Индекс остался один — BACKLOG.md. Поле меты Секция стало
Категория; теги goal:<слаг>, decomposed и раздел Завершение упразднены;
команды list --goal, edit --goal, edit --section и ключи [tasks] roadmap,
[tasks] completion_heading — тоже. Появились ключ [tasks] stage, команда
tasks.py stage и флаги init --stage, adopt scan --stage.
Что сделать проекту. Порядок шагов обязателен, и первый шаг — не команда:
пока в [tasks] лежит упразднённый ключ, любая подкоманда tasks.py
отвечает кодом 3 и работать нечем.
-
Вычистить конфиг руками. Из секции
[tasks]в.av-dev.tomlудалить ключиroadmap(илиplan) иcompletion_heading. Каждый из них — код 3 на любой команде, и названы они здесь оба: второй легко пропустить, потому что его упразднение не видно по имени файла. -
Удалить
tasks/ROADMAP.md. СекцияГотовоуходит вместе с ним и не переносится: «что приложение умеет» отвечают спеки, «когда это появилось» —git logбеклога. Проект безopenspec/specs/теряет здесь единственный связный перечень достигнутого — если он нужен, сохрани его сам до удаления (документом проекта, не задачами). -
Прогнать
tasks.py check --fix. Он снимет тегиgoal:<слаг>иdecomposed, переименует полеСекция→Категорияи перепишет старую форму меты — в том числе у самих записей типаgoal. Записиgoalпри этом останутся: во что превращается цель, машина не решает и говоритНЕОДНОЗНАЧНО. -
Разобрать цели поштучно. У каждой два исхода, и выбирает человек: она становится задачей (
edit <слаг> --type feature|fix|chore|research) либо уходит (close <слаг> --reason …). Строки в беклоге у неё нет — её жильём был роадмап, — иedit --typeзаведёт её сам, в первую секцию и в конец, сказав об этом; место назначь потом. РазделЗавершениев теле переехавшей записи удали руками: схеме нового типа он не принадлежит, иcheckоставит о нём замечание. Задачи, носившие тег цели, живут дальше сами по себе — разбирать их не нужно. -
Объявить стадию —
tasks.py stage buildилиtasks.py stage support. Приложение ещё строится и список работ линеен по зависимости —build; работает и правится точечно —support. Без ключаcheckотказывает: порядок строк нечем прочитать.Объявление беклог не трогает — ни секций, ни файлов: оно называет то, что уже верно. Поэтому проекту с несколькими полками, объявляющему
build, команда откажет и назовёт выход: слить полки самому (move <слаг> --section <куда> --reason …), потому что порядок строк в слитом списке знает только человек. Флаг--sectionsпри объявлении не принимается — он для смены стадии, где сливать просят явно. -
Поправить шапку
BACKLOG.md. Абзац про стадию теперь размечен парой<!-- стадия -->…<!-- /стадия -->, и по немуcheckсверяет шапку с конфигом. В беклоге, заведённом до этой версии, разметки нет —stageоб этом скажет. Возьми готовый абзац из свежего каталога (tasks.py initво временном месте) или напиши сам: он объясняет, что значит порядок строк, и читают вместо документации именно его. -
Поднять версию —
docs.py bump. Последним шагом. Он двигает одну запись за раз: отставшему на две записи проекту зовётся дважды, следом за шагами каждой. -
docs.py checkиtasks.py check --dir <каталог задач>— до отсутствия дрейфа.
Проект, не прошедший записи 1 и 2, начинает с этой. Их собственные шаги
велят гонять tasks.py check до зелёного, а он на упразднённом ключе отвечает
кодом 3 — то есть пройти их сегодня нельзя, не сделав шаг 1 отсюда. Записи от
этого не переписываются: порядок между ними прежний, добавлено одно условие
входа.
Версия 2 — 2026-08-13
Скилл doc-canon стал canon: префикс называл материал (doc-), а скилл
занят не материалом, а формой — раскладкой всех частей проекта и общим
повышением версии. Ни один файл проекта от этого не переехал; сменились путь к
скрипту и имя вызова, а оба живут в проекте: первый — строкой гейта, второй
— в CLAUDE.md и в записях задач.
Что переехало в вызовах. av-dev:doc-canon → av-dev:canon. Прочие имена не
тронуты.
Что сделать проекту.
- Поправить шаг гейта. Путь к
docs.pyсменился вместе с именем каталога скилла:skills/doc-canon/scripts/docs.py→skills/canon/scripts/docs.py. Шаг, который не нашёл скрипт, обязан краснеть, а не пропускаться, — проверь, что он краснеет. - Поправить свои вызовы скилла —
grep -rn "doc-canon" --exclude-dir=.git .по проекту целиком: имя встречается вCLAUDE.md, вTaskfile, в записях задач и в документах канона. Прежнее полное имя не разрешится вовсе. - Поднять версию —
docs.py bump. Последним шагом. docs.py checkиtasks.py check --dir <каталог задач>— до отсутствия дрейфа.
Проект, не прошедший запись 1, переименовывает дважды подряд — skills/canon/
→ skills/doc-canon/ записью 1 и обратно этой. Порядок записей от этого не
меняется: каждая исполняется на том состоянии, которое оставила предыдущая, и
прошлая запись под новое имя не переписывается.
Версия 1 — 2026-08-13
Три плагина — av-dev-docs, av-dev-tasks и av-dev-code — слились в один,
av-dev. Раскол делался под раздельную установку: проект мог взять учёт работ
без документов канона или конвейер без обоих. Практика посылку не подтвердила —
подмножество не понадобилось ни разу, — а платился раскол помеченными копиями
общих правил и веткой «плагина нет» на каждый вызов соседа.
Что переехало в проекте. Служебных файла было два, стал один:
| Было | Стало |
|---|---|
docs/.docs.json, ключ canon |
.av-dev.toml в корне, ключ version |
docs/.docs.json, ключ migrations |
.av-dev.toml, секция [docs] |
<каталог задач>/.tasks.json, ключ tasks |
тот же version: версия теперь одна |
<каталог задач>/.tasks.json, имена частей |
.av-dev.toml, секция [tasks] |
Корень выбран потому, что он есть у обоих: и у проекта без docs/, и у проекта
без каталога задач. Формат TOML — ради комментариев: файл лежит в репозитории
проекта, и назначение числа читают из него самого, а не из документации плагина.
Что переехало в вызовах. Имена скиллов сменили пространство имён и получили
префикс по прежнему плагину: av-dev-docs:canon → av-dev:doc-canon,
av-dev-docs:init → av-dev:doc-init, av-dev-docs:docs → av-dev:doc-sync,
av-dev-docs:healthcheck → av-dev:doc-healthcheck, av-dev-tasks:tasks →
av-dev:task-track, av-dev-tasks:groom → av-dev:task-groom,
av-dev-code:openspec → av-dev:code-openspec, av-dev-code:resolve →
av-dev:code-resolve, av-dev-code:review → av-dev:code-review.
Что сделать проекту.
- Отставшим сперва прежние журналы. Версия канона в
docs/.docs.jsonменьше 14 — пройди записи до 14 по changelog-before-merge.md, и только потом эту. Иначе повышение объявит приведённым то, чего никто не делал. - Завести
.av-dev.tomlв корне репозитория:version = 1, секция[docs]сmigrations, если ключ был, секция[tasks]сdirи теми именами частей, которые в.tasks.jsonотличались от умолчаний. Комментарии пиши свои — файл читает человек. - Удалить
docs/.docs.jsonи<каталог задач>/.tasks.json. Прежние имена не читаются: два дома для одной версии расходятся молча. Пока старые файлы на месте,docs.py checkиtasks.py checkназывают это прежней раскладкой. - Переставить плагины.
av-dev-docs,av-dev-tasksиav-dev-codeудалить,av-devпоставить — команды в README репозитория плагинов. - Поправить гейт проекта. Пути к
docs.py,tasks.pyиopenspec.pyсменились вместе с именами каталогов скиллов:skills/canon/→skills/doc-canon/,skills/tasks/→skills/task-track/,skills/openspec/→skills/code-openspec/. Шаг, который не нашёл скрипт, обязан краснеть, а не пропускаться, — проверь, что он краснеет. - Поправить свои вызовы скиллов — в
CLAUDE.md, вTaskfile, в записях задач: короткое имя разрешится в проектную копию, а прежнее полное не разрешится вовсе. - Найти, где проект читает служебный файл сам. Шаг гейта, скрипт, шаблон —
что угодно, что брало значение из
docs/.docs.json, чтобы не заводить факту второй дом. Такое чтение переезжает на.av-dev.tomlи наtomllibвместоjson:python3 -c 'import tomllib; print(tomllib.load(open(".av-dev.toml","rb"))["docs"]["migrations"])'. Ищется командойgrep -rn "\.docs\.json\|\.tasks\.json" --exclude-dir=.git .— по проекту целиком, а не по документам: на первом же живом переезде это нашлось вTaskfile.yml, и нашёл это гейт, а не человек. - Поднять версию —
docs.py bump. Последним шагом: число объявляет пройденными шаги журнала, и раньше времени поднятое врёт. docs.py checkиtasks.py check --dir <каталог задач>— до отсутствия дрейфа.
Чего делать не надо. Переписывать прошлые записи журналов под новые имена. Они описывают состояния, которые были, и адрес, верный на день записи, остаётся верным как свидетельство.