Files
dev-skills/av-dev/skills/canon/SKILL.md
T
av ed83ec7dc0 задачи: починена смена стадии, разобраны находки ревью плагина
Команда 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
перестал объявлять юрисдикцию над чужим плагином.
2026-08-13 15:08:29 +03:00

30 KiB

name, description
name description
canon Форма раскладки проекта под av-dev и её обновление — три операции одной машиной сравнения. check — что разошлось с текущей версией раскладки; adopt — перевод проекта из любой прежней раскладки (docs/specs, drafts, backlog, BRIEF.md, review-brief) в канон с переносом файлов и вызовом владельцев каталога задач и openspec/; upgrade — повышение проекта с версии N до текущей по журналу версий, и повышается им вся раскладка, включая каталог задач. Использовать, когда просят проверить документацию проекта, перевести проект на канон, обновить его под новую версию раскладки или когда пришли в старый проект и надо понять, что в нём не так. Имя без префикса намеренно — скилл держит форму всех артефактов проекта, а не один их вид. Содержимое документов ведёт av-dev:doc-sync, форму записей задач — av-dev:task-track, заведение проекта с нуля — av-dev:doc-init.

Форма раскладки проекта

Три операции, одна машина сравнения с разными исходами:

Операция Когда Исход
check начало сессии, шаг синка, гейт что разошлось
adopt проект в чужой раскладке перенос в канон
upgrade канон вырос, проект отстал по журналу версий

Имя без префикса, и это не случайность. Остальные скиллы названы по материалу, с которым работают, — doc-, task-, code-; этот работает не с материалом, а с формой, и она у всех частей проекта одна. check сверяет раскладку документов, adopt заводит все части сразу и зовёт владельцев каталога задач и openspec/, upgrade повышает всю раскладку одним журналом версий — и документы, и каталог задач. Содержимое при этом не его: документы ведёт av-dev:doc-sync, записи задач — av-dev:task-track.

Определение канона — references/canon.md. Здесь оно не пересказывается: два описания одной раскладки разъедутся, и работать будет то, которое прочитали последним. Прочитай его до первой правки.

  • references/skeletons.mdчто именно класть в каждый незаполненный слот. Не выдумывай заглушку своей формы: docs.py узнаёт только плейсхолдер <!-- заполнить: … --> из шаблонов.
  • shared/language.mdкак это написано словами: информационный стиль, применённый к проектным текстам, таблицы англицизмов и жаргона. Раскладка отвечает, где текст лежит, — этот файл отвечает, каким он должен быть. Правила общие для документов канона, задач, решений ADR и записок разведки, и это их дом. Вычитывают их два прохода по охвату: документы — doc-wording, записи каталога задач — task-wording.
  • references/changelog.md — журнал версий раскладки; закрытые журналы до слияния плагинов лежат рядом.

Три правила, из которых всё следует

  1. Сперва карта, потом файлы. Человеку показывается, что найдено, как разложилось и что не разложилось, — и только после подтверждения переносится хоть один файл. Массовый перенос без подтверждения разгребать дороже, чем согласовать.
  2. Ничего не терять. Содержимое переезжает целиком; ссылки чинятся тем же проходом, что и перенос. Старый файл удаляется только после того, как всё его содержимое нашло дом, и это названо поимённо.
  3. Что не классифицировалось — назвать. Проглоченный абзац выглядит как «всё перенеслось». Список «не разложилось» идёт в доклад целиком, с причиной по каждому пункту.

Инструмент

ds="$CLAUDE_PLUGIN_ROOT/skills/canon/scripts/docs.py"

python3 $ds check --dir <корень> [--base <rev>]   # раскладка, ссылки, версия, сверки
python3 $ds version --dir <корень>                # версия раскладки: скрипта и проекта
python3 $ds bump --dir <корень>                   # поднять версию проекта до версии скрипта

Формы openspec/config.yaml здесь больше нет. Каталог принадлежит конвейеру, и форму смотрит его скрипт — скилл av-dev:code-openspec, команда openspec.py check. Проект работает по OpenSpec, а каталога openspec/ нет — форму не проверяет никто, и это надо сказать строкой доклада, а не считать, что она верна.

Копия. Дом словаря — shared/axes.md в репозитории плагина: словарь общий для всех скриптов, и ни один скилл им не владеет. Правится дом, а не этот файл.

Коды выхода — общий словарь всех скриптов av-dev. Ветвись на коде, а не на тексте вывода.

