session стал groom: два вопроса вместо ритуала спринта

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

Из четырёх шагов сессии выжили два (вопросы, переоценка порциями), один
заменился расстановкой очереди вместо набора спринта, два выпали.
Приёмка — грумингу не по предмету, ритуала у неё больше нет, остаётся
reopen; цена названа в тексте. Разбор процесса потерял якорь, и вместе
с ним ушёл прямой вызов агентов doc-consistency и doc-code-drift — это
починка, а не потеря: агенты принадлежат av-dev-docs, и груминг звал их
мимо правила обращения к соседу.

sprint.md удалён, cadence.md стал portions.md.

Канон 12: запись в журнал велит проектам снести SPRINT.md и расставить
порядок, с точным порядком шагов — сперва удалить файл, потом check
--fix, иначе он увидит третий индекс и станет ругаться, а не чинить.

Побочно: canon.md объявлял себя версией 7 при текущей 11. Пять версий
дом канона врал о себе — машина сверяет константу скрипта, а прозу в
заголовке не читает никто.
This commit is contained in:
av
2026-08-09 16:49:07 +03:00
parent 3653c5cff5
commit 4a56753f0b
15 changed files with 532 additions and 817 deletions
@@ -0,0 +1,162 @@
# Порции, разбор и расстановка
Процедура шагов 2–4 груминга. Рамка и правила — [SKILL.md](../SKILL.md).
Начинается всё с `tasks.py check``check --fix`, если дрейф накопился) —
результат идёт строкой в доклад.
## Шаг 2. Разбор вопросов
`tasks.py list --questions` — всё, что накопилось. Порядок по каждому вопросу:
1. **Проверь, не отвечен ли он уже** — решением, документом, соседним
изменением, самим ходом сделанной с тех пор работы. Отвеченный вопрос не
выносится человеку: это самая частая находка и она не требует ничьего
решения.
2. **Сформулируй развилку** с вариантами и последствием каждого, рекомендация —
первым вариантом.
3. **Вынеси пачкой** через `AskUserQuestion`, не больше трёх за раз.
4. **Запиши ответ в тело задачи, опустоши раздел «Вопросы»**, сними тег
(`edit <slug> --rm-tag question`), **перепиши «зачем»**: «Решено: …» на вопрос
«почему это лежит в беклоге» уже не отвечает. Опустошение раздела — не
уборка, а условие взятия: правило и причина в скилле `tasks`,
[references/task-format.md](../../tasks/references/task-format.md).
**Вопросы на верхних строках очереди разбираются вне очереди порции** — здесь
же, даже если сама задача в порцию переоценки не попала. Иначе правило «задача с
открытым вопросом в работу не берётся» создаёт стимул вопрос не записывать, лишь
бы не вычеркнуть задачу из ближайшей работы.
## Шаг 3. Что перестало быть важным
Цель — выкинуть то, что перестало быть задачей, и вернуть остальному честное
состояние. Не «пересмотреть всё», а «пересмотреть порцию до конца».
### Порция и правило остановки
- **5–8 задач за порцию.** Размер обоснован усталостью, а не пропускной
способностью, и менять его не надо — **надо брать несколько порций**.
- **Отбор порций по порядку:**
1. **свежее** — заведённое с прошлого груминга: оно ещё не проходило ни одной
проверки на нужность. Свежесть меряется git'ом, как и залежалость, — датой
появления файла в истории;
2. дальше **по залежалости**`list --stale`;
3. по потребности — одна секция целиком, один тег (партия ревью), одна цель
(`--goal`), список от человека.
- **Останавливайся на границе порции**, даже если «ещё чуть-чуть осталось».
Между порциями — промежуточный доклад.
### Что делать с каждой задачей
Сперва то, что не требует ничьего решения:
1. **Проверь, не сделано ли уже.** Задача, реализованная попутно в соседнем
изменении, — самая частая находка. Смотри код, документацию, историю коммитов
по ключевым словам. Удаление «как реализованной» деструктивно и без следа
`REJECTED.md` реализованные не пишутся), поэтому порог улики жёсткий:
`close <slug> --implemented` только имея **конкретный коммит или строку
документа**, закрывающие задачу, и ссылка идёт в доклад. Есть лишь косвенные
признаки — не удаляй сам, вынеси в пачку вопросов. Сделана частично → задача
сжимается до остатка: тело правишь редактором, заголовок и «зачем» — через
`edit`.
2. **Проверь, не отменена ли решением.** Документ, ADR или архивное изменение
мог закрыть вопрос иначе — тогда `close <slug> --reason "<ссылка на
решение>"`. Задача закрывается не только коммитом.
3. **Проверь пересечения.** Две задачи об одном — содержимое в одну, вторую
`close <slug> --reason "слита с <другой-слаг>"`. Смотри **шире порции**:
интейк дедуплицирует новое против существующего, но никогда не пересматривает
уже лежащее, и две задачи с одной причиной могут лежать рядом месяцами.
4. **Пере-кластеризуй по общей причине.** Несколько задач, оказавшихся симптомами
одного дефекта, сливаются в одну — это находка, которую интейк дать не мог.
5. **Гигиена полей** — протухшее «зачем», вопрос в прозе, снятый ответ, свойство
репозитория в рамках, предписание процесса в теле, тип, разошедшийся с
задачей, границы вместо реализации в разделе «Затрагивает». Список и правила —
в скилле `tasks`. **Груминг — то самое место, где беклог добирает тип и
разделы его схемы:** требовать их на входе значило бы выгонять в заметки то,
что должно лежать задачей, а к взятию в работу они уже обязательны (`ready`).
Блок здоровья `check` печатает, сколько записей готово к взятию, — по этому
числу и видно, добрал ли груминг.
Гигиена — **побочный продукт, а не предмет**. Тридцать полей вместо трёх
решений о важности означают, что груминг не состоялся.
Затем — то, что решает человек:
6. **Жива ли она вообще.** Контекст мог измениться: ушла зависимость, отпал
сценарий, обошли иначе. Здесь и звучит вопрос, выкидывать ли.
7. **Та ли цель — и нужна ли она вообще.** `feature`, которой не находится цель,
— кандидат на выход: новая возможность вне цели это возможность, которой никто
не заказывал. Операционной задаче (`fix`, `chore`, `research`) цель не нужна,
и выдумывать её здесь не надо.
**Отменяется и сама цель** — когда замысел оказался неверен, а не когда
задача выбрала не ту. Тогда порция расширяется до всех задач этой цели: каждую
либо закрыть своей причиной, либо перевесить на другую цель, и только потом
закрыть цель. Порядок и почему он такой —
[task-goal.md](../../tasks/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель).
8. **Задача ли это по-прежнему.** Не проходит `ready` по существу, а не по
недописанным разделам → `edit <slug> --type research` и опустошённый раздел
«Вопрос», то есть сырьё; дальше штурм. Разрослась → это несколько задач под
той же целью, дальше декомпозиция.
9. **Не подешевела ли она.** Сделанная с прошлого раза работа меняет цену
**других** задач: рядом с только что тронутым кодом та же работа стоит меньше.
Это довод и на шаге 4 — задача, внезапно подешевевшая, поднимается в очереди
не потому, что стала важнее, а потому, что окно открыто.
### Храповик на залежавшихся
Сильно залежавшаяся задача — сигнал сама по себе: её либо ни разу не собирались
делать, либо нечем взять. Измеряй наблюдаемым — датой последней правки из git
(`list --stale` ставит такие первыми); счётчик «сколько грумингов пережила»
нигде не хранится.
Задача из верхних строк `--stale`, которую и этот заход оставляет без изменений,
**либо двигается (меняет цель, поднимается в очереди, уходит с причиной), либо
остаётся с явно записанной причиной**, почему её держим (`move <slug> --section
<та же> --reason …`). Молчаливое «оставить как есть» на давно неподвижной задаче
— это решение не принимать решение; запись причины превращает его в осознанное и
не даёт тому же вопросу всплыть на следующем груминге.
## Шаг 4. Что важно сейчас — расстановка
Разбирается **верх очереди**, а не весь беклог: первые три-пять строк каждой
секции. Ниже пятой строки порядок всё равно перестаёт что-либо значить.
1. **Покажи текущий верх**`list --index backlog`, по секциям, в том порядке,
в каком строки лежат. Плюс состояние проекта из роадмапа: секция `Готово`
отвечает на «где мы», `Запланировано` — на «куда шли».
2. **Спрашивай сравнением, а не оценкой.** «Что из этих двух делают раньше»
имеет проверяемый ответ, «насколько важна эта задача» — нет. Веди попарно и
сверху: что первое, что после него.
3. **Двигай командой, с причиной**`move <slug> --after <другой> --reason …`
или `move <slug> --first --reason …`. Довод берётся из перечня в
[SKILL.md](../SKILL.md#приоритет-как-его-расставляют): сломано сейчас,
разблокирует остальное, дешевеет от сделанного, дорожает от ожидания,
названная цель.
4. **Проверь верх на готовность**`tasks.py ready <слаг> …` по первым строкам.
Задача, стоящая первой и не проходящая `ready`, — это очередь, которая врёт:
взять её нельзя. Либо дописывается здесь же, либо уступает место.
Пример одной итерации:
> **Верх секции «Игра», сейчас в таком порядке:**
> `board-render-once` · `draw-before-full-board` · `move-parse-strict`
>
> 1. Что делаем первым?
> - `draw-before-full-board` *(рекомендую)* — ничья объявляется на неполном
> поле: игра врёт о результате, это сломано сейчас
> - `board-render-once` — печать поля дублируется; мешает всякой правке
> отрисовки, то есть разблокирует остальное
> - оставить как есть
> 2. `move-parse-strict` — третьей или выше?
> - Оставить третьей *(рекомендую)* — ошибка ввода видна игроку сразу
> - Поднять второй: тот же разбор трогает `board-render-once`, окно открыто
Каждый вариант несёт причину — ту самую, что уедет в `--reason`.
## Что делать, если разбирать нечего
Беклог пуст или в нём три задачи и все живые — груминг кончается за минуту, и
это законный исход. Скажи строкой: очередь такая-то, сдвигать нечего. Придумывать
работу, чтобы груминг «состоялся», — ровно тот ритуал без выгоды, от которого
процесс избавлялся.