av-dev-tasks: починены находки ревью, добавлена адаптация чужого репозитория

- атомарность: sprint drop и move собирают план правок целиком и пишут
  одним проходом; раньше отказ на втором слаге оставлял первый файл
  переписанным при нетронутом индексе
- хук переехал в мета-строку файла: индекс стал производным, и check --fix
  больше не теряет текст, восстанавливая строку
- механизировано то, что было записано, но не проверялось: слаг спринта и
  автотег, отказ по факту непустого раздела вопросов, число критериев,
  пометка decomposed, покрытие причин
- reopen возвращает закрытую задачу: без него порядок «пайплайн доложил →
  приёмщик судит → владелец закрывает» был односторонним
- скилл adopt: приходит в чужой репозиторий и выводит заполненный каталог
  задач. На копии беклога healthlog — 12 целей, 38 задач, 36 переименований,
  86 ссылок в 36 файлах, check зелёный
This commit is contained in:
av
2026-08-03 11:45:23 +03:00
parent 9219f4a5cd
commit 20dca29add
8 changed files with 1768 additions and 329 deletions
+31 -11
View File
@@ -63,7 +63,11 @@ description: Ритуал между спринтами и ведение сам
немедленно. Иначе спринт, из которого задачи вышли поштучно, выглядел бы штатно
завершённым, а вопросы тихо ждали бы сессии.
**Отличать вопрос от застревания:**
**Отличать вопрос от застревания.** Правило про остаток принадлежит управлению
задачами: оно решает, **сделана задача или вышла**, а это исход планирования, не
исполнения. **Ниже канонический текст; пайплайн проекта на него ссылается, а не
пересказывает** — два экземпляра одного правила разъезжаются, и разъезжаются
незаметно, потому что расхождение видно только на редком входе.
> Есть остаток, который доводится без ответа, — задача продолжается, вопрос
> записывается в файл. Остатка нет — задача выходит из спринта.
@@ -71,9 +75,11 @@ description: Ритуал между спринтами и ведение сам
С двумя оговорками, без которых тест ошибается:
> **Остаток, который материализует нерешённое** — записывает в хранилище,
> журнал, витрину или наружу состояние, зависящее от неотвеченного вопроса,
> **не остаток**. Решение поднимается до начала записи: откатить запись дороже,
> чем подождать ответ, а иногда невозможно.
> журнал, витрину **или наружу** состояние, зависящее от неотвеченного вопроса,
> **не остаток**. Решение поднимается до начала записи: откатить запись
> дороже, чем подождать ответ, а иногда невозможно. «Наружу» — часть правила, а
> не пример: выкладка, публикация и отправка данных третьей стороне не
> откатываются тем более.
> **Пол для остатка:** остаток, из которого пропала польза, названная в хуке, —
> это не сделанная задача, а вышедшая из спринта.
@@ -125,15 +131,26 @@ description: Ритуал между спринтами и ведение сам
прежде всего:
```
python3 $tk check # с этого начинается любая сессия
python3 $tk list --questions # шаг 1: что накопилось
python3 $tk list --tag sprint:<слаг> # шаг 3: урожай прошедшего спринта, первая порция
python3 $tk list --stale # шаг 3: дальше по залежалости
python3 $tk list --goal <слаг> # шаг 4: кандидаты под названную цель
python3 $tk sprint start --goal <слаг> # шаг 4
python3 $tk sprint take <слаг> … # шаг 4: набор
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 take --dir D <слаг> … # шаг 4: набор
python3 $tk sprint close --dir D # конец спринта; --dissolve при блокере
python3 $tk reopen <слаг> --dir D --reason … # приёмка не сошлась после закрытия
```
`D` — каталог задач проекта; цепочка его разрешения и вызов из чужого контекста
описаны в скилле `tasks` («Переносимость»). **Коды выхода** — там же: 1 это
дрейф в беклоге, 3 это «каталога нет», и ветвиться на них надо по-разному.
**Слаг спринта заводит `sprint start`** (по умолчанию — дата) и пишет его в
`SPRINT.md`; всё заведённое при открытом спринте помечается `sprint:<слаг>`
автоматически. Поэтому «первая порция — урожай прошедшего спринта» работает без
чьей-либо памяти.
Правки задач делаются мутациями (`edit`, `move`, `close`), а не редактором:
руками правится только тело файла. Это правило скилла `tasks`, здесь оно не
пересказывается.
@@ -181,6 +198,9 @@ python3 $tk sprint take <слаг> … # шаг 4: набор
решает проект.
6. **Ориентир по размеру спринта**, если он замерялся. Умолчание — 5–8 задач, и
это **ориентир, а не закон**.
7. **Команда учёта задач** — готовая строка вызова `tasks.py` (слот скилла
`tasks`). Ею владелец спринта закрывает задачи и заводит урожай; чужой
контекст сам путь к плагину не знает и знать не должен.
Числа проекта (сколько задач в спринте, сколько времени на задачу, каков прирост
беклога) — предмет шага 2, а не константы этого скилла.
@@ -68,7 +68,9 @@
задачи, заведённые за спринт; при урожае в 15 это две-три порции.
- **Отбор порций по порядку:**
1. **урожай спринта** — `list --tag sprint:<слаг>`: свежезаведённое ещё не
проходило ни одной проверки на нужность;
проходило ни одной проверки на нужность. Слаг спринта берётся из
`SPRINT.md` (его завёл `sprint start`), тег на задачах проставлен
автоматически при заведении — руками не метят и не вспоминают;
2. дальше **по залежалости** — `list --stale`;
3. по потребности — одна секция целиком, один тег (партия ревью), одна цель
(`--goal`), список от пользователя.
@@ -176,8 +178,9 @@
4. **Набор показывается человеку до старта работ.** Показ — это и есть момент
заморозки: после него набор не двигается.
5. Задача, которой для взятия не хватает только критериев приёмки, дописывается
здесь же — но если для критериев нужен ответ человека, это вопрос, и задача в
набор не идёт.
здесь же — 2–5 утверждений, у каждого назван оракул (меньше двух `sprint
take` не примет). Но если для критериев нужен ответ человека, это вопрос, и
задача в набор не идёт.
**Размер — ориентир, а не закон:** 5–8 задач. Можно взять больше, можно меньше —
набор под цель важнее круглого числа; одна крупная задача спринтом тоже бывает.
@@ -11,7 +11,8 @@
след.
- **Сделана** — по определению готовности ниже. `close <slug> --implemented`:
файл и строка удаляются, следом остаётся коммит.
файл и строка удаляются, следом остаётся коммит. **Закрывает владелец спринта
и только после вердикта приёмки** — см. «Кто и когда закрывает».
- **Вышла из спринта** — `sprint drop <slug> --reason …`: возвращается в беклог
с вопросом в файле и **без живого незакоммиченного предложения** — иначе при
следующем взятии оно столкнётся с новым. Наработки, которые жалко терять,
@@ -27,6 +28,13 @@
«все сделаны»: иначе одна застрявшая задача держит спринт бесконечно. Затем
`sprint close`.
**Урожай заводится при закрытии спринта, а не при закрытии задачи.** Это
обязанность закрывающего: пройти по спискам находок от исполнителей и завести
недостающее интейком скилла `tasks` — с дедупликацией и картой человеку. Заводимое
метится тегом спринта само (`sprint:<слаг>`), поэтому первая порция следующей
сессии поднимается одной командой `list --tag sprint:<слаг>`. Спринт, закрытый
без этого шага, оставляет находки жить в отчётах — то есть нигде.
**Провал спринта.** Сработал блокер — спринт распускается (`sprint close
--dissolve --reason …`), недоделанное возвращается в беклог, новый набор
делается после ответа человека. Спринт не «ждёт»: ждать может человек, а
@@ -44,8 +52,32 @@
2. **Критерии приёмки проверены поимённо** — каждый со своим оракулом, исход по
каждому назван. Это единственное, что добавляет управление задачами: пайплайн
отвечает «сделано по правилам», критерии — «сделано то, что заказывали».
3. **Урожай заведён** — вопросы и задачи, найденные по ходу, лежат в беклоге, а
не в отчёте.
3. **Находки по ходу отданы списком** — исполнитель обязан их **назвать**
(каждую, с пометкой «заведена / не заведена: причина»), но **не обязан
заводить**: заведение интерактивно, оно требует дедупликации против беклога и
кладбища и решений человека. Обязанность **завести урожай** — на закрытии
спринта, ниже. Так автономный исполнитель не оказывается одновременно обязан
завести задачи и не вправе это сделать в одиночку.
### Кто и когда закрывает
**Задачу закрывает не пайплайн, а владелец спринта — после приёмки.** Порядок:
1. пайплайн доводит задачу до коммита и **докладывает исход**; файл задачи он не
трогает — своей процедуры закрытия у него нет;
2. приёмщик (не исполнитель) сверяет критерии поимённо и выносит вердикт;
3. вердикт сошёлся — владелец спринта зовёт `close <slug> --implemented`
командой учёта задач из `CLAUDE.md` проекта.
Обратный порядок ломает приёмку физически: закрытие **удаляет файл**, и
приёмщику, нашедшему расхождение, возвращать нечего.
**Дорога назад существует и обязана быть названа.** Закрыли раньше вердикта, а
приёмка не сошлась — `tasks.py reopen <slug> --reason "приёмка не сошлась: …"`:
файл восстанавливается из истории git, строка возвращается в набор идущего
спринта (или в беклог, если спринта нет), строка кладбища снимается. Тело
восстанавливается **на момент удаления** — всё, что было дописано позже, живёт
только в коммите задачи, и это называется в докладе.
### Кто и по чему принимает