Код Что случилось
0 сошлось
1 дрейф: рабочая ситуация, чинится
2 ошибка употребления: аргументы или нарушенное правило
3 окружение: не тот каталог, битый конфиг, нет инструмента
4 внутренний сбой — дефект скрипта, доложить

Различать 1 и 3 обязательно. «Дрейф» — рабочая ситуация, и чинится она правкой предмета; «окружение» — нерабочая, и повтор той же командой не поможет. Одинаковая реакция на них неверна в обоих случаях.

Здесь это значит: «дрейф раскладки» — рабочая ситуация, «это не корень проекта» — нерабочая.

Граница механизируемого — объявляется вслух

Скрипт печатает её сам последним абзацем, и эту строку из доклада выбрасывать нельзя. check, отчитавшийся «канон соблюдён» на проекте, где из шести файлов три лишние, хуже отсутствующего.

Машина дрейфом считает: отсутствующий путь канона, файл вне канона, битую ссылку, отставшую версию, capability без упоминания в обзоре, миграцию без правки database.md. Замечанием — незаполненный плейсхолдер и слабое упоминание capability: незаполненный канон это переходное состояние, а не отказ. Маркеры долга просто считает числом.

Того, чего она не умеет, ты не судишь сам — для этого есть два агента, и разведены они по глубине:

Агент Что смотрит Читает
doc-consistency смысловой дубль, прямое противоречие между документами, поведение в architecture.md вместо спек, ADR без ссылки и парного статуса, число без провенанса, заглушка вместо честной строки docs/, openspec/
doc-code-drift протухший факт: имя ветки, команды, пути, зависимости поимённо, настройки с числом, единые точки проекта, capability весь репозиторий

Судит не тот, кто писал: самопроверка документа слабее всего ровно там, где формулировка казалась удачной при написании. Ни один из них ничего не правит — оба возвращают готовые формулировки, подставляешь ты.

Чего может не быть

adopt зовёт двоих: av-dev:code-openspec (шаг 4, пункт 3) и av-dev:task-track (шаг 4, пункт 5). Каталоги openspec/ и tasks/ каноном не ведутся, и трогать их этому скиллу нечем, кроме вызова.

Копия. Дом правила — shared/absence.md в репозитории плагина. Правится дом, а не этот файл.

Скилл не вправе считать раскладку проекта полной. Части заводятся порознь и живут порознь; каждая узнаётся своим следом:

Чего нет Как видно Чего теперь не делает никто
настройки av-dev нет .av-dev.toml в корне проект под процесс не заводился; версии нет, настроек нет
документы канона нет docs/ проектную конкретику брать неоткуда — темы, инварианты, прецеденты
учёт работ нет каталога задач запись остаётся владельцу: назови её текстом в докладе
источник требований нет openspec/config.yaml цикл SDD не запускается: спеки не с чем сверять

Свой скилл зовётся полным именемav-dev:canon, av-dev:task-track, av-dev:code-review. Короткое имя может разрешиться в устаревшую проектную копию из .claude/skills/, и подмены не будет видно ни в докладе, ни в поведении.

Внешний плагин может не стоять. Их два: opsx:* — цикл SDD, и av-dev-git:commit — сообщения коммитов. Путь в дерево чужого плагина не пишется никогда: $CLAUDE_PLUGIN_ROOT ведёт только в своё дерево, а вычисленный от него путь к соседу либо не откроется, либо откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его сам.

Отсутствие — исход, а не поломка. Назови строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от сделанного. Выдумывать обходной путь нельзя тоже.

Присутствие узнаётся следом в проекте, а не объявлением. Перечня того, что здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.

Чем оборачивается отсутствие каждого — на самих пунктах шага 4. adopt из-за этого не останавливается ни в одном из двух случаев.

check

  1. docs.py check, при наличии базы диффа — с --base.
  2. Судей документов на каждом check не зови. Ими владеет отдельный скилл — av-dev:doc-healthcheck, — и там же записано, когда его звать: он дорог, и прогон по каждому check не окупается. check отвечает на «сходится ли форма», doc-healthcheck — на «не разошлись ли утверждения».
  3. Доклад: вывод скрипта строкой исхода и граница покрытия — что смотрели и чего не смотрели. Если суждение здесь нужно, скажи это строкой и предложи doc-healthcheck, а не зови агентов сам.

Дрейф раскладки чинится переносом; смысловые находки — это либо правка документа, либо задача, если работы больше чем на абзац.

adopt — проект в чужой раскладке

1. Осмотрись

