From 3653c5cff59e5543c5ba2a58614aedbaca50902e Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Sun, 9 Aug 2026 16:36:26 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D0=BA=D0=B8=D0=BB=D0=BB=20tasks:=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BE=D1=80=D0=B8=D1=82=D0=B5=D1=82=20=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=20=D0=BF=D0=BE=D1=80=D1=8F=D0=B4=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=20=D1=81=D1=82=D1=80=D0=BE=D0=BA=20=D0=B2=20=D0=B1=D0=B5?= =?UTF-8?q?=D0=BA=D0=BB=D0=BE=D0=B3=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Правило 4 переписано целиком. Было «порядка нет, есть цель», и обосновано это было тем, что на «что делать дальше» отвечает набор спринта. Набора нет — вопрос остался, отвечать нечем. Приоритет — свойство очереди, а не задачи, поэтому его дом индекс: то же исключение из правила 2, что и «в каком индексе лежит запись». Положи его в файл числом — два соседних файла смогли бы утверждать одно место, а строка индекса противоречить обоим. Цель и приоритет — независимые оси: очередь может идти поперёк целей. Расстановка — это move --after и move --first, и только они: руками поправленная строка не оставляет причины. Место сырья в конце секции из очереди изъято: оно производно от типа и заполненности, его назначает машина, приоритетом оно не становится. Схема состояний потеряла SPRINT.md и четыре перехода; шесть уставов типов, task-format, split, from-review и adopt переведены со «взятия в спринт» на ready. --- av-dev-tasks/skills/tasks/SKILL.md | 120 ++++++++++-------- av-dev-tasks/skills/tasks/references/adopt.md | 18 +-- .../skills/tasks/references/from-review.md | 18 +-- av-dev-tasks/skills/tasks/references/split.md | 11 +- .../skills/tasks/references/task-chore.md | 8 +- .../skills/tasks/references/task-feature.md | 8 +- .../skills/tasks/references/task-fix.md | 10 +- .../skills/tasks/references/task-format.md | 60 +++------ .../skills/tasks/references/task-goal.md | 8 +- .../skills/tasks/references/task-research.md | 17 +-- av-dev-tasks/skills/tasks/scripts/tasks.py | 2 +- 11 files changed, 142 insertions(+), 138 deletions(-) diff --git a/av-dev-tasks/skills/tasks/SKILL.md b/av-dev-tasks/skills/tasks/SKILL.md index faa2d2a..12e5dbb 100644 --- a/av-dev-tasks/skills/tasks/SKILL.md +++ b/av-dev-tasks/skills/tasks/SKILL.md @@ -1,6 +1,6 @@ --- name: tasks -description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). У каждой записи есть тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение записи из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, штурм сырья, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Ритуал между спринтами — скилл session. Не реализует задачи — этим занимается пайплайн проекта. +description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). У каждой записи есть тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение записи из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, штурм сырья, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Расстановка приоритетов и разбор накопившегося — скилл groom. Не реализует задачи — этим занимается скилл решения задачи. --- # Задачи @@ -9,9 +9,9 @@ description: Ведение задач и целей как каталога mar строка **ровно в одном** индексе. Скилл владеет **форматом и содержимым**: заводит, редактирует, закрывает, разбирает находки ревью, дробит, штурмует сырьё. -Чем он **не** владеет: ритуалом между спринтами (разбор вопросов → разбор -прошедшего спринта → переоценка → выбор цели и набор) — это скилл `session`; и -выполнением задачи — это пайплайн проекта. +Чем он **не** владеет: **очередью** — что делать следующим и что перестало быть +важным, решает скилл `groom`, а этот скилл лишь даёт ему операции; и выполнением +задачи — это пайплайн проекта. ## Шесть правил, из которых всё следует @@ -35,27 +35,38 @@ description: Ведение задач и целей как каталога mar Поэтому **«зачем» живёт в мете файла**, а строка индекса его лишь повторяет: пока поле лежало только в индексе, восстановление пропавшей строки теряло его молча и навсегда. Единственное исключение намеренное: **в каком - индексе лежит задача, знают индексы** — «в спринте» это свойство спринта, а - не файла, поля-состояния нет. + индексе лежит запись, знают индексы** — поля-состояния в файле нет. И + **порядок строк в беклоге**: приоритет это свойство очереди, а не задачи, и в + файле ему места нет (правило 4). 3. **Причина переживает запись.** Выкинутая без причины задача вернётся через квартал тем же текстом. Реализованная оставляет след в коммите — выкинутая не оставляет ничего, поэтому у неё есть `REJECTED.md`. -4. **Порядка нет, есть цель — но цель есть не у всякой задачи.** Приоритетов, - «повысить» и «встать раньше» нет: «что делать дальше» отвечает набор спринта, - а между спринтами порядок не нужен никому. Цель обязательна там, где она и - есть содержание работы, — у **новой возможности** (`feature`). Починка, - техдолг и разведка служат работоспособности, а не направлению, и живут без - цели законно; в набор спринта они входят помимо его цели. Придуманная им цель - — то же враньё, от которого спасает тип. +4. **Приоритет — это порядок строк, а цель есть не у всякой задачи.** Очередь + внутри секции беклога значима: **первая строка — то, что делают следующим**. + Приоритет назначает человек на груминге, машина его не выводит и не угадывает. - Единственный порядок, который в беклоге всё-таки есть, **производен от типа**, - а не назначен человеком: **сырьё** (`research` без раздела «Вопрос») стоит в - конце своей категории. Его не берут, и между берущимся оно каждый раз требует - открыть файл, чтобы это понять. Раз порядок выводится, его проверяет машина — - и приоритетом он не становится. + Прежде здесь стояло «порядка нет, есть цель», и обосновано это было тем, что + на «что делать дальше» отвечает **набор спринта**. Набора больше нет, а + вопрос остался — и без порядка отвечать на него стало нечем. + + **Дом приоритета — индекс, а не файл.** Это то же исключение из правила 2, + что и «в каком индексе лежит запись»: приоритет — свойство очереди. Положи он + в файл числом, и два соседних файла смогли бы утверждать одно и то же место, + а строка индекса — противоречить обоим. + + Цель обязательна там, где она и есть содержание работы, — у **новой + возможности** (`feature`). Починка, техдолг и разведка служат + работоспособности, а не направлению, и живут без цели законно. Придуманная им + цель — то же враньё, от которого спасает тип. **Цель и приоритет — + независимые оси:** очередь может идти поперёк целей, и это законно. + + Одно место в очереди назначено **не человеком, а типом**: **сырьё** + (`research` без раздела «Вопрос») стоит в конце своей категории. Его не берут, + и между берущимся оно каждый раз требует открыть файл, чтобы это понять. Раз + это выводится, проверяет и чинит это машина. 5. **Тип решает, что с записью можно делать.** Тип — единственная ось и первое поле меты: от него зависит, какие разделы обязательны в теле, нужна ли цель, - берётся ли запись в спринт и в каком индексе живёт её строка. Словарь закрыт; + берётся ли запись в работу и в каком индексе живёт её строка. Словарь закрыт; ни один тип не подошёл — значит, в записи их два, и её надо разделить. ## Раскладка @@ -70,14 +81,14 @@ description: Ведение задач и целей как каталога mar tasks/ items/ задачи и цели файлами, .md, слаги английские ROADMAP.md состояние проекта: что уже умеет и чего ещё не умеет - BACKLOG.md что можно взять — только задачи, целей здесь нет - SPRINT.md текущий спринт: цель (или её отсутствие), набор, дата + BACKLOG.md что можно взять — только задачи, целей здесь нет. + Порядок строк в секции значим: это очередь REJECTED.md ушедшее БЕЗ реализации, с причиной и датой ``` Правило, снимающее путаницу: **`BACKLOG.md` — то, что берут; `ROADMAP.md` — то, -подо что берут.** Цель в спринт взять нельзя, поэтому в списке берущихся ей не -место. +подо что берут.** Цель в работу взять нельзя — берут её задачи, — поэтому в +списке берущихся ей не место. **Четыре секции роадмапа, и последняя отвечает на половину вопроса:** @@ -99,7 +110,7 @@ tasks/ роадмап, названный по-своему, читался бы только своим автором. Категории беклога (`Ядро`, `Инфра`) смысла не несут — это полки домена, и остаются делом проекта. Отсюда и разные имена поля меты: у цели **Секция** (часть роадмапа — состояние -очереди), у задачи **Категория** (полка, в которую она вернётся из спринта). +очереди), у задачи **Категория** (полка домена, на которой она лежит). Отсюда четыре правила, которые проверяет `tasks.py check`: **состав закреплён** (чужая секция — ошибка, а не вольность), **все четыре обязаны быть** (нет @@ -118,24 +129,31 @@ tasks/ называла слишком много: роадмап **весь** про разработку, и секция с таким именем не отличалась от остальных ничем. -**Секции «блокеры» в беклоге нет.** Блокер — это *состояние* (спринт не может +**Секции «блокеры» в беклоге нет.** Блокер — это *состояние* (работа не может продолжаться ни одной задачей), а не полка: он живёт ровно до ответа человека, и записи в такой секции не успевают жить. Следы блокера остаются вопросами в -файлах задач распущенного спринта. Постоянно пустая секция со старой семантикой +файлах задач. Постоянно пустая секция со старой семантикой «разбираются пачками» противоречила бы правилу «блокер эскалируется немедленно», поэтому `init` её заводить отказывается, а `check` о ней говорит. **Проекту, который переезжает с такой секцией, её надо удалить** — это единственное место, где это сказано. -**Задача живёт в одном индексе за раз.** Взята в спринт — строка переезжает из -`BACKLOG.md` в `SPRINT.md`; вышла — обратно. Файл в `items/` при этом **не -двигается**: он и есть запись, индексы лишь показывают, где она числится. +**Запись живёт в одном индексе за раз.** Индексов два, и выбирает между ними +тип: цель в роадмапе, задача в беклоге. Сменился тип — строка переезжает +(`edit --type`). Файл в `items/` при этом **не двигается**: он и есть запись, +индексы лишь показывают, где она числится и в каком порядке стоит. + +**Порядок строк в беклоге — приоритет**, и он единственное, чего в файле нет +(правило 4). Отсюда следствие для всякой машинной правки индекса: +восстановленная или перенесённая строка встаёт **в конец своей секции**, и +скрипт об этом говорит. Молчаливая вставка выдала бы машинную позицию за +решение человека — а решение это его. **У сделанной задачи записи не остаётся** — файл и строка удаляются (`close --implemented`). Ей хватает коммита и документации проекта; вторая запись была -бы вторым домом для того же факта. Вопрос «что было в спринте N» отвечается -даром: `SPRINT.md` лежит под git, `git log -p tasks/SPRINT.md` отдаёт историю -всех наборов без отдельного журнала. +бы вторым домом для того же факта. Вопрос «что было сделано и когда» отвечается +даром: индексы лежат под git, а закрытие коммитится отдельным коммитом учёта — +`git log -p tasks/BACKLOG.md` отдаёт историю без отдельного журнала. **У достигнутой цели запись остаётся, и это единственное исключение.** Файл удаляется так же, а строка переезжает в секцию `Готово` с датой. Причина в том, @@ -152,7 +170,6 @@ tasks/ stateDiagram-v2 state "BACKLOG.md — что берут" as B state "ROADMAP.md — подо что берут" as P - state "SPRINT.md — набор спринта" as S state "REJECTED.md — ушла без реализации" as R state "записи нет — реализована" as D state "ROADMAP.md, «умеет» — цель достигнута" as A @@ -161,12 +178,9 @@ stateDiagram-v2 [*] --> P: add --type goal B --> P: edit --type goal --section P --> B: edit --type feature|fix|chore|research --section - B --> S: sprint take - S --> B: sprint drop --reason - S --> D: close --implemented + B --> D: close --implemented P --> A: close --implemented B --> R: close --reason - S --> R: close --reason P --> R: close --reason D --> B: reopen --reason R --> B: reopen --reason @@ -247,7 +261,7 @@ stateDiagram-v2 **поле меты `Тип` первой строкой**; эмодзи в заголовке H1 от него производна, её ставит `add` и чинит `check --fix`. -| Тип | Обязательные разделы | Цель | В спринт | Устав | +| Тип | Обязательные разделы | Цель | В работу | Устав | | --- | --- | --- | --- | --- | | 🎯 `goal` | `Завершение` | — | нет | [task-goal.md](references/task-goal.md) | | ✨ `feature` | `Затрагивает`, `Критерии приёмки` | **обязательна** | да | [task-feature.md](references/task-feature.md) | @@ -270,14 +284,14 @@ stateDiagram-v2 незаполненности** — «первый, второй или третий вопрос теста готовности не отвечается», — а состояние типом быть не может: оно меняется по мере того, как запись дописывают, а тип меняют командой. Теперь это состояние называется честно: -`research` без раздела «Вопрос» — **сырьё**. В спринт не берётся ровно как +`research` без раздела «Вопрос» — **сырьё**. В работу не берётся ровно как прежняя идея, лежит в конце своей категории и отбирается `list --raw`. Словарь **закрыт**. Открытый разъедется на синонимах — `bug`, `bugfix`, `fix`, `defect`, — и отбор по типу перестанет отвечать на свой единственный вопрос. Ни один тип не подходит — это сигнал, что в задаче их два и её надо разделить. -**Требуется тип там, где по нему принимают решение:** `sprint take` без типа +**Требуется тип там, где по нему принимают решение:** `ready` без типа откажет, потому что не знает, каких разделов требовать. `check` о пропаже только **напоминает** — беклог, заведённый до появления типа, законен, и переоформлять его «заодно» здесь не просят. @@ -324,7 +338,7 @@ stateDiagram-v2 делать, и какие границы это трогает: эндпоинт или команду, таблицу и миграцию, формат на диске, публичный тип пакета, внешний сервис. Перечень живёт разделом «Затрагивает» (форма — [references/task-format.md](references/task-format.md)) и -требуется к взятию в спринт. Без него задача оценивается по объёму текста, а не +требуется к взятию в работу. Без него задача оценивается по объёму текста, а не по объёму поверхности, — и оценка систематически занижена ровно там, где текст короткий, а границ много. Названы **границы**, а не то, как они изменятся: план реализации живёт в предложении об изменении, а не в задаче. @@ -373,7 +387,7 @@ python3 $tk move S --dir D --section S [--reason R] [--after S | --first] python3 $tk close S --dir D --reason R # в REJECTED.md + удалить (ушла без реализации) python3 $tk close S --dir D --implemented # просто удалить (реализована и закоммичена) python3 $tk reopen S --dir D --reason R # вернуть закрытую: приёмка не сошлась -python3 $tk sprint start (--goal S | --no-goal) --dir D | take S… | drop S… --reason R | close [--dissolve --reason R] +python3 $tk ready S… --dir D # схема типа выполнена — можно брать в работу python3 $tk init --dir D [--sections …] [--items …] [--backlog …] … python3 $tk adopt scan --from … | apply --plan … # разовая адаптация, references/adopt.md ``` @@ -397,7 +411,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап заголовке ставит скрипт. **Мутации правят файл и индексы заодно** — руками строку индекса или мету -не пиши, зови `add`/`edit`/`move`/`close`/`sprint`. Смена заголовка, «зачем», типа, +не пиши, зови `add`/`edit`/`move`/`close`/`reopen`. Смена заголовка, «зачем», типа, цели и **тегов** — это `edit`: он держит H1 (вместе с эмодзи), мету и индекс согласованными. Снятие тега — `--rm-tag` (после ответа на вопрос снимается `question`), смена цели — `--goal`, типа — `--type`; оба заменяют прежнее @@ -410,7 +424,12 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап `move` двигает только внутри одного индекса и пишет причину. `--section` у `edit` работает **только** при таком переезде — иначе он отсылает к `move`, потому что смена секции без причины и есть тот дрейф, который потом никто не -объяснит. Задача в наборе спринта тип не меняет вовсе: сперва `sprint drop`. +объяснит. + +**`move --after <слаг>` и `move --first` — это и есть расстановка приоритета.** +Порядок строк в секции значим (правило 4), и двигают его только этой командой: +руками поправленная строка не оставляет причины, а причина здесь и есть половина +решения. Тело задачи скрипт не трогает: `add` кладёт заголовок, мета-блок и шаблон с подсказками, тело дописываешь @@ -439,9 +458,9 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап где по нему принимают решение. Такие записи идут в `НЕОДНОЗНАЧНО`, и тип им проставляет человек — `edit <слаг> --type …`. -**Что механизировано, а что нет.** У задачи, взятой в набор (`sprint take` и -`check` по задачам спринта), проверяется схема её типа, и у каждой части своя -глубина: +**Что механизировано, а что нет.** Схему типа проверяет `ready` на входе в +работу — там, где по ней принимают решение; `check` о недостающем только +напоминает счётчиком «готово к взятию». У каждой части своя глубина: - **тип** — жёстко: назван и из закрытого словаря; - **критерии приёмки** (`feature`, `fix`, `chore`) — число пунктов жёстко @@ -602,7 +621,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап ровно там, где по нему отбирают, **и требует не тех разделов**: у брошенного `fix` останется «Воспроизведение», которого нечем заполнить; - **сырьё, у которого появился вопрос** — разведка обросла формулировкой, но - раздел «Вопрос» так и пуст: она числится сырьём и в спринт не берётся. + раздел «Вопрос» так и пуст: она числится сырьём и в работу не берётся. Записывается вопрос, и `check --fix` поднимает строку из конца категории; - **границы, названные вместо реализации** — «переписать хранилище на новый драйвер» в разделе «Затрагивает» это не граница, а замысел. Границы — @@ -691,6 +710,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап ## Чего этот скилл не делает Не пишет код, не заводит спеки и предложения об изменении, не берёт задачу в -работу — этим занимается пайплайн проекта. Не ведёт спринт и не проводит сессию -между спринтами — это `session`. Не решает за пользователя, что важно. Не +работу — этим занимается пайплайн проекта. **Не ведёт очередь:** что делать +следующим и что перестало быть важным — скилл `groom`, а этот даёт ему операции. +Не решает за пользователя, что важно. Не переоформляет существующие задачи «заодно»: правится то, чего касается операция. diff --git a/av-dev-tasks/skills/tasks/references/adopt.md b/av-dev-tasks/skills/tasks/references/adopt.md index bb76d8e..0d34b7d 100644 --- a/av-dev-tasks/skills/tasks/references/adopt.md +++ b/av-dev-tasks/skills/tasks/references/adopt.md @@ -2,7 +2,7 @@ Проект, где задачи уже как-то ведутся, и из имеющегося материала **выводится** заполненный каталог задач: цели, задачи, кладбище, индексы. Операция разовая — -после неё проект живёт скиллами `tasks` и `session`. +после неё проект живёт скиллами `tasks` и `groom`. **Это часть приведения проекта к канону.** Раскладку `docs/` целиком ведёт скилл `av-dev-docs:canon`; он же зовёт этот сценарий на шаге «каталог задач», потому что @@ -94,13 +94,15 @@ python3 $tk adopt apply --plan tasks-adopt-plan.json \ быть названо, иначе следующий агент примет пустой беклог за поломку. `apply` печатает состояние по факту: сколько задач без цели (это **ошибки** -`check`) и сколько без критериев (`check` их ошибкой не считает, но `sprint -take` такую задачу не возьмёт). Закрывается это **порциями переоценки** — шаг 3 -скилла `session`, 5–8 задач за порцию: проставить цели, превратить «готово, -когда» в критерии с оракулами, вынуть вопросы из прозы в раздел «Вопросы». +`check`) и сколько без критериев (`check` их ошибкой не считает, но `ready` +такую задачу не пропустит). Закрывается это **порциями груминга** — скилл +`groom`, 5–8 задач за порцию: проставить цели, превратить «готово, когда» в +критерии с оракулами, вынуть вопросы из прозы в раздел «Вопросы». Там же +беклогу впервые назначается **порядок**: после адаптации его нет вовсе, а +очередь и есть то, ради чего каталог заводят. -Готовность к первому спринту — не «`check` зелёный», а «есть 2–5 критериев хотя -бы у набора под одну цель». +Готовность к первой задаче — не «`check` зелёный», а «`ready` пропускает хотя бы +верхние строки очереди». ## Чего адаптация не делает @@ -109,7 +111,7 @@ take` такую задачу не возьмёт). Закрывается эт - **Не переписывает подписи ссылок.** `[docs/backlog](tasks/BACKLOG.md)` — цель поправлена, текст остался; это правится глазами, и таких мест немного. - **Не сочиняет критерии приёмки и не придумывает цели**, которых в материале - нет. Придуманная цель хуже отсутствующей: под неё соберут спринт. + нет. Придуманная цель хуже отсутствующей: под неё заведут задачи. - **Не трогает историю.** В коммитах старые слаги остаются, и это нормально. ## Доклад diff --git a/av-dev-tasks/skills/tasks/references/from-review.md b/av-dev-tasks/skills/tasks/references/from-review.md index 66dd984..44d5fe4 100644 --- a/av-dev-tasks/skills/tasks/references/from-review.md +++ b/av-dev-tasks/skills/tasks/references/from-review.md @@ -25,7 +25,7 @@ переживает запись. - **Находка без свидетельства / низкой уверенности** → **сырьё**: `research`, у которого раздел «Вопрос» и есть недостающее свидетельство («при каких условиях - это воспроизводится»). Не `fix`: без `Воспроизведения` его в спринт не + это воспроизводится»). Не `fix`: без `Воспроизведения` его в работу не возьмут, и правильно — чинить нечего, пока непонятно, что ломается. Судьба сырья — штурм, где либо найдётся подтверждение, либо оно уедет в `REJECTED.md`. @@ -46,7 +46,7 @@ устареть, выноси пользователю, а не заводи молча заново. 4. **Разложи по целям — там, где цель нужна.** Большинство находок ревью это `fix` и `chore`, и **цель им не требуется**: они служат работоспособности, а - не направлению, и в спринт входят помимо его цели. Придуманная им цель — + не направлению. Придуманная им цель — ровно то враньё, от которого спасает тип. Цель обязательна у находки, которая оказалась **новой возможностью** @@ -79,13 +79,13 @@ Правило замены: - **тяжёлая находка со свидетельством** → задача под ту цель, которой она - угрожает, и **кандидат в ближайший набор**: серьёзность здесь превращается в - довод при выборе цели следующего спринта, а не в уровень в файле. Довод - записывается причиной в мете (`--reason`), иначе к моменту набора его - никто не вспомнит; -- **находка, ломающая уже идущий спринт**, — не интейк вовсе: см. правило - вторжения в скилле `session`. В беклог она падает, только если врываться не - положено; + угрожает, и **кандидат на верх очереди**: серьёзность здесь превращается в + довод при расстановке приоритета, а не в уровень в файле. Довод записывается + причиной в мете (`--reason`), иначе к моменту груминга его никто не вспомнит. + Саму строку интейк ставит в конец секции: очередь назначает человек; +- **находка, которая не ждёт груминга вовсе** (необратимый ущерб, сломан общий + станок), — не интейк: это работа прямо сейчас, а в беклог она падает, только + если ждать всё-таки можно; - **низкая уверенность или нет свидетельства** → сырьё (`research` с пустым разделом «Вопрос»); - **мелочь** → строка в пакетный файл; diff --git a/av-dev-tasks/skills/tasks/references/split.md b/av-dev-tasks/skills/tasks/references/split.md index 64ab164..e48ef32 100644 --- a/av-dev-tasks/skills/tasks/references/split.md +++ b/av-dev-tasks/skills/tasks/references/split.md @@ -66,13 +66,14 @@ той же целью. Если частям нужен общий заголовок — значит у них общая возможность, и её надо назвать целью, а не заводить временный тип. -## Когда декомпозиция случается посреди спринта +## Когда декомпозиция случается посреди работы Задача, которая **оказалась крупнее задачи**, распознаётся до того, как под неё заведено предложение об изменении: иначе его придётся выбрасывать. Она выходит -из набора (`sprint drop … --reason "крупнее задачи"`), уходит на декомпозицию, а -спринт продолжается остальными. Части заводятся сразу под той же целью, но в -текущий набор **не добавляются** — набор заморожен. +уходит на декомпозицию, а её строка возвращается в беклог с причиной +(`move … --reason "крупнее задачи"`). Части заводятся сразу под той же целью, и +**место в очереди им назначает человек**: машина поставит их в конец секции, а +крупная задача редко распадается на что-то менее срочное, чем была сама. ## Мозговой штурм сырья @@ -80,7 +81,7 @@ тест «готова к взятию», потому что неясно, что именно делаем. Штурм проясняет — и это **generative-операция, а не applicative**. -Исход штурма и есть заполненный «Вопрос» (тогда разведку можно брать в спринт) +Исход штурма и есть заполненный «Вопрос» (тогда разведку можно брать в работу) или набор задач с типами, которые из ответа следуют. Третий законный исход — `close --reason`. diff --git a/av-dev-tasks/skills/tasks/references/task-chore.md b/av-dev-tasks/skills/tasks/references/task-chore.md index 52fd11d..a7d2095 100644 --- a/av-dev-tasks/skills/tasks/references/task-chore.md +++ b/av-dev-tasks/skills/tasks/references/task-chore.md @@ -15,8 +15,8 @@ | Допустимые сверх того | `Рамки`, `Вопросы` | | Поле места | **Категория** — полка домена беклога | | Цель (`goal:<слаг>`) | нет: цель — это возможность, а здесь её не появляется | -| Индекс | `BACKLOG.md` → `SPRINT.md` | -| Берётся в спринт | да | +| Индекс | `BACKLOG.md` | +| Берётся в работу | да | ## Адресат — разработчик, и это законно @@ -49,12 +49,12 @@ («обновить зависимости и переписать сборку и убрать мёртвый код»). Не мерджится порознь — это несколько задач ([split.md](split.md)). 6. **Цель не проставлять.** `chore` служит работоспособности, а не направлению, - и в набор спринта входит помимо его цели. Работа по сопровождению проекта + работоспособности, а не направлению. Работа по сопровождению проекта при этом видна в роадмапе — секцией `Сопровождение`, но целью не становится. ## Что видит машина, а что человек -`check` и `sprint take` смотрят на **наличие непустого** `Затрагивает` и на +`check` и `ready` смотрят на **наличие непустого** `Затрагивает` и на **число** критериев — ровно то же, что у `feature`. Разница между типами здесь не в строгости проверки, а в том, **кому адресован ответ** на «что станет наблюдаемо иначе», — и это судит человек. diff --git a/av-dev-tasks/skills/tasks/references/task-feature.md b/av-dev-tasks/skills/tasks/references/task-feature.md index ec2a27f..df92abd 100644 --- a/av-dev-tasks/skills/tasks/references/task-feature.md +++ b/av-dev-tasks/skills/tasks/references/task-feature.md @@ -16,12 +16,12 @@ | Допустимые сверх того | `Рамки`, `Вопросы` | | Поле места | **Категория** — полка домена беклога | | Цель (`goal:<слаг>`) | **обязательна** | -| Индекс | `BACKLOG.md` → `SPRINT.md` | -| Берётся в спринт | да | +| Индекс | `BACKLOG.md` | +| Берётся в работу | да | **Цель обязательна, и это единственный тип, у которого так.** Новая возможность и есть содержание цели: подходящей нет — либо она заводится, либо перед тобой не -`feature`. `sprint take` без цели откажет. +`feature`. `ready` без цели откажет. ## Алгоритм @@ -48,7 +48,7 @@ ## Что видит машина, а что человек -`check` и `sprint take` смотрят на **наличие непустого** раздела `Затрагивает`, +`check` и `ready` смотрят на **наличие непустого** раздела `Затрагивает`, на **число** критериев (меньше двух — отказ, больше пяти — замечание) и на цель. Наличие оракула проверяется **эвристикой** — словом «оракул» в пункте. diff --git a/av-dev-tasks/skills/tasks/references/task-fix.md b/av-dev-tasks/skills/tasks/references/task-fix.md index d83d47e..15b0011 100644 --- a/av-dev-tasks/skills/tasks/references/task-fix.md +++ b/av-dev-tasks/skills/tasks/references/task-fix.md @@ -17,14 +17,14 @@ | Допустимые сверх того | `Рамки`, `Вопросы` | | Поле места | **Категория** — полка домена беклога | | Цель (`goal:<слаг>`) | необязательна | -| Индекс | `BACKLOG.md` → `SPRINT.md` | -| Берётся в спринт | да | +| Индекс | `BACKLOG.md` | +| Берётся в работу | да | ## `Воспроизведение` — раздел, которого нет у других типов **Не воспроизводится — это `research`, а не `fix`.** Правило было записано и раньше, но проверять его было нечем, и «починки» без единого шага повторения -уходили в спринт наравне с остальными. Раздел делает правило проверяемым: он +уходили в работу наравне с остальными. Раздел делает правило проверяемым: он называет, **что сделать, чтобы расхождение проявилось, и что при этом видно вместо ожидаемого**. @@ -55,7 +55,7 @@ («ввод `а1` принимается по-прежнему»). Без него починка чинит одно и ломает соседнее. 6. **Цель не выдумывать.** `fix` служит работоспособности, а не направлению, и в - набор спринта входит помимо его цели. Придуманная цель — то же враньё, от + работоспособности, а не направлению. Придуманная цель — то же враньё, от которого спасает тип. 7. **Записать дефект в журнал** `docs/review.md` с пометкой «проскочил / пойман ревью». Проскочившие — проверочный набор для калибровки конвейера; пойманные с @@ -64,7 +64,7 @@ ## Что видит машина, а что человек -`check` и `sprint take` смотрят на **наличие непустого** `Воспроизведения` и +`check` и `ready` смотрят на **наличие непустого** `Воспроизведения` и `Затрагивает` и на **число** критериев. Годность воспроизведения — человеку: шаги, по которым ничего не воспроизводится, машина от годных не отличает, и делать вид, что проверено больше проверенного, хуже, чем не проверять вовсе. diff --git a/av-dev-tasks/skills/tasks/references/task-format.md b/av-dev-tasks/skills/tasks/references/task-format.md index 19b7ff0..788a235 100644 --- a/av-dev-tasks/skills/tasks/references/task-format.md +++ b/av-dev-tasks/skills/tasks/references/task-format.md @@ -23,9 +23,9 @@ # 🐞 Не отбрасывать молча лишние символы в ходе - **Тип:** fix -- **Категория:** Ядро — вышла из спринта: остаток писал нерешённое в журнал +- **Категория:** Ядро — вернулась из работы: остаток писал нерешённое в журнал - **Зачем:** ввод «а1б2» ходит в a1 — игрок не видит, что ошибся, и винит игру -- **Теги:** goal:merge-robustness, sprint:2026-08-03 +- **Теги:** goal:merge-robustness Разбор хода читает первые два символа и молча выбрасывает остаток строки. @@ -63,11 +63,11 @@ здоровье; годность формулировки смотрит агент `task-form`. - **Мета-блок** — список сразу после заголовка, **поле на строку**. Обязательны **тип** и **место**, причина после тире желательна (именно она объясняет, - почему задача здесь оказалась — в том числе «вышла из спринта: …»), «зачем» и + почему задача здесь оказалась — в том числе «вернулась из работы: …»), «зачем» и теги необязательны. Нераспознанные поля сохраняются: скрипт правит свои и не трогает чужие. - **Тип — первым полем.** Он решает, что у записи вообще может быть: какие - разделы обязательны, нужна ли цель, берётся ли она в спринт, — и читается + разделы обязательны, нужна ли цель, берётся ли она в работу, — и читается раньше всего остального. Словарь **закрыт**: `goal` | `feature` | `fix` | `chore` | `research`. Не подходит ни один — это сигнал, что в записи их два и её надо разделить. @@ -93,11 +93,11 @@ | Тип | Поле | Значения | Что это | | --- | --- | --- | --- | | `goal` | **Секция** | `Запланировано`, `Направления`, `Сопровождение` | часть роадмапа: состояние очереди | -| прочие | **Категория** | секции беклога проекта (`Ядро`, `Инфра`, …) | полка домена, в которую задача вернётся из спринта | +| прочие | **Категория** | секции беклога проекта (`Ядро`, `Инфра`, …) | полка домена, на которой задача лежит | -Разные имена потому, что это **разные вещи**. У задачи поле переживает спринт: -`sprint drop` возвращает её именно туда. У цели оно называет не полку, а место в -очереди работ. Одно имя на два смысла их и смешивало; `check` называет +Разные имена потому, что это **разные вещи**. У задачи это полка: куда её +положили и куда вернут, если она уйдёт в работу и вернётся. У цели оно называет +не полку, а место в очереди работ. Одно имя на два смысла их и смешивало; `check` называет несовпадение дрейфом, `check --fix` переименовывает. Имя самого места принадлежит **заголовку индекса** — файл на него лишь @@ -142,7 +142,7 @@ имя таблицы стабильно, номер последней миграции протухает молча. Пишется `таблица points и её миграция`, а не `миграция 0042`. -**Что из этого механизировано.** `check` и `sprint take` смотрят только на +**Что из этого механизировано.** `check` и `ready` смотрят только на **наличие непустого раздела**. Полнота перечня машине не видна: границу, которую забыли назвать, она от отсутствующей не отличает. Раздела нет — отказ во взятии: оценивать нечем. @@ -158,7 +158,7 @@ конкретизация вопроса «по чему видно, что закончено» из теста готовности ниже: там сказано «признак завершённости», здесь — «признак плюс чем проверяется». -**Что из этого механизировано.** `check` и `sprint take` считают пункты: меньше +**Что из этого механизировано.** `check` и `ready` считают пункты: меньше двух — отказ («— работает» одной строкой больше не проходит), больше пяти — замечание, обычно это признак, что задача крупнее задачи. Наличие оракула проверяется **эвристикой** — словом «оракул» в пункте, — и потому даёт только @@ -205,8 +205,8 @@ ответом. Затем снимается тег (`edit --rm-tag question`) и переписывается «зачем»: «Решено: …» на вопрос «зачем нужна эта задача» уже не отвечает. -**Порядок именно такой, потому что судит раздел, а не тег.** `sprint take` -смотрит в непустой раздел и откажет взять задачу даже со снятым тегом, а `check` +**Порядок именно такой, потому что судит раздел, а не тег.** `ready` +смотрит в непустой раздел и откажет даже при снятом теге, а `check` на снятый тег при непустом разделе посоветует тег вернуть. Снять тег, не опустошив раздел, — значит закольцевать себя между двумя советами. @@ -240,7 +240,7 @@ `check` напоминает о нём у цели без задач замечанием — неразобранная цель законна и зелёного прогона не ломает; `check --fix` сам ставит его цели, у которой задачи есть, а цель с тегом и без задач — прямое приглашение закрыть. -- Цель живёт в `ROADMAP.md` и **никогда** — в `BACKLOG.md` или `SPRINT.md`. +- Цель живёт в `ROADMAP.md` и **никогда** — в `BACKLOG.md`. - **Достигнутая цель не исчезает.** `close <слаг> --implemented` удаляет файл и переносит строку в секцию `Готово` с датой: `- 2026-08-04 \`merge-order\` — Исход слияния не зависит от порядка доставки. …` @@ -277,33 +277,23 @@ | Файл | Что отвечает | Секции | | --- | --- | --- | | `ROADMAP.md` | что приложение уже умеет и чего ещё не умеет | канонические и в этом порядке: `Запланировано`, `Направления`, `Сопровождение`, `Готово` (англ. `Planned`, `Directions`, `Operations`, `Done`) | -| `BACKLOG.md` | что **можно взять** — только задачи | категории проекта (по умолчанию Ядро/Инфра) | -| `SPRINT.md` | какая цель (или что её нет) и какой набор заморожен | одна: «Набор» | +| `BACKLOG.md` | что **можно взять** — только задачи, **в порядке очереди** | категории проекта (по умолчанию Ядро/Инфра) | | `REJECTED.md` | что ушло без реализации и почему | — | -Шапку `SPRINT.md` пишет `sprint start` — **тем же мета-блоком, что у задачи**: -поле на строку, `- **Цель:** [Заголовок](items/slug.md)`, `- **Начат:**` датой, -`- **Спринт:**` слагом, которым метится урожай. У спринта без цели -(`sprint start --no-goal`) поле «Цель» остаётся на месте и пишется прозой без -ссылки — «не названа»: **«цели нет» и «цель потерялась» обязаны различаться**. -Поэтому и признак «спринт идёт» — слаг, а не цель: слаг есть у любого спринта, -без него нечем метить урожай. Прежняя форма (три поля одной -строкой через `·`) читается по-прежнему и уходит сама: файл переписывается на -следующем `sprint start` и очищается на `sprint close`. - Секции — **единственные заголовки `##` в индексе**: любой другой `##` в преамбуле проверка сочтёт секцией. -**Порядка «по важности» внутри секции беклога нет** — «что делать дальше» -отвечает набор спринта. Единственный порядок, который есть, **производен от типа -и заполненности**: **сырьё** (`research` без раздела «Вопрос») стоит в конце +**Порядок строк внутри секции беклога значим: это очередь.** Первая строка — то, +что делают следующим; назначает порядок человек на груминге, и двигают его +`move --after` и `move --first`. Одно место из очереди изъято и **производно от +типа и заполненности**: **сырьё** (`research` без раздела «Вопрос») стоит в конце своей секции, потому что его не берут, и между берущимся оно каждый раз требует открыть файл, чтобы это понять. Проверяет `check`, переставляет `check --fix`, и человек этот порядок не назначает — иначе он был бы приоритетом, которого здесь нет. **Секции «блокеры» среди них нет.** Блокер — состояние, а не полка: он живёт до -ответа человека, а следы остаются вопросами в файлах задач распущенного спринта. +ответа человека, а следы остаются вопросами в файлах задач. Постоянно пустая секция со старой семантикой «разбираются пачками» противоречила бы правилу «эскалируем немедленно», поэтому `init` её не заводит, а `check` говорит о ней в чужом беклоге. Переезжаешь с такой секцией — удали её. В секции @@ -333,9 +323,6 @@ SKILL.md. Порядок закреплён потому, что `Готово` Поэтому отказ на второй задаче из пяти не оставляет первую переписанной при нетронутых индексах. -`SPRINT.md` и есть артефакт заморозки: без него набор существует только в -контексте сессии, и нарушение заморозки ненаблюдаемо. - ## `REJECTED.md` Туда уходит задача, покинувшая беклог **без реализации**. Строку пишет @@ -361,15 +348,8 @@ SKILL.md. Порядок закреплён потому, что `Готово` - `goal:<слаг>` — цель, которой служит задача. Обязателен **у `feature`**: новая возможность и есть содержание цели. У `fix`, `chore` и `research` его - может не быть — они служат работоспособности, а не направлению, и в набор - спринта входят помимо его цели. + может не быть — они служат работоспособности, а не направлению. - `question` — в файле есть неразобранный раздел «Вопросы». -- `sprint:<слаг>` — задача заведена в этом спринте; по нему отбирается первая - порция разбора («урожай спринта»). **Ставится сам**: слаг спринта заводит - `sprint start` (по умолчанию — дата начала, он же пишется в `SPRINT.md`), и - `add` при открытом спринте помечает заводимое. Тег, который надо помнить - ставить руками, не ставится никогда — а на нём висит правило «первая порция - разбора — урожай прошедшего спринта». - `decomposed` — на цели: разложена на задачи (см. «Файл цели»). Тега `kind:<род>` больше нет: род работы стал типом. Оставшийся в файле `check` diff --git a/av-dev-tasks/skills/tasks/references/task-goal.md b/av-dev-tasks/skills/tasks/references/task-goal.md index 9fb2b1b..e0170bf 100644 --- a/av-dev-tasks/skills/tasks/references/task-goal.md +++ b/av-dev-tasks/skills/tasks/references/task-goal.md @@ -16,11 +16,11 @@ | Допустимые сверх того | — | | Поле места | **Секция** — часть роадмапа | | Цель (`goal:<слаг>`) | запрещена: цель и есть цель | -| Индекс | `ROADMAP.md`, и никогда `BACKLOG.md` или `SPRINT.md` | -| Берётся в спринт | нет — берутся её задачи | +| Индекс | `ROADMAP.md`, и никогда `BACKLOG.md` | +| Берётся в работу | нет — берутся её задачи | Поле места у цели называется **«Секция»**, а не «Категория», и это не разнобой: -у задачи оно называет полку домена, в которую она вернётся из спринта, а у цели +у задачи оно называет полку домена, на которой она лежит, а у цели — часть роадмапа, то есть состояние очереди. Одно имя на два смысла их и смешивало. @@ -77,7 +77,7 @@ **Место этому — переоценка на сессии, а не отдельный заход.** Отмена цели значит разбор всех её задач, а разбор задач и есть шаг 3 сессии -([cadence.md](../../session/references/cadence.md), пункт 7). Отменять на ходу, +(скилл `groom`, разбор «что перестало быть важным»). Отменять на ходу, между делом, — верный способ закрыть скопом то, что стоило перевесить. ## Что видит машина, а что человек diff --git a/av-dev-tasks/skills/tasks/references/task-research.md b/av-dev-tasks/skills/tasks/references/task-research.md index f7dd0ea..e235b91 100644 --- a/av-dev-tasks/skills/tasks/references/task-research.md +++ b/av-dev-tasks/skills/tasks/references/task-research.md @@ -15,8 +15,8 @@ | Допустимые сверх того | `Рамки`, `Вопросы` | | Поле места | **Категория** — полка домена беклога | | Цель (`goal:<слаг>`) | нет | -| Индекс | `BACKLOG.md` → `SPRINT.md` | -| Берётся в спринт | да — **но только с заполненным «Вопросом»** | +| Индекс | `BACKLOG.md` | +| Берётся в работу | да — **но только с заполненным «Вопросом»** | **Критериев приёмки у `research` нет, и это не поблажка.** Критерии в форме «оракул: тест» разведке натянуты: проверять нечего, пока ответа нет. Её приёмка @@ -39,13 +39,14 @@ | | сырьё | разведка | | --- | --- | --- | | Раздел `Вопрос` | пуст или отсутствует | заполнен | -| `sprint take` | отказ | берёт | +| `ready` | отказ | берёт | | Место в секции беклога | **конец**, `check --fix` сносит туда сам | среди прочих | | `tasks.py list --raw` | показывает | нет | -Порядка «по важности» в беклоге по-прежнему нет. Этот порядок **производен от -типа и заполненности**, а не назначен человеком, — потому его и проверяет машина, -и потому он не противоречит правилу «порядка нет, есть цель». +Порядок строк в беклоге назначает человек — это приоритет (правило 4 скилла). +Место сырья **из него изъято**: оно производно от типа и заполненности, а не от +чьего-то решения, и потому его проверяет и чинит машина. Приоритетом оно не +становится: сырьё не берут вовсе, и место в конце говорит именно это. Сырьём заводится и **сырая функция**: «Подсказка следующего хода» — ещё не `feature`, потому что неизвестно, что именно делать. Работа над ней — думание, и @@ -67,14 +68,14 @@ проход ревью обязан читать как условие, а не как замер. 5. **Разложить исход на задачи** — если он их родил. Разведка кончается одним из трёх: заведены задачи, записано знание, отказ. **Отказ — полноправный исход**: - «проверили, не проблема» экономит спринт. + «проверили, не проблема» экономит работу. 6. **Закрыть** — `close <слаг> --implemented`, когда ответ записан. Файл удаляется: запись ответа и есть след, второго не нужно. Ушла без ответа — `close --reason`, и строка уезжает в `REJECTED.md`. ## Что видит машина, а что человек -`check` и `sprint take` смотрят на **наличие непустых** разделов `Вопрос` и +`check` и `ready` смотрят на **наличие непустых** разделов `Вопрос` и `Куда ляжет ответ`, считают сырьё отдельной строкой здоровья и держат его в конце секции. Годность вопроса — человеку: «вопрос это или тема» машина не различает, и `check` о годности молчит намеренно. diff --git a/av-dev-tasks/skills/tasks/scripts/tasks.py b/av-dev-tasks/skills/tasks/scripts/tasks.py index 535a1ff..24d3250 100755 --- a/av-dev-tasks/skills/tasks/scripts/tasks.py +++ b/av-dev-tasks/skills/tasks/scripts/tasks.py @@ -3012,7 +3012,7 @@ def cmd_adopt_apply(a: argparse.Namespace) -> int: print(f" задач, не собравших разделы своего типа: {len(unfit)} —" f" check это ошибкой не считает, но `ready` их не пропустит:" f" брать сегодня физически нечего") - print(f" закрывается порциями переоценки по 5–8 задач (скилл session, шаг 3):" + print(f" закрывается порциями груминга по 5–8 задач (скилл groom):" f" проставить цели, превратить «готово, когда» в критерии с оракулами," f" вынуть вопросы из прозы в раздел. Готовность к первой задаче —" f" не «check зелёный», а «есть {CRITERIA_MIN}+ критериев хотя бы у набора"