готово | запланировано | направления | разработка, англ. done | planned | directions | tooling. Из четырёх предложенных имён отвергнуто одно, и по проверяемой причине: «окружение» уже занято — в architecture.md это боевое окружение приложения, «где работает, что рядом, кто перезапускает», и одно слово в двух смыслах развело бы документы канона. Секции роадмапа стали каноническими, в отличие от секций беклога, и разница выведена, а не назначена: у каждой секции роадмапа своя семантика, в первую пишет сам close, и роадмап, названный по-своему, читался бы только своим автором. Секции беклога — полки, смысла не несут, остаются делом проекта. check проверяет три вещи: состав закреплён (чужая секция — ошибка), все четыре обязаны быть, язык один на весь индекс. Проверено на том случае, ради которого правило и заводилось: «Что уже пройдено», которую healthlog вёл руками, теперь называется ошибкой поимённо. Оба языка прогнаны вживую, включая close в английский роадмап. Ключа tasks.achieved_section не появилось — секция достигнутого опознаётся по каноническому имени в любом из языков; --roadmap-sections у init упразднён, выбирать больше нечего. Названные вслух компромиссы: «готово» слегка тянет в трекерную рамку «состояние работы», тогда как секция про возможность — перевесила читаемость; цель в «запланировано» может быть уже наполовину построена, это очередь, а не «не начато», «в работе» живёт в SPRINT.md. DECISIONS 19: ГГГ переписан, добавлен ДДД, следствие 78 заменено. TODO 7 закрыт. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
126 KiB
Решения по устройству процесса
Журнал согласований: что решено, почему и что из этого следует. Пишется по ходу разбора тем, одна тема — один раздел. Причина обязательна: через месяц она забывается раньше факта.
Незакрытые остатки прошлого захода — REMAINING.md.
Требования, зафиксированные по ходу
Не решения — вход, который обязан быть удовлетворён и разбирается в названной теме.
Т1. Адаптация и проверка проекта под канон — обязательный скилл. Нужно уметь прийти в любой старый проект и перевести его на текущие рельсы. Канон при этом сам будет меняться, поэтому уже приведённые проекты тоже должны повышаться до новых версий. Разбирается в теме 5 (старт и жизненный цикл проекта).
Следствия, которые из этого уже видны:
- У канона обязана быть версия, а у проекта — отметка, под какую он приведён. Иначе «соответствует канону» не имеет определённого ответа: сравнение идёт с тем, что модель помнит сейчас, а это и есть дрейф.
- Журнал изменений канона — как миграции. Каждое повышение версии несёт запись «что добавилось, что переехало, что удалено, что сделать проекту». Без него адаптация переизобретается на каждом проекте.
- Отметка версии машиночитаема.
.docs.jsonотвергнут как указатель путей (решение F), но отметка версии — другое: её читает скрипт, и разбирать прозуCLAUDE.mdдля этого не нужно. Прецедент —.tasks.json. - Операций три:
check(соответствие текущему канону),adopt(перевод чужой раскладки),upgrade(повышение с версии N до M по журналу). Первая и третья — одно сравнение с разными исходами. - Механизируемое и суждение не смешивать. Скрипт проверяет пути, лишние
файлы, битые ссылки, версию. Агент судит о смысловых дублях (
docs/specs/ recognition.mdпротив capabilityrecognition) и об оставшемся поведении в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:
- Три места с веткой деградации переписываются на объявленную предпосылку плюс
проверку на старте (есть
openspec/, разрешаютсяopsx:*) и внятный отказ:task-pipelineпредпосылки,review-pipelineпредпосылки,task-batchпредпосылки. - Описание
av-dev-pipelineв маркетплейсе получает строку «требует OpenSpec». - Факт для темы «объединять ли tasks и pipeline»: объединение потянуло бы зависимость от OpenSpec на управление задачами, которой там сейчас нет.
Из B:
- Правило «поведение — в спеку, устройство и границы — в архитектуру» становится
контрактом плагина документов и правилом шага «синк документации» в
task-pipeline. - healthlog чистится не разом: раздел вычищается той задачей, которая его касается. Нужен способ не потерять остаток — иначе 950 строк «Хранилища» останутся навсегда.
- Дыра, которую решение открывает: «почему» после архивации. Сегодня
CLAUDE.mdhealthlog велит писать причину решения вarchitecture.md— а мы её оттуда выселяем. Спеки нормативны и «почему» не держат;design.mdживёт внутри change и уезжает в архив. Либо ADR (как у jellybit), либо явное правило «почему живёт в архивных change». Первый вопрос следующей темы.
Из C:
av-dev-pipelineдаёт образецopenspec/config.yamlотдельным reference — он владеет связью с OpenSpec. Заполняется при старте проекта и приadopt.- У обоих проектов из
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.mdhealthlog («порядок и его обоснование», 11 шагов) и<tasks>/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 растворяется в <tasks>/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/<capability>/spec.md что система делает — нормативно
changes/archive/ журнал изменений с design.md — сырьё для ADR
Слотов нет у: docs/drafts/, docs/specs/, docs/plan.md, BRIEF.md,
docs/backlog/, docs/review/journal.md.
Что из этого следует
- Переезд healthlog:
architecture.md1611 → обзор (поведение уезжает вopenspec/specsпо разделу за задачу);conventions.md→conventions/README.md;local-research.md1829 →research/;plan.md→docs/tasks/PLAN.md;backlog/→docs/tasks/; завестиdocs/adr/. - Переезд 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/. adoptменяет природу — теперь он переносит файлы, а не правит указатели. Разбирается в теме про старт проекта.- Открыто до темы 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/<capability>/spec.md, changes/archive/
Слотов нет у: docs/review-brief.md, docs/drafts/, docs/specs/,
docs/plan.md, BRIEF.md, docs/backlog/, docs/review-journal.md.
Что из этого следует
- Скилл
project-briefрастворяется. Заведение недостающих документов канона — часть скилла старта/адаптации (тема 5, требование Т1). - Девять charter'ов переписываются второй раз. Сейчас каждый читает «из
раздела
## Xбрифа»; станет — из файла канона. Цена названа вслух: первая переписка (вынос в плагин) осталась незамеренной —REMAINING.md, пункт 1. Вторая делает замер по четырём реальным находкам healthlog обязательным, а не желательным: два неизмеренных изменения подряд в том самом месте, где присваивается severity. - Теряется соседство фактов, и charter обязан сшивать. Контракт настаивал,
что замер становится находкой только рядом с настройкой: «768 МиБ пика» —
аномалия, лишь если известно, что запись лежит сжатой и распаковывается
целиком; «5.019 с удержания блокировки» — отказ соседа, лишь если известен
таймаут занятости. Теперь это
research/иdatabase.md, и charter'ыops,adversary,reimplобязаны прямо говорить «собери из этих двух», иначе проход снимет верное число и честно понизит находку до гипотезы. - Деградация становится поразрядной — и это лучше прежнего «нет брифа →
деградирует всё». Нет
security.md— деградируетadversary; нетresearch/— числа неизвестныops,adversaryиreimpl; нетpassport.md— архитектурный проход теряет границу домена. Каждый проход пишет свою строку в границы покрытия. - Открытый вопрос из
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 случайно.
Что из этого следует
- Переименование
av-dev-tasks→av-dev-pmтянетplugin.json,marketplace.jsonи пространство имён скиллов:av-dev-tasks:session→av-dev-pm:session, включая ссылку изtask-pipeline:112. - Раздел «Стимулы, которые процесс создаёт» в
sessionпереписывается. Снятая граница выбила механическую опору у трёх защит: «сжать задачу до остатка», «занизить урожай», «занизить критерии приёмки» — во всех трёх приёмщик и исполнитель теперь совпадают. Остаются: отчёт триажа вopenspec/changes/<id>/review/(независимый артефакт,task-batchуже сверяет полноту ревью по нему, а не по прозе исполнителя),SPRINT.mdпод git с видимой историей иreopen <slug> --reason— закрытие не окончательно, приёмка человеком на сессии его отменяет. Раздел обязан назвать их поимённо, иначе обещает защиту, которой нет. - Конфликт владения
docs/tasks/снят — канон и задачи теперь в одном плагине. - Скилл
adoptизav-dev-tasksпоглощается скиллом адаптации проекта уровня канона (требование Т1). Разбирается в теме 5. - Состав
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/ выводятся из него.
Они заводятся скелетом с честной строкой («архитектуры пока нет: кода нет,
заводится первой задачей») и наполняются шагом синка документации.
Что из этого следует
docs/.pm.jsonпоглощает<tasks>/.tasks.json. Меняется цепочка разрешения вtasks.py— сегодня он ищет.tasks.jsonвверх от текущего каталога. Нужен переходный период либо чтение обоих.tasks.py adoptстановится шагом внутриcanon adopt, а не отдельной пользовательской операцией:docs/tasks/— часть той же раскладки.- Версия канона — целое число, не semver: у канона нет обратной совместимости, есть только «приведён» и «не приведён».
- Журнал изменений канона живёт в плагине —
av-dev-pm/skills/canon/references/changelog.md, запись на версию: что добавилось, что переехало, что удалено, что сделать проекту. - Открыто до темы 6: звать ли
docs.py checkиз гейта проекта. У healthlogtask 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. Остаток чистки помечается маркером и считается числом. Неразобранный
раздел получает <!-- канон: поведение → openspec/specs/<capability> -->,
docs.py считает маркеры и печатает остаток. Закрывается порциями, как
переоценка задач.
Маркеры гейт не красят. Это долг, а не отказ: покрасневший гейт на первом маркере сделал бы постепенный переезд невозможным, а разовый — обязательным. Число печатается и убывает на глазах.
Что из этого следует
- Шаг 9
task-pipelineпереписывается из четырёх пунктов прозой в построчный доклад по документам канона. promote.md, шаг 3, переписывается: «вычеркнуть пункт из брифа, правило переезжает в перечень механизированного в разделе## Карта» → перечень механизированного живёт вconventions/README.md. Брифа нет.docs/.pm.jsonдержит не только версию канона, но и пути, нужные проверкам: каталог миграций — как минимум.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». Имя, которое нигде не работает, — украшение.
Что из этого следует
- Решение P уточняется: оркестратор закрывает задачи вызовом скилла
av-dev-pm:tasks, а не запуском скрипта по пути. Плагина в проекте нет — вызов не разрешается, и пайплайн, как прежде, только докладывает исход. - Слот исчезает из двух скиллов —
tasks(слот 6) иsession(слот 7), — и из текстовtask-pipelineиtask-batch, которые на него ссылаются. canon upgradeотвечает за раскладку и версию вdocs/.pm.json. Скрипты обновляются обновлением маркетплейса, а не проектом.- Скрипты живут в
av-dev-pm/skills/{tasks,canon}/scripts/.docs.py— вcanon, потому что раскладку проверяет он. canon checkсверяет версию канона проекта с версией установленного плагина и говорит, кто отстал. Это нужно и без вендоринга: маркетплейс — git-клон, обновляется явно, и на момент разбора отставал на четыре коммита.- Установленный маркетплейс требует обновления перед любой работой —
сейчас в нём нет ни
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
Что из этого следует
REMAINING.mdчастично устарел: пункт 2 «Завести брифы» отменён темой 3; закрыты открытые вопросы про## Триггеры,av-dev-backlog, имя процесса иAGENTIC-TASKS.md. Пункт 1 (калибровка) стал обязательным, а не желательным. Пересобрать на шаге 1.7.- Замер — единственный шаг, который нельзя переставить. Всё остальное в порядке 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 исключён из проверки. Плагин помечен устаревшим и живёт
до перевода последнего проекта, после чего удаляется целиком. Шесть его находок
косметические (os.replace, l как имя), а правка замороженного кода без
тестов — риск без выгоды. Исключение уходит вместе с плагином.
II. Голый except Exception разрешён только помеченный. Правило BLE
включено, а два места последнего рубежа (main обоих скриптов, код выхода 4 по
словарю) несут # noqa: BLE001 с причиной. Так третий такой except не
появляется молча.
Что из этого следует
- Найдено и починено 27 находок ruff и 14 pyrefly. Содержательных две:
мёртвая переменная
quesвcheck(вычислялась и не использовалась — вопросы проверяетquestions_open) и два места вcheck --fix, гдеfind_entry_indexможет вернутьNone, а результат идёт прямо вlist.popи вrange. Оба сегодня недостижимы, и недостижимость держалась на рассуждении о вызывающем коде, а не на проверке. Поправлено по ревью: там стоитraise, а неcontinue. Тихий пропуск превратил бы сломанный инвариант в отчёт «индексы согласованы» — то есть в враньё; громкий отказ кодом 4 честнее. osизtasks.pyушёл целиком.os.replace→Path.replace,os.path.basename→Path.name; импорт стал не нужен.fail()вdocs.pyобъявленNoReturn. Без этогоread_configвыглядел как возвращающий неинициализированное значение — и это ровно то, что читатель кода тоже не мог знать наверняка.- Проверка не входит ни в один гейт. 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 уходит в «не проверялось». Секции живут в заголовках ##
индекса и второго дома не получают.
Что из этого следует
- Класс находок тот же, что и в прошлые три круга: стыки. Не новый код, а
место, где один файл ссылается на другой.
sprint.mdв пункте «Сделана» всё ещё отсылал к порядку, который сам же тремя экранами ниже отменил; три остатка «шаг 9а» несли предкоммитную позицию закрытия; путь отчёта триажа не переживалopsx:archive, хотя по нему сверяют полноту ревью четверо. - Инструкция, которую нельзя выполнить, выглядит как выполненная. Ответ на
вопрос по документированной процедуре (снять тег) оставлял задачу
незабираемой, потому что судит раздел, а не тег;
canon adoptтребовал гнатьdocs.py check«до отсутствия дрейфа», недостижимого без нарушения запрета сочинять цели; урожай спринта, заведённый послеsprint close, терял автотег молча. - Два прохода по разным предметам дороже одного, но не вдвое. Перекрытие оказалось ровно в одной находке из двадцати — той самой, что подтвердилась дважды. Практика остаётся: ревью на плагин, а не одно на репозиторий.
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 <плагин>:<скилл>.
Что из этого следует
- Знаниевый цикл есть и он законен, но каждый его контракт обязан иметь
единственный дом. Пайплайн описывает раскладку
pm,pmописывает артефакты пайплайна — пять симметричных контрактов, из них два уже разошлись: форма журнала дефектов (шесть полей против пяти, «Причина» потеряна) и список читателейdocs/research/(specsвыпал). Дома назначены: форма журнала — у конвейера, список читателей — у канона; в обеих копиях стоит явное указание на дом. - Пайплайн больше не называет внутренние имена файлов
pm.items/<slug>.mdиSPRINT.mdв его тексте были вторым домом для раскладки, которую проект вправе переименовать черезdocs/.pm.json. - Описания плагинов в манифестах врали умолчанием. Ни
marketplace.json, ниplugin.jsonне говорили, чтоav-dev-pmдля конвейера опционален, а задача принимается текстом. Теперь говорят — это первое, что читает человек, выбирая, что подключать.
12. Механическая проверка копий (2026-08-03)
Что было
Разделение плагинов оставлено (тема 11), но цена его названа: пять симметричных
контрактов в двух домах, два уже разошлись — форма журнала дефектов потеряла в
копии поле «Причина», список читателей docs/research/ потерял specs. Оба раза
копия выглядела актуальной, и оба раза расхождение прошло мимо трёх ревью подряд.
Решено
OO. Копия допустима, но обязана быть дословной и помеченной. Разметка —
HTML-комментарии, невидимые в отрендеренном markdown: <!-- дом: <id> --> …
<!-- /дом: <id> --> и <!-- копия: <id> из <путь> --> … <!-- /копия: <id> -->.
scripts/copies.py требует побайтового совпадения текста между маркерами.
Почему комментарии, а не манифест копий отдельным файлом: маркер уезжает в репозиторий проекта вместе со скелетом, и там он полезен — говорит читателю, что у текста есть дом и правится он там. Манифест остался бы в маркетплейсе и проекту ничего не сказал.
PP. Идентификатор строгий — буквы, цифры, дефис — и повторяется в закрывающем
маркере. Иначе документация о самом механизме объявляет дом и роняет проверку:
это случилось на первом же прогоне, README.md объявил дом примером. Теперь
пример пишется <id>, угловые скобки под шаблон не подходят.
QQ. Ограда блока кода в сверку не входит. В доме текст обрамлён своей ```, а в скелете тот же текст лежит внутри чужой, объемлющей ограды. Сверяется содержимое, а не разметка вокруг него.
RR. Коды выхода — общий словарь (0 сошлось, 1 расхождение, 2 разметка, 3 не тот каталог, 4 сбой). Третий скрипт репозитория, и третий по тем же кодам.
Что из этого следует
- Помечены два контракта: форма записи журнала дефектов (дом — конвейер ревью, копия — скелет канона; это кросс-плагинная пара) и «когда заводить ADR» (дом — канон, копия — его же скелет). Второй пришлось сперва сделать дословным: копия говорила «обязателен статус», дом — «обязателен статус „заменено на"», и это ровно тот класс, который и ищется.
- Чего проверка не ловит — копию, которую забыли пометить. Помечать
остаётся решением человека, и это названо в
README.mdвслух: иначе зелёный прогон читался бы как «копий больше нет». - Дом без копий — расхождение, а не замечание. Маркер, обещающий дисциплину, за которой не за чем следить, — такая же ложная запись, как разошедшаяся копия.
- Запись в журнал версий канона проверка не заменяет. Она видит, что копия отстала, но не видит, что проект уже унёс старую версию к себе. Это остаётся на человеке и сказано в обоих домах.
13. Секции PLAN.md переименованы (2026-08-03)
Что было
Секции назывались «линия» и «кусты» — метафора, требующая расшифровки при каждом употреблении. В текстах она и расшифровывалась: «звено упорядоченной линии продукта», «тематический куст — цель, в последовательность не встающая». Если название приходится объяснять рядом с каждым употреблением, объясняет не название.
Решено
SS. «порядок» и «темы». Заголовок называет ровно то свойство, которым секции различаются: в первой очередь значима и обоснована прозой, во второй порядка нет вовсе. Расшифровывать нечего — правило написано в самом имени.
TT. Записи в журнал версий канона не требуется — канон этих имён не знает.
canon.md называет файл docs/tasks/PLAN.md и ничего не говорит о его секциях:
их дом — заголовки ## индекса, а умолчание живёт в tasks.py. Версия канона
поэтому не меняется, и проект вправе называть секции по-своему. Причина названа
вслух, потому что соблазн повысить версию «на всякий случай» здесь сильный, а
повышение обязало бы каждый проект что-то делать — при том что делать нечего.
Что из этого следует
- Умолчание одно и живёт в
DEFAULT_PLAN_SECTIONS. Имена секций по-прежнему настраиваются--plan-sections, а домом остаются заголовки##индекса — переименование не трогает механику, только умолчание и тексты. - Метафора — плохое имя для секции индекса. Секция читается человеком без
контекста, часто из вывода
list, и второго шанса объяснить себя у неё нет.
14. Умолчания режимов прогона перевёрнуты (2026-08-03)
Что было
Оба скилла держали одно и то же умолчание — «по очереди», — хотя цена очереди у
них разная. review-pipeline гнал проходы последовательно и требовал для
параллельности двух условий (явная просьба и поимённо названный набор).
task-batch, наоборот, планировал волны параллельных задач с потолком 2–3 и
считал параллельность нормой прогона.
Перепутаны оказались уровни. Проход ревью — чтение и рассуждение: он ничего не поднимает, ни за что не дерётся и по построению не видит выводов соседа. Задача батча — полный цикл пайплайна: гейт, поднятие сервиса вживую, вложенное ревью, общие порты и рабочие каталоги. Дешёвое стояло в очереди, дорогое гонялось разом.
Решено
UU. В ревью умолчание — параллельно. Стадии по-прежнему идут по порядку, параллельность касается только проходов внутри стадии. Последовательно гоняем по трём особым причинам, и каждая называется в отчёте: сказал оператор; проходы меряют; машина занята — причём занятость видит вызывающий, а не конвейер. Просьба «гони последовательно» набора не требует: очередь ничего не портит, она только дольше, и домысливать тут нечего — в отличие от прежнего правила, где неназванный набор блокировал отступление.
VV. Меряющая пара — правило стадии, а не решение прогона. adversary и ops
идут по очереди всегда: оба доказывают находки числами и оба меряют одно железо, а
испорченный оракул хуже отсутствующего. Общее «гони параллельно» этого не
отменяет; отменяет только прямое слово оператора про эту пару, и тогда в
границы покрытия идёт строка про замеры под соседней нагрузкой.
WW. В батче умолчание — по одной задаче, параллельность — по графу зависимостей. План собирается как граф (рёбра — жёсткие зависимости и сериализуемые пересечения) и в умолчании линеаризуется в один порядок. Просьба «гони параллельно» разрешает использовать ширину графа, а не гнать всё разом: потолок 2–3, замеряющая задача — волной по одной. Прежние правила волн сохранены целиком, они просто перестали быть умолчанием.
Что из этого следует
- Режим батча задаёт режим ревью внутри задачи, и его называет charter. Батч идёт по одной — машина свободна, сабагент гонит проходы параллельно; батч идёт волнами — сабагенту предписан последовательный режим с этой самой причиной. Сабагент своего соседа не видит, поэтому решать это ему нельзя.
- Ранний выход из ревью переехал на границу стадии. Стадии идут по порядку в любом режиме, так что остановиться между ними можно всегда; остановка внутри стадии осталась побочной выгодой последовательного режима — но не поводом его выбирать.
- Цена параллельного батча проверяется до первой волны. Тесты, делящие фиксированный порт или файл БД, и проект, умеющий поднимать один экземпляр, — основание гнать по одной даже после просьбы, сказанное строкой: просьба была про параллельность, а не про сломанные тесты.
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 перед коммитом — синтаксическая ошибка в блоке не видна при чтении
и молча ломает рендер.
Что из этого следует
- Триаж — сток по определению, а не «стадия 5». Отсюда без отдельного обоснования следует правило, которое раньше приходилось защищать: на неполном графе триаж не запускается, потому что агрегировал бы половину и выглядел бы полным.
- Словарь рёбер общий у ревью и батча. «Жёсткая зависимость» и
«сериализуемое пересечение» в
task-batch— те же два вида рёбер; формулировки сведены, и в обоих скиллах стоит ссылка на другой. - Значения режима стали
по графуилинейно. Прежние «параллельно» и «последовательно» описывали способ запуска, а не структуру; линеаризация осталась отступлением с тремя причинами (оператор, занятая машина, разбор самого конвейера). - Проход, держащий машину, знает об этом из своего charter'а.
adversaryиopsполучили по абзацу: цепочка гарантирует им чистое железо, значит их число — оракул, и шум в нём объясняется замером, а не соседом. - У каждой диаграммы объявлено старшинство — это цена второго дома. Схема
и проза вокруг неё описывают один факт, и разойтись они могут молча: то
самое, против чего написан
copies.py. Механической сверки здесь нет — дословного соответствия между текстом и графом не существует, — поэтому работает объявление: вreview-pipelineстарший граф (он и есть алгоритм планировщика, проза объясняет рёбра), в остальных местах старшая проза (диаграмма там сводка). Для агента это не философия: без объявления он идёт за тем, что конкретнее, то есть чаще за схемой. - Рендер диаграмм проверяется скриптом, а не памятью автора.
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, а не для всех документов
корня скопом.
Что из этого следует
- Цена изменения — версия канона, а не правка одного файла. Обратной
совместимости у канона нет, поэтому в счёт входят:
docs.py(check_strayс егоALLOWED_FILES/ALLOWED_DIRS,check_required— обязательный путь становится развилкой,check_capabilities— сегодня читает ровно один файл),skeletons.md,project-facts.md, девять charter'ов, запись вchangelog.mdканона и веткаupgradeв скиллеcanon. - Раздутый документ канона — сначала подозреваемый, потом кандидат на
вынос. Диагностика перед раскладкой — счёт маркеров долга
(
grep -c "<!-- канон:") и вопрос, не поведение ли это. Разложить дрейф по файлам значит перестать его видеть. - Материал для решения даёт
healthlog, а неjellybit. У второго 169 строк архитектуры — там вопрос не стоит вовсе, и принимать по нему решение значит принимать его без предмета.
17. Разбор заметок: ступень ревью, род работы, роадмап (2026-08-04)
Что было
Семь заметок из NOTES.md, накопленных по ходу работы: переименование
PLAN.md, тип у каждой задачи, цвета сабагентов по модели, кавычки во
фронтматтерах, уровни ревью для проекта, задачи в терминах функций и границ,
язык задач без англицизмов. Разного размера и из разных мест, но три из них
оказались об одном — о том, можно ли оценить задачу, не открывая код.
Решено
HHH. Цвет charter'а кодирует модель, а не роль прохода. Раскладка
sonnet → green, opus → yellow, fable → red. Роль прохода видна из имени, а
стоимость прогона — ниоткуда; цвет, розданный по ролям, не отвечает ни на один
вопрос, который задают во время прогона. Дом раскладки — таблица «Модель по
проходу» в review-pipeline/SKILL.md.
III. Фронтматтеры проверяются машиной, а не вниманием. Три описания из
четырнадцати содержали : в незакавыченном значении — для YAML это вложенное
отображение, то есть синтаксическая ошибка, которую нельзя увидеть чтением:
текст читается правильно. Тот же класс, что у mermaid-диаграмм, и лечится тем же
способом — scripts/frontmatter.py. Он же держит раскладку цветов (HHH) и
сверку name с именем каталога.
JJJ. Между standard и deep заведена ступень wide. (содержание
триггеров пересмотрено темой 18, TTT: миграция схемы и публичный контракт ступень
не поднимают.) Прыжок стоил самого
дорогого прохода конвейера, а платить приходилось за одну архитектурную находку:
изменений, которые трогают публичный контракт, но не вводят нового правила
слияния, — большинство. wide — это standard плюс architecture (вход шире
диффа, отсюда имя), семь проходов против восьми у deep.
KKK. Триггер независимой реализации стал триггером профиля. Раньше условие
«изменение вводит новое правило идентичности, слияния или разбора» стояло
внутри deep, и профиль означал то семь проходов, то восемь. Реестр состава,
который «сверяется взглядом до коммита», проверять было нечем: у профиля не было
одного правильного ответа. Теперь условие выбирает профиль, а reimpl в deep
безусловен — и он единственное, чем deep отличается от wide.
LLL. Барьер стоимости остался только в deep. В wide за ним стоял бы один
дешёвый проход с потолком в 3 находки, а барьер не бесплатен — он сериализует то,
что могло идти разом. Вторая причина помельче: барьер спрашивает «выживает ли
форма изменения», а architecture — как раз тот, кто на этот вопрос отвечает.
MMM. Род работы — вторая ось типа, и живёт тегом. Тип записи
(goal/idea/epic/task) отвечает «что это за запись», род
(feature/fix/chore/research) — «какого рода работа». В один префикс их не
свести: идея бывает про функцию, эпик функцией и является. Дом — тег
kind:<род>, потому что теги здесь и есть единственный механизм разметки, а
list --kind работает даром. Принятая цена: в строку индекса род не попадает
(индексы производны), и состав набора по роду виден командой, а не глазами.
Словарь закрыт — открытый разъехался бы на синонимах bug/bugfix/fix.
NNN. У chore тест готовности ослаблен честно. Вопрос «что станет наблюдаемо
иначе» для обслуживания отвечается разработчику, а не пользователю. Пока рода не
было, такие задачи либо не заводились, либо придумывали себе пользовательскую
пользу — и это второе хуже: оно проходит проверку.
OOO. Задача называет границы, а не намерения. Раздел «Затрагивает» — эндпоинт, таблица и миграция, формат на диске, публичный тип пакета. Без него задача оценивается по объёму текста, а не по объёму поверхности, и оценка систематически занижена ровно там, где текст короткий, а границ много. Механизм проверяет наличие непустого раздела: полноту перечня машина не видит, и делать вид, что видит, хуже, чем не проверять.
PPP. Род и границы требуются к взятию в спринт, а не к заведению. Тот же
приём, что уже работает для критериев приёмки, и по той же причине: беклог
пополняется чаще, чем разбирается, а требование на входе выгоняет в заметки то,
что должно лежать задачей. check о пропаже напоминает замечанием — иначе два
живых проекта покраснели бы на 98 задачах, заведённых до этого решения.
QQQ. PLAN.md → ROADMAP.md, вместе с ключом конфига и токенами команд.
Слово «план» в репозитории значит три разных вещи — оглавление целей, план
реализации внутри задачи и PLAN.json разовой адаптации. Переименовано всё:
tasks.plan → tasks.roadmap, --index plan → --index roadmap,
--plan-sections → --roadmap-sections. Старый ключ в docs/.pm.json не
игнорируется молча — скрипт останавливается и называет переименование.
Что из этого следует
- Версия канона 3 занята этим изменением. Отложенное решение темы 16
(каталог вместо файла в
docs/) вводится теперь версией 4, а не 3. - Род работы ничего не предписывает конвейеру. Профиль ревью выбирается по
факту изменения:
choreбывает миграцией схемы,fix— правкой публичного контракта. Правило «предписание процесса в теле задачи снимается» родом не отменяется, а подтверждается. - Проверка фронтматтеров — третья проверка репозитория того же класса. Копии, диаграммы, фронтматтеры: всё это ошибки, невидимые при чтении. Класс опознаётся по признаку «диff выглядит разумно, а результат ломается», и каждый его представитель получает скрипт, а не пункт чек-листа.
- Ступеней профиля четыре, и правило выбора читается сверху вниз. Первое
сработавшее условие и есть ответ: правило слияния →
deep, контракт или схема →wide, видимое снаружи поведение →standard, иначеquick.
18. Ступень поднимает проход, а не риск (2026-08-04)
Что было
Наблюдение с живых проектов: полный набор проходов гоняется чаще, чем оправдано — архитектура и независимая реализация нужны заметно реже, чем запускаются. Развилка названа сразу: крупные задачи с частым полным ревью либо мелкие и средние задачи со средним ревью. Выбран второй путь.
Разбор показал, что размер задач — только половина причины, и не главная.
Решено
RRR. Профиль — максимум по поверхности, а не средневзвешенное. Условия
читаются сверху вниз, первое подошедшее отвечает за весь дифф. Значит цена ревью
растёт быстрее размера задачи: на крупной задаче верхний профиль оплачивается в
том числе за ту её часть, которая сама по себе была бы quick. Это и есть
механизм, ради которого выбран путь мелких задач.
SSS. Ступень поднимает то, что даёт работу новому проходу, а не то, что кажется рискованным. Правило вывода, по которому спорные случаи решаются без нового списка. Проверка нынешних триггеров этим правилом:
| Триггер | Кто закрывает | Где этот проход |
|---|---|---|
| миграция схемы | gate (шаг миграций), ops (миграция под потоком, откат при двух версиях) |
уже в standard |
| публичный контракт | specs, направление code → spec |
во всех профилях |
| инвариант проекта | основание для critical у любого прохода |
во всех |
| новый пакет, новое понятие | architecture |
только wide |
| новое правило слияния | reimpl |
только deep |
Три верхних триггера не добавляли ни одного прохода — они поднимали ступень «на всякий случай». На проекте с базой и эндпоинтами это делало верхнюю ступень умолчанием, то есть правило объявляло исключением то, что происходит всегда.
TTT. Миграция схемы, публичный контракт и инвариант уехали в standard.
wide теперь означает ровно одно: изменение вводит новое понятие или
структурную единицу — новый пакет или слой, новая точка входа, второй способ
делать то, что уже делается, перенос ответственности между узлами. Добавленное
поле в существующем ответе концептом не является. Это отменяет часть JJJ темы
17: ступень wide остаётся, её содержание меняется. Проект, где изменение
контракта и правда архитектурное (публичный SDK, чужие потребители), поднимает
его сам в docs/review.md — уточнением, а не возвратом прежнего умолчания.
UUU. Чекпоинт design получил то же условие. review-specs в режиме «дизайн
ДО кода» идёт всегда — это самый дешёвый чекпоинт конвейера. review-rubric и
review-architecture — только при новом понятии. Причина арифметическая: чекпоинт
стоит на каждой задаче, поэтому при мелкой нарезке три прохода умножаются на
число задач и становятся самой большой статьёй. Причина по существу та же, что в
SSS: рубрика на узел без нового понятия порождает свойства уже существующего
рода, записанные конвенциями и спеками.
VVV. Шов нарезки — граница, за которой падает ступень. Тест декомпозиции отвечает, допустим ли разрез; шов отвечает, где его провести. Раздел «Затрагивает» перечисляет границы; строка, поднимающая ступень выше остальных, и есть кандидат на отдельную задачу.
WWW. Костяк из четырёх проходов платится за каждую задачу. Гейт, спеки, код, триаж несокращаемы, поэтому разрез, после которого обе половины остаются в одной ступени, делает ревью дороже: тот же объём тем же составом, но костяк оплачен дважды. Резать — когда разрез снимает дорогой проход с большей части диффа.
XXX. Верхняя ступень задана тестом, а не списком. «Идентичность, слияние,
разбор» — формулировка, пришедшая из одного проекта, и в общем виде она не
читалась: вопрос «как это применить к моему проекту» не имел ответа в тексте.
Теперь класс задан тремя условиями, независимыми от домена и языка: вариантов
несколько и оба защитимы; спека между ними не выбирает; неверный выбор не падает,
а молча меняет смысл данных. Отрицательный тест сильнее положительных — то, что
красит гейт или роняет запрос, в класс не входит. Три слова остались как три
места, где такие правила водятся (граница входа данных и место их встречи), а
проект перечисляет свои места в docs/review.md — перечень производен от теста и
не расширяет класс.
Оговорка, без которой правило вырождается: триггер — новое или изменённое по
существу правило, а не код рядом с ним. Проект, чей домен и состоит из таких
правил, иначе оказывался бы в deep всегда — та же болезнь, от которой лечилась
ступень wide.
Что из этого следует
- Порога в числе границ не заводится. Тот же принцип, что в теме 16 (CCC): размер не триггер. Шов проходит по скачку ступени, а не по длине перечня.
- Ступень — признак для планирования, но не запись в задаче. Строка «делать профилем standard» в теле — тот самый второй дом правила выбора, который снимает гигиена полей. Профиль выбирает тот, кто видит изменение.
- Дешёвое место заметить разнородную задачу — показ набора спринта. Там
«Затрагивает» уже написан, а предложение об изменении ещё не заведено: разрез
стоит одного
editвместо выброшенного предложения. - Замер остаётся за обкаткой. Правило выведено из состава проходов, а не из статистики прогонов: считать, какая доля задач попадает в каждую ступень, можно только на спринтах нового процесса (TODO шаг 4).
- Отсутствие верхней ступени — законное состояние проекта. Бывают проекты,
где данные приходят нормализованными, ничего ни с чем не сливается, а внешних
форматов нет:
deepтам не срабатывает никогда, и придумывать ему повод не надо. Раньше это читалось как недонастройка. - Ступень определяет класс правила, а не вид работы. Миграция схемы —
standard, но миграция, переносящая данные по правилу («сложить дубли», «привести к одному виду перед сравнением»), несёт правило идентичности и потомуdeep. Одно слово в описании задачи попадает в разные ступени — это не противоречие, смотрят не на слово.
19. Роадмап — состояние проекта, а не очередь работ (2026-08-04)
Что было
Основной инструмент владельца — роадмап и набор целей: «на каком этапе проект, что сделали и что осталось». Оценка идёт по поведению, а не по внутреннему устройству: что приложение уже может делать и чего ещё не может. Отсюда требование к формулировкам: цель отвечает на «что приложение будет делать», задача — на «что для этого нужно сделать».
Разбор показал, что инструмент отвечал ровно на половину этого вопроса.
Решено
YYY. Достигнутая цель из роадмапа не исчезает. close --implemented удалял
у цели и файл, и строку — роадмап по построению показывал только «что осталось».
Свидетельство нашлось в самом роадмапе healthlog: там руками заведена секция «Что
уже пройдено» на двадцать строк прозы, и заканчивается она фразой «Эти звенья
целями не заведены: закрытая цель записи не оставляет, ей хватает коммита и
спеки». Обходной путь и его причина записаны рукой владельца. Теперь строка с
датой переезжает в секцию достигнутого; файл удаляется по-прежнему.
Вторым домом поведения это не делает: нормативное поведение живёт в
openspec/specs/, роадмап отвечает когда и в каком порядке оно появилось —
другой вопрос. Ссылки на файл в строке нет намеренно: файла больше нет, а битая
ссылка это законная ошибка check. Форма строки — как в REJECTED.md, и по той
же причине.
ZZZ. Цель — возможность приложения, задача — шаг к ней. Заголовок цели отвечает на «что приложение будет уметь»: не «Работа со слиянием», а «Исход слияния не зависит от порядка доставки». Свойство поведения — тоже возможность: «сообщает о своём состоянии», «исход не зависит от порядка» — законные цели, переформулировки в функцию не требуют. Единственный настоящий чужак — работа над инструментом и процессом: на вопрос «что приложение будет уметь» она не отвечает и живёт в отдельной секции роадмапа.
ААА. Тест готовности задачи сменил защиту. Требование «что станет наблюдаемо иначе снаружи» переехало к цели. У задачи вместо него — какую строку «Завершения» своей цели она двигает. «Отрефакторить X» проваливает тест не потому, что невидим снаружи, а потому, что не находит строки, к которой относится. Побочная выгода: видно и обратное — строка «Завершения», к которой не относится ни одна задача, это незакрытая часть возможности. Отсюда требование к «Завершению» быть списком, а не абзацем: на абзац не сошлёшься.
БББ. Цель обязательна не у всякой задачи. Прежнее правило — «у каждой задачи
должен быть goal:, иначе она не попадёт ни в один спринт» — было угрозой, а не
аргументом, и заставляло операционную работу выдумывать себе направление.
Граница проходит по роду работы: feature без цели не бывает (новая возможность
и есть содержание цели), fix, chore и research живут без цели законно и
входят в набор спринта помимо его цели. Это второй раз, когда род работы
окупается, — и первый, когда он что-то определяет за пределами отбора.
ВВВ. Тип [epic] упразднён. Зонтик между целью и задачами не нужен: зонтиком
стала цель, а слишком крупный шаг дробится на шаги помельче под ней. Замер: ноль
употреблений на 97 записей двух живых проектов, при том что тип занимал место в
словаре, тесте готовности, автомате переходов, split.md и трёх местах
tasks.py.
ГГГ. Имена секций роадмапа — готово / запланировано / направления /
разработка. Первый набор (умеет / строим / станок) прожил один заход и
был признан неудачным. Из четырёх предложенных имён отвергнуто одно, и по
проверяемой причине: окружение уже занято — в architecture.md это боевое
окружение приложения, «где работает, что рядом, кто перезапускает», и одно слово
в двух смыслах развело бы документы канона. Взято разработка.
Принятый компромисс назван вслух: готово слегка тянет обратно в трекерную рамку
«состояние работы», тогда как секция про возможность. Перевесила читаемость с
первого взгляда, а смысл несут заголовки целей внутри секции. Так же принято, что
цель в запланировано может быть уже наполовину построена: это очередь, а не
«не начато», а «в работе» живёт в SPRINT.md.
ДДД. Секции роадмапа канонические, секции беклога — нет. Разница выведена, а
не назначена: у секций роадмапа есть семантика (достигнутое, очередь, долгое,
не про продукт), в первую пишет сам close, и роадмап, названный по-своему,
читался бы только своим автором. Секции беклога (ядро, инфра) семантики не
несут — это полки. Поэтому check проверяет у роадмапа три вещи: состав закреплён
(чужая секция — ошибка), все четыре обязаны быть, язык один на весь индекс;
--roadmap-sections у init упразднён. Английский набор — done | planned |
directions | tooling.
Проверено на том самом случае, ради которого правило и заводилось: секция «Что уже пройдено», которую healthlog вёл руками, теперь называется ошибкой поимённо.
Что из этого следует
- Ключа
tasks.achieved_sectionне появилось. Секция достигнутого опознаётся по каноническому имени в любом из двух языков, и лишний knob не заводится: канонический состав отвечает на тот же вопрос надёжнее конфига. reopenцели снимает строку достигнутого. Иначе роадмап продолжает утверждать, что приложение умеет то, что вернулось в работу.- Прозаический раздел в индексе — дрейф. Любой
##проверка считает секцией, поэтому «Что уже пройдено» и «Почему в таком порядке» в healthlog формально были двумя лишними секциями, куда могла уехать задача. При повышении они разбираются: звенья — строками вумеет, обоснование очереди — прозой внутристроим. - Правил стало пять, и нулевое — про смысл, а не про механику. «Цель — возможность, задача — шаг к ней» стоит перед правилами о гниении беклога и производности индексов, потому что из него следует, зачем эти механики нужны.