docs.py check — он уже назовёт упразднённые слоты с адресом, куда каждый уезжает. Но смотрит он только верхний уровень docs/: упразднённое в корне репозитория (BRIEF.md) и во вложенных каталогах он не назовёт никогда, поэтому корневые *.md читай глазами. Плюс: CLAUDE.md, openspec/specs/ (список capability), openspec/config.yaml.

2. Составь карту

Каждый найденный файл получает строку: куда едет, целиком или разбирается, что делать с оригиналом. Разбор docs/specs/ — самое дорогое место, и он делается поимённо по capability:

Что в файле Куда
требования, сценарии, поведение openspec/specs/<capability>/spec.mdили уже там, тогда файл дубль
компоненты, транспорты, раскладка, деплой docs/architecture.md
конвенции чужой системы, формат чужих данных docs/research/
обоснование принятого решения docs/adr/

Дубль удаляется только после поимённой сверки: открыть спеку capability, открыть файл, убедиться, что в файле нет ничего сверх спеки. Нашлось сверх — сперва переезжает в спеку дельтой, потом файл удаляется.

3. Покажи карту человеку

AskUserQuestion, не больше трёх вопросов за итерацию, рекомендация первым вариантом. Показывается: сколько файлов, куда каждый, спорные отнесения, список «не разложилось». Механику (порядок строк, имена файлов внутри research/) не выноси — это не развилка.

4. Перенеси

Порядок важен — он минимизирует окно, в котором ссылки битые:

  1. .av-dev.toml в корне: version = <текущая версия> и путь миграций в [docs], если БД есть;

  2. каталоги канона и скелет по references/skeletons.md: незаполненное — одной честной информативной строкой, а не «TBD»;

  3. OpenSpec, если его нет или config.yaml остался примеромвызови Skill av-dev:code-openspec. Каталог принадлежит конвейеру, и команда заведения с формой файла живут там. Пересказ инвариантов, конвенций и правил ревью из context вычисти ссылкой на дом — на переводимом проекте он там почти наверняка есть. Проект решил жить без OpenSpec — docs.py о каталоге тогда тоже молчит, и форму config.yaml не проверяет никто; скажи это строкой;

  4. переносы содержимого;

  5. каталог задач — вызови скилл av-dev:task-track, сценарий адаптации: он владеет форматом задач. Он же переименует транслитные слаги в английские и тем же проходом починит перекрёстные ссылки;

  6. починка ссылок на перенесённое во всём репозитории — docs/, openspec/, CLAUDE.md, README.md;

  7. удаление оригиналов — только тех, чьё содержимое найдено в новом доме;

  8. шаг docs.py check в гейт проекта. Путь к скрипту — переменной с умолчанием на канонический путь маркетплейса, чтобы переустановка плагина не меняла Taskfile; шаг обязан краснеть внятно, если скрипт не найден, а не пропускаться. Передай ему базу диффа (--base) той же переменной, что и остальным шагам гейта: без неё сверка миграций со схемой не гоняется вовсе. Пример строки покажи человеку — гейт принадлежит проекту, и правит его он.

    Шагов в гейте три, и они независимы. docs.py check не тянет за собой ни задачи, ни конвейер: без своих строк дрейф каталога задач и формы openspec/config.yaml перестаёт ловиться совсем. Ставь соседние шаги по следу присутствия — каталог задач с индексом на месте, значит ставится tasks.py check --dir <каталог задач>; openspec/config.yaml есть, значит ставится openspec.py check. Следа нет — этой части в проекте нет, шаг не ставится, и это строка доклада, а не поломка: назови, чего теперь не проверяет никто. У каждого шага своя переменная пути с тем же умолчанием на канонический путь маркетплейса; $CLAUDE_PLUGIN_ROOT в гейт не подставляй — он ведёт только в свой плагин;

  9. docs.py check — до отсутствия дрейфа раскладки. Замечания (незаполненные плейсхолдеры, слабое упоминание capability) остаются: незаполненный канон это объявленное переходное состояние из шага 5, а не отказ. Пересчитай эти пункты в докладе переходного состояния — не выдавай их за поломку и не молчи о них.

    Задачи docs.py не проверяет — их ведёт другой скилл, и согласованность каталога показывает только tasks.py check. Позвал на шаге 5 скилл задач — его отчёт идёт в доклад отдельной строкой, и зелёным он сразу не станет: у перенесённых записей нет критериев приёмки, а check без объявленной стадии отказывает вовсе. Стадию называет человек (tasks.py stage build|support) — машина её не выводит: список пунктов одинаково выглядит и планом стройки, и очередью правок.

