Files
dev-skills/av-dev/skills/task-groom/SKILL.md
T
av ed83ec7dc0 задачи: починена смена стадии, разобраны находки ревью плагина
Команда stage была дефектна по шести пунктам, и все шесть подтверждены
прогоном: не звала raw_last (переход оставлял каталог красным), не
переписывала шапку беклога (индекс продолжал объявлять прежнюю стадию),
шла в обход write_config, молча пропускала файлы с непересобираемой метой,
ломалась на беклоге без заголовков и схлопывала полки при первом
объявлении стадии.

Объявление и смена разведены: объявление беклога не трогает вовсе, смена
трогает состав секций только по явному --sections, а слить полки скрипт
не берётся ни в одном случае. Абзац шапки размечен парой «стадия», и
расхождение с конфигом стало обычным дрейфом.

Отказ по недостающей строке индекса запирал запись, пережившую упразднение
роадмапа: edit, close и reopen теперь заводят или пропускают строку сами.
Прочее: регистр stage нормализуется при чтении; --fix снимает мёртвые теги
и у неразобранных записей; move отказывает переставлять сырьё; adopt
держит место сырья; docs.py bump двигает одну запись журнала за раз;
tasks.py получил перечень упразднённых адресов, и гейт наконец видит
собственное упразднение ROADMAP.md.

Запись «Версия 3» переписана по прогону на игрушечном проекте: прежний
порядок шагов был неисполним. Закрыты дыры модели стадий (пересмотр плана
стройки стал сценарием, приёмка отвязана от груминга, from-review,
research и adopt получили развилку по стадии, перечень осей пересчитан) и
находки, старшие этой сессии: review-triage получил режим без метки, три
списка проектных копий сведены к дому с проверяемыми копиями, пять
пересказов правил стали помеченными копиями или ссылками, language.md
перестал объявлять юрисдикцию над чужим плагином.
2026-08-13 15:08:29 +03:00

