From 4a56753f0bbcfc8029b5c0e2ab44a77ceb817102 Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Sun, 9 Aug 2026 16:49:07 +0300 Subject: [PATCH] =?UTF-8?q?session=20=D1=81=D1=82=D0=B0=D0=BB=20groom:=20?= =?UTF-8?q?=D0=B4=D0=B2=D0=B0=20=D0=B2=D0=BE=D0=BF=D1=80=D0=BE=D1=81=D0=B0?= =?UTF-8?q?=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D1=80=D0=B8=D1=82?= =?UTF-8?q?=D1=83=D0=B0=D0=BB=D0=B0=20=D1=81=D0=BF=D1=80=D0=B8=D0=BD=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Предмет сузился до двух: что сейчас самое важное и что перестало быть важным. Ответ записывается порядком строк в беклоге. Из четырёх шагов сессии выжили два (вопросы, переоценка порциями), один заменился расстановкой очереди вместо набора спринта, два выпали. Приёмка — грумингу не по предмету, ритуала у неё больше нет, остаётся reopen; цена названа в тексте. Разбор процесса потерял якорь, и вместе с ним ушёл прямой вызов агентов doc-consistency и doc-code-drift — это починка, а не потеря: агенты принадлежат av-dev-docs, и груминг звал их мимо правила обращения к соседу. sprint.md удалён, cadence.md стал portions.md. Канон 12: запись в журнал велит проектам снести SPRINT.md и расставить порядок, с точным порядком шагов — сперва удалить файл, потом check --fix, иначе он увидит третий индекс и станет ругаться, а не чинить. Побочно: canon.md объявлял себя версией 7 при текущей 11. Пять версий дом канона врал о себе — машина сверяет константу скрипта, а прозу в заголовке не читает никто. --- .claude-plugin/marketplace.json | 2 +- DECISIONS.md | 57 ++++ README.md | 8 +- REMAINING.md | 2 +- TODO.md | 41 +-- av-dev-code/skills/resolve/SKILL.md | 2 +- av-dev-docs/skills/canon/references/canon.md | 2 +- .../skills/canon/references/changelog.md | 43 +++ av-dev-docs/skills/canon/scripts/docs.py | 2 +- av-dev-tasks/.claude-plugin/plugin.json | 2 +- av-dev-tasks/skills/groom/SKILL.md | 246 ++++++++++++++ .../skills/groom/references/portions.md | 162 ++++++++++ av-dev-tasks/skills/session/SKILL.md | 304 ------------------ .../skills/session/references/cadence.md | 277 ---------------- .../skills/session/references/sprint.md | 199 ------------ 15 files changed, 532 insertions(+), 817 deletions(-) create mode 100644 av-dev-tasks/skills/groom/SKILL.md create mode 100644 av-dev-tasks/skills/groom/references/portions.md delete mode 100644 av-dev-tasks/skills/session/SKILL.md delete mode 100644 av-dev-tasks/skills/session/references/cadence.md delete mode 100644 av-dev-tasks/skills/session/references/sprint.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 745ff1d..3872e25 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -13,7 +13,7 @@ { "name": "av-dev-tasks", "source": "./av-dev-tasks", - "description": "Задачи и цели каталогом markdown-файлов, у каждой записи тип, и тип задаёт её схему. Спринт под одну цель, ритуал между спринтами, проверка согласованности скриптом tasks.py. Задача выполняется чем угодно: пайплайна плагин не требует и сам его не зовёт." + "description": "Задачи и цели каталогом markdown-файлов, у каждой записи тип, и тип задаёт её схему. Приоритет — порядок строк в беклоге, расставляет его скилл груминга. Проверка согласованности скриптом tasks.py. Задача выполняется чем угодно: пайплайна плагин не требует и сам его не зовёт." }, { "name": "av-dev-code", diff --git a/DECISIONS.md b/DECISIONS.md index c520e18..85bc171 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -3496,3 +3496,60 @@ change нет — берём источником актуальные спек предписаниях.** Правило «не задним числом» защищает от подделки фактов, а не от починки инструкций: инструкция, ссылающаяся на несуществующее, — не свидетельство эпохи, а поломка с отложенным сроком. + +## 57. Спринты отменены: приоритет стал порядком строк, `session` стал `groom` (2026-08-09) + +**АЕАКП. Спринт отвечал на вопрос «что делать дальше» замороженным набором, а +между наборами на этот вопрос не отвечал никто.** Процесс идёт задача за задачей, +и набор перестал что-либо удерживать: он не синхронизировал (некого), не +ограничивал по времени (тайм-бокс не брали) и не защищал от врывания (врывалось +ровно два класса, оба назывались правилом). Осталась цена — обязанность собрать, +показать, заморозить и распустить. + +**Приоритет вернулся, и вернулся туда, где ему место.** Прежнее правило «порядка +нет, есть цель» было обосновано **набором спринта**, и с ним потеряло опору. +Приоритет — свойство очереди, а не задачи, поэтому его дом **индекс**: то же +исключение из правила «файл — источник истины», что уже было у «в каком индексе +лежит запись». Числом в файле он быть не мог — два соседних файла смогли бы +утверждать одно место, а строка индекса противоречить обоим. + +**Гейт готовности стоял на `sprint take` и чуть не исчез вместе с ним.** Это было +единственное место, где запись судили целиком: тип, цель у `feature`, пустой +раздел вопросов, схема типа. Без спринта момента не осталось бы вовсе, а узнают +о недописанной задаче на приёмке, когда сверять уже не с чем. Момент назвали +заново — команда `tasks.py ready <слаг>`, и зовёт её тот, кто берёт задачу. +Отказ там **код 1, а не 2**: запись не дописана — это рабочая ситуация, а не +ошибка употребления. + +**`session` стал `groom`, и предмет сузился до двух вопросов** — что сейчас +самое важное и что перестало быть важным. Из четырёх шагов прежней сессии выжили +два (вопросы, переоценка порциями), один заменился (расстановка очереди вместо +набора спринта), два выпали: + +- **приёмка закрытых задач** — грумингу не по предмету. Ритуала у неё больше нет, + остаётся `reopen` по требованию. Цена названа прямо: приёмка происходит только + тогда, когда что-то уже бросилось в глаза; +- **разбор процесса** — его якорем был прошедший спринт. Вместе с ним из скилла + ушёл прямой вызов агентов `doc-consistency` и `doc-code-drift`, и это **не + потеря, а починка**: агенты принадлежат `av-dev-docs`, и груминг звал их мимо + правила обращения к соседу, без ветки «плагина нет». Груминг теперь только + **называет повод** сверить канон, а когда их звать — решает их владелец. + +**Побочно найдено:** `canon.md` — дом определения канона — объявлял себя версией +7, когда скрипт шёл на 11. Пять версий дом врал о себе, и не заметил никто: +машина сверяет версию проекта с константой скрипта, а прозу в заголовке не +читает. + +### Что из этого следует + +190. **Правило, обоснованное механикой, умирает вместе с ней — и надо проверять, + что вопрос умер тоже.** «Порядка нет» держалось на наборе спринта; набор + ушёл, а вопрос «что делать дальше» остался и повис без ответа. Снимая + механику, ищи не только то, что на ней стояло, но и то, на что она отвечала. +191. **Гейт живёт в моменте, а не в команде.** Проверка готовности была свойством + `sprint take` — и была бы потеряна как деталь удаляемой команды. Момент + «запись впервые судят целиком» существует независимо от того, чем он + назван, и переезжает вместе с процессом. +192. **Версия в прозе, которую не читает машина, протухает молча.** Дом канона + назвал себя версией 7 при текущей 11: сверка шла по константе скрипта, а + заголовок документа не сверял никто. diff --git a/README.md b/README.md index 7280d71..4d80251 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,11 @@ (`goal`, `feature`, `fix`, `chore`, `research`), и тип задаёт её схему; вычитывают их два отдельных прохода: `task-form` (форма записи) и `task-wording` (язык записей); - - `session` — ритуал между спринтами и ведение спринта. + - `groom` — груминг беклога: что сейчас самое важное и что перестало быть + важным. Ответ записывается **порядком строк** — приоритет это свойство + очереди, и живёт он в индексе. Интерактивный: разбирает вопросы пачкой, + переоценивает порциями по 5–8, расставляет верх очереди с доводом на + каждое движение. - **av-dev-code** — код по задачам: решение одной задачи и его проверка. Владеет `openspec/`. **Требует OpenSpec и сам его заводит.** - `openspec` — завести, настроить и **проверить** `openspec/` в проекте: @@ -71,7 +75,7 @@ flowchart TB end subgraph tasksp["av-dev-tasks — учёт работ"] direction LR - session["session"] --> tasks["tasks"] + groom["groom"] --> tasks["tasks"] end init --> tasks init --> osp diff --git a/REMAINING.md b/REMAINING.md index dedf961..349f8ba 100644 --- a/REMAINING.md +++ b/REMAINING.md @@ -83,7 +83,7 @@ check` сверяет версию, но не то, что миграционн **Не выродились ли «границы покрытия» в шаблон.** Строка «что смотрели и чего не смотрели» обязательна в докладе `check`, `adopt`, интейка, штурма, сессии, спринта и всех четырёх агентов — семь и больше раз за сессию, и проверить её -исполнение некому: приёмщик и исполнитель одно лицо (`session/SKILL.md`, +исполнение некому: приёмщик и исполнитель одно лицо (`groom/SKILL.md`, «Стимулы»). Выродившаяся строка **хуже отсутствия**: доклад выглядит проверенным. Приём не правится: это гипотеза об износе, а не находка, и менять работающее по diff --git a/TODO.md b/TODO.md index a2551a4..02c25ca 100644 --- a/TODO.md +++ b/TODO.md @@ -20,7 +20,7 @@ цикл SDD, конвейер ревью, OpenSpec), `av-dev-git`. Общее, что нужно нескольким дословно, живёт домом в `shared/` и уезжает копиями. -Канон документов — **версия 11**. Живые проекты стоят на 2–3 и на плагине +Канон документов — **версия 12**. Живые проекты стоят на 2–3 и на плагине `av-dev-pm`, которого больше нет. ## 1. Живые проекты — вернуть в рабочее состояние @@ -39,11 +39,11 @@ - [ ] удалить проектные копии: `.claude/skills/healthlog-{task,review}-pipeline` и девять `.claude/agents/healthlog-review-*.md`. Они прошлого поколения и после переезда указывают на документы, которых уже не будет -- [ ] `av-dev-docs:canon` в режиме `adopt` — он приведёт проект к канону 11 +- [ ] `av-dev-docs:canon` в режиме `adopt` — он приведёт проект к канону 12 сразу, картой и с подтверждением. Файл-в-файл здесь не расписан: раскладку знает скилл, и второй перечень разошёлся бы с ним -- [ ] каталог задач — в `tasks/` корня (канон 11), не в `docs/tasks/`. Скилл - задач зовётся из `adopt` сам +- [ ] каталог задач — в `tasks/` корня (канон 11), не в `docs/tasks/`, и без + `SPRINT.md` (канон 12). Скилл задач зовётся из `adopt` сам - [ ] гейт проекта: три шага вместо одного — `docs.py check`, `tasks.py check --dir tasks`, `openspec.py check`. **Второй и третий раньше не были нужны:** согласованность задач тянул за собой `docs.py`, форму `config.yaml` @@ -61,33 +61,16 @@ `review-pipeline` — **ровно как в плагине**, и короткое имя может увести в устаревшую копию молча (REMAINING) -## 2. Учёт работ без спринтов +## 2. Учёт работ без спринтов — что осталось -Решено: спринты отменяются, беклог и роадмап остаются. Причина — процесс идёт -задача за задачей, и замороженный набор перестал что-либо удерживать. +Сделано: спринт снят со скрипта и текстов, приоритет стал порядком строк в +беклоге, гейт готовности переехал в `tasks.py ready`, `session` стал скиллом +`groom`, запись 12 в журнал версий канона написана. -- [ ] снять спринт: `SPRINT.md`, команды `sprint *`, переходы схемы состояний, - правило «задача живёт в одном индексе за раз» упрощается до беклога -- [ ] **приоритет — явный порядок строк в беклоге.** Правило 4 скилла задач - («порядка нет, есть цель») переписывается целиком: оно обосновано тем, что - «что делать дальше» отвечает набор спринта, — а набора больше нет. - Записать, что приоритет это **свойство очереди, а не задачи**, и потому его - дом индекс: то же исключение из правила 2, что уже есть у «в каком индексе - лежит задача, знают индексы» -- [ ] **перевесить гейт готовности.** Схема типа (обязательные разделы, ≥2 - критерия, границы) проверяется на `sprint take`. Спринта нет — момента нет; - нужен `tasks.py ready <слаг>` или `check --task <слаг>`, иначе задача уедет - в работу без критериев приёмки. Сейчас `resolve` держит это глазами: он - отказывает сырью (`research` без «Вопроса») и называет строкой невыполненную - схему у прочих типов — то есть **машина в этом месте не участвует** -- [ ] `check --fix`: восстановленная строка индекса теряет позицию, а позиция - теперь и есть приоритет. Класть в конец категории и печатать пометкой, что - приоритет назначен не человеком -- [ ] `session` → скилл груминга внутри `av-dev-tasks`: пересортировка беклога, - разбор вопросов, переоценка. `references/sprint.md` в мусор, `cadence.md` - переписать под ритуал без спринта -- [ ] запись в журнал версий канона: проектам надо снести `SPRINT.md` и - расставить порядок +- [ ] прогнать груминг на живом беклоге — на фикстуре проверялись команды, а не + сам разбор. Наблюдение к первому прогону: **не выродился ли шаг 4 в + «оставить как есть»** — признак тот, что доклад не называет ни одного + движения с доводом ## 3. Калибровка — блокирует переезд jellybit diff --git a/av-dev-code/skills/resolve/SKILL.md b/av-dev-code/skills/resolve/SKILL.md index 675e2b0..0b19681 100644 --- a/av-dev-code/skills/resolve/SKILL.md +++ b/av-dev-code/skills/resolve/SKILL.md @@ -163,7 +163,7 @@ flowchart TD в объявленных границах. **Что остатком не является — правило живёт не здесь.** Канонический текст с обеими -оговорками — в плагине `av-dev-tasks`, скилл `av-dev-tasks:session`, раздел +оговорками — в плагине `av-dev-tasks`, скилл `av-dev-tasks:groom`, раздел `## Вопрос, блокер, необратимое`, подраздел «Отличать вопрос от застревания». Правило принадлежит управлению задачами, потому что решает **сделана задача или вышла**, — это исход планирования, а не исполнения. **Ссылайся, не diff --git a/av-dev-docs/skills/canon/references/canon.md b/av-dev-docs/skills/canon/references/canon.md index bb706c1..b2e85c0 100644 --- a/av-dev-docs/skills/canon/references/canon.md +++ b/av-dev-docs/skills/canon/references/canon.md @@ -1,6 +1,6 @@ # Канон документов проекта -**Версия 7.** +**Версия 12.** Это **единственный дом определения канона**. Скиллы `init`, `canon` и `docs` читают его, а не пересказывают: три описания одной раскладки разъедутся, и diff --git a/av-dev-docs/skills/canon/references/changelog.md b/av-dev-docs/skills/canon/references/changelog.md index e38dc68..7fc9f64 100644 --- a/av-dev-docs/skills/canon/references/changelog.md +++ b/av-dev-docs/skills/canon/references/changelog.md @@ -13,6 +13,49 @@ upgrade` идёт по записям снизу вверх от версии п --- +## Версия 12 — 2026-08-09 + +Спринты отменены. Работа идёт задача за задачей, и замороженный набор перестал +что-либо удерживать: он отвечал на вопрос «что делать дальше», а между наборами +на этот вопрос не отвечал никто. + +**Что изменилось.** Индексов задач два вместо трёх: `SPRINT.md` упразднён. +Приоритет стал тем, чем он и является, — **порядком строк в `BACKLOG.md`**: +первая строка секции это то, что делают следующим. Назначает порядок человек, +машина его не выводит; двигают его `move --after` и `move --first` с причиной. + +Гейт готовности записи стоял на взятии задачи в спринт — единственном месте, где +её судили целиком. Момент нужен и без спринта: теперь это команда +`tasks.py ready <слаг>`, и зовёт её тот, кто берёт задачу в работу. + +Ритуал между спринтами (`av-dev-tasks:session`) стал скиллом груминга +(`av-dev-tasks:groom`): два вопроса — что сейчас самое важное и что перестало +быть важным. + +**Что сделать проекту.** + +1. **Вернуть задачи из набора в беклог и снести `SPRINT.md`.** Порядок такой: + `git rm tasks/SPRINT.md`, затем `tasks.py check --dir tasks --fix`. Строки + набора после удаления файла становятся бездомными, и `--fix` возвращает их в + беклог **в конец своей секции** — с пометкой, что позицию назначает человек. + Наоборот делать нельзя: `check` без удалённого файла увидит третий индекс и + станет ругаться на него, а не чинить. +2. **Снять теги `sprint:<слаг>`** с записей — `tasks.py edit <слаг> --rm-tag + sprint:<слаг>`. Тег больше никем не читается, а `check` о нём молчит: он + законный свободный тег. Пропущенный вреда не сделает, но и пользы не несёт. +3. **Расставить порядок** — первый груминг: `av-dev-tasks:groom`. После шага 1 + очередь состоит из того, что машина поставила в конец, то есть очереди нет + вовсе. Пока порядок не назначен, «что делать дальше» по-прежнему без ответа. +4. Поправить упоминания спринта в `CLAUDE.md` проекта, если они были: слот + «общий станок» переехал в груминг под именем «что считается сломанным», + ориентир «5–8 задач в спринте» стал ориентиром размера порции разбора. +5. `docs/.pm.json`: `"canon": 12`. + +**Чего делать не надо.** `REJECTED.md`, `ROADMAP.md` и файлы `items/` не +меняются: спринт жил только в собственном индексе и в тегах. + +--- + ## Версия 11 — 2026-08-09 Каталог задач уехал из `docs/` в корень репозитория. Версия 8 отпустила его из diff --git a/av-dev-docs/skills/canon/scripts/docs.py b/av-dev-docs/skills/canon/scripts/docs.py index a202ee2..4173249 100644 --- a/av-dev-docs/skills/canon/scripts/docs.py +++ b/av-dev-docs/skills/canon/scripts/docs.py @@ -25,7 +25,7 @@ from dataclasses import dataclass, field from pathlib import Path from typing import NoReturn -CANON_VERSION = 11 +CANON_VERSION = 12 OK, DRIFT, USAGE, ENV, INTERNAL = 0, 1, 2, 3, 4 diff --git a/av-dev-tasks/.claude-plugin/plugin.json b/av-dev-tasks/.claude-plugin/plugin.json index cb2ece2..b143cbb 100644 --- a/av-dev-tasks/.claude-plugin/plugin.json +++ b/av-dev-tasks/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "av-dev-tasks", - "description": "Задачи и цели каталогом markdown-файлов: одна запись — файл в items/ плюс строка ровно в одном индексе, у записи тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение из диалога с фильтром и дедупом, разбор находок ревью в задачи, декомпозиция на независимо полезные части, гигиена полей, согласованность индексов скриптом tasks.py. Спринт под одну цель с заморозкой набора и ритуал между спринтами. Записи вычитывают два прохода: task-form (форма записи) и task-wording (язык). Канон документов ведёт плагин av-dev-docs, он опционален. Задач не выполняет — этим занимается пайплайн проекта.", + "description": "Задачи и цели каталогом markdown-файлов: одна запись — файл в items/ плюс строка ровно в одном индексе, у записи тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение из диалога с фильтром и дедупом, разбор находок ревью в задачи, декомпозиция на независимо полезные части, гигиена полей, согласованность индексов скриптом tasks.py. Приоритет — явный порядок строк в беклоге, и расставляет его скилл groom: интерактивный разбор на два вопроса, что сейчас самое важное и что перестало быть важным. Готовность записи к работе проверяет команда ready. Записи вычитывают два прохода: task-form (форма записи) и task-wording (язык). Канон документов ведёт плагин av-dev-docs, он опционален. Задач не выполняет — этим занимается пайплайн проекта.", "author": { "name": "Anton Vakhrushev", "email": "anwinged@gmail.com" diff --git a/av-dev-tasks/skills/groom/SKILL.md b/av-dev-tasks/skills/groom/SKILL.md new file mode 100644 index 0000000..e471159 --- /dev/null +++ b/av-dev-tasks/skills/groom/SKILL.md @@ -0,0 +1,246 @@ +--- +name: groom +description: "Груминг беклога — интерактивный разбор, отвечающий на два вопроса: что сейчас самое важное и что перестало быть важным. Ответ записывается порядком строк в беклоге: первая строка — то, что делают следующим. Разбирает накопившиеся вопросы, переоценивает задачи порциями по 5–8 (сделано попутно, отменено решением, слилось с соседней, подешевело, разрослось, стало сырьём), закрывает отжившее с причиной и расставляет очередь. Использовать, когда просят разобрать беклог, расставить приоритеты, решить «что делать дальше», провести груминг или переоценку, а также когда вернулись к проекту после перерыва и надо понять, где остановились. Формат и содержимое записей — скилл tasks; выполнение задачи — пайплайн проекта." +--- + +# Груминг: что важно, что перестало + +Скилл отвечает на **два вопроса**, и всё, что не служит им, — не его работа: + +1. **Что сейчас самое важное?** +2. **Что перестало быть важным?** + +Ответ на оба **записывается порядком строк в беклоге**: первая строка секции — +то, что делают следующим; то, что перестало быть важным, из беклога уходит с +причиной. Приоритет — свойство очереди, а не задачи, и живёт он в индексе +(правило 4 скилла `tasks`). Груминг — единственное место, где очередь +назначается человеком. + +**Скилл интерактивный.** Он не «приводит беклог в порядок» сам: суждение о +важности принадлежит человеку, и весь ход — это подготовленные развилки с +рекомендацией. Что решается фактом (сделано, отменено, дублируется), решается +без вопросов и показывается списком. + +Форматом и содержимым записей владеет скилл `tasks` — груминг зовёт его +операции, а не правит файлы руками. Выполнением задачи — пайплайн проекта. + +## Три правила, из которых всё следует + +1. **Порядок назначает человек, машина его не выводит.** Ни давность, ни тип, ни + число задач под целью приоритетом не являются. Единственное место в очереди, + назначенное не человеком, — конец секции у сырья, и оно из очереди изъято + (`tasks`, правило 4). +2. **Порция важнее охвата.** Тридцать задач за заход — это усталость и + штамповка: последние десять получат «оставить» не потому, что живы, а потому, + что разбор затянулся. Лучше две честные порции, чем один полный проход. +3. **Причина уезжает в запись.** Всё, что решено здесь, оставляет след: + `--reason` у закрытия и переноса, ответ в теле задачи, строка в докладе. + Решение, оставшееся в переписке, будет принято заново через месяц. + +## Когда груминг созрел + +**Зовёт человек.** Скилл сам себя не назначает, но обязан **напоминать**, и +признак наблюдаемый, а не календарный: + +- в беклоге появились записи, которых человек ещё не видел (заведены интейком по + ходу работы, урожаем ревью, разбором находок); +- на верхних строках очереди есть задача с открытым вопросом — очередь + показывает то, что взять нельзя; +- `tasks.py check` печатает «готово к взятию: 0 из N» — брать сегодня нечего. + +Порога в неделях нет намеренно: счётчик простоя пришлось бы вести руками, а +решает всё равно человек. Признак — **очередь перестала быть твоей**: взялся +перечитывать, почему эти задачи стоят в таком порядке, — пора. + +## Вопрос, блокер, необратимое + +| | Что это | Когда спрашиваем | Что останавливает | +| --- | --- | --- | --- | +| **Вопрос** | решение человека | на груминге, пачкой | взятие задачи в работу | +| **Блокер** | работа не может продолжаться ни одной задачей | немедленно | всё | + +Право на **необратимое** — третье и отдельное: что именно необратимо, называет +`CLAUDE.md` проекта, и спрашивается оно всегда, независимо от того, когда был +последний груминг. + +**Блокер определяется исходом, а не одновременностью.** Встали разом или +задачи выпадали по одной — если продолжать нечем, это блокер, и человек +спрашивается немедленно, а не ждёт ближайшего груминга. + +**Отличать вопрос от застревания.** Правило про остаток принадлежит управлению +задачами: оно решает, **сделана задача или вышла**, а это исход планирования, не +исполнения. **Ниже канонический текст; пайплайн проекта на него ссылается, а не +пересказывает** — два экземпляра одного правила разъезжаются, и разъезжаются +незаметно, потому что расхождение видно только на редком входе. + +> Есть остаток, который доводится без ответа, — задача продолжается, вопрос +> записывается в файл. Остатка нет — задача возвращается в беклог. + +С двумя оговорками, без которых тест ошибается: + +> **Остаток, который материализует нерешённое** — записывает в хранилище, +> журнал, витрину **или наружу** состояние, зависящее от неотвеченного вопроса, +> — **не остаток**. Решение поднимается до начала записи: откатить запись +> дороже, чем подождать ответ, а иногда невозможно. «Наружу» — часть правила, а +> не пример: выкладка, публикация и отправка данных третьей стороне не +> откатываются тем более. + +> **Пол для остатка:** остаток, из которого пропала польза, названная в «зачем», — +> это не сделанная задача, а вернувшаяся в беклог. + +## Ход груминга + +Четыре шага, и порядок — зависимость, а не список. + +```mermaid +flowchart TD + check["tasks.py check (+ --fix)
результат — строкой в доклад"] + s1["1. Осмотреться
что накопилось, чего человек ещё не видел"] + s2["2. Разобрать вопросы
пачкой, не больше трёх за раз"] + s3["3. Что перестало быть важным
порциями по 5–8"] + s4["4. Что важно сейчас
расставить порядок строк"] + + 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-docs`, и когда их звать — решает он. + +Но повод назвать это здесь есть: беклог и документы протухают от одного и того +же — от сделанной работы. Пришёл на груминг и видишь, что с прошлого раза сделан +десяток задач, — скажи строкой, что канон стоит сверить (`av-dev-docs:canon`), и +иди дальше. Плагина в проекте нет — сверять нечем, и это тоже строка. + +## Интерактив + +- Вопросы — через `AskUserQuestion`, **не больше трёх за раз**. Порция в 5–8 + задач обычно даёт больше трёх суждений: веди несколько итераций по ≤3, а не по + одному вопросу на задачу и не одним перегруженным запросом. +- К каждому варианту — **предварительное суждение, рекомендация первым + вариантом**: «предлагаю выкинуть, потому что …». Возразить дешевле, чем судить + с нуля. +- Всё, что решается фактом, решай сам и показывай списком в докладе. +- **Останавливайся на границе порции**, даже если «ещё чуть-чуть осталось». + Между порциями — промежуточный доклад. + +Примеры итераций, отбор порции, храповик на залежавшихся — +[references/portions.md](references/portions.md). + +## Стимулы, которые процесс создаёт + +Правило, которое можно обойти в свою пользу, будет обойдено. + +**Приёмщик и исполнитель совпадают, и это надо назвать вслух.** Задачу закрывает +тот же агент, который её и сделал. Груминг приёмкой не занимается — отдельного +ритуала у неё нет, — и настоящих опор остаётся две: + +- **независимый отчёт ревью** — артефакт, написанный не исполнителем; при + конвейере `av-dev-code` это отчёт триажа в + `openspec/changes/archive//review/` (до архивации — `changes//review/`); +- **`reopen <слаг> --reason`** — закрытие не окончательно. Заметил на груминге, + что закрытая задача сделана не тем, чем обещала, — возвращай, это штатная + операция, а не скандал. Индексы под git: `git log -p` по беклогу показывает, + что и когда закрыто, потому что закрытие коммитится отдельным коммитом учёта. + +Известные обходы: + +- **Не записать вопрос** на задаче, которую хочется поднять наверх очереди. + Защита: вопросы верхних строк разбираются вне очереди порции, шагом 2. +- **Оставить всё как есть.** Груминг, на котором ничего не сдвинулось и ничего + не закрылось, — это не «беклог в порядке», а не проведённый груминг. Защита: + задача из верхних строк, которую и этот заход оставляет без изменений, **либо + двигается, либо получает записанную причину**, почему её держат. +- **Расставить порядок молча**, без доводов: тогда через месяц он неотличим от + случайного. Защита: причина у каждого движения и строка доклада. +- **Разобрать много и мелко** вместо немногого и важного: тридцать полей гигиены + вместо трёх решений о важности. Защита: гигиена — работа скилла `tasks` и + побочный продукт здесь; доклад называет **решения**, а не правки. + +## Слоты проекта + +Груминг не знает ни языка, ни сборки, ни CI. Проект дописывает в `CLAUDE.md`: + +1. **Что считается сломанным** — какая красная проверка обгоняет развитие. + Не названо — спрашиваем человека, а не решаем сами. +2. **Необратимое** — что спрашивается всегда (тот же слот, что у скилла `tasks`; + дом один). +3. **Ориентир по размеру порции**, если он замерялся. Умолчание — 5–8 задач, и + это **ориентир, а не закон**. + +Числа проекта (сколько задач приходит за месяц, каков прирост беклога) — предмет +наблюдения человека, а не константы этого скилла. + +## Доклад + +- Что просмотрено: N из M, сколько порций, по какому признаку отобраны. +- Вопросы: разобрано N, из них отвечено без человека N, снято тегов N. +- **Что перестало быть важным**: удалено как реализованное (со ссылками), ушло + без реализации (с причинами), понижено до сырья, слито, сменило тип или цель. +- **Что важно сейчас**: верх очереди по каждой секции — слаги в порядке, и по + каждому движению довод одной строкой. +- **Границы покрытия**: сколько задач не трогали и какие именно секции, теги или + цели остались — иначе доклад читается как «беклог разобран». +- `tasks.py check` после правок — результат строкой. + +## Чего этот скилл не делает + +Не пишет код и не выполняет задачи. Не заводит и не переоформляет записи сам по +себе — формат и содержимое ведёт `tasks` (груминг зовёт его операции). Не решает +за человека, что важно: он готовит развилки и рекомендует. Не принимает +закрытые задачи отдельным ритуалом — `reopen` есть, момента у него нет. Не судит +документы проекта — это плагин `av-dev-docs`. diff --git a/av-dev-tasks/skills/groom/references/portions.md b/av-dev-tasks/skills/groom/references/portions.md new file mode 100644 index 0000000..a8b3401 --- /dev/null +++ b/av-dev-tasks/skills/groom/references/portions.md @@ -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 --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 --implemented` только имея **конкретный коммит или строку + документа**, закрывающие задачу, и ссылка идёт в доклад. Есть лишь косвенные + признаки — не удаляй сам, вынеси в пачку вопросов. Сделана частично → задача + сжимается до остатка: тело правишь редактором, заголовок и «зачем» — через + `edit`. +2. **Проверь, не отменена ли решением.** Документ, ADR или архивное изменение + мог закрыть вопрос иначе — тогда `close --reason "<ссылка на + решение>"`. Задача закрывается не только коммитом. +3. **Проверь пересечения.** Две задачи об одном — содержимое в одну, вторую + `close --reason "слита с <другой-слаг>"`. Смотри **шире порции**: + интейк дедуплицирует новое против существующего, но никогда не пересматривает + уже лежащее, и две задачи с одной причиной могут лежать рядом месяцами. +4. **Пере-кластеризуй по общей причине.** Несколько задач, оказавшихся симптомами + одного дефекта, сливаются в одну — это находка, которую интейк дать не мог. +5. **Гигиена полей** — протухшее «зачем», вопрос в прозе, снятый ответ, свойство + репозитория в рамках, предписание процесса в теле, тип, разошедшийся с + задачей, границы вместо реализации в разделе «Затрагивает». Список и правила — + в скилле `tasks`. **Груминг — то самое место, где беклог добирает тип и + разделы его схемы:** требовать их на входе значило бы выгонять в заметки то, + что должно лежать задачей, а к взятию в работу они уже обязательны (`ready`). + Блок здоровья `check` печатает, сколько записей готово к взятию, — по этому + числу и видно, добрал ли груминг. + + Гигиена — **побочный продукт, а не предмет**. Тридцать полей вместо трёх + решений о важности означают, что груминг не состоялся. + +Затем — то, что решает человек: + +6. **Жива ли она вообще.** Контекст мог измениться: ушла зависимость, отпал + сценарий, обошли иначе. Здесь и звучит вопрос, выкидывать ли. +7. **Та ли цель — и нужна ли она вообще.** `feature`, которой не находится цель, + — кандидат на выход: новая возможность вне цели это возможность, которой никто + не заказывал. Операционной задаче (`fix`, `chore`, `research`) цель не нужна, + и выдумывать её здесь не надо. + + **Отменяется и сама цель** — когда замысел оказался неверен, а не когда + задача выбрала не ту. Тогда порция расширяется до всех задач этой цели: каждую + либо закрыть своей причиной, либо перевесить на другую цель, и только потом + закрыть цель. Порядок и почему он такой — + [task-goal.md](../../tasks/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель). +8. **Задача ли это по-прежнему.** Не проходит `ready` по существу, а не по + недописанным разделам → `edit --type research` и опустошённый раздел + «Вопрос», то есть сырьё; дальше штурм. Разрослась → это несколько задач под + той же целью, дальше декомпозиция. +9. **Не подешевела ли она.** Сделанная с прошлого раза работа меняет цену + **других** задач: рядом с только что тронутым кодом та же работа стоит меньше. + Это довод и на шаге 4 — задача, внезапно подешевевшая, поднимается в очереди + не потому, что стала важнее, а потому, что окно открыто. + +### Храповик на залежавшихся + +Сильно залежавшаяся задача — сигнал сама по себе: её либо ни разу не собирались +делать, либо нечем взять. Измеряй наблюдаемым — датой последней правки из git +(`list --stale` ставит такие первыми); счётчик «сколько грумингов пережила» +нигде не хранится. + +Задача из верхних строк `--stale`, которую и этот заход оставляет без изменений, +**либо двигается (меняет цель, поднимается в очереди, уходит с причиной), либо +остаётся с явно записанной причиной**, почему её держим (`move --section +<та же> --reason …`). Молчаливое «оставить как есть» на давно неподвижной задаче +— это решение не принимать решение; запись причины превращает его в осознанное и +не даёт тому же вопросу всплыть на следующем груминге. + +## Шаг 4. Что важно сейчас — расстановка + +Разбирается **верх очереди**, а не весь беклог: первые три-пять строк каждой +секции. Ниже пятой строки порядок всё равно перестаёт что-либо значить. + +1. **Покажи текущий верх** — `list --index backlog`, по секциям, в том порядке, + в каком строки лежат. Плюс состояние проекта из роадмапа: секция `Готово` + отвечает на «где мы», `Запланировано` — на «куда шли». +2. **Спрашивай сравнением, а не оценкой.** «Что из этих двух делают раньше» + имеет проверяемый ответ, «насколько важна эта задача» — нет. Веди попарно и + сверху: что первое, что после него. +3. **Двигай командой, с причиной** — `move --after <другой> --reason …` + или `move --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`. + +## Что делать, если разбирать нечего + +Беклог пуст или в нём три задачи и все живые — груминг кончается за минуту, и +это законный исход. Скажи строкой: очередь такая-то, сдвигать нечего. Придумывать +работу, чтобы груминг «состоялся», — ровно тот ритуал без выгоды, от которого +процесс избавлялся. diff --git a/av-dev-tasks/skills/session/SKILL.md b/av-dev-tasks/skills/session/SKILL.md deleted file mode 100644 index 93a685f..0000000 --- a/av-dev-tasks/skills/session/SKILL.md +++ /dev/null @@ -1,304 +0,0 @@ ---- -name: session -description: "Ритуал между спринтами и ведение самого спринта: разбор накопившихся вопросов, разбор прошедшего спринта про процесс, переоценка задач порциями, выбор цели (или решение, что спринт без цели) и набор нового спринта с заморозкой. Плюс правила по ходу спринта — что врывается в замороженный набор, чем вопрос отличается от блокера, когда задача выходит из спринта, что считается сделанным и что идёт в доклад. Использовать, когда просят закрыть или начать спринт, собрать набор, разобрать вопросы, провести груминг/переоценку/ретроспективу, решить «что делать дальше» или доложить итоги, а также когда вернулись к проекту после перерыва и надо понять, где остановились. Формат и содержимое задач — скилл tasks." ---- - -# Сессия между спринтами - -Работа идёт спринтами: **набор задач, замороженный до конца спринта** — обычно -под одну цель, но бывает и без неё. Между спринтами — одна сессия из четырёх шагов. Этот скилл владеет -**ритуалом**: как сессия проводится и как спринт ведётся. Форматом и содержимым -задач владеет скилл `tasks`, выполнением задачи — пайплайн проекта. - -## Почему не Scrum - -Терминология близка — спринт, груминг, определение готовности, ретроспектива, — -и это удобно: не нужно изобретать слова. Но добрая половина Scrum существует -ради синхронизации людей, которых здесь нет. - -**Не берём:** тайм-бокс (спринт ограничен объёмом, а не временем), velocity и -оценки в очках, ежедневный стендап (стендап — это и есть диалог), планирование -отдельно от груминга (владелец беклога один), роль скрам-мастера. - -**Берём:** цель спринта, заморозку набора, определение готовности, груминг — -каждое потому, что снимает решение, которое иначе принимается заново каждый раз. -**Ретроспективу берём содержанием, но не отдельным ритуалом:** она шаг той же -сессии. Процесс личный, синхронизировать некого, а отдельная встреча ради трёх -вопросов — та самая плата ритуалом без выгоды. - -## Роли - -**Человек** выбирает цель спринта — **или решает, что этот спринт без цели**, — -разбирает вопросы, держит право на необратимое и на истину в самих данных. - -**Агент — оркестрация.** Он собирает набор под названную цель, ставит задачи, -принимает отчёты и докладывает. Кто именно делает задачу — исполнитель, сабагент, -пайплайн — дело проекта; сессия про это не знает и знать не должна. - -## Единицы - -- **Цель** — то, ради чего набирается спринт. Файл типа `goal` (🎯), - перечисленный в `ROADMAP.md`. Цель постоянна: живёт, пока живёт направление, — - и уходит вместе с ним, если замысел оказался неверен (порядок отмены — в - [tasks](../tasks/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель)). -- **Задача** — то, что мерджится целиком и даёт видимую пользу. -- **Вопрос** — решение человека. Не останавливает начатую работу, но **блокирует - взятие** задачи в спринт. Живёт внутри файла задачи разделом «Вопросы» и тегом - `question`. -- **Блокер** — состояние, когда спринт не может продолжаться **ни одной** - задачей. -- **Спринт** — набор задач, замороженный до его конца. Под одной целью — или - **без цели вовсе**, законно: багфикс, техдолг, спринт здоровья. Такой набор - собран по работоспособности, а не по направлению, и заводится явно - (`sprint start --no-goal`). - -## Вопрос, блокер, необратимое - -| | Что это | Когда спрашиваем | Что останавливает | -| --- | --- | --- | --- | -| **Вопрос** | решение человека | на сессии, пачкой | взятие задачи в спринт | -| **Блокер** | спринт не может продолжаться ни одной задачей | немедленно | всё | - -Право на **необратимое** — третье и отдельное: что именно необратимо, называет -`CLAUDE.md` проекта, и спрашивается оно всегда, независимо от спринта. - -**Блокер определяется исходом, а не одновременностью.** Встали разом или -высыпались из спринта по одной — если продолжать нечем, это блокер: спринт -распускается (`sprint close --dissolve --reason …`), человек спрашивается -немедленно. Иначе спринт, из которого задачи вышли поштучно, выглядел бы штатно -завершённым, а вопросы тихо ждали бы сессии. - -**Отличать вопрос от застревания.** Правило про остаток принадлежит управлению -задачами: оно решает, **сделана задача или вышла**, а это исход планирования, не -исполнения. **Ниже канонический текст; пайплайн проекта на него ссылается, а не -пересказывает** — два экземпляра одного правила разъезжаются, и разъезжаются -незаметно, потому что расхождение видно только на редком входе. - -> Есть остаток, который доводится без ответа, — задача продолжается, вопрос -> записывается в файл. Остатка нет — задача выходит из спринта. - -С двумя оговорками, без которых тест ошибается: - -> **Остаток, который материализует нерешённое** — записывает в хранилище, -> журнал, витрину **или наружу** состояние, зависящее от неотвеченного вопроса, -> — **не остаток**. Решение поднимается до начала записи: откатить запись -> дороже, чем подождать ответ, а иногда невозможно. «Наружу» — часть правила, а -> не пример: выкладка, публикация и отправка данных третьей стороне не -> откатываются тем более. - -> **Пол для остатка:** остаток, из которого пропала польза, названная в «зачем», — -> это не сделанная задача, а вышедшая из спринта. - -## Заморозка набора - -**Целей не больше одной.** Названа цель — набор служит ей: задача под чужой -целью в спринт не попадает, даже если взять удобно (`sprint take` это и -запрещает). **Задача с открытым вопросом в набор не берётся** — это верно всегда. - -**Спринт без цели — законный случай, а не недосмотр.** Багфикс, техдолг, -здоровье: работа на работоспособность, а не на направление. Цель не названа — -сверять нечего, и в такой набор идёт что угодно готовое к взятию, в том числе -задачи под разными целями. Заводится он **явно**, `sprint start --no-goal`: -забытый флаг и решение человека иначе неотличимы, а это решение продуктовое. -Взамен проверки цели остаётся доклад — спринт без цели **называется таковым и -объясняется** одной строкой. - -**Новая работа падает в беклог, а не в идущий спринт.** Решение «врываться или -отложить» принимается один раз правилом, а не заново каждый раз. Врывается -только два класса: - -1. **Необратимый ущерб** — потеря, порча или утечка данных: то, что не чинится - доделкой потом. -2. **Сломан общий станок** — красная проверка, на которой стоит определение - готовности **всех** задач набора. Это не новая работа, а починка того, на чём - делается вся остальная. - -Что в проекте считается необратимым ущербом и что — общим станком, называет -`CLAUDE.md` проекта. Не названо — спрашиваем человека, а не решаем сами. - -**Конец спринта** — когда каждая задача набора либо сделана, либо вышла с -записанной причиной. Не «все сделаны»: иначе одна застрявшая задача держит -спринт бесконечно. Пустой набор закрывается `sprint close` — скрипт не даст -закрыть непустой. - -Ведение спринта целиком — исходы задачи, определение готовности, приёмка, -доклад — [references/sprint.md](references/sprint.md). - -## Сессия: четыре шага в этом порядке - -Это зависимость, а не список. - -1. **Разбор вопросов.** -2. **Разбор прошедшего спринта — про процесс, а не про задачи.** Здесь же оба - судьи документов канона на весь канон разом, раз в спринт: `doc-consistency` - (документы между собой) и `doc-code-drift` (документы против кода). -3. **Переоценка задач** порциями. -4. **Выбор цели и набор спринта.** Цель называет человек — либо называет, что - этот спринт без цели; набор собирает агент и показывает **до старта работ**. - -Рёбра подписаны тем, что ломается при их нарушении: - -```mermaid -flowchart TD - check["tasks.py check (+ --fix)
результат — строкой в доклад"] - s1["1. Разбор вопросов
пачкой, не больше трёх за раз"] - s2["2. Разбор прошедшего спринта
про процесс → docs/review.md"] - s3["3. Переоценка задач порциями"] - s4["4. Цель называет человек,
набор собирает агент"] - sprint["спринт: набор заморожен"] - - check --> s1 - s1 --> s2 - s2 --> s3 - s1 -->|"неотвеченный вопрос → переоценка вслепую"| s3 - s3 -->|"без переоценки набор берётся из протухшего"| s4 - s4 --> sprint -``` - -Схема — **сводка**: процедура каждого шага в -[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). - -## Инструмент - -Тот же `tasks.py`, что у скилла `tasks` — оба скилла в одном плагине, путь -общий: `tk="$CLAUDE_PLUGIN_ROOT/skills/tasks/scripts/tasks.py"`. Сессии нужны -прежде всего: - -``` -python3 $tk check --dir D # с этого начинается любая сессия -python3 $tk list --dir D --questions # шаг 1: что накопилось -python3 $tk list --dir D --tag sprint:<слаг> # шаг 3: урожай спринта, первая порция -python3 $tk list --dir D --stale # шаг 3: дальше по залежалости -python3 $tk list --dir D --goal <слаг> # шаг 4: кандидаты под названную цель -python3 $tk sprint start --dir D --goal <слаг> # шаг 4: заводит и слаг спринта -python3 $tk sprint start --dir D --no-goal # шаг 4: набор без цели, явным флагом -python3 $tk sprint take --dir D <слаг> … # шаг 4: набор -python3 $tk sprint close --dir D # конец спринта; --dissolve при блокере -python3 $tk reopen <слаг> --dir D --reason … # приёмка не сошлась после закрытия -``` - -`D` — каталог задач проекта, всегда `tasks/` в корне; `--dir` передаётся -явно каждой командой. Вызов из чужого контекста описан в скилле `tasks` -(«Переносимость»). **Коды выхода** — там же: 1 это дрейф в беклоге, 3 это -«каталога нет», и ветвиться на них надо по-разному. - -**Слаг спринта заводит `sprint start`** (по умолчанию — дата) и пишет его в -`SPRINT.md`; всё заведённое **при открытом спринте** помечается `sprint:<слаг>` -автоматически. Поэтому «первая порция — урожай прошедшего спринта» работает без -чьей-либо памяти — но ровно до команды `sprint close`, которая `SPRINT.md` -очищает. Отсюда порядок: **урожай заводится до закрытия, слаг для сессии берётся -из отчёта `sprint close`** ([references/sprint.md](references/sprint.md)). - -Правки задач делаются мутациями (`edit`, `move`, `close`), а не редактором: -руками правится только тело файла. Это правило скилла `tasks`, здесь оно не -пересказывается. - -## Стимулы, которые процесс создаёт - -Правило, которое можно обойти в свою пользу, будет обойдено. - -**Приёмщик и исполнитель здесь совпадают, и это надо назвать вслух.** Задачу -закрывает и двигает по индексам агент-оркестратор — тот же, кто её и сделал. -Прежде границу держала механика: моста между плагинами не было, и закрыть задачу -пайплайн физически не мог. Теперь мост есть, и защита у трёх обходов ниже — -**только текстовая**. Опоры, которые остались настоящими: - -- **независимый отчёт ревью** — артефакт, написанный не исполнителем; по нему - сверяют состав прогона и урожай. Где он лежит, знает пайплайн проекта; при - конвейере `av-dev-code` это отчёт триажа в - `openspec/changes/archive//review/` (до архивации — `changes//review/`); -- **`SPRINT.md` под git** — `git log -p` показывает, что и когда было закрыто. - Работает, только если закрытие **закоммичено**: удаление файла задачи и правка - индекса, оставшиеся в рабочем дереве, никакой истории не образуют; -- **`reopen <слаг> --reason`** — закрытие не окончательно. Приёмка человеком на - сессии его отменяет, и это штатная операция, а не скандал. - -Известные обходы: - -- **Скрыть блокер** — он останавливает всё и выглядит как провал исполнителя. - Защита: тест про остаток плюс прямая запись, что **объявление блокера - неудачей не считается**. -- **Не записать вопрос** на задаче-кандидате, чтобы не вычеркнуть её из - ближайшего набора. Защита: вопросы кандидатов разбираются на той же сессии - **вне очереди порции**. -- **Занизить критерии приёмки**, раз они пол. Защита ослаблена: правит их тот же, - кто по ним отчитывается. Остаётся требование, что расхождение критериев с - сутью — **дефект критериев, о котором сообщают, а не молча дорабатывают**, и - переоценка на сессии, где критерии видит человек. -- **Сжать задачу до остатка** и отчитаться «сделана». Защита ослаблена там же. - Пол для остатка — польза, названная в «зачем»; проверяет его человек при приёмке, - и `reopen` — его инструмент. -- **Объявить спринт без цели**, чтобы не задавать человеку продуктовый вопрос: - набор без цели берёт что угодно, и собрать его можно молча. Защита: цели нет - — это **ответ человека, а не умолчание** (`--no-goal` спрашивается так же, как - цель), плюс строка доклада, называющая спринт бесцельным и объясняющая почему. - Два бесцельных спринта подряд — предмет разбора процесса, а не мелочь. -- **Занизить урожай** — не заводить найденное по ходу. Защита: поимённая сверка - с **сохранённым независимым отчётом**, а не с прозой исполнителя. Каждая - отложенная находка имеет либо слаг, либо строку «не заведена: причина». - Нулевой урожай при непустом отчёте виден сразу. - -**Проект без конвейера ревью — независимого отчёта нет, и это надо сказать, а не -обойти молча.** Задачи делались руками или чужим пайплайном, сверять урожай не с -чем: остаётся проза исполнителя, то есть тот же взгляд, что и у автора. Тогда -защита от занижения урожая **снята**, и доклад спринта обязан нести строку «урожай -сверялся с отчётом исполнителя — независимого отчёта в проекте нет». Дальше это -решение человека: завести конвейер, принимать выборочной перепроверкой или -согласиться с ценой. Молчание здесь хуже любого из трёх исходов. - -Стимулы внутри пайплайна задачи (занизить требования к проверке, пропустить -проход) принадлежат ему и защищены там же. - -## Слоты проекта - -Сессия не знает ни языка, ни сборки, ни CI. На часть проектного отвечает своей -структурой канон документов (его ведёт плагин `av-dev-docs`): разбор процесса -(шаг 2) живёт в `docs/review.md`, оракулы и «чем краснеет безусловно» — в -семантике гейта в `CLAUDE.md`. Пути известны, ссылки в чужое дерево нет: канон -ставится отдельно, а без него оба файла всё равно читаются по имени. Остальное проект **дописывает в `CLAUDE.md`**: - -1. **Пайплайн задачи** — чем задача выполняется и что входит в его определение - готовности. Сессия требует только форму: пайплайн пройден + критерии приёмки - проверены поимённо. -2. **Общий станок** — какая проверка, покраснев, врывается в замороженный - спринт. -3. **Необратимое** — что спрашивается у человека всегда (тот же слот, что у - скилла `tasks`; дом один). -4. **Ориентир по размеру спринта**, если он замерялся. Умолчание — 5–8 задач, и - это **ориентир, а не закон**. - -Слота «куда копируются критерии приёмки» здесь нет намеренно: на него отвечает -**пайплайн проекта** — он переносит критерии в описание изменения, когда его -заводит. Проект без пайплайна называет своё место сам, в слоте 1. - -Числа проекта (сколько задач в спринте, сколько времени на задачу, каков прирост -беклога) — предмет шага 2, а не константы этого скилла. - -## Чего этот скилл не делает - -Не пишет код и не выполняет задачи. Не заводит и не переоформляет задачи сам по -себе — формат и содержимое ведёт `tasks` (сессия зовёт его операции). Не решает -за человека, какая цель следующая. Не двигает набор идущего спринта. diff --git a/av-dev-tasks/skills/session/references/cadence.md b/av-dev-tasks/skills/session/references/cadence.md deleted file mode 100644 index cf76cb4..0000000 --- a/av-dev-tasks/skills/session/references/cadence.md +++ /dev/null @@ -1,277 +0,0 @@ -# Сессия: четыре шага - -Одна сессия между спринтами. Порядок шагов — **зависимость, а не список**: -переоценивать задачи, не разобрав вопросы, значит переоценивать вслепую; набирать -спринт, не переоценив, значит набирать из протухшего. - -Начинается сессия с `tasks.py check` (и `check --fix`, если дрейф накопился) — -результат идёт строкой в доклад. - -## Шаг 1. Разбор вопросов - -`tasks.py list --questions` — всё, что накопилось. Вопрос это решение человека, -и разбирается он **пачкой**, а не по одному, как только возник: по одному — -это дёрганье, пачкой — это сессия. - -Порядок по каждому вопросу: - -1. **Проверь, не отвечен ли он уже** — решением, документом, соседним - изменением, самим ходом прошедшего спринта. Отвеченный вопрос не выносится - человеку: это самая частая находка и она не требует ничьего решения. -2. **Сформулируй развилку** с вариантами и последствием каждого, рекомендация — - первым вариантом. -3. **Вынеси пачкой** через `AskUserQuestion`, не больше трёх за раз. -4. **Запиши ответ в тело задачи, опустоши раздел «Вопросы»**, сними тег - (`edit --rm-tag question`), **перепиши «зачем»**: «Решено: - …» на вопрос «почему это лежит в беклоге» уже не отвечает. Опустошение - раздела — не уборка, а условие взятия: правило и причина в скилле `tasks`, - [references/task-format.md](../../tasks/references/task-format.md). - -**Вопросы на задачах-кандидатах разбираются вне очереди порции** — здесь же, на -этой сессии, даже если сама задача в порцию переоценки не попала. Иначе правило -«задача с открытым вопросом в набор не берётся» создаёт стимул вопрос не -записывать, лишь бы не вычеркнуть задачу из ближайшего спринта. - -## Шаг 2. Разбор прошедшего спринта — про процесс, а не про задачи - -Не «что мы сделали» (это доклад спринта, он уже был), а: - -- **что сломалось в процессе и почему не поймали** — промах, доехавший до конца; -- **что оказалось дороже, чем выглядело при заведении** — не число, а сам факт и - причина: чего не было видно в постановке; -- **какие правила не сработали или сработали не так** — в том числе правила - этого плагина. - -Замеров процесс не ведёт намеренно: оценки в очках и velocity не взяты -(«[Почему не Scrum](../SKILL.md#почему-не-scrum)»), а спринт ограничен объёмом, а -не временем — сравнивать «сколько заняло» не с чем. Разбор здесь качественный, и -это не упущение. - -**Артефакт обязателен.** Вывод, оставшийся в контексте сессии, не существует: -следующая сессия его не увидит. Дом у него один и известен из канона — -**`docs/review.md`**: вывод про конвейер и про то, что перестали проверять, идёт -в раздел настройки, вывод про воспроизведённый дефект — в журнал. Решение с -долгим следом — в `docs/adr/`. - -Отдельным ритуалом ретроспектива не выделяется: процесс личный, -синхронизировать некого. - -**Здесь же зовутся оба судьи документов** — на весь канон разом, а не на пачку, -отобранную работой: - -- **`doc-consistency`** — согласованность документов между собой и с openspec: - факт в двух домах, прямое противоречие, поведение в `architecture.md` вместо - спек, ADR без парного статуса при замене, число без провенанса; -- **`doc-code-drift`** — сверка с кодом по закрытому перечню фактов: имя основной - ветки, команды, пути, внешние зависимости поимённо, настройки с числовым - значением, единые точки проекта, capability. - -Раз в спринт, а не чаще. Дорог из них по-настоящему первый — `doc-consistency` -на `opus`: он сличает утверждения двух документов, и это суждение. Второй с -недавних пор на `sonnet` — у него закрытый перечень фактов и команда на каждый, — -но он читает репозиторий целиком, и дешёвым от смены модели не стал. Но и не -реже — **спринт это ровно то, что двигает код и документы**: -переименованная цель сборки, ушедшая зависимость, второй способ делать то, что -обзор объявил единственным; факт, дописанный в `architecture.md`, уже живущий в -`CLAUDE.md`. Протухшее и раздвоившееся неотличимо от свежего, и по нему принимают -решения, пока кто-нибудь не наткнётся. - -**Пачка — весь канон, и это не расточительство, а охват.** Когда пачку отбирала -работа, без присмотра оставалось ровно то, чего работа не касалась: правка, -отменившая решение, живёт в одном документе, а парный статус нужен в другом. -Канон мал, раз в спринт он читается целиком. - -Находки обоих — обычный материал переоценки: строка на замену идёт в документ -сразу, работа больше чем на абзац становится задачей типа `chore`. **Позвал — -скажи в докладе, кого именно позвал, и приложи границы покрытия**; не позвал — -скажи и это, иначе доклад читается как «сверено». - -## Шаг 3. Переоценка задач - -Цель — выкинуть то, что перестало быть задачей, и вернуть остальному честное -состояние. Не «пересмотреть всё», а «пересмотреть порцию до конца». - -### Порция и правило остановки - -Тридцать задач за один заход — это усталость и штамповка: последние десять -получат «оставить» не потому, что живы, а потому, что сессия затянулась. - -- **5–8 задач за порцию.** Размер обоснован усталостью, а не пропускной - способностью, и менять его не надо — **надо брать несколько порций за - сессию**. -- **Сколько порций:** не меньше `⌈урожай прошедшего спринта / 8⌉`. Урожай — это - задачи, заведённые за спринт; при урожае в 15 это две-три порции. -- **Отбор порций по порядку:** - 1. **урожай спринта** — `list --tag sprint:<слаг>`: свежезаведённое ещё не - проходило ни одной проверки на нужность. Тег на задачах проставлен - автоматически при заведении — руками не метят и не вспоминают. **Слаг - берётся из отчёта `sprint close`, а не из `SPRINT.md`:** сессия идёт после - закрытия, а закрытие этот файл очищает; - 2. дальше **по залежалости** — `list --stale`; - 3. по потребности — одна секция целиком, один тег (партия ревью), одна цель - (`--goal`), список от пользователя. -- **Останавливайся на границе порции**, даже если «ещё чуть-чуть осталось». - Между порциями — промежуточный доклад. - -### Что делать с каждой задачей - -Сперва то, что не требует ничьего решения: - -1. **Проверь, не сделано ли уже.** Задача, реализованная попутно в соседнем - изменении, — самая частая находка. Смотри код, документацию, историю коммитов - по ключевым словам. Удаление «как реализованной» деструктивно и без следа - (в `REJECTED.md` реализованные не пишутся), поэтому порог улики жёсткий: - `close --implemented` только имея **конкретный коммит или строку - документа**, закрывающие задачу, и ссылка идёт в доклад. Есть лишь косвенные - признаки — не удаляй сам, вынеси в пачку вопросов. Сделана частично → задача - сжимается до остатка: тело правишь редактором, заголовок и «зачем» — через - `edit`. -2. **Проверь, не отменена ли решением.** Документ, ADR или архивное изменение - мог закрыть вопрос иначе — тогда `close --reason "<ссылка на - решение>"`. Задача закрывается не только коммитом. -3. **Проверь пересечения.** Две задачи об одном — содержимое в одну, вторую - `close --reason "слита с <другой-слаг>"`. Смотри **шире порции**: - интейк дедуплицирует новое против существующего, но никогда не - пересматривает уже лежащее, и две задачи с одной причиной могут лежать рядом - месяцами. -4. **Пере-кластеризуй по общей причине.** Несколько задач, оказавшихся симптомами - одного дефекта, сливаются в одну — это находка, которую интейк дать не мог. -5. **Гигиена полей** — протухшее «зачем», вопрос в прозе, снятый ответ, свойство - репозитория в рамках, предписание процесса в теле, тип, разошедшийся с - задачей, границы вместо реализации в разделе «Затрагивает». Список и правила — - в скилле `tasks`. **Переоценка — то самое место, где беклог добирает тип и - разделы его схемы:** требовать их на входе значило бы выгонять в заметки то, - что должно лежать задачей, а к взятию в спринт они уже обязательны. Блок - здоровья `check` печатает, сколько записей готово к взятию, — по этому числу - и видно, добрала переоценка или нет. - -Затем — то, что решает пользователь: - -6. **Жива ли она вообще.** Контекст мог измениться: ушла зависимость, отпал - сценарий, обошли иначе. Здесь и звучит вопрос, выкидывать ли. -7. **Та ли цель — и нужна ли она вообще.** Приоритетов нет, и «повысить» нечего - — вместо повышения задача **меняет цель** (`edit --goal <другой>`) или - входит в ближайший набор. `feature`, которой не находится цель, — кандидат - на выход: новая возможность вне цели это возможность, которой никто не - заказывал. Операционной задаче (`fix`, `chore`, `research`) цель не нужна, и - выдумывать её здесь не надо. - - **Отменяется и сама цель** — когда замысел оказался неверен, а не когда - задача выбрала не ту. Тогда порция расширяется до всех задач этой цели: каждую - либо закрыть своей причиной, либо перевесить на другую цель, и только потом - закрыть цель. Порядок и почему он такой — - [task-goal.md](../../tasks/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель). - Здесь этому и место: отмена цели это разбор её задач, а разбор задач — этот - шаг. -8. **Задача ли это по-прежнему.** Не проходит тест «готова к взятию» → `edit - --type research` и опустошённый раздел «Вопрос», то есть сырьё; дальше - штурм. Разрослась → это несколько задач под той же целью, дальше - декомпозиция. -9. **Переоценка по пройденному.** Прошедший спринт показывает, чего на самом - деле стоит такая работа. Это меняет цену **других** задач, и именно здесь - применяется: задача, оказавшаяся заметно дороже, чем думалось, при прежней - пользе — кандидат на выход. Судит человек по тому, что помнит о прошедшем - спринте; замеров процесс не ведёт и оценок не хранит. - -### Храповик на залежавшихся - -Сильно залежавшаяся задача — сигнал сама по себе: её либо ни разу не собирались -делать, либо нечем взять. Измеряй наблюдаемым — датой последней правки из git -(`list --stale` ставит такие первыми); счётчик «сколько сессий пережила» нигде -не хранится. - -Задача из верхних строк `--stale`, которую и этот заход оставляет без изменений, -**либо двигается (меняет цель, идёт в набор, уходит с причиной), либо остаётся с -явно записанной причиной**, почему её держим (`move --section <та же> ---reason …`). Молчаливое «оставить как есть» на давно неподвижной задаче — это -решение не принимать решение; запись причины превращает его в осознанное и не -даёт тому же вопросу всплыть на следующей сессии. - -### Интерактив - -- Вопросы — через `AskUserQuestion`, **не больше трёх за раз**. Порция в 5–8 - задач обычно даёт больше трёх суждений — тогда веди несколько итераций по ≤3, - а не по одному на задачу и не одним перегруженным запросом. -- К каждому варианту — **предварительное суждение, рекомендация первым - вариантом**: «предлагаю выкинуть, потому что …». Пользователю дешевле - возразить, чем судить с нуля. -- Всё, что решается фактом (сделано / отменено / дублируется), решай сам и - показывай списком в докладе, а не выноси в вопросы. - -Пример одной итерации — три залежавшихся задачи, механику по ним уже разобрали: - -> **Переоценка: 3 залежавшихся (порция по `--stale`)** -> -> 1. `versii-kachestvo-repaki` — версии и качество одного тайтла -> - Выкинуть *(рекомендую)* — помечена «не боль», за полгода ни разу не возникла -> - Оставить под целью `nadyozhnost-razdach` -> - Перевести под цель `kachestvo-mediateki` — там она первая в очереди -> 2. `backup-sqlite` — бэкап базы -> - Оставить под текущей целью *(рекомендую)* — не сработала, но риск реальный -> - Взять в ближайший набор — без бэкапа ретеншн опасен -> - Выкинуть -> 3. `guessit-sputnik` — вынести распознавание в сервис-спутник -> - Понизить до сырья (`--type research`) *(рекомендую)* — не проходит тест «готова к взятию» -> - Оставить задачей - -Каждый вариант несёт причину — ту самую, что уедет в `--reason`. Ответы применяй -сразу и, если в порции осталось ещё, следующей итерацией показывай следующие ≤3. - -## Шаг 4. Выбор цели и набор спринта - -1. **Покажи состояние проекта**: секцию `Готово` (что приложение уже умеет — - это половина ответа на «где мы»), затем `Запланировано` с обоснованием - очереди, `Направления`, и - по каждой цели-кандидату — сколько под ней задач без открытых вопросов - (`list --goal <слаг>`). Цель без готовых задач набором не станет: её сперва - надо декомпозировать. -2. **Цель называет человек** — либо называет, что цели не будет. Это - продуктовое решение, а не механика: агент предлагает и объясняет, но не - выбирает. **Оба ответа законны**, и «без цели» — такой же ответ, как слаг: - спринт бывает под багфикс, под техдолг, под здоровье проекта. Спрашивается он - так же, как цель, и в отдельный вопрос не выносится: это один и тот же вопрос - «подо что набираем». -3. **Набор собирает агент** — `sprint start --goal <слаг>` (или `sprint start - --no-goal`), затем `sprint take …`. Скрипт не даст взять цель, задачу с чужой - целью, с открытым вопросом, без типа и **без разделов, которых требует её - тип** (у `fix` это в том числе `Воспроизведение`, у `research` — `Вопрос` и - `Куда ляжет ответ`, и сырьё поэтому не берётся вовсе). Задача без цели (`fix`, - `chore`, `research`) берётся свободно — операционная работа входит в набор - помимо его цели. **В спринте без цели чужой цели нет вовсе**: сверять не с - чем, берётся что угодно готовое, и единственной защитой остаётся показ набора - человеку. -4. **Набор показывается человеку до старта работ.** Показ — это и есть момент - заморозки: после него набор не двигается. **В показе называется состав по - типам** — три `fix` и ни одной `feature` под целью развития это разговор про - цель, а не про набор, и увидеть его надо до заморозки, а не в докладе по - итогам. **У набора без цели показ — единственная проверка состава**: скрипту - там отказывать не по чему, и «что угодно готовое» превращается в осмысленный - набор только глазами человека. - - Здесь же последний дешёвый момент заметить **разнородную задачу**: раздел - «Затрагивает» показывает границы до того, как заведено предложение об - изменении. Строка, которая одна тянет задачу на метку выше остального - перечня, — кандидат на разрез (шов — в `tasks`, `references/split.md`). - Замеченная здесь, она стоит одного `edit`; замеченная на ревью — выброшенного - предложения. -5. Задача, которой для взятия не хватает только разделов её типа, дописывается - здесь же — критерии с оракулами, перечень границ, шаги воспроизведения. Но - если для этого нужен ответ человека, это вопрос, и задача в набор не идёт. - -**Размер — ориентир, а не закон:** 5–8 задач. Можно взять больше, можно меньше — -набор под цель важнее круглого числа; одна крупная задача спринтом тоже бывает. - -## Доклад сессии - -- Что просмотрено: N из M, сколько порций, по какому признаку отобраны. -- Вопросы: разобрано N, из них отвечено без человека N, снято тегов N. -- Разбор процесса: что записано и куда. -- Сверка документов с кодом: звался ли `doc-code-drift`, что проверено из - названного, что разошлось. -- Изменения списком: удалено как реализованное (со ссылками), ушло без - реализации (с причинами), понижено до сырья, слито, сменило тип или цель. -- Новый спринт: цель — **или строка «без цели» с объяснением, почему** (багфикс, - техдолг, здоровье), — набор со слагами, дата, состав по типам. -- **Границы покрытия**: сколько задач не трогали и какие именно секции, теги или - цели остались — иначе доклад читается как «беклог разобран». -- `tasks.py check` после правок — результат строкой. diff --git a/av-dev-tasks/skills/session/references/sprint.md b/av-dev-tasks/skills/session/references/sprint.md deleted file mode 100644 index 2bb53a2..0000000 --- a/av-dev-tasks/skills/session/references/sprint.md +++ /dev/null @@ -1,199 +0,0 @@ -# Ведение спринта - -Спринт — набор задач, замороженный до его конца: под одну цель или **без цели** -(багфикс, техдолг, здоровье — это законно, `sprint start --no-goal`). Здесь то, -что происходит **внутри** спринта: как задача заканчивается, что считается сделанным, -кто принимает и что идёт в доклад. Как спринт набирается — шаг 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-tasks: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-code` — отчёт триажа в - `openspec/changes/archive//review/`, до архивации — `changes//review/`), - `SPRINT.md` под git и `reopen`. Переоценка на сессии и есть момент, когда - критерии видит не исполнитель. **Конвейера ревью в проекте нет — первой опоры - нет тоже**, и это называется строкой доклада, а не обходится молча - (`SKILL.md`, «Стимулы»). -3. **Расхождение — дефект критериев.** Приёмщик правит критерии и возвращает - задачу исполнителю **в этом же спринте**: ответ есть, остаток есть, по тесту - про остаток это не выход из спринта. - -## Что врывается в замороженный набор - -Только два класса — правило и его обоснование в SKILL.md. Здесь механика: - -- вторжение **не добавляет** задачу в набор: `SPRINT.md` остаётся тем набором, - который заморозили и показали. Внеплановая работа делается и называется в - докладе отдельной строкой «внеплановое: что и почему»; -- если внеплановое требует больше пары часов, честнее распустить спринт, чем - делать вид, что набор соблюдается; -- всё остальное падает в беклог через обычный интейк и ждёт сессии. - -## Доклад в конце спринта - -Проверяемые якоря, а не пересказ: - -- **Цель спринта** — или строка «спринт без цели» с тем, чем он был (багфикс, - техдолг, здоровье): у бесцельного набора это единственное место, где состав - вообще объясняется. И по каждой задаче набора: **хеш коммита**, дословный - исход проверок проекта, **исход по каждому критерию приёмки**. -- **Какие развилки решались** и чем обоснованы. -- **Урожай:** сколько задач заведено, какие вопросы накопились, что вышло из - спринта и почему, что было внеплановым. -- **Поимённая сверка урожая** с независимыми отчётами ревью: каждая отложенная - находка имеет либо слаг, либо строку «не заведена: причина». Нулевой урожай при - непустом отчёте — сигнал, а не благополучие. **Отчётов нет** (проект без - конвейера ревью) — сверять не с чем, и строка доклада говорит именно это, а не - «сверено». -- **Созрела ли порция для сессии.** Решение звать — человека, напоминание — - обязанность агента: `⌈урожай / 8⌉` порций. -- **Границы покрытия** сжатой строкой: что в этом спринте не проверялось вовсе.