# Решения по устройству процесса Журнал согласований: что решено, почему и что из этого следует. Пишется по ходу разбора тем, одна тема — один раздел. Причина обязательна: через месяц она забывается раньше факта. Незакрытые остатки прошлого захода — [REMAINING.md](REMAINING.md). ## Требования, зафиксированные по ходу Не решения — вход, который обязан быть удовлетворён и разбирается в названной теме. **Т1. Адаптация и проверка проекта под канон — обязательный скилл.** Нужно уметь прийти в **любой** старый проект и перевести его на текущие рельсы. Канон при этом сам будет меняться, поэтому уже приведённые проекты тоже должны повышаться до новых версий. *Разбирается в теме 5 (старт и жизненный цикл проекта).* Следствия, которые из этого уже видны: - **У канона обязана быть версия, а у проекта — отметка, под какую он приведён.** Иначе «соответствует канону» не имеет определённого ответа: сравнение идёт с тем, что модель помнит сейчас, а это и есть дрейф. - **Журнал изменений канона — как миграции.** Каждое повышение версии несёт запись «что добавилось, что переехало, что удалено, что сделать проекту». Без него адаптация переизобретается на каждом проекте. - **Отметка версии машиночитаема.** `.docs.json` отвергнут как *указатель путей* (решение F), но отметка версии — другое: её читает скрипт, и разбирать прозу `CLAUDE.md` для этого не нужно. Прецедент — `.tasks.json`. - **Операций три:** `check` (соответствие текущему канону), `adopt` (перевод чужой раскладки), `upgrade` (повышение с версии N до M по журналу). Первая и третья — одно сравнение с разными исходами. - **Механизируемое и суждение не смешивать.** Скрипт проверяет пути, лишние файлы, битые ссылки, версию. Агент судит о смысловых дублях (`docs/specs/ recognition.md` против capability `recognition`) и об оставшемся поведении в `architecture.md`. Скрипт, отчитавшийся «канон соблюдён» на проекте с тремя лишними файлами, хуже отсутствующего. - **Границы плагинов:** `docs/tasks/` — часть канона документов, но владеет им `av-dev-tasks` со своим `tasks.py adopt`. Два плагина сходятся на одном каталоге. *Тема 7.* ## 1. Статус OpenSpec (2026-08-03) ### Что было OpenSpec несёт оба проекта: healthlog — 5 capability, 3530 строк спек, 9 архивных change за две недели; jellybit — 11 capability, 3895 строк, 43 архивных change. При этом в трёх местах плагина написана ветка «проект без OpenSpec» (`task-pipeline` предпосылки, `review-pipeline` предпосылки, `task-batch` предпосылки) — и **не исполнялась ни разу**. Проектные факты живут в пяти домах: `CLAUDE.md`, `docs/architecture.md`, `openspec/specs/`, `openspec/config.yaml` → `context`, и планируется шестой — `docs/review-brief.md`. Расхождение измерено: у healthlog раздел «Хранилище» в `docs/architecture.md` — 950 строк (377–1328) против `openspec/specs/storage/spec.md` на 1337 строк. Два описания одного поведения, никем не сверяемые. У jellybit того же нет: `docs/specs/architecture.md` — 300 строк обзора, детали в 11 спеках. **Проект с 43 изменениями держит архитектуру втрое короче проекта с 9.** ### Решено **A. OpenSpec — жёсткая предпосылка `av-dev-pipeline`.** Ветки деградации удаляются, вместо них объявленная зависимость и проверка на старте. Зависимость на уровне **плагина, а не процесса**: `av-dev-tasks`, `av-dev-git` и будущий плагин документов от OpenSpec не зависят и работают на python/ansible-проектах. *Причина:* непроверенная ветка деградации хуже честной строки «требуется OpenSpec» — она даёт ложную уверенность, что проект без спек поедет. **B. Нормативный дом поведения — `openspec/specs/`.** `architecture.md` переопределяется как **обзор**: принципы, компоненты со ссылками на capability, внешние форматы данных, раскладка, деплой, открытые вопросы. Поведения он не описывает. *Причина:* `opsx:archive` вливает дельты именно в `openspec/specs/` — любой другой нормативный дом обязан синхронизироваться руками и разойдётся. Форма jellybit это уже подтвердила на 43 изменениях. **C. `openspec/config.yaml` → `context` держит только нужды генерации.** Язык, правила именования capability, придирки валидатора RFC 2119 — и ссылки. Правило ревью, пересказ конвенций и инварианты оттуда вычищаются: у них есть свои дома. *Причина:* блок «Ревью (процесс, не артефакт)» в обоих `config.yaml` дословно повторяет шаги 4 и 7 `task-pipeline`. Это второй дом для правила, которым владеет плагин, и он разойдётся на первой же правке. ### Что из этого следует Из A: 1. Три места с веткой деградации переписываются на объявленную предпосылку плюс проверку на старте (есть `openspec/`, разрешаются `opsx:*`) и внятный отказ: `task-pipeline` предпосылки, `review-pipeline` предпосылки, `task-batch` предпосылки. 2. Описание `av-dev-pipeline` в маркетплейсе получает строку «требует OpenSpec». 3. **Факт для темы «объединять ли tasks и pipeline»:** объединение потянуло бы зависимость от OpenSpec на управление задачами, которой там сейчас нет. Из B: 4. Правило «поведение — в спеку, устройство и границы — в архитектуру» становится контрактом плагина документов и правилом шага «синк документации» в `task-pipeline`. 5. healthlog чистится **не разом**: раздел вычищается той задачей, которая его касается. Нужен способ не потерять остаток — иначе 950 строк «Хранилища» останутся навсегда. 6. **Дыра, которую решение открывает:** «почему» после архивации. Сегодня `CLAUDE.md` healthlog велит писать причину решения в `architecture.md` — а мы её оттуда выселяем. Спеки нормативны и «почему» не держат; `design.md` живёт внутри change и уезжает в архив. Либо ADR (как у jellybit), либо явное правило «почему живёт в архивных change». **Первый вопрос следующей темы.** Из C: 7. `av-dev-pipeline` даёт образец `openspec/config.yaml` отдельным reference — он владеет связью с OpenSpec. Заполняется при старте проекта и при `adopt`. 8. У обоих проектов из `config.yaml` вычищается блок «Ревью (процесс, не артефакт)», пересказ конвенций и инвариантов. ## 2. Канон документов проекта (2026-08-03) ### Что было Измерено по обоим проектам: - **«Почему» не теряется — оно не находится.** `design.md` пишется почти всегда (jellybit 39 из 43 архивных change, healthlog 9 из 9 — ≈285 КБ за две недели) и имеет секции `Context` / `Goals / Non-Goals` / `Decisions` / `Risks / Trade-offs`, то есть является ADR по структуре. Против этого ADR руками: **6 записей у jellybit, четыре из них 13 июня — в день старта**; между 15 июня и 23 июля прошло ~40 изменений и ноль ADR. У healthlog ADR нет вовсе, а настоящее ADR-рассуждение (отказ от DuckDB) лежит в разделе «Открытые вопросы» файла `architecture.md`, потому что больше некуда. - **Два плана.** `docs/plan.md` healthlog («порядок и его обоснование», 11 шагов) и `/PLAN.md` из `av-dev-tasks` («цели с обоснованием очереди прозой») — один артефакт под двумя именами. - **Дубли спек у jellybit.** Из шести файлов `docs/specs/` три (`recognition`, `review-ux`, `workflow`) описывают поведение, уже покрытое capability в `openspec/specs/`. - **`docs/drafts/` раскладывается без остатка:** `roadmap.md` → цели в «порядок», `conventions-backlog.md` → задачи `[idea]`, `logical-title-model.md` (293 строки, итог «сущность `title` не вводим») → намеренный отказ, то есть ADR. ### Решено **D. «Почему» — ADR как промоут поверх архива.** Обоснование по-прежнему пишет `design.md`; ADR — короткая запись, цитирующая решение и ссылающаяся на архивный `design.md`. Заводит её **шаг «синк документации» пайплайна по названному триггеру** (дорогой откат / намеренный отказ от очевидного / пересмотр прежнего решения), а не человек по вдохновению. *Причина:* ручной ритуал эмпирически не выжил — 6 записей на 52 изменения. Автоматический (`opsx:propose` пишет `design.md` всегда) работает и производит на порядок больше. Чинить надо не дом, а индекс и критерий промоута. **E. `docs/plan.md` растворяется в `/PLAN.md`.** Файл удаляется, 11 шагов становятся целями в «порядке», ссылки в `CLAUDE.md` и паспорте переводятся. **F. Пути жёсткие, оба проекта приводятся к одному виду.** Плагин знает раскладку поимённо; указателя вида `.docs.json` нет. *Причина (словами владельца):* «так проще ориентироваться во множестве проектов, а не видеть слегка похожую, но разную структуру в каждом. Все проекты малого и среднего размера, проще подогнать их под одну структуру. Кроме того, у OpenSpec тоже структура строгая». Цена принята сознательно: плагин перестаёт быть переносимым на чужой репозиторий, а `adopt` из «поправь указатели» превращается в «перенеси файлы». **G. Конвенции и разведка — каталогами с README-индексом.** `docs/conventions/` и `docs/research/`: путь жёсткий, нарезка внутри свободна. Схема хранилища — **отдельный** `docs/database.md` (своя каденция: меняется миграцией, а не архитектурным решением; гейт healthlog уже сверяет миграции с документацией). Конвенции идентификаторов и именования — не схема, они в `conventions/`. **H. Слота для черновиков нет.** Идея → задача `[idea]`; намеренный отказ → ADR; порядок работ → `PLAN.md`; незрелое размышление → `opsx:explore` внутри change. ### Канон ``` CLAUDE.md памятка агенту: что это, стек, инварианты, команды, слоты docs/ passport.md зачем и для кого; чем НЕ является; сценарии; референсы architecture.md как сложено — обзор: принципы, компоненты со ссылками на capability, внешние границы, раскладка, деплой database.md схема хранилища (там, где есть БД) conventions/README.md + <тема>.md как пишем код; README держит правило промоута research/README.md + <тема>.md что показала реальность: чужие форматы, живые данные adr/README.md + template.md + ADR-*.md почему — промоут поверх архивных design.md review-journal.md промахи конвейера ревью ← уточнено в теме 3 review-brief.md предмет ревью — см. тему 3 ← отменено в теме 3 tasks/ av-dev-tasks: items/, PLAN.md, BACKLOG.md, SPRINT.md, REJECTED.md openspec/ config.yaml только нужды генерации + ссылки specs//spec.md что система делает — нормативно changes/archive/ журнал изменений с design.md — сырьё для ADR ``` Слотов **нет** у: `docs/drafts/`, `docs/specs/`, `docs/plan.md`, `BRIEF.md`, `docs/backlog/`, `docs/review/journal.md`. ### Что из этого следует 9. **Переезд healthlog:** `architecture.md` 1611 → обзор (поведение уезжает в `openspec/specs` по разделу за задачу); `conventions.md` → `conventions/README.md`; `local-research.md` 1829 → `research/`; `plan.md` → `docs/tasks/PLAN.md`; `backlog/` → `docs/tasks/`; завести `docs/adr/`. 10. **Переезд jellybit:** `BRIEF.md` → `docs/passport.md` (заодно обновить — не трогался с 13 июня); `docs/specs/architecture.md` → `docs/architecture.md`; `docs/specs/database.md` → `docs/database.md`; `docs/specs/jellyfin-layout.md` → `docs/research/`; `docs/specs/{recognition,review-ux,workflow}.md` сверить с capability и удалить как дубли; `docs/review/journal.md` → `docs/review-journal.md`; `drafts/` растворить по H; `docs/backlog/` → `docs/tasks/`. 11. **`adopt` меняет природу** — теперь он переносит файлы, а не правит указатели. Разбирается в теме про старт проекта. 12. **Открыто до темы 6 (поддержание):** точная формулировка триггера промоута в ADR; нужен ли механический `check` раскладки документов, раз пути жёсткие; как не потерять остаток при постепенной чистке `architecture.md`. ## 3. Брифа ревью нет — бриф это и есть канон (2026-08-03) ### Что было Контракт брифа — 413 строк, 13 разделов, отдельный файл `docs/review-brief.md`, который каждый проход читает как истину. Заполнение на обоих проектах дало 841 и 734 строки, и `REMAINING.md` уже отметил, что часть разделов вырождается в пересказ. Разбор по разделам после решения F (жёсткие пути) показал: **посредник между агентом и файлом не нужен, когда путь известен**. Восемь из тринадцати разделов дублируют канон или снимаются жёсткими путями. ### Решено **I. Отдельного файла-брифа нет.** Проектную конкретику проходам дают документы канона напрямую, по жёстким путям. Формулировка владельца: «артефакты в `docs` и должны стать частями брифа, а для ревью достаточно дать ссылки на эти артефакты». *Причина:* один факт — один дом. Бриф был вторым домом для паспорта, инвариантов и карты, а разошедшийся бриф хуже отсутствующего: он выглядит актуальным. **J. Заводится `docs/security.md`.** Периметр **первой строкой** (целевой и сегодняшний, если контур не развёрнут), недоверенный вход и его каналы, из чего строятся пути и ключи, что разграничивает доступ, что чувствительнее чего, что вне модели. Материал уже есть, но рассыпан: у healthlog — раздел «Аутентификация» в `architecture.md` и строка про секреты в `CLAUDE.md`, у jellybit — секреты в `conventions/config.md`. **Периметра нет ни у одного**, а без него враждебный проход не выбирает между «открыт наружу» и «контур доверенный». **K. `review-journal.md` → `docs/review.md`:** журнал дефектов плюс настройка конвейера под проект. Туда садится остаток брифа, который фактом о проекте не является — типовые узлы, типовые ложноположительные, вопросы к проходам, недоступно проверке. *Причина:* все четыре — производные калибровки, и журнал им источник. `## Вопросы к проходам` сам называет журнал главным источником; `### Перестали проверять сознательно` требует ссылки на его запись. **L. Журнал расширяется до всех воспроизведённых дефектов** с пометкой «проскочил / пойман ревью». Проверочный набор для калибровки — выборка по пометке. *Причина:* пойманные дефекты с оракулом (768 МиБ пика, 5.019 с удержания блокировки) сегодня не сохраняются нигде, кроме отчётов триажа в архиве change, а они и есть лучшая опора для прохода — проектные, воспроизводимые, однажды оказавшиеся правдой. **M. Семантика гейта — в `CLAUDE.md`, расширением раздела «Команды».** Чем краснеет безусловно и почему, где логи, что означает исход, чего в гейте намеренно нет, **кто и когда обязан гонять дорогое вне гейта**, что запускать запрещено (с путями). Гейт краснеет не только в ревью — это факт о проекте. **N. Severity инвариантов дописывается в `CLAUDE.md`** рядом с формулировкой. Контракт брифа сам называл это лучшим исходом; жёсткие пути делают возможным. Оговорка «выведена по обратимости» исчезает вместе с пересказом. ### Канон после темы 3 ``` CLAUDE.md что это, стек, инварианты с severity, команды, семантика гейта, запреты, слоты docs/ passport.md зачем и для кого; чем НЕ является; сценарии; референсы architecture.md как сложено — обзор; окружение, внешние зависимости, наблюдатель, характер потока database.md схема хранилища; представление данных и настройки с числовым значением (таймаут занятости, лимит тела, режим журналирования, ретеншен) security.md периметр первой строкой; недоверенный вход; из чего строятся пути и ключи; разграничение; что вне модели conventions/README.md + <тема>.md research/README.md + <тема>.md наблюдения и измеренные числа с провенансом adr/README.md + template.md + ADR-*.md review.md настройка конвейера под проект + журнал дефектов tasks/ av-dev-tasks openspec/ config.yaml, specs//spec.md, changes/archive/ ``` Слотов **нет** у: `docs/review-brief.md`, `docs/drafts/`, `docs/specs/`, `docs/plan.md`, `BRIEF.md`, `docs/backlog/`, `docs/review-journal.md`. ### Что из этого следует 13. **Скилл `project-brief` растворяется.** Заведение недостающих документов канона — часть скилла старта/адаптации (тема 5, требование Т1). 14. **Девять charter'ов переписываются второй раз.** Сейчас каждый читает «из раздела `## X` брифа»; станет — из файла канона. **Цена названа вслух:** первая переписка (вынос в плагин) осталась незамеренной — `REMAINING.md`, пункт 1. Вторая делает замер по четырём реальным находкам healthlog **обязательным, а не желательным**: два неизмеренных изменения подряд в том самом месте, где присваивается severity. 15. **Теряется соседство фактов, и charter обязан сшивать.** Контракт настаивал, что замер становится находкой только рядом с настройкой: «768 МиБ пика» — аномалия, лишь если известно, что запись лежит сжатой и распаковывается целиком; «5.019 с удержания блокировки» — отказ соседа, лишь если известен таймаут занятости. Теперь это `research/` и `database.md`, и charter'ы `ops`, `adversary`, `reimpl` обязаны прямо говорить «собери из этих двух», иначе проход снимет верное число и честно понизит находку до гипотезы. 16. **Деградация становится поразрядной** — и это лучше прежнего «нет брифа → деградирует всё». Нет `security.md` — деградирует `adversary`; нет `research/` — числа неизвестны `ops`, `adversary` и `reimpl`; нет `passport.md` — архитектурный проход теряет границу домена. Каждый проход пишет свою строку в границы покрытия. 17. **Открытый вопрос из `REMAINING.md` закрыт:** раздел `## Триггеры` удаляется вместе с брифом. Правило выбора профиля остаётся в скилле конвейера; проектная конкретизация, если понадобится, — в `docs/review.md`. ## 4. Границы плагинов (2026-08-03) ### Что было Связь `tasks` ↔ `pipeline` уже сделана **ролями, а не именами**: скиллы говорят «пайплайн проекта», «владелец спринта», «тот, кто ведёт задачи». Жёсткая ссылка по имени ровно одна — `task-pipeline:112` на канонический текст правила про остаток внутри `session`, и рядом обработан случай «плагин не подключён». Слоты `CLAUDE.md` при этом дублировались уже внутри одного плагина: шесть у `tasks`, семь у `session`, три пары — одно и то же. Темы 2–3 растворили ещё часть: «куда переезжает суть» отвечает канон, «оракулы» — семантика гейта (решение M), «где живёт разбор процесса» — `docs/review.md` (решение K). Из тринадцати остаётся около четырёх. ### Решено **O. Три плагина: `av-dev-pm`, `av-dev-pipeline`, `av-dev-git`.** - **`av-dev-pm`** (бывший `av-dev-tasks`) — управление продуктом: канон документов, задачи, цели, спринты, старт и адаптация проекта. Владеет всем `docs/`, включая `docs/tasks/`. - **`av-dev-pipeline`** — исполнение: SDD-цикл, конвейер ревью, девять агентов. - **`av-dev-git`** — стиль коммитов; работает в любом репозитории. *Причина (словами владельца):* «пайплайн можно и переиспользовать в других проектах с более простым подходом к управлению». Это подтверждается разбором: пайплайн зависит от **файлов канона и от OpenSpec, а не от плагина** `av-dev-pm`. В чужом проекте нужных файлов нет — включается поразрядная деградация (следствие 16), и это штатный режим, а не поломка. *Имя:* `pm` = product management, «объединение всех операций по управлению продуктом», и согласуется с `av-dev-git`. **P. Граница «пайплайн не закрывает задачу» снимается.** Закрывает задачу и двигает строки между `SPRINT.md` / `BACKLOG.md` / `REJECTED.md` **агент- оркестратор** — `task-pipeline` и `task-batch`, а не сабагенты внутри них. Зовёт он `tasks.py` через слот «Команда учёта задач» в `CLAUDE.md`. Слот, следовательно, **не исчезает, а становится мостом между плагинами** — и заодно тем, чего в чужом проекте нет, отчего пайплайн там работает как прежде: докладывает исход, записей учёта не трогает. **Q. `av-dev-backlog` помечается устаревшим и остаётся** до перевода jellybit. *(заменено на тему 30: плагин удалён раньше этого срока — условие пережило свою причину.)* Описание переписывается так, чтобы не ловить триггер «добавь задачу в беклог» — иначе агент выбирает между ним и `av-dev-pm` случайно. ### Что из этого следует 18. **Переименование `av-dev-tasks` → `av-dev-pm`** тянет `plugin.json`, `marketplace.json` и пространство имён скиллов: `av-dev-tasks:session` → `av-dev-pm:session`, включая ссылку из `task-pipeline:112`. 19. **Раздел «Стимулы, которые процесс создаёт» в `session` переписывается.** Снятая граница выбила механическую опору у трёх защит: «сжать задачу до остатка», «занизить урожай», «занизить критерии приёмки» — во всех трёх приёмщик и исполнитель теперь совпадают. Остаются: **отчёт триажа** в `openspec/changes//review/` (независимый артефакт, `task-batch` уже сверяет полноту ревью по нему, а не по прозе исполнителя), **`SPRINT.md` под git** с видимой историей и **`reopen --reason`** — закрытие не окончательно, приёмка человеком на сессии его отменяет. Раздел обязан назвать их поимённо, иначе обещает защиту, которой нет. 20. **Конфликт владения `docs/tasks/` снят** — канон и задачи теперь в одном плагине. 21. **Скилл `adopt` из `av-dev-tasks` поглощается** скиллом адаптации проекта уровня канона (требование Т1). Разбирается в теме 5. 22. **Состав `av-dev-pm`:** `tasks`, `session` (есть), `docs` — ведение канона, `project` — старт, adopt, check, upgrade (тема 5). ## 5. Старт проекта и жизненный цикл под каноном (2026-08-03) ### Что было Требование Т1: прийти в любой старый проект и перевести на текущие рельсы; канон сам меняется, значит уже приведённые проекты тоже повышаются. Существующий `adopt` (уровень задач) даёт готовую форму: **`scan` — только чтение, карта → суждение человека → `apply` — запись одним проходом**, с отказом до первой записи при неверной карте и с обязательным разделом «не разложилось» поимённо. Форма переносится на уровень канона как есть. Четыре операции различаются не поровну: `adopt`, `check` и `upgrade` — одна машина сравнения с разными исходами, а `init` — принципиально другой режим, разговор, а не сверка. ### Решено **R. Два скилла: `av-dev-pm:init` и `av-dev-pm:canon`.** `init` — интервью по входному брифу для нового проекта. `canon` — привести к канону: `check`, `adopt`, `upgrade` одной машиной. **S. Скелет канона заводится целиком, незаполненное называется пустым.** Все файлы канона есть с первого дня, но незаполненный держит **одну честную информативную строку**: «наблюдений на живых данных нет — внешний источник один, формат документирован», «прецедентов не накоплено», «внешних зависимостей нет, смотри на диск и на СУБД». *Причина:* это тот же принцип, что был в контракте брифа, поднятый на уровень файлов. Проход читает такую строку **как факт**, а не как пробел, и не тратит обязательный вопрос впустую. Отсутствие файла он прочитать не может никак. **Защита от вырождения в заглушки** берётся у `tasks.py`: пока на месте стоит плейсхолдер шаблона, `check` о нём напоминает. Строка «TBD» — это не «пустое названо пустым», и `check` обязан их различать. **T. Скрипт `docs.py` плюс версия канона в `docs/.pm.json`.** Отдельный скрипт, не расширение `tasks.py`: рефакторинг 2421 работающей строки ради удобства вызова не окупается. `docs.py check` зовёт `tasks.py check` для своей части. **Граница механизируемого объявляется вслух — иначе `check` соврёт.** | Проверяет `docs.py` | Судит агент | | --- | --- | | отсутствующие пути канона | смысловой дубль (`docs/specs/recognition.md` против capability) | | файлы в `docs/` вне канона | поведение, оставшееся в `architecture.md` | | битые относительные ссылки | протухший факт, разошедшийся с кодом | | версия канона и её отставание | достаточность честной строки в пустом слоте | | нетронутый плейсхолдер шаблона | | `check`, отчитавшийся «канон соблюдён» на проекте, где из шести файлов три лишние, хуже отсутствующего. ### Порядок интервью `init` — зависимость, а не удобство Цель и потребители → чем это **не** является и мера успеха → периметр и что недоверенное → стек, хранилище, необратимое → чем краснеет гейт → первые цели в `PLAN.md`. Каждый блок опирается на ответ предыдущего. Вход — свободный текст «что мне нужно и почему» (образец формы: `BRIEF.md` jellybit, 6 КБ). После `init` его дом — `passport.md`; отдельным файлом он не остаётся. **`init` физически не производит полный канон.** В новом репозитории нет кода, а `architecture.md`, `database.md`, `conventions/` и `research/` выводятся из него. Они заводятся скелетом с честной строкой («архитектуры пока нет: кода нет, заводится первой задачей») и наполняются шагом синка документации. ### Что из этого следует 23. **`docs/.pm.json` поглощает `/.tasks.json`.** Меняется цепочка разрешения в `tasks.py` — сегодня он ищет `.tasks.json` вверх от текущего каталога. Нужен переходный период либо чтение обоих. 24. **`tasks.py adopt` становится шагом внутри `canon adopt`**, а не отдельной пользовательской операцией: `docs/tasks/` — часть той же раскладки. 25. **Версия канона — целое число**, не semver: у канона нет обратной совместимости, есть только «приведён» и «не приведён». 26. **Журнал изменений канона** живёт в плагине — `av-dev-pm/skills/canon/references/changelog.md`, запись на версию: что добавилось, что переехало, что удалено, что сделать проекту. 27. **Открыто до темы 6:** звать ли `docs.py check` из гейта проекта. У healthlog `task gate` уже сверяет миграции с документацией, так что место есть; но гейт принадлежит проекту, и плагин может только рекомендовать строкой в отчёте. ## 6. Поддержание документов по ходу разработки (2026-08-03) ### Что было Гейт healthlog **уже изобрёл нужный механизм** для одного документа — `scripts/gate.py:177-181`: миграция изменена, а `docs/database.md` нет → `FAIL`. Документ канона сверяется с кодом красным гейтом, а не напоминанием. Против этого — прямое доказательство, что́ не работает: у `adr/` был список триггеров прозой («выбор технологии, структурные решения, дорогой откат, намеренный отказ»), и он дал **6 записей на 43 изменения**. Прозаический триггер, который некому проверить, не срабатывает. Механизируемы три документа из десяти: `database.md` (миграция), `architecture.md` (capability в `openspec/specs/` без упоминания в обзоре), `tasks/` (`tasks.py check`). Плюс `openspec/specs/` вливает `opsx:archive`. ### Решено **U. Принуждённое отрицание в докладе шага синка.** Шаг обязан назвать **каждый** документ канона: обновлён — чем, либо «не требуется, потому что…». Нетронутые группируются одной строкой с общей причиной. *Причина:* это тот же приём, что «границы покрытия» в отчёте ревью и «пустой пункт называется пустым» в каноне — и единственный, о котором в этом репозитории есть данные, что он работает. Отличить «не написал» от «написал, что не требуется» можно только тогда, когда отрицание обязательно. **Триггер ADR, окончательная формулировка.** Запись заводится, когда верно одно из трёх: **дорогой откат** (переделка стоит дороже переписывания одного файла); **намеренный отказ** от очевидного подхода; **пересмотр прежнего решения** — тогда у старой записи обязателен статус «заменено на». Не заводится для рутины и для того, что видно из кода и `git log`. Источник — архивный `design.md`: ADR его цитирует и на него ссылается, а не пересказывает. **V. `docs.py check` обязателен в гейте проекта.** Скилл `canon` при адаптации добавляет шаг и печатает это в отчёте. *Причина:* гейт — единственный общий станок, который нельзя пропустить. Проверка, которую зовёт агент, может быть не позвана; прецедент в самом healthlog уже есть. Сверка «миграция изменена — `database.md` нет» **обобщается**: путь миграций проекта записывается в `docs/.pm.json` рядом с версией канона, и `docs.py` делает эту проверку сам, а не каждый проект заново. **W. Остаток чистки помечается маркером и считается числом.** Неразобранный раздел получает ``, `docs.py` считает маркеры и печатает остаток. Закрывается порциями, как переоценка задач. **Маркеры гейт не красят.** Это долг, а не отказ: покрасневший гейт на первом маркере сделал бы постепенный переезд невозможным, а разовый — обязательным. Число печатается и убывает на глазах. ### Что из этого следует 28. **Шаг 9 `task-pipeline` переписывается** из четырёх пунктов прозой в построчный доклад по документам канона. 29. **`promote.md`, шаг 3, переписывается:** «вычеркнуть пункт из брифа, правило переезжает в перечень механизированного в разделе `## Карта`» → перечень механизированного живёт в `conventions/README.md`. Брифа нет. 30. **`docs/.pm.json` держит не только версию канона**, но и пути, нужные проверкам: каталог миграций — как минимум. 31. **`docs.py check` получает две сверки с кодом**, а не только раскладку: миграции ↔ `database.md`, capability ↔ упоминание в `architecture.md`. ## 7. Раскладка скиллов и доставка скриптов (2026-08-03) ### Решено **X. Пять скиллов в `av-dev-pm`.** ``` av-dev-pm/skills/ init/ интервью по брифу → канон нового проекта canon/ раскладка: check / adopt / upgrade docs/ содержимое канона: ADR из архивного design.md, промоут конвенций, запись в research/ и review.md, чистка architecture.md tasks/ формат и содержимое задач session/ ритуал спринта ``` *Причина отдельного `docs`:* правила ведения содержимого канона обязаны жить у владельца канона, а не в шаге синка чужого плагина — иначе проект без пайплайна документацию вести не может. Это работает потому, что **вызов скилла через пространство имён между плагинами возможен**, в отличие от `$CLAUDE_PLUGIN_ROOT`: `task-pipeline` уже зовёт `opsx:propose` и `av-dev-pipeline:review-pipeline`. Шаг синка зовёт `av-dev-pm:docs`, а в чужом проекте деградирует до прозаического списка. Симметрия, по которой резалось: **раскладка и содержимое разделены и для документов, и для задач** — `canon` / `docs`, `tasks` / `session`. **Y. Скрипты не копируются — живут вместе со скиллами.** Три вызывающих, три способа дотянуться: | Кто зовёт | Как | | --- | --- | | скиллы `tasks`, `canon`, `docs` | `$CLAUDE_PLUGIN_ROOT` — свой плагин, работает всегда | | `task-pipeline`, `task-batch` | **вызов скилла** `av-dev-pm:tasks`, а не путь | | гейт проекта | путь переменной с умолчанием на канонический путь маркетплейса; пишет `canon adopt`, внятный красный отказ, если не найден | **Слот «Команда учёта задач» всё равно исчезает** — но снимает его не копия, а **вызов скилла через пространство имён**. Тот же приём, которым шаг синка зовёт `av-dev-pm:docs` (решение X): чужой плагин зовёт скилл, скилл разрешает свой `$CLAUDE_PLUGIN_ROOT` сам. Путь наружу не выносится вовсе. *Первоначально здесь было решено вендорить `scripts/tasks.py` и `scripts/docs.py` в проект. Отменено после проверки фактов:* - **CI нет ни в одном проекте** (ни `.github`, ни woodpecker, ни drone). Pre-commit есть только у jellybit — `lefthook` с gofmt/vet/lint/test/gitleaks — и гоняется на той же машине, где установлен плагин. Довод «не работает в CI и у человека без Claude Code» оказался гипотетическим. - **Пара «источник — копия» существует и без вендоринга.** Установленный маркетплейс — git-клон; на момент разбора он стоял на `092d07c`, на четыре коммита позади `master`, и `av-dev-tasks` с `av-dev-pipeline` в нём отсутствовали вовсе. Довод «вендоринг создаёт вторую копию» был слабее, чем подан. - **Обновление маркетплейса — одна точка на все проекты.** При вендоринге каждый проект повышается отдельно, и проекты расходятся друг с другом — ровно та разнородность, против которой принято решение F. **Z. Имени у процесса нет — процесс это `av-dev`.** Маркетплейс уже `av-dev-skills`, плагины `av-dev-*`; в `CLAUDE.md` проекта пишется «процесс av-dev, канон версии N». Имя, которое нигде не работает, — украшение. ### Что из этого следует 32. **Решение P уточняется:** оркестратор закрывает задачи **вызовом скилла** `av-dev-pm:tasks`, а не запуском скрипта по пути. Плагина в проекте нет — вызов не разрешается, и пайплайн, как прежде, только докладывает исход. 33. **Слот исчезает из двух скиллов** — `tasks` (слот 6) и `session` (слот 7), — и из текстов `task-pipeline` и `task-batch`, которые на него ссылаются. 34. **`canon upgrade` отвечает за раскладку и версию в `docs/.pm.json`.** Скрипты обновляются обновлением маркетплейса, а не проектом. 35. **Скрипты живут в `av-dev-pm/skills/{tasks,canon}/scripts/`.** `docs.py` — в `canon`, потому что раскладку проверяет он. 36. **`canon check` сверяет версию канона проекта с версией установленного плагина** и говорит, кто отстал. Это нужно и без вендоринга: маркетплейс — git-клон, обновляется явно, и на момент разбора отставал на четыре коммита. 37. **Установленный маркетплейс требует обновления перед любой работой** — сейчас в нём нет ни `av-dev-tasks`, ни `av-dev-pipeline`. Это первый шаг выката (тема 8), иначе проверять будет нечего. ## 8. Порядок выката (2026-08-03) ### Объём Ссылок на бриф — **168 строк в 19 файлах** `av-dev-pipeline`, из них ~48 уходят вместе с удаляемыми `project-brief/SKILL.md`, `references/project-brief.md` и `references/brief-template.md`. Остальное переписывается на пути канона. ### Решено **AA. Инструмент строится целиком, потом проверяется.** Не пилот руками. *Риск принят сознательно:* если замер покажет деградацию severity, чинить придётся канон, зашитый к тому моменту в три скилла, скрипт и мигрированные файлы healthlog. *Удешевление, которое обязано быть заложено сразу:* **определение канона живёт в единственном reference-файле**, который читают `init`, `canon` и `docs`, а не повторяется в каждом. Правка канона — одно место плюс запись в журнал версий. *Страховка порядка:* **замер ставится перед переездом jellybit**, а не после всего, — он всё ещё блокирует то, что дороже всего откатывать. **BB. Работа ведётся в `docs/tasks/` самого `dev-skills`.** Скилл `tasks` не требует ни OpenSpec, ни языка — задачи для него просто каталог markdown. Цели — крупные куски, задачи — следствия. Заодно первая боевая обкатка собственного инструмента. **CC. `AGENTIC-TASKS.md` сжимается до истории решений и переезжает в `dev-skills`** отдельным `HISTORY.md`: почему не Scrum, числа первого замера, что отвергнуто и почему. Он описывает процесс, а процесс живёт здесь, не в healthlog. Остальное содержимое уже в плагинах, и второй дом для тех же правил — ровно то, против чего документ сам и написан. ### Порядок ``` 0. обновить установленный маркетплейс предусловие всего 0.5 завести docs/tasks в dev-skills, разложить 37 следствий по целям 1. РЕПОЗИТОРИЙ ПЛАГИНОВ 1.1 av-dev-tasks → av-dev-pm, пространство имён 1.2 канон одним reference-файлом — единственный дом определения 1.3 правки tasks и session: слоты, «Стимулы», .pm.json 1.4 новые init, canon, docs + docs.py 1.5 av-dev-pipeline: удалить project-brief, снять ветки деградации OpenSpec, переписать шаг 9, девять charter'ов, promote.md, убрать слот 1.6 av-dev-backlog устаревшим; README; журнал канона v1; HISTORY.md 1.7 REMAINING.md пересобрать — часть его вопросов закрыта этим разбором 2. HEALTHLOG — первая боевая проверка инструмента canon adopt, заполнение канона, security.md, review.md, ADR, маркеры в architecture.md, docs.py check в гейте 3. КАЛИБРОВКА на четырёх находках healthlog БЛОКИРУЕТ шаг 5 4. один-два спринта healthlog на новом процессе 5. JELLYBIT — переезд, удаление дублей specs, растворение drafts ``` ### Что из этого следует 38. **`REMAINING.md` частично устарел:** пункт 2 «Завести брифы» отменён темой 3; закрыты открытые вопросы про `## Триггеры`, `av-dev-backlog`, имя процесса и `AGENTIC-TASKS.md`. Пункт 1 (калибровка) стал обязательным, а не желательным. Пересобрать на шаге 1.7. 39. **Замер — единственный шаг, который нельзя переставить.** Всё остальное в порядке 1–5 можно тасовать; шаг 3 стоит перед шагом 5 жёстко. ## 9. Линтеры скриптов (2026-08-03) ### Что было Три скрипта на python, 3600 строк, ни одной проверки. `tasks.py` — 2450 строк, которые ходят по файловой системе, переименовывают и удаляют файлы задач. Требование к самим скриптам прежнее и не обсуждается: **голый `python3` 3.12, ноль внешних зависимостей** — они лежат рядом со скиллами и запускаются в чужом проекте, где ничего ставить нельзя. ### Решено **DD. `pyproject.toml` в корне `dev-skills`, зависимости через `uv`.** Файл живёт только здесь и не уезжает никуда: он держит **линтеры**, а не зависимости скриптов. Скрипты остаются запускаемыми любым `python3` — это проверено прогоном всех операций через `/usr/bin/python3`, а не через `.venv`. **EE. Ноль зависимостей охраняется двумя способами, и главный — второй.** `banned-api` у ruff ловит частые соблазны по имени (`requests`, `yaml`, `pydantic`, `click`, `rich`) — список заведомо неполный. Настоящий страж — pyrefly: в окружении нет ничего, кроме линтеров, поэтому **любой** сторонний импорт у него не разрешается. Первый способ даёт понятное сообщение, второй — полноту. **FF. Версии линтеров прибиты точно** (`ruff==0.16.1`, `pyrefly==1.2.0`) плюс `uv.lock` в git. Обновление линтера меняет набор находок, а находки правятся руками в скриптах, которые уезжают в чужие проекты. Обновление обязано быть отдельной осознанной правкой, а не побочным эффектом `uv sync`. **GG. `RUF001`–`RUF003` выключены.** Весь текст скриптов русский: сообщения, докстроки, комментарии. «Похожая на латиницу кириллица» здесь норма, а не опечатка, и три этих правила давали **311 срабатываний из 338** — шум, в котором тонут остальные 27. **HH. `av-dev-backlog` исключён из проверки.** *(исчерпано темой 30: плагин удалён, исключение снято из `pyproject.toml` и `copies.py`.)* Плагин помечен устаревшим и живёт до перевода последнего проекта, после чего удаляется целиком. Шесть его находок косметические (`os.replace`, `l` как имя), а правка замороженного кода без тестов — риск без выгоды. Исключение уходит вместе с плагином. **II. Голый `except Exception` разрешён только помеченный.** Правило `BLE` включено, а два места последнего рубежа (`main` обоих скриптов, код выхода 4 по словарю) несут `# noqa: BLE001` с причиной. Так третий такой except не появляется молча. ### Что из этого следует 40. **Найдено и починено 27 находок ruff и 14 pyrefly.** Содержательных две: мёртвая переменная `ques` в `check` (вычислялась и не использовалась — вопросы проверяет `questions_open`) и два места в `check --fix`, где `find_entry_index` может вернуть `None`, а результат идёт прямо в `list.pop` и в `range`. Оба сегодня недостижимы, и недостижимость держалась на рассуждении о вызывающем коде, а не на проверке. *Поправлено по ревью:* там стоит `raise`, а не `continue`. Тихий пропуск превратил бы сломанный инвариант в отчёт «индексы согласованы» — то есть в враньё; громкий отказ кодом 4 честнее. 41. **`os` из `tasks.py` ушёл целиком.** `os.replace` → `Path.replace`, `os.path.basename` → `Path.name`; импорт стал не нужен. 42. **`fail()` в `docs.py` объявлен `NoReturn`.** Без этого `read_config` выглядел как возвращающий неинициализированное значение — и это ровно то, что читатель кода тоже не мог знать наверняка. 43. **Проверка не входит ни в один гейт.** CI у репозитория нет, хука нет; запускается руками командой из README. Заводить хук ради двух скриптов, которые правятся раз в месяц, — плата ритуалом без выгоды. ## 10. Ревью готовых плагинов двумя проходами (2026-08-03) ### Что было Два независимых сабагента `fable` — по одному на `av-dev-pm` и `av-dev-pipeline`. **20 находок, из них две найдены обоими независимо.** Прошлые три круга ревью шли по одному проходу на всё; два прохода с разными предметами дали и больший урожай, и перекрёстное подтверждение самого дорогого дефекта. ### Что оказалось сломано по существу **JJ. Перестановка закрытия за коммит (решение из темы 8) сломала `reopen` и батч — и это нашли оба прохода.** `close --implemented` печатает «дорога назад: файл восстанавливается из git», а `reopen` искал **коммит удаления**, которого в новом порядке ещё нет: шаг 11 идёт последним, и учёт остаётся незакоммиченным. Проверено прогоном: `reopen` отказывал кодом 2 на свежезакрытой задаче — то есть в самом вероятном своём применении. Тем же грязным деревом ломался `task-batch`: `git rebase` и `git worktree remove` отказывают, и **каждая успешно закрывшая задачу ветка** уезжала бы в провалившиеся. Починено с обеих сторон: `reopen` берёт текст из `HEAD`, если коммита удаления нет, а шаг 11 обязан **коммитить учёт вторым коммитом** — иначе закрытие не доезжает до основной ветки и опора «`SPRINT.md` под git» остаётся словами. **KK. Канонический пример `docs/.pm.json` убивал `tasks.py`.** `canon.md`, `skeletons.md`, `tasks/SKILL.md` и `adopt.md` показывали ключ `tasks.sections`, которого скрипт не знает: `_validate_config` отвергает неизвестные ключи кодом 3 на **любой** команде. Проект, заведённый по канону дословно, остался бы без работы с задачами целиком — а `docs.py check` при этом печатал «канон соблюдён», потому что чужой код 3 уходит в «не проверялось». Секции живут в заголовках `##` индекса и второго дома не получают. ### Что из этого следует 44. **Класс находок тот же, что и в прошлые три круга: стыки.** Не новый код, а место, где один файл ссылается на другой. `sprint.md` в пункте «Сделана» всё ещё отсылал к порядку, который сам же тремя экранами ниже отменил; три остатка «шаг 9а» несли **предкоммитную** позицию закрытия; путь отчёта триажа не переживал `opsx:archive`, хотя по нему сверяют полноту ревью четверо. 45. **Инструкция, которую нельзя выполнить, выглядит как выполненная.** Ответ на вопрос по документированной процедуре (снять тег) оставлял задачу незабираемой, потому что судит **раздел**, а не тег; `canon adopt` требовал гнать `docs.py check` «до отсутствия дрейфа», недостижимого без нарушения запрета сочинять цели; урожай спринта, заведённый после `sprint close`, терял автотег молча. 46. **Два прохода по разным предметам дороже одного, но не вдвое.** Перекрытие оказалось ровно в одной находке из двадцати — той самой, что подтвердилась дважды. Практика остаётся: ревью на плагин, а не одно на репозиторий. ## 11. Зависимости между плагинами (2026-08-03) ### Целевая картина, которую проверяли `av-dev-git` ни от чего не зависит. `av-dev-pipeline` сам по себе: задача приходит **и обычным текстом**, и из `tasks`. `av-dev-pm` оперирует абстрактным «сделать задачу» и не знает, чем она выполняется. ### Что показала проверка **LL. Первые две цели выполняются, третья в исходной формулировке недостижима — и формулировку надо поправить, а не картину.** `av-dev-pm` **владеет конфигурационным файлом конвейера**: `docs/review.md` держит «Вопросы к проходам» и «Триггеры профиля», то есть перечисляет проходы поимённо, а скелет `review.md` несёт форму журнала дефектов. Кто-то этим словарём владеть обязан — канон и есть схема данных, которую конвейер читает. Честная формулировка цели: **`av-dev-pm` не зовёт пайплайн и не требует его наличия**. Она выполняется. **MM. Настоящая протечка была одна — необъявленная деградация опор приёмки.** «Стимулы» в `session` и приёмка в `sprint.md` держались на «сохранённом отчёте триажа» по конкретному OpenSpec-пути. В проекте без конвейера ревью защита от занижения урожая исчезала **молча**: сверять не с чем, а текст об этом не говорил. Теперь опора названа абстрактно («независимый отчёт ревью»), путь `av-dev-pipeline` дан как частный случай, а отсутствие конвейера обязано попадать строкой в доклад спринта. **NN. Ветка деградации шага 9 была неисполнима — ровно в том случае, ради которого написана.** «Плагина нет — открой `av-dev-pm/skills/canon/references/canon.md`»: путь в дерево маркетплейса, из проекта без установленного плагина не разрешается ниоткуда. Кросс-плагинные пути в дерево маркетплейса теперь не используются вообще: пайплайн ходит в **свой** `references/project-facts.md`, а ссылки в чужой плагин даются через `Skill <плагин>:<скилл>`. ### Что из этого следует 47. **Знаниевый цикл есть и он законен, но каждый его контракт обязан иметь единственный дом.** Пайплайн описывает раскладку `pm`, `pm` описывает артефакты пайплайна — пять симметричных контрактов, из них два уже разошлись: форма журнала дефектов (шесть полей против пяти, «Причина» потеряна) и список читателей `docs/research/` (`specs` выпал). Дома назначены: форма журнала — у конвейера, список читателей — у канона; в обеих копиях стоит явное указание на дом. 48. **Пайплайн больше не называет внутренние имена файлов `pm`.** `items/.md` и `SPRINT.md` в его тексте были вторым домом для раскладки, которую проект вправе переименовать через `docs/.pm.json`. 49. **Описания плагинов в манифестах врали умолчанием.** Ни `marketplace.json`, ни `plugin.json` не говорили, что `av-dev-pm` для конвейера **опционален**, а задача принимается текстом. Теперь говорят — это первое, что читает человек, выбирая, что подключать. ## 12. Механическая проверка копий (2026-08-03) ### Что было Разделение плагинов оставлено (тема 11), но цена его названа: пять симметричных контрактов в двух домах, два уже разошлись — форма журнала дефектов потеряла в копии поле «Причина», список читателей `docs/research/` потерял `specs`. Оба раза копия выглядела актуальной, и оба раза расхождение прошло мимо трёх ревью подряд. ### Решено **OO. Копия допустима, но обязана быть дословной и помеченной.** Разметка — HTML-комментарии, невидимые в отрендеренном markdown: `` … `` и `` … ``. `scripts/copies.py` требует побайтового совпадения текста между маркерами. *Почему комментарии, а не манифест копий отдельным файлом:* маркер уезжает в репозиторий проекта вместе со скелетом, и там он **полезен** — говорит читателю, что у текста есть дом и правится он там. Манифест остался бы в маркетплейсе и проекту ничего не сказал. **PP. Идентификатор строгий — буквы, цифры, дефис — и повторяется в закрывающем маркере.** Иначе документация о самом механизме объявляет дом и роняет проверку: это случилось на первом же прогоне, `README.md` объявил дом примером. Теперь пример пишется ``, угловые скобки под шаблон не подходят. **QQ. Ограда блока кода в сверку не входит.** В доме текст обрамлён своей ```, а в скелете тот же текст лежит внутри чужой, объемлющей ограды. Сверяется содержимое, а не разметка вокруг него. **RR. Коды выхода — общий словарь** (0 сошлось, 1 расхождение, 2 разметка, 3 не тот каталог, 4 сбой). Третий скрипт репозитория, и третий по тем же кодам. ### Что из этого следует 50. **Помечены два контракта:** форма записи журнала дефектов (дом — конвейер ревью, копия — скелет канона; это кросс-плагинная пара) и «когда заводить ADR» (дом — канон, копия — его же скелет). Второй пришлось сперва **сделать** дословным: копия говорила «обязателен статус», дом — «обязателен статус „заменено на"», и это ровно тот класс, который и ищется. 51. **Чего проверка не ловит — копию, которую забыли пометить.** Помечать остаётся решением человека, и это названо в `README.md` вслух: иначе зелёный прогон читался бы как «копий больше нет». 52. **Дом без копий — расхождение, а не замечание.** Маркер, обещающий дисциплину, за которой не за чем следить, — такая же ложная запись, как разошедшаяся копия. 53. **Запись в журнал версий канона проверка не заменяет.** Она видит, что копия отстала, но не видит, что проект уже унёс старую версию к себе. Это остаётся на человеке и сказано в обоих домах. ## 13. Секции `PLAN.md` переименованы (2026-08-03) ### Что было Секции назывались **«линия»** и **«кусты»** — метафора, требующая расшифровки при каждом употреблении. В текстах она и расшифровывалась: «звено упорядоченной линии продукта», «тематический куст — цель, в последовательность не встающая». Если название приходится объяснять рядом с каждым употреблением, объясняет не название. ### Решено **SS. «порядок» и «темы».** Заголовок называет ровно то свойство, которым секции различаются: в первой очередь значима и обоснована прозой, во второй порядка нет вовсе. Расшифровывать нечего — правило написано в самом имени. **TT. Записи в журнал версий канона не требуется — канон этих имён не знает.** `canon.md` называет файл `docs/tasks/PLAN.md` и ничего не говорит о его секциях: их дом — заголовки `##` индекса, а умолчание живёт в `tasks.py`. Версия канона поэтому не меняется, и проект вправе называть секции по-своему. Причина названа вслух, потому что соблазн повысить версию «на всякий случай» здесь сильный, а повышение обязало бы каждый проект что-то делать — при том что делать нечего. ### Что из этого следует 54. **Умолчание одно и живёт в `DEFAULT_PLAN_SECTIONS`.** Имена секций по-прежнему настраиваются `--plan-sections`, а домом остаются заголовки `##` индекса — переименование не трогает механику, только умолчание и тексты. 55. **Метафора — плохое имя для секции индекса.** Секция читается человеком без контекста, часто из вывода `list`, и второго шанса объяснить себя у неё нет. ## 14. Умолчания режимов прогона перевёрнуты (2026-08-03) ### Что было Оба скилла держали одно и то же умолчание — «по очереди», — хотя цена очереди у них разная. `review-pipeline` гнал проходы последовательно и требовал для параллельности **двух** условий (явная просьба **и** поимённо названный набор). `task-batch`, наоборот, планировал волны параллельных задач с потолком 2–3 и считал параллельность нормой прогона. Перепутаны оказались уровни. Проход ревью — чтение и рассуждение: он ничего не поднимает, ни за что не дерётся и по построению не видит выводов соседа. Задача батча — полный цикл пайплайна: гейт, поднятие сервиса вживую, вложенное ревью, общие порты и рабочие каталоги. Дешёвое стояло в очереди, дорогое гонялось разом. ### Решено **UU. В ревью умолчание — параллельно.** Стадии по-прежнему идут по порядку, параллельность касается только проходов внутри стадии. Последовательно гоняем по трём особым причинам, и каждая называется в отчёте: сказал оператор; проходы меряют; машина занята — причём занятость видит вызывающий, а не конвейер. Просьба «гони последовательно» **набора не требует**: очередь ничего не портит, она только дольше, и домысливать тут нечего — в отличие от прежнего правила, где неназванный набор блокировал отступление. **VV. Меряющая пара — правило стадии, а не решение прогона.** `adversary` и `ops` идут по очереди всегда: оба доказывают находки числами и оба меряют одно железо, а испорченный оракул хуже отсутствующего. Общее «гони параллельно» этого не отменяет; отменяет только прямое слово оператора **про эту пару**, и тогда в границы покрытия идёт строка про замеры под соседней нагрузкой. **WW. В батче умолчание — по одной задаче, параллельность — по графу зависимостей.** План собирается как граф (рёбра — жёсткие зависимости и сериализуемые пересечения) и в умолчании линеаризуется в один порядок. Просьба «гони параллельно» разрешает использовать **ширину графа**, а не гнать всё разом: потолок 2–3, замеряющая задача — волной по одной. Прежние правила волн сохранены целиком, они просто перестали быть умолчанием. ### Что из этого следует 56. **Режим батча задаёт режим ревью внутри задачи, и его называет charter.** Батч идёт по одной — машина свободна, сабагент гонит проходы параллельно; батч идёт волнами — сабагенту предписан последовательный режим с этой самой причиной. Сабагент своего соседа не видит, поэтому решать это ему нельзя. 57. **Ранний выход из ревью переехал на границу стадии.** Стадии идут по порядку в любом режиме, так что остановиться между ними можно всегда; остановка **внутри** стадии осталась побочной выгодой последовательного режима — но не поводом его выбирать. 58. **Цена параллельного батча проверяется до первой волны.** Тесты, делящие фиксированный порт или файл БД, и проект, умеющий поднимать один экземпляр, — основание гнать по одной даже после просьбы, сказанное строкой: просьба была про параллельность, а не про сломанные тесты. ## 15. Порядок проходов ревью — граф зависимостей (2026-08-03) ### Что было Решение 14 перевернуло умолчание, но оставило порядок в прежней форме: «стадии идут по порядку номеров, параллельность — только внутри стадии». Номер стадии при этом ничего не означает: между стадиями 1–4 ни один проход не читает вывод другого, так что очередь между ними была платой ни за что. А правило про замеры держалось на **двух именах** — `adversary` и `ops`, — и рассыпалось бы в тот день, когда мерить начнёт третий проход или проект добавит свой. ### Решено **XX. Порядок задаёт граф; стадии остаются единицей состава.** Профиль по-прежнему набирается стадиями, но запускается всё, у чего закрыты входящие рёбра. Рёбер три вида, и смешивать их нельзя: **зависимость** (гейт → все опиниативные, все проходы → триаж), **конфликт за ресурс** (ненаправленный, между теми, кто держит машину), **барьер стоимости** (только `deep`). **YY. Сериализует ресурс, а не имена.** Пометка «держит машину» — таблицей в скилле: `gate`, `adversary`, `ops`, `triage`; читают и рассуждают — `specs`, `code`, `reimpl`, `architecture`, `rubric`. Проект вправе пометить свой проход в `docs/review.md`; снимать пометку с перечисленных нельзя. Правило теперь самораспространяется: начнёт проход мерить — попадёт в цепочку по факту, а не по поправке. **ZZ. Ранний выход заменён барьером стоимости.** Он стоит там, где ранний выход зарабатывал: перед `reimpl` (пишет реализацию целиком) и `architecture`. В `quick`/`standard` барьера нет — стадий 3–4 там не бывает; в `design` нет по другой причине — предметом там и является форма, защищать нечего. **AAA. Ребро — это порядок, никогда не данные.** В обычном графе задач ребро тянет за собой вывод предшественника; здесь это запрещено: проход, увидевший чужие находки, соглашается с ними, и разведённость — вся ценность конвейера — обнуляется. Сказано в самом правиле, потому что графовый словарь провоцирует ровно эту ошибку. Исключение одно и оно же сток: триаж. **BBB. Диаграммы в скиллах — `mermaid`.** Граф, описанный прозой, читается как инструкция и теряет форму; диаграмма показывает её целиком. В конвейере четыре: общий граф прогона, граф профиля `design`, пример графа задач батча, веер финальной сверки. **Критерий, где диаграмма уместна: структура — граф или автомат, и проза вынуждена его пересказывать.** По этому критерию диаграммы заведены ещё в шести местах: жизненный цикл записи по индексам (`tasks`), четыре шага сессии с причинами на рёбрах (`session`), исходы задачи в спринте (`sprint.md`), одиннадцать шагов пайплайна с развилкой «тривиальная» (`task-pipeline`), храповик промоута с обратным ребром (`promote.md`), счётчик `retune` до `drop` (`calibration.md`) и граф вызовов между плагинами (`README.md`). Где структура — таблица соответствий (чек-лист синка в `docs`, профили ревью, коды выхода), диаграмма не заводится: она бы дублировала таблицу и разошлась с ней. Все диаграммы прогоняются через `mermaid-cli` перед коммитом — синтаксическая ошибка в блоке не видна при чтении и молча ломает рендер. ### Что из этого следует 59. **Триаж — сток по определению, а не «стадия 5».** Отсюда без отдельного обоснования следует правило, которое раньше приходилось защищать: на неполном графе триаж не запускается, потому что агрегировал бы половину и выглядел бы полным. 60. **Словарь рёбер общий у ревью и батча.** «Жёсткая зависимость» и «сериализуемое пересечение» в `task-batch` — те же два вида рёбер; формулировки сведены, и в обоих скиллах стоит ссылка на другой. 61. **Значения режима стали `по графу` и `линейно`.** Прежние «параллельно» и «последовательно» описывали способ запуска, а не структуру; линеаризация осталась отступлением с тремя причинами (оператор, занятая машина, разбор самого конвейера). 62. **Проход, держащий машину, знает об этом из своего charter'а.** `adversary` и `ops` получили по абзацу: цепочка гарантирует им чистое железо, значит их число — оракул, и шум в нём объясняется замером, а не соседом. 63. **У каждой диаграммы объявлено старшинство — это цена второго дома.** Схема и проза вокруг неё описывают один факт, и разойтись они могут молча: то самое, против чего написан `copies.py`. Механической сверки здесь нет — дословного соответствия между текстом и графом не существует, — поэтому работает объявление: **в `review-pipeline` старший граф** (он и есть алгоритм планировщика, проза объясняет рёбра), **в остальных местах старшая проза** (диаграмма там сводка). Для агента это не философия: без объявления он идёт за тем, что конкретнее, то есть чаще за схемой. 64. **Рендер диаграмм проверяется скриптом, а не памятью автора.** `scripts/diagrams.py` вынимает все блоки `mermaid` и гонит их через `mmdc` или `npx @mermaid-js/mermaid-cli`; коды выхода — общий словарь, нет рендерера — код 3, а не молчаливый успех. Причина та же, что у остальных проверок репозитория: **ошибка в блоке не видна при чтении** — текст правдоподобен, дифф разумен, падает только рендер. Расхождение с прозой скрипт не ловит и не притворяется, что ловит: это работа правила 63. ## 16. Каталог вместо файла в `docs/` — отложено до переезда healthlog (2026-08-04) ### Что было Вопрос: разрешить документам в корне `docs/` быть не только файлом, но и каталогом — когда документ описывает несколько принципиальных решений или перерастает 400–500 строк. Паспорт остаётся файлом в любом случае: компактность и есть его функция. Механизм в каноне уже работает — `conventions/`, `research/`, `adr/` каталоги с обязательным `README.md`-индексом, — так что вопрос не «можно ли», а «от чего лечим». ### Решено **CCC. Порог в строках триггером не становится.** Замер по проектам: у порога ровно один документ — `healthlog/docs/architecture.md`, 1662 строки. В нём десять маркеров долга, а разделы — «Слои гранулярности» (211 строк), «Тренировки и прочие секции» (222), «Условный запрос», «Свёртка и размер ответа», «Форма ответа». Это **поведение**, чей нормативный дом `openspec/specs/`, где у проекта уже лежат пять capability. Остальные документы 108–438 строк, `jellybit` — 169. Порог сработал бы ровно там, где надо не разносить, а доводить переезд, и дал бы долгу постоянное жильё: разложить 1662 строки по файлам дешевле, чем вынести их в спеки, а после раскладки давление исчезнет и второй дом поведения останется навсегда. **DDD. Шов выноса — другой читатель или другой срок жизни, а не размер.** По этому критерию кандидатов два. `review.md` — сильнее прочих: у него уже записаны два раздела с разными сроками жизни, настройка конвейера стабильна и читается проходами, а журнал дефектов растёт неограниченно. `architecture.md` — по шву «окружение, деплой, наблюдатель», у которого отдельный читатель `ops`. А вот расщепление архитектуры **по принципиальным решениям отвергнуто**: у факта «почему решено так» дом `adr/`, и вынесенные разделы немедленно станут его вторым домом. **EEE. `security.md` и `passport.md` каталогом не становятся.** У `security.md` ценность именно в цельности: периметр первой строкой и «что вне модели» читаются враждебным проходом за один раз, а разнесённые — расходятся первыми. У `database.md` механизм заводить не под что: 241 и 211 строк. **FFF. Если вводить — точка входа остаётся одна.** `docs/architecture.md` упомянут в репозитории 66 раз: девять charter'ов, карта `project-facts.md`, `docs.py`, скелеты. Развилка «файл или каталог» размножится на девять «прочитай либо обойди». Поэтому форма жёсткая: каталог легален только при `<имя>/README.md`, и он **и есть** прежний документ — обзор целиком со ссылками на вынесенное, а не оглавление к нему. Каждый файл каталога обязан быть достижим ссылкой из `README.md`; это проверяется сегодняшним механизмом ссылок `docs.py` и ловит файл-сироту. Вынеся раздел, `README.md` на него **ссылается, а не пересказывает** — тот же приём, которым в архитектуре уже описаны компоненты со ссылкой на capability. **GGG. Решение отложено до конца переезда `healthlog` (шаг 2 TODO).** Порядок: довести поведение в спеки, замерить остаток. Жмёт после этого — вводить каноном версии 3, и сразу для `review.md` и `architecture.md`, а не для всех документов корня скопом. ### Что из этого следует 65. **Цена изменения — версия канона, а не правка одного файла.** Обратной совместимости у канона нет, поэтому в счёт входят: `docs.py` (`check_stray` с его `ALLOWED_FILES`/`ALLOWED_DIRS`, `check_required` — обязательный путь становится развилкой, `check_capabilities` — сегодня читает ровно один файл), `skeletons.md`, `project-facts.md`, девять charter'ов, запись в `changelog.md` канона и ветка `upgrade` в скилле `canon`. 66. **Раздутый документ канона — сначала подозреваемый, потом кандидат на вынос.** Диагностика перед раскладкой — счёт маркеров долга (`grep -c "`, а требовал ``; нашлось это первой же попыткой ими воспользоваться. Пример в докстроке — тот же образец, что плейсхолдер в схеме. ## 29. Обкатка `doc-consistency` на самом dev-skills (2026-08-05) Первый прогон агента — по репозиторию, который его же и содержит. Два прохода (av-dev-pm; пайплайн плюс верхний уровень), 17 находок, все подтверждены по файлам. **ЧЧШШ. Агент нашёл ровно тот класс, ради которого заводился, и в свежей работе.** Пять находок — остатки прежней модели типов в файлах, которые я не дошёл поправить двумя коммитами раньше: `adopt.md` держал имена секций **канона 2**, `from-review.md` и `TODO.md` — упразднённый `[idea]`, `task-batch` в другом плагине — «задачи-идеи». Правку модели я вёл от документов, которые менял, а не от документов, которые на них ссылаются, — и обратный обход не сделал ни разу. **ЩЩЪЪ. Самая дорогая находка была моей и свежей.** Таблица типов в `canon.md` объявляла цель у `fix` запрещённой, а `tasks/SKILL.md` и `task-fix.md` — необязательной; код на стороне вторых. Копия разошлась с домом **за один день** — я написал обе половины в одном коммите. Это и есть цена второго дома в чистом виде: не «когда-нибудь разойдётся», а «разошлось прежде, чем высохли чернила». Исход не «поправить значение», а **убрать причину**: `canon.md` дважды объявлял, что фиксирует только словарь типов, — значит колонкам «разделы» и «цель» в нём не место. Осталась таблица из двух колонок и ссылка на дом схемы. **ЫЫЬЬ. Копии перечня «чем держат проект» разъехались втроём.** `canon.md`, `tasks/SKILL.md` и `task-goal.md` пересказывали его своими словами: «метрики и логи» против «мониторинга», «проверки» есть в двух из трёх. При этом `tasks/SKILL.md` **ссылался на дом рядом с собственным пересказом** — ссылка не мешает копии разойтись, если копия всё равно стоит. **ЭЭЮЮ. Находка про коммиты снята как неверная, и это дефект самого агента.** Он прочитал `av-dev-git/skills/commit/SKILL.md` («без `Co-Authored-By`») как описание практики этого репозитория и предъявил 38 коммитов с трейлером. Но dev-skills — **маркетплейс плагинов**: скилл коммита здесь продукт, уезжающий в чужие проекты, а не правило, которому подчиняется сам репозиторий. Устав агента не различает «документ описывает этот репозиторий» и «документ описывает то, что репозиторий производит». **ЮЮЯЯ. Счётчики в документах отменены как класс.** `REMAINING.md` держал «после разбора двенадцати тем и 16 коммитов» (стало 28 и 52) и «три неизмеренных изменения подряд» (стало больше). Оба числа обязан двигать человек, и оба отстали молча. Заменены на формулировки, которые не надо поддерживать, и в шапку записана причина. ### Что из этого следует 109. **Правка модели идёт по обратным ссылкам, а не по изменённым файлам.** Меняешь дом — обойди тех, кто на него ссылается: `grep` по упразднённому слову дал бы все пять остатков за минуту. Это дешевле любого агента и должно идти до него. 110. **Ссылка на дом не отменяет копию, стоящую рядом.** Проверять надо не «есть ли ссылка», а «есть ли пересказ»; `tasks/SKILL.md` имел и то и другое. 111. **Копия расходится с домом в пределах одного коммита.** Прежняя оценка («разойдётся на первой правке») занижена: расхождение возникает при написании, если оба места пишет один проход. 112. **Агент, читающий репозиторий-продукт, обязан различать «про нас» и «про то, что мы производим».** Иначе он предъявляет продукту практику его потребителя. Устав `doc-consistency` этого различения не содержит — остаток записан в REMAINING. 113. **Число в документе — обязанность, которую никто не берёт.** Счётчик тем, коммитов, правок протухает молча; формулировка без числа дешевле его сопровождения. ## 30. `av-dev-backlog` удалён (2026-08-05) Плагин был помечен устаревшим решением Q и жил до перевода jellybit. Удалён раньше этого срока. **ААББВВ. Замороженный плагин стоит дороже, чем кажется.** Он не менялся, но платил собой в каждой проверке репозитория: `exclude` в `pyproject.toml`, `SKIP_DIRS` в `copies.py`, два абзаца README, оговорка в описании маркетплейса, чтобы не ловить триггер «добавь задачу в беклог». Пять исключений ради кода, который никто не читает, — и каждое надо было объяснять всякий раз, когда кто-нибудь спрашивал, почему проверка обходит каталог. **ААББГГ. Понимание старой раскладки уехало из плагина раньше самого плагина.** `docs/backlog/` читает не `backlog.py`, а `av-dev-pm:tasks` — `adopt.md` и адаптер в `tasks.py` держат ту же раскладку как **вход миграции**. Плагин перестал быть единственным, кто её знает, ещё когда писался `adopt`; условие «живёт до перевода последнего проекта» с тех пор охраняло пустоту. **ААББДД. Опасение про порядок снятия не подтвердилось.** Удаление опередило снятие: на jellybit плагин оставался включённым, когда записи в маркетплейсе уже не было, и ожидалась ручная чистка `enabledPlugins` и `installed_plugins.json`. `claude plugin uninstall` отработал штатно — он идёт **по реестру, а не по манифесту маркетплейса**, и отсутствие записи там ему безразлично. Предупреждение из README снято, вместо него записан проверенный факт. ### Что из этого следует 114. **Устаревшее удаляют, а не замораживают.** Заморозка выглядит бесплатной, но растекается исключениями по конфигам и требует объяснения в каждом месте, куда попала. Если удалять пока рано — назвать условие и срок; условие без срока переживает свою причину. 115. **Условие «живёт до X» проверяют на живость, а не на X.** Здесь X (перевод jellybit) не наступил, но причина условия отпала раньше: знание раскладки переехало в `adopt`. Перепроверять надо основание, иначе условие держит само себя. 116. **Порядок снятия и удаления из маркетплейса свободный.** `uninstall` живёт реестром, манифест ему не нужен. Правило записано после проверки, а не из осторожности, — и осторожность здесь стоила бы лишнего абзаца в README про починку, которой не бывает. ## 31. Ревизия покрытия `av-dev-pm` продакт-оптикой (2026-08-05) Сабагент в роли продакт-менеджера оценил покрытие жизненного цикла личного проекта (один человек, недели-месяцы) скиллами и агентами `av-dev-pm`. Скоуп сужен по ходу разбора: деплой и разбор инцидентов на проде делаются вручную, скиллов под них не заводим. Осталось планирование, разработка и доработка. **ААББЕЕ. Шаг 2 сессии требовал чисел, которых процесс отказался собирать решением.** `cadence.md` делал обязанностью пересмотр «ориентира по размеру спринта, прироста беклога на закрытую задачу, времени на задачу» и «сколько заняли задачи **против ожидания**» — с обоснованием «иначе обязанность висит ничья». Данных под это нет: у записи нет дат заведения, взятия и закрытия, `close --implemented` удаляет файл, `sprint close` очищает `SPRINT.md`. Хуже того, «против ожидания» и «время на задачу» требуют оценки и тайм-бокса, а `session/SKILL.md` в «Почему не Scrum» их прямо не берёт: пункт противоречил решению, стоящему через файл от него. Исход — **выкинуть, а не подпереть данными**. На практике числа не пересматривались ни разу, и заводить под них учёт дат значило бы обслуживать обязанность, которой никто не брал. Осталось качественное: что сломалось в процессе, что оказалось дороже, чем выглядело при заведении, какие правила не сработали. Шаг 3 пункт 9 переименован из «переоценки по измеренному» в «переоценку по пройденному», судит человек по памяти о спринте. Рядом записано, что замеров нет **намеренно** — иначе следующий читатель заведёт их обратно как недостающие. **ААББЖЖ. `doc-consistency` переехал с каждого синка на сессию, к `doc-code-drift`.** Агент на `opus` зовётся шагом 9 пайплайна, то есть на каждой задаче: 5–8 opus-проходов за спринт по документам, которые за спринт меняются на несколько абзацев. Обоснование в каноне («сверка текста с текстом дёшева») верно относительно второго агента, но не в абсолюте на одиночке. Довод сильнее денег: **расхождение между двумя документами по определению требует двух документов**, а на большинстве задач синк правит один. И пачка, отбираемая работой, не видит того, чего работа не касалась, — а расхождение живёт ровно там: правка отменяет решение в одном документе, парный статус нужен в другом. Это был открытый вопрос `REMAINING` про охват ADR при пересмотре; переезд его закрыл. Цена — потеря привязки находки к задаче, которая её породила: по теме 29 именно эта привязка дала пять самых точных находок. Принято сознательно. **ААББЗЗ. Отмена цели получила порядок, но не флаг.** `close` запрещал закрыть цель с живыми задачами, а что делать с этими задачами, не говорил нигде: шаг 3 сессии знал только «та ли цель», `task-goal.md` описывал одно достижение, а `session/SKILL.md` вдобавок утверждал «цель постоянна». Человек получал отказ с перечнем и никакой подсказки. Порядок записан: сперва задачи поштучно (`close --reason` своей причиной либо `edit --goal` на другую цель), потом сама цель через `close --reason` в `REJECTED.md`, а не в `Готово` — отменённая цель не умеет ничего. Флаг `--cascade` отвергнут: отмена цели редка и дорога, и поштучный разбор здесь не церемония, а единственный момент, когда видно, что из задач переживёт цель. Каскад превратил бы его в один Enter. **Причина у каждой задачи своя**: «цель отменена» это пересказ команды, в `REJECTED.md` от него нет пользы через квартал. Место процедуры — переоценка на сессии, а не отдельный заход: отмена цели **и есть** разбор всех её задач, а разбор задач — шаг 3. **ААББИИ. У брошенного спринта появился второй законный исход, без порога.** `--dissolve` во всех текстах был привязан к блокеру, и скрипт отказывал словами «роспуск объясняется блокером». Вернувшийся к набору, который стоял месяц, не имел законного хода: двигать нельзя (заморозка), распускать не по чему. Теперь роспуск объясняется блокером **или тем, что набор протух**. Порога в неделях сознательно нет — это тот же класс, что выкинутые числа шага 2: счётчик простоя пришлось бы вести руками, а решает всё равно человек. Признак не срок, а **что набор перестал быть твоим**: перечитываешь, зачем эти задачи вместе — он протух. Туда же добавлена точка входа «вернулся, а спринт открыт»: `check`, `SPRINT.md`, развилка продолжать/распустить. Середины у развилки нет намеренно — «доделаю пару штук и решу» это работа по набору, которого ты не понимаешь. **ААББКК. Журнал канона прогоняется как есть, а проверка исхода поручена судьям.** Схлопнуть записи 3 и 4 в один переход «с 2 на 4» отвергнуто: журнал описывает не только *что сделать*, но и порядок, в котором это делалось, и слитая запись экономит один проход ценой невоспроизводимости остальных. Оба живых проекта пройдут 2→3→4 по записям. Взамен появилась проверка исхода: **шагом 6 `adopt` и шагом 6 `upgrade` зовутся оба судьи документов**. Это прямой ответ на открытый вопрос REMAINING «как проверять, что канон не разошёлся с проектами после `upgrade`»: `check` сверяет **число** в `.pm.json` с версией скрипта и про существо записи не знает ничего. Проект несёт `"canon": 4` и может не иметь того, чего требовала любая из пройденных версий — записи применяются руками, а ручной проход по трём записям подряд ровно то место, где половина шага делается и забывается. У `adopt` добавка другого рода: там судьи ловят не недоделанную миграцию, а последствия переноса — факт, растащенный по двум домам, поведение, осевшее в `architecture.md`, ADR, оторванный от своего `design.md`. Им передаётся объявленное переходное состояние из шага 5, иначе честная строка в незаполненном слоте вернётся находкой. ### Что из этого следует 117. **Обязанность без источника данных отменяют, а не механизируют.** Первый позыв — дать шагу данные (дописать даты, сводку спринта). Но обязанность, не исполнявшуюся ни разу, дешевле снять: механизация под неё производит учёт, который надо вести, ради разбора, который не делается. 118. **Требование, противоречащее решению через файл от него, — не мелочь, а признак копии.** «Против ожидания» пережило решение «не берём оценки», потому что стояло в другом документе. Обратный обход по решению «что мы не берём» нашёл бы это сразу — тот же приём, что и следствие 109. 119. **Частота вызова агента выводится из того, что он ищет.** Судья расхождений **между** документами бессмысленен там, где документ один; значит его место не на задаче, а на наборе задач. Цена вызова подтвердила вывод, но не она его дала. 120. **Запрет обязан называть выход.** `close` верно не давал осиротить задачи, но текст отказа перечислял препятствия и молчал о ходе. Проверка без названного следующего шага — половина работы: она защищает данные и бросает человека. 121. **Признак вместо порога там, где счётчик пришлось бы вести руками.** «Набор перестал быть твоим» проверяется в момент вопроса и ничего не требует хранить; «прошло N недель» требует учёта, который никто не ведёт, и всё равно кончается решением человека. 122. **Версионирование без единого переехавшего проекта — не журнал миграций, а история правок.** Довод за схлопывание был верен по факту и отвергнут по принципу: обкатка на живых проектах и проверяет, работает ли механизм. Схлопнуть значило бы не прогнать его ни разу и оставить вопрос открытым. 123. **Проверка версии не есть проверка миграции.** Число в `.pm.json` двигает тот же проход, что делал шаги, — и двигает независимо от того, все ли сделаны. Механической проверки существа нет; там, где её нет, ставится судья, а не отметка. ## 32. Сквозной проход по словарю: пять слов сняты, девять закрыты списком (2026-08-05) Проход упрощения (тема 31) уткнулся в один и тот же класс у всех пяти агентов: слово, живущее в трёх-шести файлах разом. Правка в одном месте развела бы словарь, правка во всех — уже не упрощение текста скилла. Каждый агент честно остановился и записал слово в свой отчёт, и одни и те же слова всплыли в разных отчётах. Разобрано отдельным проходом. **ААББЛЛ. «Слово прижилось» не проверяется, поэтому заменено списком.** Оговорка в `language.md` звучала так: не переводится «термин, у которого нет точного русского эквивалента и который в команде уже прижился». Проверить это на глаз нельзя — прижившимся выглядит любое слово, встреченное трижды, и ровно так пять агентов подряд и рассудили. Оговорка заменена **закрытым списком из девяти терминов** с колонкой «что называет»: интейк, триаж, провенанс, дедуп, чек-лист, дифф, промпт, сущности OpenSpec, роды проходов ревью. Слово не из списка и не из таблицы имён вещей — находка, а не принятый стиль. Список заведён домом `язык-словарь` в `language.md` и копией в уставе `doc-wording`. Копия обязательна: агент работает в репозитории проекта, где плагина может не быть, и без списка предъявил бы «интейк» как англицизм. **ААББММ. Пять слов сняты, и все пятеро выглядели словарём, не будучи им.** `конфляция` → смешение (4 места), `декорреляция` → разведённость (6), `непоймание` → почему не поймали (9), `эвал-сет` → проверочный набор (4), `гайд` → руководство (6). Латинизм или калька при живом русском слове в каждом случае. Разбор `декорреляции` показателен: проект **уже владел** нужным словом — «агенты разведены по глубине», «разведены по охвату» — и держал рядом латинский синоним того же понятия. Это не англицизм, а второй дом для слова. `непоймание` снято ещё и потому, что форма журнала дефектов, которую канон кладёт в проекты, спрашивает «Почему не поймали» — а проза рядом называла это «причиной непоймания». Скелет и проза о скелете говорили разными словами. **ААББНН. Снятое записано вместе с оставленным, в одном списке.** Иначе снятое возвращается: слово уходит из текстов, но ничто не мешает следующему проходу завести его заново — оно ведь короткое и точное. Пять слов названы поимённо с заменой каждого. ### Что из этого следует 124. **Escape hatch без перечня — это разрешение, а не исключение.** «Термин, который прижился» освобождает от правила любое слово: проверка «прижился ли» возвращает «да» всякий раз, когда слово встретилось. Исключение из правила обязано быть списком, иначе оно съедает правило. 125. **Слово, от которого агент отказался править, — материал для отдельного прохода, а не мусор отчёта.** Пять независимых агентов сошлись на одном наборе слов, ни разу друг друга не видя. Список «что не тронул» оказался полезнее списка правок именно этим. 126. **Снятое слово называется вместе с заменой и остаётся записанным.** Убрать из текстов недостаточно: без записи «это снято и вот чем заменено» слово возвращается первым же, кто найдёт его удачным.