Files
dev-skills/av-dev-pm/skills/session/references/cadence.md
T
avandClaude Opus 5 e847bfa0ea роадмап — состояние проекта, а не очередь работ
Основной инструмент владельца отвечал на половину своего вопроса. Оценка идёт
по поведению: что приложение уже может и чего ещё не может, — а close
--implemented удалял у достигнутой цели и файл, и строку, так что роадмап по
построению показывал только «что осталось». Свидетельство лежало в самом
роадмапе healthlog: секция «Что уже пройдено» на двадцать строк прозы, руками,
с припиской «Эти звенья целями не заведены: закрытая цель записи не оставляет».

Теперь строка с датой переезжает в секцию достигнутого, файл удаляется
по-прежнему. Вторым домом поведения это не делает: нормативное поведение живёт
в openspec/specs, роадмап отвечает, когда и в каком порядке оно появилось.
Ссылки на файл в строке нет — файла больше нет, форма как в REJECTED.md.

Цель стала возможностью приложения, задача — шагом к ней:
- заголовок цели отвечает на «что приложение будет уметь»; свойство поведения
  («сообщает о своём состоянии», «исход не зависит от порядка») — тоже
  возможность и переформулировки не требует;
- «Завершение» — списком, а не абзацем: задача ссылается на его строку, и это
  новая защита от «отрефакторить X» вместо прежнего «наблюдаемо снаружи».
  Заодно видно обратное: строка, к которой не относится ни одна задача, —
  незакрытая часть возможности;
- работа над инструментом и процессом на этот вопрос не отвечает и живёт в
  отдельной секции.

Цель обязательна не у всякой задачи. Прежнее «иначе она не попадёт ни в один
спринт» было угрозой, а не аргументом, и заставляло операционную работу
выдумывать себе направление. Граница по роду: feature без цели не бывает, fix,
chore и research живут без неё и входят в набор помимо цели спринта.

Тип [epic] упразднён: зонтиком стала цель, а слишком крупный шаг дробится под
ней. Ноль употреблений на 97 записей двух живых проектов.

Секции роадмапа — умеет / строим / направления / станок, четыре вместо двух;
имена приняты как временные и запаркованы (TODO 7). Имя секции достигнутого
знает скрипт — docs/.pm.json, ключ tasks.achieved_section. reopen цели снимает
строку достигнутого, круг проверен вживую.

Всё дописано в версию 3 канона: она ещё нигде не выкачена. DECISIONS 19,
YYY–ГГГ и следствия 78–81.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 17:43:55 +03:00

