скилл tasks: приоритет стал порядком строк в беклоге
Правило 4 переписано целиком. Было «порядка нет, есть цель», и обосновано это было тем, что на «что делать дальше» отвечает набор спринта. Набора нет — вопрос остался, отвечать нечем. Приоритет — свойство очереди, а не задачи, поэтому его дом индекс: то же исключение из правила 2, что и «в каком индексе лежит запись». Положи его в файл числом — два соседних файла смогли бы утверждать одно место, а строка индекса противоречить обоим. Цель и приоритет — независимые оси: очередь может идти поперёк целей. Расстановка — это move --after и move --first, и только они: руками поправленная строка не оставляет причины. Место сырья в конце секции из очереди изъято: оно производно от типа и заполненности, его назначает машина, приоритетом оно не становится. Схема состояний потеряла SPRINT.md и четыре перехода; шесть уставов типов, task-format, split, from-review и adopt переведены со «взятия в спринт» на ready.
This commit is contained in:
@@ -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/ задачи и цели файлами, <slug>.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`, а этот даёт ему операции.
|
||||
Не решает за пользователя, что важно. Не
|
||||
переоформляет существующие задачи «заодно»: правится то, чего касается операция.
|
||||
|
||||
Reference in New Issue
Block a user