diff --git a/DECISIONS.md b/DECISIONS.md new file mode 100644 index 0000000..d30fd10 --- /dev/null +++ b/DECISIONS.md @@ -0,0 +1,697 @@ +# Решения по устройству процесса + +Журнал согласований: что решено, почему и что из этого следует. Пишется по ходу +разбора тем, одна тема — один раздел. Причина обязательна: через месяц она +забывается раньше факта. + +Незакрытые остатки прошлого захода — [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. +Описание переписывается так, чтобы не ловить триггер «добавь задачу в беклог» — +иначе агент выбирает между ним и `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 жёстко. diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..a41bbce --- /dev/null +++ b/TODO.md @@ -0,0 +1,110 @@ +# Работы по итогам разбора + +Порядок и обоснование — [DECISIONS.md](DECISIONS.md), тема 8. Номера в скобках — +следствия оттуда. + +Замер (шаг 3) — **единственный шаг, который нельзя переставить**: он блокирует +переезд jellybit. Всё остальное можно тасовать. + +## 0. Предусловие + +- [ ] `git push` — четыре коммита с `av-dev-tasks` и `av-dev-pipeline` не + отправлены на origin, поэтому маркетплейс их не видит (37) +- [ ] `claude plugin marketplace update av-dev-skills` — повторно, после push + +## 1. Репозиторий плагинов + +### 1.1 Переименование + +- [ ] `av-dev-tasks` → `av-dev-pm`: каталог, `plugin.json`, `marketplace.json` (18) +- [ ] пространство имён во всех текстах: `av-dev-tasks:session` → + `av-dev-pm:session`, включая ссылку из `task-pipeline` (18) + +### 1.2 Канон — единственный дом определения + +- [ ] `av-dev-pm/skills/canon/references/canon.md` — раскладка, роли документов, + правило единственного дома. Читают `init`, `canon`, `docs` (AA) +- [ ] `av-dev-pm/skills/canon/references/changelog.md` — журнал версий канона, + версия 1 (26) + +### 1.3 Правки существующих скиллов + +- [ ] `tasks`: убрать слот 6 «Команда учёта задач» (33) +- [ ] `tasks`: путь каталога жёсткий `docs/tasks`, убрать цепочку разрешения (F) +- [ ] `tasks`: `.tasks.json` → `docs/.pm.json`, там же версия канона и путь + миграций (23, 30) +- [ ] `tasks`: убрать слоты 3 «куда переезжает суть» и 5 «оракулы» — отвечает + канон и семантика гейта (тема 4) +- [ ] `session`: убрать слот 7 и слот 4 «где живёт разбор процесса» (33, K) +- [ ] `session`: переписать «Стимулы, которые процесс создаёт» — снятая граница + выбила опору у трёх защит (19) + +### 1.4 Новые скиллы + +- [ ] `init` — интервью по брифу → канон нового проекта (R) +- [ ] `canon` — `check` / `adopt` / `upgrade`; поглощает скилл `adopt` (R, 21, 24) +- [ ] `docs` — содержимое канона: ADR из архивного `design.md`, промоут + конвенций, запись в `research/` и `review.md`, чистка `architecture.md` (X) +- [ ] `docs.py` — раскладка, лишние файлы, битые ссылки, версия, плейсхолдеры, + маркеры долга; сверки миграции ↔ `database.md` и capability ↔ + `architecture.md` (T, 31) + +### 1.5 av-dev-pipeline + +- [ ] удалить скилл `project-brief` и `references/{project-brief,brief-template}.md` (13) +- [ ] снять ветки деградации OpenSpec в трёх местах: `task-pipeline`, + `review-pipeline`, `task-batch` (1) +- [ ] девять charter'ов: разделы брифа → пути канона; `ops`/`adversary`/`reimpl` + обязаны сшивать `research/` и `database.md` (14, 15) +- [ ] `review-pipeline`: убрать бриф, поразрядная деградация по документам (16) +- [ ] `task-pipeline` шаг 9 → построчный доклад по документам канона (28) +- [ ] `task-pipeline`/`task-batch`: закрытие задачи вызовом скилла + `av-dev-pm:tasks`, слот убрать (32, 33) +- [ ] `promote.md` шаг 3: перечень механизированного → `conventions/README.md` (29) +- [ ] описание плагина: «требует OpenSpec» (2) + +### 1.6 Прочее + +- [ ] `av-dev-backlog` — пометить устаревшим, переписать описание, чтобы не + ловило триггер (Q) +- [ ] `README.md` маркетплейса — три плагина, канон, установка +- [ ] `HISTORY.md` — сжать `AGENTIC-TASKS.md` до истории решений (CC) +- [ ] `REMAINING.md` пересобрать: пункт 2 отменён, четыре вопроса закрыты, + калибровка стала обязательной (38) + +## 2. healthlog — первая боевая проверка + +- [ ] `canon adopt`; `docs/backlog/` → `docs/tasks/` +- [ ] `architecture.md` 1611 строк → обзор, остаток маркерами (W) +- [ ] завести `security.md` с периметром первой строкой (J) +- [ ] `review-journal.md` → `review.md` + настройка конвейера (K, L) +- [ ] `conventions.md` → `conventions/`, `local-research.md` → `research/` (G) +- [ ] `plan.md` → `docs/tasks/PLAN.md` (E) +- [ ] завести `docs/adr/` +- [ ] `CLAUDE.md`: severity инвариантов, семантика гейта, убрать раздел + «Процесс» (M, N) +- [ ] `docs.py check` в `task gate` (V) +- [ ] почистить `openspec/config.yaml` (C) + +## 3. Калибровка — блокирует шаг 5 + +- [ ] замер на четырёх находках healthlog: скелет из `null`, откат бинаря, + канонизация в транзакции, `-1 >= -1` (1 из REMAINING, 14) + +## 4. Обкатка + +- [ ] один-два спринта healthlog на новом процессе + +## 5. jellybit + +- [ ] `BRIEF.md` → `docs/passport.md`, обновить +- [ ] `docs/specs/{recognition,review-ux,workflow}.md` — сверить с capability и + удалить как дубли (10) +- [ ] `docs/specs/architecture.md` → `docs/architecture.md`, `database.md` → + `docs/database.md`, `jellyfin-layout.md` → `docs/research/` +- [ ] `docs/review/journal.md` → `docs/review.md` +- [ ] `drafts/` растворить: roadmap → `PLAN.md`, conventions-backlog → задачи + `[idea]`, logical-title-model → ADR (H) +- [ ] `docs/backlog/` → `docs/tasks/` +- [ ] удалить проектные копии скиллов и агентов (4 из REMAINING) +- [ ] `av-dev-backlog` удалить из маркетплейса