5. Объяви переходное состояние

Сразу после переноса канон заполнен не весь, и это нормально, но обязано быть названо, иначе следующий агент примет скелет за поломку.

Печатается по факту: сколько документов стоят честной строкой вместо содержания, сколько маркеров долга в architecture.md, сколько задач без критериев приёмки. Закрывается порциями по ходу работы, а не одним заходом.

6. Позови обоих судей

docs.py увидел раскладку, а не смысл: перенос растащил один факт по двум домам, оставил в architecture.md поведение, которому место в спеке, и оторвал ADR от его design.md. Ничего из этого скрипт не видит, и первый прогон на живом проекте обычно самый урожайный — правило единственного дома до адаптации никто не проверял.

Вызови Skill av-dev:doc-healthcheck — он зовёт обоих судей на весь канон разом и держит разбор урожая порциями.

Передай им объявленное переходное состояние из шага 5 — иначе честная строка в незаполненном слоте вернётся находкой, а это не поломка, а объявленный долг.

7. Вычитай написанное — агент doc-wording

Судьи смотрят утверждения, а adopt только что писал текст: честные строки в пустые слоты, переписанные при переносе абзацы, шапки перенесённых документов. Язык этого текста не проверяет никто другой, а зовущий здесь по определению тот, кто его и написал.

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

upgrade — канон вырос

  1. docs.py version — версия проекта и версия скрипта.
  2. Проект новее скрипта — обнови маркетплейс, а не проект: это отстал плагин.
  3. Иначе иди по changelog.md снизу вверх от версии проекта до текущей и делай названное в каждой записи. Записи независимы и применяются по порядку.
  4. Подними версию — docs.py bump. Он правит строку, а не переписывает файл: комментарии в нём принадлежат проекту. Последним шагом, потому что число объявляет пройденными записи журнала.
  5. docs.py check.
  6. Позови судей — Skill av-dev:doc-healthcheck.
  7. Позови вычитку — агент doc-wording, но только по тем документам, которых записи журнала коснулись, и только если правка была текстовой, а не переименованием файла. Записи журнала пишутся руками в проектной прозе, и дописанный по журналу раздел — такой же свежий текст, как на синке.

Записи журнала описывают что сделать проекту. Если запись этого не говорит — это дефект журнала, и о нём надо сказать, а не догадываться.

Каталог задач повышается этим же журналом. Версия одна на всю раскладку — version в .av-dev.toml, — и записи журнала говорят про обе половины: и про документы, и про каталог задач. Порознь версии жили, пока плагинов было три и проект мог взять одну половину без другой; с одним плагином два числа означали бы только вопрос, по какому журналу повышать. Что каталог задач отстал, скажет tasks.py check своей строкой гейта — той же версией, что и docs.py.

Шаг 6 обязателен, и вот почему. check сверяет число в .av-dev.toml с версией скрипта — и только его. Применена ли запись журнала по существу, он не знает: проект несёт version текущей версии и может не иметь того, чего требовала любая из пройденных версий. Записи применяются руками (переименовать секцию, проставить типы, дописать раздел каждому fix), а ручной проход по нескольким записям подряд — ровно то место, где половина шага делается и забывается. Судьи и есть проверка, которой у upgrade иначе нет: doc-consistency увидит, что документы разошлись после переименований, doc-code-drift — что переехавший факт разошёлся с кодом.

Чего этот скилл не делает

  • Не сочиняет содержание. Пустой слот получает честную строку о том, что его наполнить пока нечем, а не выдуманный абзац. Придуманный периметр модели угроз хуже отсутствующего: по нему будут строиться находки.
  • Не удаляет то, чьё содержимое не нашло дом. Оригинал живёт, пока не названо поимённо, куда переехал каждый его кусок.
  • Не ведёт содержимое канона — это скилл doc-sync. Здесь только раскладка.
  • Не заводит проект с нуля — это скилл doc-init.
  • Не правит историю. В старых коммитах старые пути остаются, и это нормально.

Доклад

  • Что нашёл docs.py: код выхода и число пунктов дрейфа.
  • Что перенесено: файл → дом, числом и поимённо для спорного.
  • Удалённые дубли — с указанием, против какой спеки сверялся каждый.
  • Не разложилось — поимённо, с причиной.
  • Переходное состояние числами: честных строк, маркеров долга, задач без критериев.
  • Граница покрытия: что проверила машина, что судил ты, чего не смотрел никто.