221 lines
20 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.
# Сессия: четыре шага
Одна сессия между спринтами. Порядок шагов — **зависимость, а не список**:
переоценивать задачи, не разобрав вопросы, значит переоценивать вслепую; набирать
спринт, не переоценив, значит набирать из протухшего.
Начинается сессия с `tasks.py check``check --fix`, если дрейф накопился) —
результат идёт строкой в доклад.
## Шаг 1. Разбор вопросов
`tasks.py list --questions` — всё, что накопилось. Вопрос это решение человека,
и разбирается он **пачкой**, а не по одному в момент возникновения: по одному —
это дёрганье, пачкой — это сессия.
Порядок по каждому вопросу:
1. **Проверь, не отвечен ли он уже** — решением, документом, соседним
изменением, самим ходом прошедшего спринта. Отвеченный вопрос не выносится
человеку: это самая частая находка и она не требует ничьего решения.
2. **Сформулируй развилку** с вариантами и последствием каждого, рекомендация —
первым вариантом.
3. **Вынеси пачкой** через `AskUserQuestion`, не больше трёх за раз.
4. **Ответ записывается в тело задачи, раздел «Вопросы» опустошается**, тег
снимается `edit <slug> --rm-tag question`, **«зачем» переписывается**: «Решено:
…» на вопрос «почему это лежит в беклоге» уже не отвечает. Опустошение
раздела — не уборка, а условие взятия: правило и причина в скилле `tasks`,
[references/task-format.md](../../tasks/references/task-format.md).
**Вопросы на задачах-кандидатах разбираются вне очереди порции** — здесь же, на
этой сессии, даже если сама задача в порцию переоценки не попала. Иначе правило
«задача с открытым вопросом в набор не берётся» создаёт стимул вопрос не
записывать, лишь бы не вычеркнуть задачу из ближайшего спринта.
## Шаг 2. Разбор прошедшего спринта — про процесс, а не про задачи
Не «что мы сделали» (это доклад спринта, он уже был), а:
- **что сломалось в процессе и почему не поймали** — промах, доехавший до конца;
- **сколько на самом деле заняли задачи** против ожидания;
- **какие правила не сработали или сработали не так** — в том числе правила
этого плагина;
- **какие числа пора пересмотреть** — ориентир по размеру спринта, прирост
беклога на одну закрытую задачу, время на задачу. Эта обязанность иначе висит
ничья: числа, помеченные как «первый замер», не пересматриваются никогда, если
их не пересматривает конкретный шаг.
**Артефакт обязателен.** Вывод, оставшийся в контексте сессии, не существует:
следующая сессия его не увидит. Дом у него один и известен из канона —
**`docs/review.md`**: вывод про конвейер и про то, что перестали проверять, идёт
в раздел настройки, вывод про воспроизведённый дефект — в журнал. Решение с
долгим следом — в `docs/adr/`.
Отдельным ритуалом ретроспектива не выделяется: процесс личный,
синхронизировать некого.
## Шаг 3. Переоценка задач
Цель — выкинуть то, что перестало быть задачей, и вернуть остальному честное
состояние. Не «пересмотреть всё», а «пересмотреть порцию до конца».
### Порция и правило остановки
Тридцать задач за один заход — это усталость и штамповка: последние десять
получат «оставить» не потому, что живы, а потому, что сессия затянулась.
- **5–8 задач за порцию.** Размер обоснован усталостью, а не пропускной
способностью, и менять его не надо — **надо брать несколько порций за
сессию**.
- **Сколько порций:** не меньше `⌈урожай прошедшего спринта / 8⌉`. Урожай — это
задачи, заведённые за спринт; при урожае в 15 это две-три порции.
- **Отбор порций по порядку:**
1. **урожай спринта**`list --tag sprint:<слаг>`: свежезаведённое ещё не
проходило ни одной проверки на нужность. Тег на задачах проставлен
автоматически при заведении — руками не метят и не вспоминают. **Слаг
берётся из отчёта `sprint close`, а не из `SPRINT.md`:** сессия идёт после
закрытия, а закрытие этот файл очищает;
2. дальше **по залежалости**`list --stale`;
3. по потребности — одна секция целиком, один тег (партия ревью), одна цель
(`--goal`), список от пользователя.
- **Останавливайся на границе порции**, даже если «ещё чуть-чуть осталось».
Между порциями — промежуточный доклад.
### Что делать с каждой задачей
Сперва то, что не требует ничьего решения:
1. **Проверь, не сделано ли уже.** Задача, реализованная попутно в соседнем
изменении, — самая частая находка. Смотри код, документацию, историю коммитов
по ключевым словам. Удаление «как реализованной» деструктивно и без следа
`REJECTED.md` реализованные не пишутся), поэтому порог улики жёсткий:
`close <slug> --implemented` только имея **конкретный коммит или строку
документа**, закрывающие задачу, и ссылка идёт в доклад. Есть лишь косвенные
признаки — не удаляй сам, вынеси в пачку вопросов. Сделана частично → задача
сжимается до остатка: тело правишь редактором, заголовок и «зачем» — через
`edit`.
2. **Проверь, не отменена ли решением.** Документ, ADR или архивное изменение
мог закрыть вопрос иначе — тогда `close <slug> --reason "<ссылка на
решение>"`. Задача закрывается не только коммитом.
3. **Проверь пересечения.** Две задачи об одном — содержимое в одну, вторую
`close <slug> --reason "слита с <другой-слаг>"`. Смотри **шире порции**:
интейк дедуплицирует новое против существующего, но никогда не
пересматривает уже лежащее, и две задачи с одной причиной могут лежать рядом
месяцами.
4. **Пере-кластеризуй по общей причине.** Несколько задач, оказавшихся симптомами
одного дефекта, сливаются в одну — это находка, которую интейк дать не мог.
5. **Гигиена полей** — протухшее «зачем», вопрос в прозе, снятый ответ, свойство
репозитория в рамках, предписание процесса в теле, род работы, разошедшийся с
задачей, границы вместо реализации в разделе «Затрагивает». Список и правила —
в скилле `tasks`. **Переоценка — то самое место, где беклог добирает род
работы и границы:** требовать их на входе значило бы выгонять в заметки то,
что должно лежать задачей, а к взятию в спринт они уже обязательны.
Затем — то, что решает пользователь:
6. **Жива ли она вообще.** Контекст мог измениться: ушла зависимость, отпал
сценарий, обошли иначе. Здесь и звучит вопрос о выкидывании.
7. **Та ли цель — и нужна ли она вообще.** Приоритетов нет, и «повысить» нечего
— вместо повышения **смена цели** (`edit <slug> --goal <другой>`) или
включение в ближайший набор. `feature`, которой не находится цель, — кандидат
на выход: новая возможность вне цели это возможность, которой никто не
заказывал. Операционной задаче (`fix`, `chore`, `research`) цель не нужна, и
выдумывать её здесь не надо.
8. **Задача ли это по-прежнему.** Не проходит тест «готова к взятию» → `edit
<slug> --type idea`, дальше штурм. Разрослась → это несколько задач под той
же целью, дальше декомпозиция.
9. **Переоценка по измеренному.** Спринт производит числа — сколько на самом
деле стоит такая работа, что оказалось дороже ожидания. Эти числа меняют цену
**других** задач, и именно здесь это применяется: задача, чья цена выросла
втрое, а польза осталась прежней, — кандидат на выход.
### Храповик на залежавшихся
Сильно залежавшаяся задача — сигнал сама по себе: её либо ни разу не собирались
делать, либо нечем взять. Измеряй наблюдаемым — датой последней правки из git
(`list --stale` ставит такие первыми); счётчик «сколько сессий пережила» нигде
не хранится.
Задача из верхних строк `--stale`, которую и этот заход оставляет без изменений,
**либо двигается (меняет цель, идёт в набор, уходит с причиной), либо остаётся с
явно записанной причиной**, почему её держим (`move <slug> --section <та же>
--reason …`). Молчаливое «оставить как есть» на давно неподвижной задаче — это
решение не принимать решение; запись причины превращает его в осознанное и не
даёт тому же вопросу всплыть на следующей сессии.
### Интерактив
- Вопросы — через `AskUserQuestion`, **не больше трёх за раз**. Порция в 5–8
задач обычно даёт больше трёх суждений — тогда веди несколько итераций по ≤3,
а не по одному на задачу и не одним перегруженным запросом.
- К каждому варианту — **предварительное суждение, рекомендация первым
вариантом**: «предлагаю выкинуть, потому что …». Пользователю дешевле
возразить, чем судить с нуля.
- Всё, что решается фактом (сделано / отменено / дублируется), решай сам и
показывай списком в докладе, а не выноси в вопросы.
Пример одной итерации — три залежавшихся задачи, механику по ним уже разобрали:
> **Переоценка: 3 залежавшихся (порция по `--stale`)**
>
> 1. `versii-kachestvo-repaki` — версии и качество одного тайтла
> - Выкинуть *(рекомендую)* — помечена «не боль», за полгода ни разу не возникла
> - Оставить под целью `nadyozhnost-razdach`
> - Перевести под цель `kachestvo-mediateki` — там она первая в очереди
> 2. `backup-sqlite` — бэкап базы
> - Оставить под текущей целью *(рекомендую)* — не сработала, но риск реальный
> - Взять в ближайший набор — без бэкапа ретеншн опасен
> - Выкинуть
> 3. `guessit-sputnik` — вынести распознавание в сервис-спутник
> - Понизить до `[idea]` *(рекомендую)* — не проходит тест «готова к взятию»
> - Оставить задачей
Каждый вариант несёт причину — ту самую, что уедет в `--reason`. Ответы применяй
сразу и, если в порции осталось ещё, следующей итерацией показывай следующие ≤3.
## Шаг 4. Выбор цели и набор спринта
1. **Покажи состояние проекта**: секцию `умеет` (что уже сделано — это половина
ответа на «где мы»), затем `строим` с обоснованием очереди, `направления`, и
по каждой цели-кандидату — сколько под ней задач без открытых вопросов
(`list --goal <слаг>`). Цель без готовых задач набором не станет: её сперва
надо декомпозировать.
2. **Цель называет человек.** Это продуктовое решение, а не механика: агент
предлагает и объясняет, но не выбирает.
3. **Набор собирает агент** — `sprint start --goal <слаг>`, затем `sprint take
`. Скрипт не даст взять цель, идею, задачу с чужой целью, с открытым
вопросом, без критериев приёмки, без рода работы или без раздела
«Затрагивает». Задача без цели вовсе (`fix`, `chore`, `research`) берётся
свободно — операционная работа входит в набор помимо его цели.
4. **Набор показывается человеку до старта работ.** Показ — это и есть момент
заморозки: после него набор не двигается. **В показе называется состав по
роду работы** — три `fix` и ни одной `feature` под целью развития это
разговор про цель, а не про набор, и увидеть его надо до заморозки, а не в
докладе по итогам.
Здесь же последний дешёвый момент заметить **разнородную задачу**: раздел
«Затрагивает» показывает границы до того, как заведено предложение об
изменении. Строка, которая одна тянет задачу на ступень выше остального
перечня, — кандидат на разрез (шов — в `tasks`, `references/split.md`).
Замеченная здесь, она стоит одного `edit`; замеченная на ревью — выброшенного
предложения.
5. Задача, которой для взятия не хватает только критериев приёмки, границ или
рода, дописывается здесь же — 2–5 утверждений с оракулами, перечень
затрагиваемых границ, `--kind`. Но если для этого нужен ответ человека, это
вопрос, и задача в набор не идёт.
**Размер — ориентир, а не закон:** 5–8 задач. Можно взять больше, можно меньше —
набор под цель важнее круглого числа; одна крупная задача спринтом тоже бывает.
## Доклад сессии
- Что просмотрено: N из M, сколько порций, по какому признаку отобраны.
- Вопросы: разобрано N, из них отвечено без человека N, снято тегов N.
- Разбор процесса: что записано и куда.
- Изменения списком: удалено как реализованное (со ссылками), ушло без
реализации (с причинами), понижено до идей, слито, сменило цель.
- Новый спринт: цель, набор со слагами, дата, состав по роду работы.
- **Границы покрытия**: сколько задач не трогали и какие именно секции, теги или
цели остались — иначе доклад читается как «беклог разобран».
- `tasks.py check` после правок — результат строкой.