280 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: task-groom
description: "Груминг беклога — интерактивный разбор, отвечающий на два вопроса: что сейчас самое важное и что перестало быть важным. Ответ записывается порядком строк в беклоге: первая строка — то, что делают следующим. Разбирает накопившиеся вопросы, переоценивает задачи порциями по 5–8 (сделано попутно, отменено решением, слилось с соседней, подешевело, разрослось, стало сырьём), закрывает отжившее с причиной и расставляет очередь. Использовать, когда просят разобрать беклог, расставить приоритеты, решить «что делать дальше», провести груминг или переоценку, а также когда вернулись к проекту после перерыва и надо понять, где остановились. Формат и содержимое записей — скилл av-dev:task-track; выполнение задачи — конвейер проекта."
---
# Груминг: что важно, что перестало
Скилл отвечает на **два вопроса**, и всё, что не служит им, — не его работа:
1. **Что сейчас самое важное?**
2. **Что перестало быть важным?**
Ответ на оба **записывается порядком строк в беклоге**: первая строка секции —
то, что делают следующим; то, что перестало быть важным, из беклога уходит с
причиной. Приоритет — свойство очереди, а не задачи, и живёт он в индексе
(правило 4 скилла `task-track`). Груминг — единственное место, где очередь
назначается человеком.
**Скилл интерактивный.** Он не «приводит беклог в порядок» сам: суждение о
важности принадлежит человеку, и весь ход — это подготовленные развилки с
рекомендацией. Что решается фактом (сделано, отменено, дублируется), решается
без вопросов и показывается списком.
Форматом и содержимым записей владеет скилл `task-track` — груминг зовёт его
операции, а не правит файлы руками. Выполнением задачи — конвейер проекта.
## Три правила, из которых всё следует
1. **Порядок назначает человек, машина его не выводит.** Ни давность, ни тип, ни
размер секции приоритетом не являются. Единственное место в очереди,
назначенное не человеком, — конец секции у сырья, и оно из очереди изъято
(`task-track`, правило 4).
2. **Порция важнее охвата.** Тридцать задач за заход — это усталость и
штамповка: последние десять получат «оставить» не потому, что живы, а потому,
что разбор затянулся. Лучше две честные порции, чем один полный проход.
3. **Причина уезжает в запись.** Всё, что решено здесь, оставляет след:
`--reason` у закрытия и переноса, ответ в теле задачи, строка в докладе.
Решение, оставшееся в переписке, будет принято заново через месяц.
## Груминг — операция доработки
**Стадия проекта решает, применим ли груминг вообще** (дом стадии —
[`task-track`, «Две стадии»](../task-track/SKILL.md#две-стадии); посмотреть —
`tasks.py stage`).
На **доработке** он и есть основная гигиена: беклог пополняется извне и
вразнобой, порядок значит важность, и назначить её может только человек.
На **стройке** оба вопроса скилла отвечены заранее. «Что сейчас самое важное» —
первая строка плана, и назначил её не приоритет, а зависимость: переставить её
значит сломать стройку. «Что перестало быть важным» возникает не порциями, а
разом — когда меняется замысел, — и тогда пересматривается **план целиком**, а
не 5–8 задач из середины. Порционный разбор здесь вреден: он вынимает шаги из
списка, порядок которого и есть его содержание.
Поэтому на стройке скилл говорит это строкой и **отсылает к другой работе**:
[пересмотр плана целиком](../task-track/SKILL.md#пересмотр-плана-стройки) —
сценарий скилла `task-track`, гигиена полей — тоже его, а исчерпанный беклог
значит переход (`tasks.py stage support`). Четыре вещи он делает и на стройке,
потому что от стадии они не зависят: `tasks.py check --fix`, разбор
накопившихся вопросов, закрытие сделанного попутно и **возврат неудавшейся
приёмки** (`reopen`).
**Возврат приёмки от стадии не зависит вовсе, и это надо сказать отдельно.**
Приёмщик и исполнитель у нас совпадают, и опор против этого две: независимый
отчёт ревью и `reopen`. Вторая привязана к грумингу только по привычке — заметил,
что закрытая задача сделана не тем, чем обещала, возвращай сразу, на любой
стадии и в любой момент.
## Когда груминг созрел
**Зовёт человек.** Скилл сам себя не назначает, но обязан **напоминать**, и
признак наблюдаемый, а не календарный:
- в беклоге появились записи, которых человек ещё не видел (заведены интейком по
ходу работы, урожаем ревью, разбором находок);
- на верхних строках очереди есть задача с открытым вопросом — очередь
показывает то, что взять нельзя;
- `tasks.py check` печатает «готово к взятию: 0 из N» — брать сегодня нечего.
**На стройке этот признак читается иначе**: он значит «план ещё не дописан», а
не «пора грумить».
Порога в неделях нет намеренно: счётчик простоя пришлось бы вести руками, а
решает всё равно человек. Признак — **очередь перестала быть твоей**: взялся
перечитывать, почему эти задачи стоят в таком порядке, — пора.
## Вопрос, блокер, необратимое
| | Что это | Когда спрашиваем | Что останавливает |
| --- | --- | --- | --- |
| **Вопрос** | решение человека | на груминге, пачкой | взятие задачи в работу |
| **Блокер** | работа не может продолжаться ни одной задачей | немедленно | всё |
Право на **необратимое** — третье и отдельное: что именно необратимо, называет
`CLAUDE.md` проекта, и спрашивается оно всегда, независимо от того, когда был
последний груминг.
**Блокер определяется исходом, а не одновременностью.** Встали разом или
задачи выпадали по одной — если продолжать нечем, это блокер, и человек
спрашивается немедленно, а не ждёт ближайшего груминга.
**Отличать вопрос от застревания.** Правило про остаток принадлежит управлению
задачами: оно решает, **сделана задача или вышла**, а это исход планирования, не
исполнения. **Ниже канонический текст; конвейер проекта на него ссылается, а не
пересказывает** — два экземпляра одного правила разъезжаются, и разъезжаются
незаметно, потому что расхождение видно только на редком входе.
> Есть остаток, который доводится без ответа, — задача продолжается, вопрос
> записывается в файл. Остатка нет — задача возвращается в беклог.
С двумя оговорками, без которых тест ошибается:
> **Остаток, который материализует нерешённое** — записывает в хранилище,
> журнал, витрину **или наружу** состояние, зависящее от неотвеченного вопроса,
> — **не остаток**. Решение поднимается до начала записи: откатить запись
> дороже, чем подождать ответ, а иногда невозможно. «Наружу» — часть правила, а
> не пример: выкладка, публикация и отправка данных третьей стороне не
> откатываются тем более.
> **Пол для остатка:** остаток, из которого пропала польза, названная в «зачем», —
> это не сделанная задача, а вернувшаяся в беклог.
## Ход груминга
Четыре шага, и порядок — зависимость, а не список.
```mermaid
flowchart TD
check["tasks.py check (+ --fix)<br/>результат — строкой в доклад"]
s1["1. Осмотреться<br/>что накопилось, чего человек ещё не видел"]
s2["2. Разобрать вопросы<br/>пачкой, не больше трёх за раз"]
s3["3. Что перестало быть важным<br/>порциями по 58"]
s4["4. Что важно сейчас<br/>расставить порядок строк"]
check --> s1 --> s2 --> s3 --> s4
s2 -->|"неотвеченный вопрос → судим о важности вслепую"| s4
s3 -->|"без переоценки очередь строится из протухшего"| s4
```
Схема — **сводка**: процедура каждого шага в
[references/portions.md](references/portions.md), и при расхождении прав текст.
**1. Осмотреться.** `tasks.py check` (при дрейфе — `--fix`), затем показать
человеку текущую очередь: верхние строки каждой секции и что появилось с
прошлого раза. Это половина ответа на «что важно»: очередь, которую не видели,
обсуждать бессмысленно.
**2. Разобрать вопросы.** Вопрос — решение человека, и разбирается он **пачкой**,
а не по одному, как только возник: по одному это дёрганье, пачкой это груминг.
Вопрос на верхних строках очереди разбирается **вне очереди порции**: иначе
правило «задача с открытым вопросом в работу не берётся» создаёт стимул вопрос
не записывать, лишь бы не вычеркнуть задачу из ближайшей работы.
**3. Что перестало быть важным.** Порциями по 5–8. Сперва то, что решается
фактом и не требует ничьего суждения (сделано попутно, отменено решением,
дублируется, симптомы одного дефекта), затем то, что решает человек (жива ли,
задача ли это ещё).
**4. Что важно сейчас.** Расстановка порядка — `move --after <слаг>` и
`move --first`. Разбирается **не весь беклог, а верх очереди**: первые три-пять
строк каждой секции. Ниже пятой строки порядок всё равно перестаёт что-либо
значить — до них дойдут после следующего груминга, и очередь к тому времени
будет другой.
## Приоритет: как его расставляют
**Вопрос ставится сравнением, а не оценкой.** «Насколько важна эта задача» не
имеет проверяемого ответа; «что из этих двух делают раньше» — имеет. Поэтому
очередь строится попарно и сверху: что первое, что после него.
Доводы, которые принимаются:
- **что сломано сейчас** — работоспособность обгоняет развитие, и это не правило
вкуса: сломанное дорожает само;
- **что разблокирует остальное** — задача, после которой можно взять три другие,
стоит раньше любой из трёх;
- **что дешевеет от того, что сделано** — работа рядом с только что тронутым
кодом стоит меньше, чем та же работа через квартал;
- **что дорожает от ожидания** — данные копятся, миграция усложняется, внешний
срок приближается;
- **то, что человек назвал следующим.**
Довод **записывается причиной** (`move --after <слаг> --reason …`). Порядок без
причины — это порядок, который на следующем груминге назначат заново с нуля.
**Тема и приоритет — независимые оси.** Очередь может идти поперёк полок, и это
законно: задачи одной темы не обязаны стоять подряд. Но если из одной полки
годами ничего не поднимается наверх — это разговор про саму работу, а не про
очередь, и он идёт на шаге 3.
## Документы устаревают тем же ходом работы
Груминг судит **задачи**, а не документы, и агентов канона не зовёт: они
принадлежат скиллам документации, и когда их звать — решают они.
Но повод назвать это здесь есть: беклог и документы протухают от одного и того
же — от сделанной работы. Пришёл на груминг и видишь, что с прошлого раза сделан
десяток задач, — скажи строкой, что документы стоит сверить
(`av-dev:doc-healthcheck`), и иди дальше. Документов канона в проекте нет —
сверять нечем, и это тоже строка.
## Интерактив
- Вопросы — через `AskUserQuestion`, **не больше трёх за раз**. Порция в 58
задач обычно даёт больше трёх суждений: веди несколько итераций по ≤3, а не по
одному вопросу на задачу и не одним перегруженным запросом.
- К каждому варианту — **предварительное суждение, рекомендация первым
вариантом**: «предлагаю выкинуть, потому что …». Возразить дешевле, чем судить
с нуля.
- Всё, что решается фактом, решай сам и показывай списком в докладе.
- **Останавливайся на границе порции**, даже если «ещё чуть-чуть осталось».
Между порциями — промежуточный доклад.
Примеры итераций, отбор порции, храповик на залежавшихся —
[references/portions.md](references/portions.md).
## Стимулы, которые процесс создаёт
Правило, которое можно обойти в свою пользу, будет обойдено.
**Приёмщик и исполнитель совпадают, и это надо назвать вслух.** Задачу закрывает
тот же агент, который её и сделал. Груминг приёмкой не занимается — отдельного
ритуала у неё нет, — и настоящих опор остаётся две:
- **независимый отчёт ревью** — артефакт, написанный не исполнителем: отчёт
триажа в
`openspec/changes/archive/<id>/review/` (до архивации — `changes/<id>/review/`);
- **`reopen <слаг> --reason`** — закрытие не окончательно. Заметил, что закрытая
задача сделана не тем, чем обещала, — возвращай, это штатная операция, а не
скандал, и ждать груминга она не требует (на стройке его и не будет). Индексы под git: `git log -p` по беклогу показывает,
что и когда закрыто, потому что закрытие коммитится отдельным коммитом учёта.
Известные обходы:
- **Не записать вопрос** на задаче, которую хочется поднять наверх очереди.
Защита: вопросы верхних строк разбираются вне очереди порции, шагом 2.
- **Оставить всё как есть.** Груминг, на котором ничего не сдвинулось и ничего
не закрылось, — это не «беклог в порядке», а не проведённый груминг. Защита:
задача из верхних строк, которую и этот заход оставляет без изменений, **либо
двигается, либо получает записанную причину**, почему её держат.
- **Расставить порядок молча**, без доводов: тогда через месяц он неотличим от
случайного. Защита: причина у каждого движения и строка доклада.
- **Разобрать много и мелко** вместо немногого и важного: тридцать полей гигиены
вместо трёх решений о важности. Защита: гигиена — работа скилла `task-track` и
побочный продукт здесь; доклад называет **решения**, а не правки.
## Слоты проекта
Груминг не знает ни языка, ни сборки, ни CI. Проект дописывает в `CLAUDE.md`:
1. **Что считается сломанным** — какая красная проверка обгоняет развитие.
Не названо — спрашиваем человека, а не решаем сами.
2. **Необратимое** — что спрашивается всегда (тот же слот, что у скилла `task-track`;
дом один).
3. **Ориентир по размеру порции**, если он замерялся. Умолчание — 5–8 задач, и
это **ориентир, а не закон**.
Числа проекта (сколько задач приходит за месяц, каков прирост беклога) — предмет
наблюдения человека, а не константы этого скилла.
## Доклад
- Что просмотрено: N из M, сколько порций, по какому признаку отобраны.
- Вопросы: разобрано N, из них отвечено без человека N, снято тегов N.
- **Что перестало быть важным**: удалено как реализованное (со ссылками), ушло
без реализации (с причинами), понижено до сырья, слито, сменило тип.
- **Что важно сейчас**: верх очереди по каждой секции — слаги в порядке, и по
каждому движению довод одной строкой.
- **Границы покрытия**: сколько задач не трогали и какие именно секции или теги
остались — иначе доклад читается как «беклог разобран».
- `tasks.py check` после правок — результат строкой.
## Чего этот скилл не делает
Не пишет код и не выполняет задачи. Не заводит и не переоформляет записи сам по
себе — формат и содержимое ведёт `task-track` (груминг зовёт его операции). Не решает
за человека, что важно: он готовит развилки и рекомендует. Не принимает
закрытые задачи отдельным ритуалом — `reopen` есть, момента у него нет. Не судит
документы проекта — это скиллы `av-dev:canon` и `av-dev:doc-healthcheck`.