ревизия покрытия av-dev-pm: три решения из шести оказались «убрать»
Сабагент в роли продакт-менеджера оценил покрытие жизненного цикла личного проекта скиллами и агентами av-dev-pm. Скоуп сужен по ходу разбора: деплой и разбор инцидентов делаются вручную, скиллов под них не заводим — три находки из восьми сняты этим сразу. Шаг 2 сессии требовал чисел, которых процесс отказался собирать решением. cadence.md делал обязанностью пересмотр «ориентира по размеру спринта, прироста беклога на закрытую задачу, времени на задачу» и «сколько заняли задачи против ожидания». Данных нет: у записи нет дат заведения, взятия и закрытия, close удаляет файл, sprint close очищает SPRINT.md. Хуже, «против ожидания» и «время на задачу» требуют оценки и тайм-бокса, а session/SKILL.md в «Почему не Scrum» их прямо не берёт — пункт противоречил решению через файл от себя. Числа не пересматривались ни разу, поэтому выкинуты, а не подперты учётом дат. Осталось качественное; рядом записано, что замеров нет намеренно, иначе следующий читатель заведёт их обратно как недостающие. Шаг 3 пункт 9 переименован из «переоценки по измеренному» в «по пройденному». doc-consistency переехал с каждого синка на сессию, к doc-code-drift. Агент на opus звался шагом 9 пайплайна, то есть 5-8 opus-проходов за спринт по документам, меняющимся на несколько абзацев. Довод сильнее денег: расхождение между двумя документами по определению требует двух, а на большинстве задач синк правит один. И пачка, отбираемая работой, не видит того, чего работа не касалась, — а расхождение живёт ровно там. Это снимает открытый вопрос REMAINING про охват парного статуса ADR. Цена — потеря привязки находки к задаче, принято сознательно. Отмена цели получила порядок, но не флаг. close запрещал закрыть цель с живыми задачами и не говорил, что с ними делать. Теперь: сперва задачи поштучно (close --reason своей причиной либо edit --goal на другую), потом цель в REJECTED.md, а не в Готово. Флаг --cascade отвергнут: поштучный разбор — не церемония, а единственный момент, когда видно, что переживёт цель. Место процедуры — переоценка на сессии, отмена цели и есть разбор её задач. У брошенного спринта появился второй законный исход. --dissolve везде был привязан к блокеру, и вернувшийся к месячному набору не имел законного хода: двигать нельзя, распускать не по чему. Теперь роспуск объясняется блокером или тем, что набор протух. Порога в неделях нет — тот же класс, что выкинутые числа: счётчик простоя пришлось бы вести руками. Признак не срок, а что набор перестал быть твоим. Плюс точка входа «вернулся, а спринт открыт» и триггер в description скилла. Журнал канона прогоняется как есть, схлопывать 3 и 4 не стали. Взамен появилась проверка исхода: шагом 6 adopt и шагом 6 upgrade зовутся оба судьи документов. Это ответ на открытый вопрос «как проверять, что канон не разошёлся с проектами после upgrade»: check сверяет число в .pm.json с версией скрипта и про существо записи не знает ничего, а записи применяются руками. Износ обязательных «границ покрытия» не правится: это гипотеза, а не находка. Записана наблюдением к первой обкатке. Предложение агента поднять обкатку выше калибровки снято — TODO уже так устроен, агент спутал «главный риск» с «первое в очереди»; в REMAINING добавлена оговорка против того же прочтения. Тема 31 в DECISIONS.md, следствия 117-123. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+121
@@ -2084,3 +2084,124 @@ dev-skills — **маркетплейс плагинов**: скилл комм
|
||||
реестром, манифест ему не нужен. Правило записано после проверки, а не
|
||||
из осторожности, — и осторожность здесь стоила бы лишнего абзаца в README
|
||||
про починку, которой не бывает.
|
||||
|
||||
## 31. Ревизия покрытия `av-dev-pm` продакт-оптикой (2026-08-05)
|
||||
|
||||
Сабагент в роли продакт-менеджера оценил покрытие жизненного цикла личного
|
||||
проекта (один человек, недели-месяцы) скиллами и агентами `av-dev-pm`. Скоуп
|
||||
сужен по ходу разбора: деплой и разбор инцидентов на проде делаются вручную,
|
||||
скиллов под них не заводим. Осталось планирование, разработка и доработка.
|
||||
|
||||
**ААББЕЕ. Шаг 2 сессии требовал чисел, которых процесс отказался собирать
|
||||
решением.** `cadence.md` делал обязанностью пересмотр «ориентира по размеру
|
||||
спринта, прироста беклога на закрытую задачу, времени на задачу» и «сколько
|
||||
заняли задачи **против ожидания**» — с обоснованием «иначе обязанность висит
|
||||
ничья». Данных под это нет: у записи нет дат заведения, взятия и закрытия,
|
||||
`close --implemented` удаляет файл, `sprint close` очищает `SPRINT.md`. Хуже
|
||||
того, «против ожидания» и «время на задачу» требуют оценки и тайм-бокса, а
|
||||
`session/SKILL.md` в «Почему не Scrum» их прямо не берёт: пункт противоречил
|
||||
решению, стоящему через файл от него.
|
||||
|
||||
Исход — **выкинуть, а не подпереть данными**. На практике числа не
|
||||
пересматривались ни разу, и заводить под них учёт дат значило бы обслуживать
|
||||
обязанность, которой никто не брал. Осталось качественное: что сломалось в
|
||||
процессе, что оказалось дороже, чем выглядело при заведении, какие правила не
|
||||
сработали. Шаг 3 пункт 9 переименован из «переоценки по измеренному» в
|
||||
«переоценку по пройденному», судит человек по памяти о спринте. Рядом записано,
|
||||
что замеров нет **намеренно** — иначе следующий читатель заведёт их обратно как
|
||||
недостающие.
|
||||
|
||||
**ААББЖЖ. `doc-consistency` переехал с каждого синка на сессию, к
|
||||
`doc-code-drift`.** Агент на `opus` зовётся шагом 9 пайплайна, то есть на каждой
|
||||
задаче: 5–8 opus-проходов за спринт по документам, которые за спринт меняются на
|
||||
несколько абзацев. Обоснование в каноне («сверка текста с текстом дёшева») верно
|
||||
относительно второго агента, но не в абсолюте на одиночке.
|
||||
|
||||
Довод сильнее денег: **расхождение между двумя документами по определению
|
||||
требует двух документов**, а на большинстве задач синк правит один. И пачка,
|
||||
отбираемая работой, не видит того, чего работа не касалась, — а расхождение живёт
|
||||
ровно там: правка отменяет решение в одном документе, парный статус нужен в
|
||||
другом. Это был открытый вопрос `REMAINING` про охват ADR при пересмотре; переезд
|
||||
его закрыл. Цена — потеря привязки находки к задаче, которая её породила: по теме
|
||||
29 именно эта привязка дала пять самых точных находок. Принято сознательно.
|
||||
|
||||
**ААББЗЗ. Отмена цели получила порядок, но не флаг.** `close` запрещал закрыть
|
||||
цель с живыми задачами, а что делать с этими задачами, не говорил нигде: шаг 3
|
||||
сессии знал только «та ли цель», `task-goal.md` описывал одно достижение, а
|
||||
`session/SKILL.md` вдобавок утверждал «цель постоянна». Человек получал отказ с
|
||||
перечнем и никакой подсказки.
|
||||
|
||||
Порядок записан: сперва задачи поштучно (`close --reason` своей причиной либо
|
||||
`edit --goal` на другую цель), потом сама цель через `close --reason` в
|
||||
`REJECTED.md`, а не в `Готово` — отменённая цель не умеет ничего. Флаг
|
||||
`--cascade` отвергнут: отмена цели редка и дорога, и поштучный разбор здесь не
|
||||
церемония, а единственный момент, когда видно, что из задач переживёт цель.
|
||||
Каскад превратил бы его в один Enter. **Причина у каждой задачи своя**: «цель
|
||||
отменена» это пересказ команды, в `REJECTED.md` от него нет пользы через квартал.
|
||||
|
||||
Место процедуры — переоценка на сессии, а не отдельный заход: отмена цели **и
|
||||
есть** разбор всех её задач, а разбор задач — шаг 3.
|
||||
|
||||
**ААББИИ. У брошенного спринта появился второй законный исход, без порога.**
|
||||
`--dissolve` во всех текстах был привязан к блокеру, и скрипт отказывал словами
|
||||
«роспуск объясняется блокером». Вернувшийся к набору, который стоял месяц, не
|
||||
имел законного хода: двигать нельзя (заморозка), распускать не по чему. Теперь
|
||||
роспуск объясняется блокером **или тем, что набор протух**.
|
||||
|
||||
Порога в неделях сознательно нет — это тот же класс, что выкинутые числа шага 2:
|
||||
счётчик простоя пришлось бы вести руками, а решает всё равно человек. Признак не
|
||||
срок, а **что набор перестал быть твоим**: перечитываешь, зачем эти задачи вместе
|
||||
— он протух. Туда же добавлена точка входа «вернулся, а спринт открыт»: `check`,
|
||||
`SPRINT.md`, развилка продолжать/распустить. Середины у развилки нет намеренно —
|
||||
«доделаю пару штук и решу» это работа по набору, которого ты не понимаешь.
|
||||
|
||||
**ААББКК. Журнал канона прогоняется как есть, а проверка исхода поручена
|
||||
судьям.** Схлопнуть записи 3 и 4 в один переход «с 2 на 4» отвергнуто: журнал
|
||||
описывает не только *что сделать*, но и порядок, в котором это делалось, и слитая
|
||||
запись экономит один проход ценой невоспроизводимости остальных. Оба живых
|
||||
проекта пройдут 2→3→4 по записям.
|
||||
|
||||
Взамен появилась проверка исхода: **шагом 6 `adopt` и шагом 6 `upgrade` зовутся
|
||||
оба судьи документов**. Это прямой ответ на открытый вопрос REMAINING «как
|
||||
проверять, что канон не разошёлся с проектами после `upgrade`»: `check` сверяет
|
||||
**число** в `.pm.json` с версией скрипта и про существо записи не знает ничего.
|
||||
Проект несёт `"canon": 4` и может не иметь того, чего требовала любая из
|
||||
пройденных версий — записи применяются руками, а ручной проход по трём записям
|
||||
подряд ровно то место, где половина шага делается и забывается.
|
||||
|
||||
У `adopt` добавка другого рода: там судьи ловят не недоделанную миграцию, а
|
||||
последствия переноса — факт, растащенный по двум домам, поведение, осевшее в
|
||||
`architecture.md`, ADR, оторванный от своего `design.md`. Им передаётся
|
||||
объявленное переходное состояние из шага 5, иначе честная строка в незаполненном
|
||||
слоте вернётся находкой.
|
||||
|
||||
### Что из этого следует
|
||||
|
||||
117. **Обязанность без источника данных отменяют, а не механизируют.** Первый
|
||||
позыв — дать шагу данные (дописать даты, сводку спринта). Но обязанность,
|
||||
не исполнявшуюся ни разу, дешевле снять: механизация под неё производит
|
||||
учёт, который надо вести, ради разбора, который не делается.
|
||||
118. **Требование, противоречащее решению через файл от него, — не мелочь, а
|
||||
признак копии.** «Против ожидания» пережило решение «не берём оценки»,
|
||||
потому что стояло в другом документе. Обратный обход по решению «что мы не
|
||||
берём» нашёл бы это сразу — тот же приём, что и следствие 109.
|
||||
119. **Частота вызова агента выводится из того, что он ищет.** Судья
|
||||
расхождений **между** документами бессмысленен там, где документ один;
|
||||
значит его место не на задаче, а на наборе задач. Цена вызова подтвердила
|
||||
вывод, но не она его дала.
|
||||
120. **Запрет обязан называть выход.** `close` верно не давал осиротить задачи,
|
||||
но текст отказа перечислял препятствия и молчал о ходе. Проверка без
|
||||
названного следующего шага — половина работы: она защищает данные и бросает
|
||||
человека.
|
||||
121. **Признак вместо порога там, где счётчик пришлось бы вести руками.**
|
||||
«Набор перестал быть твоим» проверяется в момент вопроса и ничего не
|
||||
требует хранить; «прошло N недель» требует учёта, который никто не ведёт, и
|
||||
всё равно кончается решением человека.
|
||||
122. **Версионирование без единого переехавшего проекта — не журнал миграций, а
|
||||
история правок.** Довод за схлопывание был верен по факту и отвергнут по
|
||||
принципу: обкатка на живых проектах и проверяет, работает ли механизм.
|
||||
Схлопнуть значило бы не прогнать его ни разу и оставить вопрос открытым.
|
||||
123. **Проверка версии не есть проверка миграции.** Число в `.pm.json` двигает
|
||||
тот же проход, что делал шаги, — и двигает независимо от того, все ли
|
||||
сделаны. Механической проверки существа нет; там, где её нет, ставится
|
||||
судья, а не отметка.
|
||||
|
||||
+24
-4
@@ -40,6 +40,10 @@ severity. Пробы готовы и синтетических не нужно
|
||||
перед переездом jellybit и блокирует его (решение 39), а ожидаемый исход уже
|
||||
назван выше.
|
||||
|
||||
**«Главный» здесь про цену, а не про очередь.** Первой идёт адаптация healthlog
|
||||
(TODO, раздел 2): без неё нет проекта под каноном, на котором работают остальные
|
||||
скиллы. Калибровка блокирует один шаг — переезд jellybit, — а не всё подряд.
|
||||
|
||||
## Что ещё не сделано
|
||||
|
||||
Список работ — в [TODO.md](TODO.md). Здесь только то, что стоит держать в голове
|
||||
@@ -66,12 +70,28 @@ severity. Пробы готовы и синтетических не нужно
|
||||
**Как проверять, что канон не разошёлся с проектами после `upgrade`.** `canon
|
||||
check` сверяет версию, но не то, что миграционные записи journal'а применены
|
||||
верно. Проект может нести `"canon": 2` и не иметь того, что версия 2 требовала.
|
||||
Ответ выбран: шагом 6 `upgrade` зовутся оба судьи документов — проверка не
|
||||
механическая, но других у существа записей нет. Останется открытым, пока не
|
||||
прогнано на живом проекте: неизвестно, ловят ли они недоделанную миграцию или
|
||||
только её последствия.
|
||||
|
||||
**Не выродились ли «границы покрытия» в шаблон.** Строка «что смотрели и чего не
|
||||
смотрели» обязательна в докладе `check`, `adopt`, интейка, штурма, сессии,
|
||||
спринта и всех четырёх агентов — семь и больше раз за сессию, и проверить её
|
||||
исполнение некому: приёмщик и исполнитель одно лицо (`session/SKILL.md`,
|
||||
«Стимулы»). Выродившаяся строка **хуже отсутствия**: доклад выглядит проверенным.
|
||||
|
||||
Приём не правится: это гипотеза об износе, а не находка, и менять работающее по
|
||||
догадке дороже. **Наблюдение к первой обкатке на живом проекте:** если в трёх
|
||||
докладах подряд границы покрытия совпали дословно или называют не то, чего
|
||||
проверка действительно не касалась, — приём выродился, и вот тогда решать.
|
||||
|
||||
**Форма ADR при пересмотре решения.** Парный статус («старая запись получает
|
||||
`заменено на`») судит агент `doc-consistency` — правило 6 его устава. Открытым
|
||||
остаётся не это, а охват: агент зовётся на синке по документам, которых синк
|
||||
касался, и пересмотр, отменяющий решение из документа, к которому не
|
||||
притрагивались, он не увидит. Механической проверки по-прежнему нет.
|
||||
`заменено на`») судит агент `doc-consistency` — правило 6 его устава. Охват был
|
||||
открытым вопросом, пока агент зовётся пачкой, отобранной работой; переезд вызова
|
||||
на сессию с пачкой «весь канон» его снял. Остаётся зазор в спринт и отсутствие
|
||||
механической проверки — то есть пересмотр, сделанный сегодня, судится на
|
||||
ближайшей сессии, а не в момент правки.
|
||||
|
||||
## Известные пределы — приняты, чинить не планируется
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: doc-code-drift
|
||||
description: "Сверка документов канона с кодом по закрытому перечню проверяемых фактов: имя основной ветки и команды из CLAUDE.md, запреты с путями, testdata и временный каталог, путь миграций из .pm.json, внешние зависимости поимённо в architecture.md против манифеста, настройки с числовым значением в database.md против конфига и кода, единые точки проекта против реального числа реализаций, capability против существующих модулей. Отвечает на «этот факт ещё верен», а не «эта архитектура правильная». Читает весь репозиторий, гоняет только читающие команды. Отдаёт готовые формулировки и ничего не правит сам. Согласованность документов между собой смотрит агент doc-consistency. Использовать на сессии между спринтами и перед приведением проекта к канону. Только чтение."
|
||||
description: "Сверка документов канона с кодом по закрытому перечню проверяемых фактов: имя основной ветки и команды из CLAUDE.md, запреты с путями, testdata и временный каталог, путь миграций из .pm.json, внешние зависимости поимённо в architecture.md против манифеста, настройки с числовым значением в database.md против конфига и кода, единые точки проекта против реального числа реализаций, capability против существующих модулей. Отвечает на «этот факт ещё верен», а не «эта архитектура правильная». Читает весь репозиторий, гоняет только читающие команды. Отдаёт готовые формулировки и ничего не правит сам. Согласованность документов между собой смотрит агент doc-consistency. Использовать на сессии между спринтами, а также после приведения проекта к канону (adopt) и после повышения версии канона (upgrade). Только чтение."
|
||||
tools: Read, Grep, Glob, Bash
|
||||
model: fable
|
||||
color: red
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: doc-consistency
|
||||
description: "Сверка документов канона между собой и с openspec: один факт, живущий в двух домах, прямое противоречие между документами (периметр, зависимости, обратимость), поведение системы, осевшее в architecture.md вместо спек, capability без обзора или с пересказом требований, число без провенанса в research, ADR без ссылки на архивный design.md и без парного статуса при замене, заглушка вместо честной строки в пустом слоте. Читает docs/ и openspec/, кода не читает. Отдаёт готовые формулировки и ничего не правит сам. Соответствие документов коду смотрит агент doc-code-drift, язык — doc-wording. Использовать на шаге синка документации и перед приведением проекта к канону. Только чтение."
|
||||
description: "Сверка документов канона между собой и с openspec: один факт, живущий в двух домах, прямое противоречие между документами (периметр, зависимости, обратимость), поведение системы, осевшее в architecture.md вместо спек, capability без обзора или с пересказом требований, число без провенанса в research, ADR без ссылки на архивный design.md и без парного статуса при замене, заглушка вместо честной строки в пустом слоте. Читает docs/ и openspec/, кода не читает. Отдаёт готовые формулировки и ничего не правит сам. Соответствие документов коду смотрит агент doc-code-drift, язык — doc-wording. Использовать на сессии между спринтами, а также после приведения проекта к канону (adopt) и после повышения версии канона (upgrade), на весь канон разом; на отдельной задаче не звать. Только чтение."
|
||||
tools: Read, Grep, Glob
|
||||
model: opus
|
||||
color: yellow
|
||||
|
||||
@@ -82,14 +82,14 @@ capability: незаполненный канон это переходное с
|
||||
## `check`
|
||||
|
||||
1. `docs.py check`, при наличии базы диффа — с `--base`.
|
||||
2. **Позови `doc-consistency`** на документы, которых касалась работа. Не «заодно
|
||||
по всему `docs/`»: агент зовётся пачкой, но пачка отбирается работой.
|
||||
3. **`doc-code-drift`** — не на каждом `check`, а перед приведением проекта к
|
||||
канону и раз в спринт (шаг сессии). Он дорог: читает репозиторий и гоняет
|
||||
команды. Позвал — передай ему раздел запретов `CLAUDE.md`.
|
||||
4. Доклад: вывод скрипта строкой исхода, находки агентов поимённо, **граница
|
||||
покрытия** — что смотрели и чего не смотрели, и **был ли позван
|
||||
`doc-code-drift`**: доклад, умолчавший об этом, читается как «с кодом сверено».
|
||||
2. **Агентов на каждом `check` не зови.** Оба — `doc-consistency` и
|
||||
`doc-code-drift` — зовутся раз в спринт (шаг сессии), а также шагом 6 `adopt`
|
||||
и шагом 6 `upgrade`, на весь канон разом. Они дороги: оба на `opus`, второй
|
||||
ещё и читает репозиторий. Позвал `doc-code-drift` — передай ему раздел
|
||||
запретов `CLAUDE.md`.
|
||||
3. Доклад: вывод скрипта строкой исхода, находки агентов поимённо, **граница
|
||||
покрытия** — что смотрели и чего не смотрели, и **кто из двоих был позван**:
|
||||
доклад, умолчавший об этом, читается как «сверено».
|
||||
|
||||
Дрейф раскладки чинится переносом; смысловые находки — это либо правка
|
||||
документа, либо задача, если работы больше чем на абзац.
|
||||
@@ -167,6 +167,20 @@ capability), `openspec/config.yaml`.
|
||||
содержания, сколько маркеров долга в `architecture.md`, сколько задач без
|
||||
критериев приёмки. Закрывается порциями по ходу работы, а не одним заходом.
|
||||
|
||||
### 6. Позови обоих судей
|
||||
|
||||
`docs.py` увидел раскладку, а не смысл: перенос растащил один факт по двум домам,
|
||||
оставил в `architecture.md` поведение, которому место в спеке, и оторвал ADR от
|
||||
его `design.md`. Ничего из этого скрипт не видит, и первый прогон на живом
|
||||
проекте обычно самый урожайный — правило единственного дома до адаптации никто не
|
||||
проверял.
|
||||
|
||||
Зови **`doc-consistency`** (документы между собой и с openspec) и
|
||||
**`doc-code-drift`** (факты против кода). Разбирай порциями, а не одним заходом.
|
||||
|
||||
**Передай им объявленное переходное состояние из шага 5** — иначе честная строка
|
||||
в незаполненном слоте вернётся находкой, а это не поломка, а объявленный долг.
|
||||
|
||||
## `upgrade` — канон вырос
|
||||
|
||||
1. `docs.py version` — версия проекта и версия скрипта.
|
||||
@@ -177,10 +191,21 @@ capability), `openspec/config.yaml`.
|
||||
применяются по порядку.
|
||||
4. Подними `canon` в `docs/.pm.json` до текущей.
|
||||
5. `docs.py check`.
|
||||
6. **Позови обоих судей** — `doc-consistency` и `doc-code-drift`.
|
||||
|
||||
Записи журнала описывают **что сделать проекту**. Если запись этого не говорит —
|
||||
это дефект журнала, и о нём надо сказать, а не догадываться.
|
||||
|
||||
**Шаг 6 обязателен, и вот почему.** `check` сверяет **число** в `.pm.json` с
|
||||
версией скрипта — и только его. Применена ли запись журнала **по существу**, он
|
||||
не знает: проект несёт `"canon": 4` и может не иметь того, чего требовала любая
|
||||
из пройденных версий. Записи применяются руками (переименовать секцию, проставить
|
||||
типы, дописать раздел каждому `fix`), а ручной проход по нескольким записям
|
||||
подряд — ровно то место, где половина шага делается и забывается. Судьи и есть
|
||||
проверка, которой у `upgrade` иначе нет: `doc-consistency` увидит, что документы
|
||||
разошлись после переименований, `doc-code-drift` — что переехавший факт
|
||||
разошёлся с кодом.
|
||||
|
||||
## Чего этот скилл не делает
|
||||
|
||||
- **Не сочиняет содержание.** Пустой слот получает честную строку о том, что его
|
||||
|
||||
@@ -390,12 +390,18 @@ kebab-case.** Причина не эстетическая: имя файла с
|
||||
| | связность и читаемость | `doc-wording` |
|
||||
|
||||
**Агентов двое, и разведены они по глубине, а не по охвату.** `doc-consistency`
|
||||
читает только `docs/` и `openspec/` — сверка текста с текстом дёшева и зовётся на
|
||||
каждом синке документации. `doc-code-drift` читает репозиторий и гоняет читающие
|
||||
команды: дорого, и зовётся раз в спринт и перед приведением проекта к канону.
|
||||
Слитый агент делал бы дешёвую половину редкой, а дорогую — поверхностной; тот же
|
||||
читает только `docs/` и `openspec/`, `doc-code-drift` — весь репозиторий и гоняет
|
||||
читающие команды. Слитый агент делал бы одну половину поверхностной; тот же
|
||||
разрез, что между `task-form` и `doc-wording`.
|
||||
|
||||
**Зовутся оба одинаково — раз в спринт на сессии, а также после `adopt` и после
|
||||
`upgrade`, на весь канон разом.** Не на синке документации: агент на `opus` по
|
||||
каждой сделанной задаче не окупается, а расхождение между двумя документами по
|
||||
определению требует двух, и на большинстве задач синк правит один. Пачка,
|
||||
отбираемая работой, вдобавок не видит того, чего работа не касалась, — а именно
|
||||
там расхождение и живёт: правка отменяет решение в одном документе, парный статус
|
||||
нужен в другом.
|
||||
|
||||
**Перечень фактов, которые `doc-code-drift` сверяет с кодом, закрыт** — имя
|
||||
основной ветки, команды, пути, зависимости поимённо, настройки с числовым
|
||||
значением, единые точки проекта, capability, проверяемые инварианты. «Сверить
|
||||
|
||||
@@ -92,9 +92,9 @@ upgrade` идёт по записям снизу вверх от версии п
|
||||
существовало. Судьи заведены и разведены по глубине: **`doc-consistency`**
|
||||
(документ ↔ документ ↔ openspec: факт в двух домах, прямое противоречие,
|
||||
поведение в `architecture.md` вместо спек, ADR без ссылки и парного статуса,
|
||||
число без провенанса, заглушка вместо честной строки) зовётся на шаге синка
|
||||
документации; **`doc-code-drift`** (документ ↔ код по закрытому перечню
|
||||
фактов) — раз в спринт на сессии и перед приведением проекта к канону.
|
||||
число без провенанса, заглушка вместо честной строки); **`doc-code-drift`**
|
||||
(документ ↔ код по закрытому перечню фактов). Оба зовутся раз в спринт на
|
||||
сессии, а также после adopt и после upgrade, на весь канон разом.
|
||||
|
||||
**Что сделать проекту:**
|
||||
|
||||
@@ -127,10 +127,13 @@ upgrade` идёт по записям снизу вверх от версии п
|
||||
человека. **Переименование ADR это перенос ссылок**: слаг стоит в
|
||||
`adr/README.md`, в `architecture.md` и в чужих документах, и делается одним
|
||||
проходом, иначе останутся битые ссылки (их `docs.py` потом и покажет).
|
||||
8. Позвать `doc-consistency` на документы канона — первый прогон на живом
|
||||
проекте обычно самый урожайный: правило единственного дома до сих пор никто
|
||||
не проверял. Разбирать порциями, а не одним заходом.
|
||||
9. `docs/.pm.json`: `"canon": 4`.
|
||||
8. `docs/.pm.json`: `"canon": 4`.
|
||||
9. Позвать **обоих судей** — `doc-consistency` и `doc-code-drift`, шагом 6
|
||||
`upgrade`. Пунктов выше девять, половина из них ручная, и именно здесь видно,
|
||||
какие сделаны только наполовину: переименования секций и полей разводят
|
||||
документы, а `check` сверяет число версии, а не существо. Первый прогон на
|
||||
живом проекте вдобавок самый урожайный — правило единственного дома до сих пор
|
||||
никто не проверял. Разбирать порциями, а не одним заходом.
|
||||
|
||||
## Версия 3 — 2026-08-04
|
||||
|
||||
|
||||
@@ -53,25 +53,25 @@ description: Вести содержимое документов канона
|
||||
- adr/ — заведён ADR-2026-08-03-queue-as-table: отказ от внешней очереди
|
||||
- research/ — новое о формате не узнано
|
||||
- passport, security, conventions, review — не требуется: изменение внутреннее
|
||||
- сверка doc-consistency: находок нет, просмотрено 4 документа из 10
|
||||
```
|
||||
|
||||
## Сверка после синка
|
||||
## Сверка — не здесь, а на сессии
|
||||
|
||||
Синк правит документы поодиночке, а расходятся они **между собой**: факт,
|
||||
дописанный в `architecture.md`, уже живёт в `CLAUDE.md`; периметр в
|
||||
`security.md` не знает про новый эндпоинт. Поймать это на своей же правке нельзя
|
||||
— поэтому последним шагом синка зовётся агент **`doc-consistency`** на те
|
||||
документы, которых синк касался.
|
||||
`security.md` не знает про новый эндпоинт. Поймать это на своей же правке нельзя,
|
||||
и судит это агент `doc-consistency`.
|
||||
|
||||
Он читает `docs/` и `openspec/`, кода не читает, ничего не правит и возвращает
|
||||
готовые формулировки. Строка его доклада входит в доклад синка — **включая
|
||||
пустую**: «находок нет, просмотрено N из M» это ответ, а молчание читается как
|
||||
«не звали».
|
||||
**Но синк его не зовёт.** Оба судьи документов — `doc-consistency` и
|
||||
`doc-code-drift` — зовутся раз в спринт, шагом сессии, на весь канон разом.
|
||||
Причина в цене: агент на `opus` по каждой сделанной задаче — самая дорогая
|
||||
церемония процесса, а расхождение между двумя документами по определению требует
|
||||
двух документов, и на большинстве задач синк правит один.
|
||||
|
||||
**Сверку с кодом синк не зовёт.** «Протухший факт, разошедшийся с кодом» смотрит
|
||||
`doc-code-drift`, он дорог (читает репозиторий) и зовётся раз в спринт на сессии
|
||||
— не на каждой сделанной задаче.
|
||||
Что теряется: привязка находки к задаче, которая её породила. Что выигрывается,
|
||||
кроме денег: пачка перестаёт отбираться синком, и в неё попадают документы,
|
||||
которых работа не касалась, — расхождение, внесённое правкой в одном месте, там
|
||||
и живёт.
|
||||
|
||||
## ADR — промоут, а не второе сочинение
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: session
|
||||
description: "Ритуал между спринтами и ведение самого спринта: разбор накопившихся вопросов, разбор прошедшего спринта про процесс, переоценка задач порциями, выбор цели и набор нового спринта с заморозкой. Плюс правила по ходу спринта — что врывается в замороженный набор, чем вопрос отличается от блокера, когда задача выходит из спринта, что считается сделанным и что идёт в доклад. Использовать, когда просят закрыть или начать спринт, собрать набор, разобрать вопросы, провести груминг/переоценку/ретроспективу, решить «что делать дальше» или доложить итоги. Формат и содержимое задач — скилл tasks."
|
||||
description: "Ритуал между спринтами и ведение самого спринта: разбор накопившихся вопросов, разбор прошедшего спринта про процесс, переоценка задач порциями, выбор цели и набор нового спринта с заморозкой. Плюс правила по ходу спринта — что врывается в замороженный набор, чем вопрос отличается от блокера, когда задача выходит из спринта, что считается сделанным и что идёт в доклад. Использовать, когда просят закрыть или начать спринт, собрать набор, разобрать вопросы, провести груминг/переоценку/ретроспективу, решить «что делать дальше» или доложить итоги, а также когда вернулись к проекту после перерыва и надо понять, где остановились. Формат и содержимое задач — скилл tasks."
|
||||
---
|
||||
|
||||
# Сессия между спринтами
|
||||
@@ -38,7 +38,9 @@ description: "Ритуал между спринтами и ведение са
|
||||
## Единицы
|
||||
|
||||
- **Цель** — то, ради чего набирается спринт. Файл типа `goal` (🎯),
|
||||
перечисленный в `ROADMAP.md`. Цель постоянна: живёт, пока живёт направление.
|
||||
перечисленный в `ROADMAP.md`. Цель постоянна: живёт, пока живёт направление, —
|
||||
и уходит вместе с ним, если замысел оказался неверен (порядок отмены — в
|
||||
[tasks](../tasks/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель)).
|
||||
- **Задача** — то, что мерджится целиком и даёт видимую пользу.
|
||||
- **Вопрос** — решение человека. Не останавливает начатую работу, но **блокирует
|
||||
взятие** задачи в спринт. Живёт внутри файла задачи разделом «Вопросы» и тегом
|
||||
@@ -116,8 +118,9 @@ description: "Ритуал между спринтами и ведение са
|
||||
Это зависимость, а не список.
|
||||
|
||||
1. **Разбор вопросов.**
|
||||
2. **Разбор прошедшего спринта — про процесс, а не про задачи.** Здесь же
|
||||
сверка документов канона с кодом — агент `doc-code-drift`, раз в спринт.
|
||||
2. **Разбор прошедшего спринта — про процесс, а не про задачи.** Здесь же оба
|
||||
судьи документов канона на весь канон разом, раз в спринт: `doc-consistency`
|
||||
(документы между собой) и `doc-code-drift` (документы против кода).
|
||||
3. **Переоценка задач** порциями.
|
||||
4. **Выбор цели и набор спринта.** Цель называет человек, набор собирает агент и
|
||||
показывает **до старта работ**.
|
||||
@@ -144,6 +147,25 @@ flowchart TD
|
||||
Схема — **сводка**: процедура каждого шага в
|
||||
[references/cadence.md](references/cadence.md), и при расхождении прав текст.
|
||||
|
||||
## Вернулся, а спринт открыт
|
||||
|
||||
Сессия — ритуал **между** спринтами, и шаг 1 предполагает только что закрытый.
|
||||
Вход после перерыва другой, и начинается он не с шага, а с вопроса, свой ли ещё
|
||||
набор:
|
||||
|
||||
1. `tasks.py check` — блок здоровья скажет состояние спринта, число готовых к
|
||||
взятию и залежавшихся; при расхождении раскладки `--fix`.
|
||||
2. Прочитать `SPRINT.md`: цель, состав, дата начала.
|
||||
3. **Развилка, и решает её человек.** Набор всё ещё твой — продолжай спринт, ни
|
||||
сессии, ни переоценки не нужно, они между спринтами. Перечитываешь, зачем эти
|
||||
задачи собраны вместе, — набор протух: `sprint close --dissolve --reason …`,
|
||||
недоделанное возвращается в беклог, дальше обычная сессия с шага 1.
|
||||
|
||||
Порога в неделях нет намеренно — почему, в
|
||||
[references/sprint.md](references/sprint.md), «Протухший набор».
|
||||
Середины у развилки тоже нет: «доделаю пару штук и решу» — это работа по набору,
|
||||
которого ты уже не понимаешь.
|
||||
|
||||
Процедура каждого шага, размер и отбор порции, храповик на залежавшихся, формат
|
||||
интерактива и доклад — [references/cadence.md](references/cadence.md).
|
||||
|
||||
|
||||
@@ -37,13 +37,15 @@
|
||||
Не «что мы сделали» (это доклад спринта, он уже был), а:
|
||||
|
||||
- **что сломалось в процессе и почему не поймали** — промах, доехавший до конца;
|
||||
- **сколько на самом деле заняли задачи** против ожидания;
|
||||
- **что оказалось дороже, чем выглядело при заведении** — не число, а сам факт и
|
||||
причина: чего не было видно в постановке;
|
||||
- **какие правила не сработали или сработали не так** — в том числе правила
|
||||
этого плагина;
|
||||
- **какие числа пора пересмотреть** — ориентир по размеру спринта, прирост
|
||||
беклога на одну закрытую задачу, время на задачу. Эта обязанность иначе висит
|
||||
ничья: числа, помеченные как «первый замер», не пересматриваются никогда, если
|
||||
их не пересматривает конкретный шаг.
|
||||
этого плагина.
|
||||
|
||||
Замеров процесс не ведёт намеренно: оценки в очках и velocity не взяты
|
||||
(«[Почему не Scrum](../SKILL.md#почему-не-scrum)»), а спринт ограничен объёмом, а
|
||||
не временем — сравнивать «сколько заняло» не с чем. Разбор здесь качественный, и
|
||||
это не упущение.
|
||||
|
||||
**Артефакт обязателен.** Вывод, оставшийся в контексте сессии, не существует:
|
||||
следующая сессия его не увидит. Дом у него один и известен из канона —
|
||||
@@ -54,20 +56,32 @@
|
||||
Отдельным ритуалом ретроспектива не выделяется: процесс личный,
|
||||
синхронизировать некого.
|
||||
|
||||
**Здесь же зовётся `doc-code-drift`** — сверка документов канона с кодом по
|
||||
закрытому перечню фактов: имя основной ветки, команды, пути, внешние зависимости
|
||||
поимённо, настройки с числовым значением, единые точки проекта, capability.
|
||||
**Здесь же зовутся оба судьи документов** — на весь канон разом, а не на пачку,
|
||||
отобранную работой:
|
||||
|
||||
Раз в спринт, а не чаще, и причина в цене: агент читает репозиторий и гоняет
|
||||
читающие команды. Но и не реже — **спринт это ровно то, что двигает код под
|
||||
документами**: переименованная цель сборки, ушедшая зависимость, второй способ
|
||||
делать то, что обзор объявил единственным. Протухший факт неотличим от свежего, и
|
||||
по нему принимают решения, пока кто-нибудь не наткнётся.
|
||||
- **`doc-consistency`** — согласованность документов между собой и с openspec:
|
||||
факт в двух домах, прямое противоречие, поведение в `architecture.md` вместо
|
||||
спек, ADR без парного статуса при замене, число без провенанса;
|
||||
- **`doc-code-drift`** — сверка с кодом по закрытому перечню фактов: имя основной
|
||||
ветки, команды, пути, внешние зависимости поимённо, настройки с числовым
|
||||
значением, единые точки проекта, capability.
|
||||
|
||||
Его находки — обычный материал переоценки: строка на замену идёт в документ сразу,
|
||||
работа больше чем на абзац становится задачей типа `chore`. **Позвал — скажи в
|
||||
докладе, что позвал, и приложи его таблицу проверенного**; не позвал — скажи и
|
||||
это, иначе доклад читается как «с кодом сверено».
|
||||
Раз в спринт, а не чаще, и причина в цене: оба на `opus`, а второй ещё и читает
|
||||
репозиторий. Но и не реже — **спринт это ровно то, что двигает код и документы**:
|
||||
переименованная цель сборки, ушедшая зависимость, второй способ делать то, что
|
||||
обзор объявил единственным; факт, дописанный в `architecture.md`, уже живущий в
|
||||
`CLAUDE.md`. Протухшее и раздвоившееся неотличимо от свежего, и по нему принимают
|
||||
решения, пока кто-нибудь не наткнётся.
|
||||
|
||||
**Пачка — весь канон, и это не расточительство, а охват.** Отбор пачки работой
|
||||
оставлял без присмотра ровно то, чего работа не касалась: правка, отменившая
|
||||
решение, живёт в одном документе, а парный статус нужен в другом. Канон мал,
|
||||
раз в спринт он читается целиком.
|
||||
|
||||
Находки обоих — обычный материал переоценки: строка на замену идёт в документ
|
||||
сразу, работа больше чем на абзац становится задачей типа `chore`. **Позвал —
|
||||
скажи в докладе, кого именно позвал, и приложи границы покрытия**; не позвал —
|
||||
скажи и это, иначе доклад читается как «сверено».
|
||||
|
||||
## Шаг 3. Переоценка задач
|
||||
|
||||
@@ -138,14 +152,23 @@
|
||||
на выход: новая возможность вне цели это возможность, которой никто не
|
||||
заказывал. Операционной задаче (`fix`, `chore`, `research`) цель не нужна, и
|
||||
выдумывать её здесь не надо.
|
||||
|
||||
**Отменяется и сама цель** — когда замысел оказался неверен, а не когда
|
||||
задача выбрала не ту. Тогда порция расширяется до всех задач этой цели: каждую
|
||||
либо закрыть своей причиной, либо перевесить на другую цель, и только потом
|
||||
закрыть цель. Порядок и почему он такой —
|
||||
[task-goal.md](../../tasks/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель).
|
||||
Здесь этому и место: отмена цели это разбор её задач, а разбор задач — этот
|
||||
шаг.
|
||||
8. **Задача ли это по-прежнему.** Не проходит тест «готова к взятию» → `edit
|
||||
<slug> --type research` и опустошённый раздел «Вопрос», то есть сырьё; дальше
|
||||
штурм. Разрослась → это несколько задач под той же целью, дальше
|
||||
декомпозиция.
|
||||
9. **Переоценка по измеренному.** Спринт производит числа — сколько на самом
|
||||
деле стоит такая работа, что оказалось дороже ожидания. Эти числа меняют цену
|
||||
**других** задач, и именно здесь это применяется: задача, чья цена выросла
|
||||
втрое, а польза осталась прежней, — кандидат на выход.
|
||||
9. **Переоценка по пройденному.** Прошедший спринт показывает, чего на самом
|
||||
деле стоит такая работа. Это меняет цену **других** задач, и именно здесь
|
||||
применяется: задача, оказавшаяся заметно дороже, чем думалось, при прежней
|
||||
пользе — кандидат на выход. Судит человек по тому, что помнит о прошедшем
|
||||
спринте; замеров процесс не ведёт и оценок не хранит.
|
||||
|
||||
### Храповик на залежавшихся
|
||||
|
||||
|
||||
@@ -81,6 +81,16 @@ flowchart TD
|
||||
делается после ответа человека. Спринт не «ждёт»: ждать может человек, а
|
||||
замороженный набор, который нельзя двигать, только мешает.
|
||||
|
||||
**Протухший набор — второй законный повод роспуска.** Работа стояла, и человек
|
||||
вернулся к спринту, состав которого уже не держит в голове. Тем же роспуском:
|
||||
`sprint close --dissolve --reason "работа стояла с <когда>"`, недоделанное в
|
||||
беклог, новый набор — после переоценки, а не поверх старого.
|
||||
|
||||
Порога в неделях нет и не будет: счётчик простоя пришлось бы вести руками, а
|
||||
решает всё равно человек. Признак — не срок, а **что набор перестал быть твоим**:
|
||||
взялся перечитывать, зачем эти задачи вместе, — он протух. Заморозка тут не
|
||||
мешает, она запрещает *двигать* набор, а не распустить его целиком.
|
||||
|
||||
## Определение готовности
|
||||
|
||||
Задача засчитывается сделанной, когда верно **всё**:
|
||||
|
||||
@@ -59,6 +59,27 @@
|
||||
открытых задач. Файл удаляется, строка с датой переезжает в `Готово`. Скрипт
|
||||
откажет, если задачи ещё живы.
|
||||
|
||||
## Отменённая цель — сперва задачи, потом цель
|
||||
|
||||
Замысел бывает неверен, и цель отменяют, не достигнув. Порядок обратный
|
||||
завершению и держится тем же запретом: цель, закрытая поверх живых задач,
|
||||
оставила бы их сиротами, и `close` этого не даст.
|
||||
|
||||
1. **Разобрать её задачи поштучно.** Задача, теряющая смысл вместе с целью, —
|
||||
`close <slug> --reason "<почему>"`; задача, переживающая цель, — `edit <slug>
|
||||
--goal <другая>`. **Причина обязательна и пишется своя каждой:** «цель
|
||||
отменена» это не причина, а пересказ команды, и в `REJECTED.md` от него нет
|
||||
пользы через квартал.
|
||||
2. **Закрыть саму цель** — `close <слаг> --reason "<почему замысел отменён>"`.
|
||||
Файл удаляется, строка с причиной и датой уходит в `REJECTED.md`. В `Готово`
|
||||
не попадает: `Готово` отвечает «что приложение умеет», а отменённая цель не
|
||||
умеет ничего.
|
||||
|
||||
**Место этому — переоценка на сессии, а не отдельный заход.** Отмена цели значит
|
||||
разбор всех её задач, а разбор задач и есть шаг 3 сессии
|
||||
([cadence.md](../../session/references/cadence.md), пункт 7). Отменять на ходу,
|
||||
между делом, — верный способ закрыть скопом то, что стоило перевесить.
|
||||
|
||||
## Что видит машина, а что человек
|
||||
|
||||
`check` считает цели, различает разобранные и пустые, ставит `decomposed`,
|
||||
|
||||
@@ -2033,7 +2033,9 @@ def cmd_close(lay: Layout, a: argparse.Namespace) -> int:
|
||||
if open_tasks:
|
||||
raise Usage(f"у цели {a.slug} осталось открытых задач: {len(open_tasks)}"
|
||||
f" ({', '.join(sorted(t[:-3] for t in open_tasks))})."
|
||||
f" Цель закрыта, когда не осталось её задач")
|
||||
f" Цель закрыта, когда не осталось её задач: каждую либо"
|
||||
f" close --reason со своей причиной, либо edit --goal на"
|
||||
f" другую цель")
|
||||
|
||||
plan = Plan()
|
||||
today = datetime.date.today().isoformat()
|
||||
@@ -2373,7 +2375,8 @@ def cmd_sprint_close(lay: Layout, a: argparse.Namespace) -> int:
|
||||
f" --reason …). Роспуск при блокере — sprint close --dissolve --reason …")
|
||||
if a.dissolve:
|
||||
if not a.reason:
|
||||
raise Usage("--dissolve без --reason: роспуск объясняется блокером")
|
||||
raise Usage("--dissolve без --reason: роспуск объясняется —"
|
||||
" сработавшим блокером или тем, что набор протух")
|
||||
drop = argparse.Namespace(slugs=sorted(n[:-3] for n in entries), reason=a.reason)
|
||||
if entries and (rc := cmd_sprint_drop(lay, drop)) != EXIT_OK:
|
||||
return rc
|
||||
|
||||
Reference in New Issue
Block a user