# Ведение спринта Спринт — набор задач под одну цель, замороженный до его конца. Здесь то, что происходит **внутри** спринта: как задача заканчивается, что считается сделанным, кто принимает и что идёт в доклад. Как спринт набирается — шаг 4 в [cadence.md](cadence.md). ## Наблюдаемые исходы задачи Как они достигаются — дело пайплайна проекта. Сессия знает только исход и его след. - **Сделана** — по определению готовности ниже. `close --implemented`: файл и строка удаляются, следом остаётся коммит. **Закрывает агент-оркестратор последним шагом пайплайна, после коммита; приёмка человеком идёт позже и отменяется `reopen`** — см. «Кто и когда закрывает». - **Вышла из спринта** — `sprint drop --reason …`: возвращается в беклог с вопросом в файле и **без живого незакоммиченного предложения** — иначе при следующем взятии оно столкнётся с новым. Наработки, которые жалко терять, переезжают в тело задачи текстом. - **Оказалась крупнее задачи** — распознаётся **до того, как под неё заведено предложение об изменении**, иначе его придётся выбрасывать. Выходит из набора, уходит на декомпозицию; спринт продолжается остальными, части заводятся под той же целью и в замороженный набор не добавляются. - **Отменена решением по ходу** — `close --reason "<ссылка на решение>"` прямо из спринта. Это редкий, но законный исход, и он называется в докладе. **Конец спринта** — когда по каждой задаче набора наступил один из исходов. Не «все сделаны»: иначе одна застрявшая задача держит спринт бесконечно. Затем `sprint close`. ```mermaid flowchart TD take["sprint take — задача в наборе"] done["сделана
close --implemented"] out["вышла
sprint drop --reason"] epic["крупнее задачи
распознаётся до заведения change"] cancel["отменена решением по ходу
close --reason"] all{"по каждой задаче набора
наступил исход?"} harvest["урожай заводится интейком tasks"] close["sprint close"] dissolve["sprint close --dissolve --reason
недоделанное — в беклог"] take --> done take --> out take --> epic take --> cancel done --> all out --> all epic --> all cancel --> all all -->|да| harvest harvest -->|"тег sprint: ставится, пока SPRINT.md не очищен"| close take -->|"продолжать нечем ни одной задачей — блокер"| dissolve done -->|"приёмка не сошлась: reopen --reason"| take ``` Два ребра на схеме — те, где порядок обязателен и нарушается молча: **урожай до `sprint close`** (после команды автотег уже не поставится) и **блокер в обход исходов** (спринт распускается, а не ждёт). Схема — **сводка**: определение готовности и правила приёмки ниже, и при расхождении прав текст. **Урожай заводится при закрытии спринта, а не при закрытии задачи.** Это обязанность закрывающего: пройти по спискам находок от исполнителей и завести недостающее интейком скилла `tasks` — с дедупликацией и картой человеку. Заводимое метится тегом спринта само (`sprint:<слаг>`), поэтому первая порция следующей сессии поднимается одной командой `list --tag sprint:<слаг>`. Спринт, закрытый без этого шага, оставляет находки жить в отчётах — то есть нигде. **Порядок здесь обязателен: урожай заводится ДО команды `sprint close`.** Автотег ставится по слагу из `SPRINT.md`, а `sprint close` этот файл очищает; заведённое после команды остаётся без тега и в первую порцию следующей сессии не попадёт — молча, потому что пустой `list --tag` выглядит как «урожая не было». Если так уже вышло, тег ставится руками: `add … --tag sprint:<слаг>`, слаг берётся из отчёта `sprint close`. **Провал спринта.** Сработал блокер — спринт распускается (`sprint close --dissolve --reason …`), недоделанное возвращается в беклог, новый набор делается после ответа человека. Спринт не «ждёт»: ждать может человек, а замороженный набор, который нельзя двигать, только мешает. **Протухший набор — второй законный повод роспуска.** Работа стояла, и человек вернулся к спринту, состав которого уже не держит в голове. Тем же роспуском: `sprint close --dissolve --reason "работа стояла с <когда>"`, недоделанное в беклог, новый набор — после переоценки, а не поверх старого. Порога в неделях нет и не будет: счётчик простоя пришлось бы вести руками, а решает всё равно человек. Признак — не срок, а **что набор перестал быть твоим**: взялся перечитывать, зачем эти задачи вместе, — он протух. Заморозка тут не мешает, она запрещает *двигать* набор, а не распустить его целиком. ## Определение готовности Задача засчитывается сделанной, когда верно **всё**: 1. **Пайплайн задачи пройден до конца** — со своим определением готовности, за которое отвечает проект: проверки, состав ревью, документация, коммит. Здесь оно не пересказывается и не подменяется — **форма фиксирована, содержание даёт `CLAUDE.md` проекта**. Пайплайна нет, задача сделана руками — условие читается как «проверки проекта зелёные и изменение влито». 2. **Критерии приёмки проверены поимённо** — каждый со своим оракулом, исход по каждому назван. Это единственное, что добавляет управление задачами: пайплайн отвечает «сделано по правилам», критерии — «сделано то, что заказывали». 3. **Находки по ходу отданы списком** — исполнитель обязан их **назвать** (каждую, с пометкой «заведена / не заведена: причина»), но **не обязан заводить**: заведение интерактивно — оно требует дедупликации против беклога и кладбища, а ещё решений человека. Обязанность **завести урожай** — на закрытии спринта, ниже. Иначе автономный исполнитель оказался бы разом и обязан завести задачи, и не вправе сделать это в одиночку. ### Кто и когда закрывает **Задачу закрывает агент-оркестратор — тот же, кто её и сделал**, последним шагом пайплайна, после коммита. Порядок: 1. пайплайн доводит задачу до коммита; 2. **после коммита** зовёт `Skill av-dev-pm:tasks` и закрывает задачу (`close --implemented`); строка уходит из `SPRINT.md`; 3. **докладывает исход и по каждому критерию — оракул и наблюдаемый исход.** Это доклад приёмщику, а не отметка «принято». **Приёмщик и исполнитель здесь совпадают, и это принято сознательно** — цена названа в `SKILL.md`, раздел «Стимулы». Поэтому закрытие **не окончательно**, а доклад по критериям — не формальность: он единственное, по чему приёмка вообще возможна. **Порядок «коммит, потом закрытие» обязателен.** Закрытие удаляет файл задачи; упавший коммит после закрытия оставил бы задачу закрытой без единого следа работы. **Само закрытие тоже коммитится, отдельным коммитом.** Удаление файла задачи и правка индекса — правки в рабочем дереве; пока они не в истории, `SPRINT.md` ничего не показывает, а `reopen` восстанавливает текст из `HEAD` в узком окне: его закроет первый посторонний коммит. Сообщение про учёт, а не про работу: `закрыта задача `. **Дорога назад существует и обязана быть названа.** Человек на сессии сверил критерии, и приёмка не сошлась — `tasks.py reopen --reason "приёмка не сошлась: …"`: файл восстанавливается из истории git, строка возвращается в набор идущего спринта (или в беклог, если спринта нет), строка кладбища снимается. Тело восстанавливается **на момент удаления** — всё, что было дописано позже, живёт только в коммите задачи, и это называется в докладе. ### Кто и по чему принимает Три условия, без которых пункт про критерии не исполняется никем: 1. **Критерии переживают файл задачи.** Файл удаляется при закрытии, поэтому критерии копируются туда, где их увидит приёмщик. Куда именно — **отвечает пайплайн проекта, а не слот в `CLAUDE.md`**: он переносит их в `tasks.md` изменения, когда заводит change. Проект без пайплайна называет своё место сам. 2. **Принимает человек на сессии, а не отдельный агент.** Декорреляция исполнителя и приёмщика в момент закрытия **снята** (решение о снятии и его цена — в `SKILL.md`, «Стимулы»). Опоры остались три: **сохранённый независимый отчёт ревью** (при конвейере `av-dev-pipeline` — отчёт триажа в `openspec/changes/archive//review/`, до архивации — `changes//review/`), `SPRINT.md` под git и `reopen`. Переоценка на сессии и есть момент, когда критерии видит не исполнитель. **Конвейера ревью в проекте нет — первой опоры нет тоже**, и это называется строкой доклада, а не обходится молча (`SKILL.md`, «Стимулы»). 3. **Расхождение — дефект критериев.** Приёмщик правит критерии и возвращает задачу исполнителю **в этом же спринте**: ответ есть, остаток есть, по тесту про остаток это не выход из спринта. ## Что врывается в замороженный набор Только два класса — правило и его обоснование в SKILL.md. Здесь механика: - вторжение **не добавляет** задачу в набор: `SPRINT.md` остаётся набором под цель. Внеплановая работа делается и называется в докладе отдельной строкой «внеплановое: что и почему»; - если внеплановое требует больше пары часов, честнее распустить спринт, чем делать вид, что набор соблюдается; - всё остальное падает в беклог через обычный интейк и ждёт сессии. ## Доклад в конце спринта Проверяемые якоря, а не пересказ: - **Цель спринта** и по каждой задаче набора: **хеш коммита**, дословный исход проверок проекта, **исход по каждому критерию приёмки**. - **Какие развилки решались** и чем обоснованы. - **Урожай:** сколько задач заведено, какие вопросы накопились, что вышло из спринта и почему, что было внеплановым. - **Поимённая сверка урожая** с независимыми отчётами ревью: каждая отложенная находка имеет либо слаг, либо строку «не заведена: причина». Нулевой урожай при непустом отчёте — сигнал, а не благополучие. **Отчётов нет** (проект без конвейера ревью) — сверять не с чем, и строка доклада говорит именно это, а не «сверено». - **Созрела ли порция для сессии.** Решение звать — человека, напоминание — обязанность агента: `⌈урожай / 8⌉` порций. - **Границы покрытия** сжатой строкой: что в этом спринте не проверялось вовсе.