канон 4: тип записи стал единственной осью и задаёт схему
Осей было две — тип записи (goal/idea/task) и род работы (kind:<род> тегом), — и ортогональность у них была фальшивой: из двенадцати клеток произведения законны шесть. У цели род запрещён, у задачи обязателен, у идеи пуст и на практике не ставится. Плюс «алгоритм работы над записью такого типа» крепится не к task, а к fix и research, то есть к роду: ось, к которой пишется алгоритм, и была настоящим типом. Схлопнуто в одну ось из пяти значений: goal | feature | fix | chore | research. Тип idea упразднён отдельно и по другой причине: он значил не род работы, а незаполненность, а состояние типом быть не может — оно меняется по мере того, как запись дописывают, а тип меняют командой. Теперь состояние выводится из заполненности: research без раздела «Вопрос» это сырьё. В спринт не берётся, как и прежняя идея, лежит в конце категории, отбирается list --raw. Дом типа — поле меты «Тип» первой строкой, эмодзи в H1 производна. Прежнее «отдельного поля типа нет: два места для одного факта разъезжаются» отменено собственным аргументом: он был против префикса плюс поля, а при переносе дома место остаётся одно. Эмодзи стоит в H1, а не в строке индекса, чтобы инвариант «заголовок в индексе дословно» остался нетронутым. Поле места названо по типу: «Секция» у цели (часть роадмапа, состояние очереди), «Категория» у задачи (полка домена, куда её вернёт sprint drop). Одинаковое переименование закрепило бы конфляцию; какое поле обязательно, решает тип — то самое, ради чего затевалась правка. Два новых обязательных раздела выросли из правил, которые были записаны и которые нечем было проверить. «Не воспроизводится — это research, а не fix» стояло в каноне: теперь есть раздел «Воспроизведение». Приёмка разведки — «записанный ответ, а не изменённый код» — тоже стояла, но sprint take требовал от research два-пять критериев с оракулами, и они писались ради проверки; вместо них «Вопрос» и «Куда ляжет ответ». Сортировка «по важности» из заметок не взята: она требует, чтобы кто-то важность поддерживал, а это приоритет, от которого отказалось правило 4. Взято только «сырьё в конец категории» — этот порядок выводится из типа и заполненности, а не назначается человеком, и потому проверяется машиной. TYPE_SCHEMA кормит и body_template, и schema_verdict: иначе add кладёт то, на чём sprint take потом откажет. check --fix мигрирует за один проход — kind:/[goal]/[idea] в поле «Тип», эмодзи в заголовок, «Секция» → «Категория», сырьё в конец. Тип, которого неоткуда взять, не угадывается: feature от chore машина не отличает, такие записи уходят в НЕОДНОЗНАЧНО поимённо. Попутно закрыт класс отказов в --fix: шагов, правящих мету, стало пять, и второй, перечитавший файл с диска, стирал правку первого. Общий stage() поверх отложенных правок; до этого корректность держалась на том, что шагов было мало. Устав на тип отдельным файлом — references/task-<тип>.md, пять штук: схема, алгоритм, что видит машина и что человек. Агент task-form получил правило «тип сходится с тем, что в записи написано» с проверяемыми расхождениями. Обкатано на демо-наборе из 13 записей: миграция за один проход, второй прогон даёт ноль починок; fix без «Воспроизведения» и сырьё в спринт не идут, годная feature берётся. DECISIONS тема 27 (ААББ–ЛЛММ, следствия 101–104). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+153
-114
@@ -1,19 +1,19 @@
|
||||
---
|
||||
name: tasks
|
||||
description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). Заведение задачи, идеи или цели из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, мозговой штурм идеи, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Ритуал между спринтами — скилл session. Не реализует задачи — этим занимается пайплайн проекта.
|
||||
description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). У каждой записи есть тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение записи из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, штурм сырья, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Ритуал между спринтами — скилл session. Не реализует задачи — этим занимается пайплайн проекта.
|
||||
---
|
||||
|
||||
# Задачи
|
||||
|
||||
Задачи — каталог markdown-файлов. Одна запись = один файл `items/<slug>.md` плюс
|
||||
строка **ровно в одном** индексе. Скилл владеет **форматом и содержимым**:
|
||||
заводит, редактирует, закрывает, разбирает находки ревью, дробит, штурмует идеи.
|
||||
заводит, редактирует, закрывает, разбирает находки ревью, дробит, штурмует сырьё.
|
||||
|
||||
Чем он **не** владеет: ритуалом между спринтами (разбор вопросов → разбор
|
||||
прошедшего спринта → переоценка → выбор цели и набор) — это скилл `session`; и
|
||||
выполнением задачи — это пайплайн проекта.
|
||||
|
||||
## Пять правил, из которых всё следует
|
||||
## Шесть правил, из которых всё следует
|
||||
|
||||
Ситуация не покрыта инструкцией — решай по ним.
|
||||
|
||||
@@ -43,10 +43,20 @@ description: Ведение задач и целей как каталога mar
|
||||
4. **Порядка нет, есть цель — но цель есть не у всякой задачи.** Приоритетов,
|
||||
«повысить» и «встать раньше» нет: «что делать дальше» отвечает набор спринта,
|
||||
а между спринтами порядок не нужен никому. Цель обязательна там, где она и
|
||||
есть содержание работы, — у **новой возможности** (`kind:feature`). Починка,
|
||||
есть содержание работы, — у **новой возможности** (`feature`). Починка,
|
||||
техдолг и разведка служат работоспособности, а не направлению, и живут без
|
||||
цели законно; в набор спринта они входят помимо его цели. Придуманная им цель
|
||||
— то же враньё, от которого спасает род работы.
|
||||
— то же враньё, от которого спасает тип.
|
||||
|
||||
Единственный порядок, который в беклоге всё-таки есть, **производен от типа**,
|
||||
а не назначен человеком: **сырьё** (`research` без раздела «Вопрос») стоит в
|
||||
конце своей категории. Его не берут, и между берущимся оно каждый раз требует
|
||||
открыть файл, чтобы это понять. Раз порядок выводится, его проверяет машина —
|
||||
и приоритетом он не становится.
|
||||
5. **Тип решает, что с записью можно делать.** Тип — единственная ось и первое
|
||||
поле меты: от него зависят обязательные разделы тела, нужна ли цель, берётся
|
||||
ли запись в спринт и в каком индексе живёт её строка. Словарь закрыт; ни один
|
||||
тип не подошёл — значит, в записи их два, и её надо разделить.
|
||||
|
||||
## Раскладка
|
||||
|
||||
@@ -82,10 +92,12 @@ docs/tasks/
|
||||
открывают чаще всего, — что делается сейчас и что дальше. Порядок проверяет
|
||||
`check`, переставляет `check --fix`.
|
||||
|
||||
**Секции роадмапа канонические, секции беклога — нет**, и разница не в любви к
|
||||
**Секции роадмапа канонические, категории беклога — нет**, и разница не в любви к
|
||||
единообразию. У каждой секции роадмапа свой смысл, в достигнутое пишет сам `close`, и
|
||||
роадмап, названный по-своему, читался бы только своим автором. Секции беклога
|
||||
(`Ядро`, `Инфра`) смысла не несут — это полки, и остаются делом проекта.
|
||||
роадмап, названный по-своему, читался бы только своим автором. Категории беклога
|
||||
(`Ядро`, `Инфра`) смысла не несут — это полки домена, и остаются делом проекта.
|
||||
Отсюда и разные имена поля меты: у цели **Секция** (часть роадмапа — состояние
|
||||
очереди), у задачи **Категория** (полка, в которую она вернётся из спринта).
|
||||
|
||||
Отсюда четыре правила, которые проверяет `tasks.py check`: **состав закреплён**
|
||||
(чужая секция — ошибка, а не вольность), **все четыре обязаны быть** (нет
|
||||
@@ -93,7 +105,7 @@ docs/tasks/
|
||||
канонический**. `--roadmap-sections` у `init` нет: выбирать нечего.
|
||||
|
||||
**Заголовок секции отбит пустой строкой с обеих сторон и написан с прописной.**
|
||||
Во всех индексах одинаково, включая секции беклога, которые проект называет сам.
|
||||
Во всех индексах одинаково, включая категории беклога, которые проект называет сам.
|
||||
Написание канонических секций правит `check --fix` (заодно и ссылку на секцию в
|
||||
мете файлов: имя секции принадлежит заголовку индекса, файл на неё только
|
||||
ссылается); отбивку и порядок он правит везде.
|
||||
@@ -143,10 +155,10 @@ stateDiagram-v2
|
||||
state "записи нет — реализована" as D
|
||||
state "ROADMAP.md, «умеет» — цель достигнута" as A
|
||||
|
||||
[*] --> B: add
|
||||
[*] --> B: add --type feature|fix|chore|research
|
||||
[*] --> P: add --type goal
|
||||
B --> P: edit --type goal --section
|
||||
P --> B: edit --type task --section
|
||||
P --> B: edit --type feature|fix|chore|research --section
|
||||
B --> S: sprint take
|
||||
S --> B: sprint drop --reason
|
||||
S --> D: close --implemented
|
||||
@@ -169,7 +181,7 @@ stateDiagram-v2
|
||||
|
||||
## Цели
|
||||
|
||||
**Цель — возможность приложения.** Такой же файл в `items/`, тип `[goal]`,
|
||||
**Цель — возможность приложения.** Такой же файл в `items/`, тип `goal` (🎯),
|
||||
перечисленный в `ROADMAP.md`. Формулируется ответом на вопрос **«что приложение
|
||||
будет уметь»**, а не названием области работ: не «Работа с чтением», а «Чтение
|
||||
данных клиентами»; не «Рефакторинг слияния», а «Исход слияния не зависит от
|
||||
@@ -226,52 +238,51 @@ stateDiagram-v2
|
||||
проектов. Встретился в чужом беклоге — это цель либо набор задач, и `check`
|
||||
назовёт его неизвестным типом.
|
||||
|
||||
## Род работы
|
||||
## Тип записи
|
||||
|
||||
**Тип записи и род работы — две оси, и путать их нельзя.** Тип отвечает «что это
|
||||
за запись» (цель, идея, задача), род — «какого рода работа»: `feature`, `fix`,
|
||||
`chore`, `research`. Одним значением на оба вопроса не ответить: идея бывает
|
||||
*про* функцию, а цель функцией *и является*.
|
||||
**Тип — единственная ось, и он решает, что с записью можно делать.** Дом типа —
|
||||
**поле меты `Тип` первой строкой**; эмодзи в заголовке H1 от него производна, её
|
||||
ставит `add` и чинит `check --fix`.
|
||||
|
||||
- **`feature`** — снаружи появляется или меняется то, чего раньше не было.
|
||||
- **`fix`** — поведение расходится с заявленным, и расхождение воспроизводится.
|
||||
Не воспроизводится — это `research`, а не `fix`.
|
||||
- **`chore`** — обслуживание: зависимости, сборка, перенос, чистка. Наблюдаемое
|
||||
поведение не меняется, и в этом всё дело: **у `chore` тест готовности слабее
|
||||
честно**, а не молча. «Что станет наблюдаемо иначе» здесь отвечается
|
||||
разработчику («перестанет собираться два раза», «уедет последний вызов
|
||||
устаревшего API»), а не пользователю. Пока рода не было, такие задачи либо не
|
||||
заводились, либо формулировались как выдуманная польза.
|
||||
- **`research`** — исход работы знание, а не изменение системы: ответ на вопрос,
|
||||
замер, разведка. Приёмка — записанный ответ (`docs/research/`, ADR, тело
|
||||
задачи), а не изменённый код.
|
||||
| Тип | Обязательные разделы | Цель | В спринт | Устав |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 🎯 `goal` | `Завершение` | — | нет | [task-goal.md](references/task-goal.md) |
|
||||
| ✨ `feature` | `Затрагивает`, `Критерии приёмки` | **обязательна** | да | [task-feature.md](references/task-feature.md) |
|
||||
| 🐞 `fix` | `Воспроизведение`, `Затрагивает`, `Критерии приёмки` | необязательна | да | [task-fix.md](references/task-fix.md) |
|
||||
| 🧹 `chore` | `Затрагивает`, `Критерии приёмки` | нет | да | [task-chore.md](references/task-chore.md) |
|
||||
| 🔬 `research` | `Вопрос`, `Куда ляжет ответ` | нет | да | [task-research.md](references/task-research.md) |
|
||||
|
||||
Дом рода — **тег `kind:<род>`**, а не префикс заголовка и не поле меты: теги
|
||||
здесь единственный механизм разметки, и `list --kind fix` работает даром. Цена
|
||||
известна: в строку индекса род не попадает (индексы производны), и «в наборе одни
|
||||
починки» видно командой, а не глазами по `SPRINT.md`.
|
||||
Сверх обязательных у любой задачи допустимы `Рамки` и `Вопросы`. Раздел не из
|
||||
схемы своего типа — **замечание, а не ошибка**: свой раздел законная вольность
|
||||
проекта, но `Воспроизведение` у `chore` почти всегда значит, что тип проставлен
|
||||
не тот, и сказать об этом стоит, не запрещая.
|
||||
|
||||
**Осей было две, и ортогональность у них была фальшивой.** Тип записи
|
||||
(`goal`/`idea`/`task`) и род работы (`kind:<род>` тегом) давали двенадцать клеток
|
||||
произведения, из которых законны были шесть: у цели род запрещён, у задачи
|
||||
обязателен, у идеи пуст. Плюс алгоритм работы крепится не к `task`, а к `fix` и
|
||||
`research` — то есть к роду. Оси схлопнуты, тег `kind:` упразднён.
|
||||
|
||||
**Тип `idea` упразднён вместе с ними.** Он значил не род работы, а **состояние
|
||||
незаполненности** — «первый, второй или третий вопрос теста готовности не
|
||||
отвечается», — а состояние типом быть не может: оно меняется по мере того, как
|
||||
запись дописывают, а тип меняют командой. Теперь это состояние называется честно:
|
||||
`research` без раздела «Вопрос» — **сырьё**. В спринт не берётся ровно как
|
||||
прежняя идея, лежит в конце своей категории и отбирается `list --raw`.
|
||||
|
||||
Словарь **закрыт**. Открытый разъедется на синонимах — `bug`, `bugfix`, `fix`,
|
||||
`defect`, — и отбор по роду перестанет отвечать на свой единственный вопрос. Ни
|
||||
один род не подходит — это сигнал, что в задаче их два и её надо разделить.
|
||||
`defect`, — и отбор по типу перестанет отвечать на свой единственный вопрос. Ни
|
||||
один тип не подходит — это сигнал, что в задаче их два и её надо разделить.
|
||||
|
||||
**Род обязателен у задачи, у цели запрещён, у идеи необязателен** — идея получает
|
||||
его, когда становится задачей. Требуется он там, где по нему принимают решение:
|
||||
`sprint take` без рода откажет. `check` о пропаже только **напоминает** — беклог,
|
||||
заведённый до появления рода, законен, и переоформлять его «заодно» здесь не
|
||||
просят.
|
||||
**Требуется тип там, где по нему принимают решение:** `sprint take` без типа
|
||||
откажет, потому что не знает, каких разделов требовать. `check` о пропаже только
|
||||
**напоминает** — беклог, заведённый до появления типа, законен, и переоформлять
|
||||
его «заодно» здесь не просят.
|
||||
|
||||
**Род решает и то, обязательна ли цель.** `feature` без цели не бывает: новая
|
||||
возможность и есть содержание цели, и если подходящей нет — либо она заводится,
|
||||
либо это не `feature`. `fix`, `chore` и `research` живут без цели законно, и
|
||||
`check` о них молчит: они служат работоспособности, а не направлению. Это
|
||||
единственный случай, когда род что-то определяет за пределами отбора, — и
|
||||
определяет он учёт, а не процесс проверки.
|
||||
|
||||
**Род не выбирает профиль ревью и вообще ничего не предписывает пайплайну.**
|
||||
Профиль выбирается по факту изменения, а не по роду задачи: `chore` бывает
|
||||
**Тип не выбирает профиль ревью и вообще ничего не предписывает пайплайну.**
|
||||
Профиль выбирается по факту изменения, а не по типу задачи: `chore` бывает
|
||||
миграцией схемы, `fix` — правкой публичного контракта. Правило «предписание
|
||||
процесса в теле задачи снимается» родом не отменяется, а подтверждается: он
|
||||
процесса в теле задачи снимается» типом не отменяется, а подтверждается: он
|
||||
описывает работу, а не то, как её проверять.
|
||||
|
||||
## Как написана задача
|
||||
@@ -283,17 +294,18 @@ stateDiagram-v2
|
||||
|
||||
| Тип | Отвечает на | Пример |
|
||||
| --- | --- | --- |
|
||||
| цель | что приложение будет уметь | Соперником может быть компьютер |
|
||||
| задача | что нужно сделать | Печатать поле одним куском кода |
|
||||
| идея | о чём она | Подсказка следующего хода |
|
||||
| 🎯 `goal` | что приложение будет уметь | Соперником может быть компьютер |
|
||||
| ✨ `feature`, 🐞 `fix`, 🧹 `chore` | что нужно сделать | Печатать поле одним куском кода |
|
||||
| 🔬 `research` | о чём разведка | Подсказка следующего хода |
|
||||
|
||||
Задача — **глаголом в неопределённой форме**, перед ним допускается «не»: «Не
|
||||
отбрасывать молча лишние символы в ходе», а не «Лишние символы молча
|
||||
отбрасываются». Описательный заголовок называет **состояние**, а из состояния не
|
||||
видно, чего от работы ждут: «Ничья объявляется, пока клетки есть» одинаково
|
||||
читается и как жалоба, и как задание, — и в списке, где решают «брать или не
|
||||
брать», это разные вещи. Идея формы действия не несёт **намеренно**: что делать,
|
||||
ещё неизвестно, и заголовок-действие обещал бы решённость, которой нет.
|
||||
брать», это разные вещи. `research` формы действия не несёт **намеренно**: её
|
||||
исход знание, что делать — ещё неизвестно, и заголовок-действие обещал бы
|
||||
решённость, которой нет.
|
||||
|
||||
Из этого же правила растёт разница индексов: роадмап — список возможностей,
|
||||
беклог — список работ, и если заголовки перепутать формами, каждый из них
|
||||
@@ -336,7 +348,7 @@ stateDiagram-v2
|
||||
|
||||
И одно требование, которое есть только у задачи: **сложность формулировки — не
|
||||
признак сложности работы.** Задачу, которую не удаётся сказать просто, чаще
|
||||
всего не удаётся и оценить: это либо две задачи, либо идея.
|
||||
всего не удаётся и оценить: это либо две задачи, либо сырьё.
|
||||
|
||||
Эти правила — про **язык**, а не про объём: короткая задача без границ хуже
|
||||
длинной с ними.
|
||||
@@ -349,10 +361,10 @@ stateDiagram-v2
|
||||
|
||||
```
|
||||
python3 $tk check --dir D # согласованность индексов + здоровье
|
||||
python3 $tk check --dir D --fix # + починить дрейф (секция, заголовок, дубли, «зачем», форма меты)
|
||||
python3 $tk list --dir D [--stale] [--section S] [--type T] [--kind K] [--tag a,b] [--goal S] [--index …] [--questions]
|
||||
python3 $tk add --dir D --slug S --title T [--type goal|idea] [--section S] [--goal G] [--kind K] [--why «зачем»] [--tag a,b]
|
||||
python3 $tk edit S --dir D [--title T] [--why «зачем»] [--type T] [--goal G] [--kind K] [--add-tag a,b] [--rm-tag c]
|
||||
python3 $tk check --dir D --fix # + починить дрейф (тип, эмодзи, место, заголовок, дубли, «зачем», форма меты)
|
||||
python3 $tk list --dir D [--stale] [--section S] [--type T] [--tag a,b] [--goal S] [--raw] [--index …] [--questions]
|
||||
python3 $tk add --dir D --slug S --title T --type goal|feature|fix|chore|research [--section S] [--goal G] [--why «зачем»] [--tag a,b]
|
||||
python3 $tk edit S --dir D [--title T] [--why «зачем»] [--type T] [--goal G] [--add-tag a,b] [--rm-tag c]
|
||||
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 # просто удалить (реализована и закоммичена)
|
||||
@@ -375,20 +387,22 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
Различать 1 и 3 обязательно: «дрейф в беклоге» — рабочая ситуация, «каталога
|
||||
нет» — нерабочая, и одинаковая реакция на них была бы неверна в обоих случаях.
|
||||
|
||||
Тип — английское ключевое слово `goal` / `idea` / `task` (как и прочие токены
|
||||
команд); `task` префикса не несёт, остальные кодируются `[goal]`/`[idea]` в
|
||||
заголовке. Текст задачи при этом русский.
|
||||
Тип — английское ключевое слово `goal` / `feature` / `fix` / `chore` /
|
||||
`research` (как и прочие токены команд), у `add` **обязательное**: без него
|
||||
неизвестно, какой шаблон тела класть. Текст задачи при этом русский, а эмодзи в
|
||||
заголовке ставит скрипт.
|
||||
|
||||
**Мутации правят файл и индексы заодно** — руками строку индекса или мету
|
||||
не пиши, зови `add`/`edit`/`move`/`close`/`sprint`. Смена заголовка, «зачем», типа,
|
||||
цели, рода работы и **тегов** — это `edit`: он держит H1, мету и индекс в синхроне.
|
||||
Снятие тега — `--rm-tag` (после ответа на вопрос снимается `question`), смена
|
||||
цели — `--goal`, рода — `--kind`; оба заменяют прежнее значение, а не добавляют
|
||||
второе.
|
||||
цели и **тегов** — это `edit`: он держит H1 (вместе с эмодзи), мету и индекс в
|
||||
синхроне. Снятие тега — `--rm-tag` (после ответа на вопрос снимается
|
||||
`question`), смена цели — `--goal`, типа — `--type`; оба заменяют прежнее
|
||||
значение, а не добавляют второе.
|
||||
|
||||
**Переезд между индексами — следствие смены типа, а не отдельная команда.**
|
||||
`edit <slug> --type goal --section <часть роадмапа>` переносит строку из
|
||||
`BACKLOG.md` в `ROADMAP.md` (и обратно `--type task --section <секция беклога>`);
|
||||
`BACKLOG.md` в `ROADMAP.md` (и обратно — задачным типом плюс
|
||||
`--section <категория беклога>`);
|
||||
`move` двигает только внутри одного индекса и пишет причину. `--section` у
|
||||
`edit` работает **только** при таком переезде — иначе он отсылает к `move`,
|
||||
потому что смена секции без причины и есть тот дрейф, который потом никто не
|
||||
@@ -401,39 +415,54 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
`check` — единственный судья согласованности; что именно он ловит, скажет его
|
||||
вывод, здесь не пересказываем. Гоняй его **в начале сессии** и **после каждой
|
||||
правки**, даже если правил мутациями: дрейф мог накопиться раньше. Накопившееся
|
||||
чини `check --fix` — он детерминированно правит то, где истина однозначна
|
||||
(секция, заголовок, дубли, «зачем» из индекса в файл, старая форма меты,
|
||||
пометка `decomposed` у цели с задачами), а неоднозначное (задача сразу в двух
|
||||
индексах, нечего восстанавливать) печатает отдельной пометкой `НЕОДНОЗНАЧНО` —
|
||||
это тебе, и это идёт строкой доклада. **Ссылка на исчезнувший файл в пометку не
|
||||
попадает:** `--fix` её просто не трогает, и она остаётся `ОШИБКА` обычного
|
||||
`check` — то есть видна, но в докладе её надо назвать отдельно.
|
||||
чини `check --fix` — он детерминированно правит то, где истина однозначна (тип в
|
||||
своё поле, эмодзи заголовка, имя поля места, секция, заголовок, дубли, «зачем» из
|
||||
индекса в файл, старая форма меты, пометка `decomposed` у цели с задачами, сырьё
|
||||
в конец категории), а неоднозначное (задача сразу в двух индексах, нечего
|
||||
восстанавливать, **тип, которого неоткуда взять**) печатает отдельной пометкой
|
||||
`НЕОДНОЗНАЧНО` — это тебе, и это идёт строкой доклада. **Ссылка на исчезнувший
|
||||
файл в пометку не попадает:** `--fix` её просто не трогает, и она остаётся
|
||||
`ОШИБКА` обычного `check` — то есть видна, но в докладе её надо назвать отдельно.
|
||||
|
||||
`--fix` правит **и файлы** — ровно в двух местах, где источник ровно один и
|
||||
выбирать не из чего: «зачем», оставшееся только в индексе, переезжает в мету,
|
||||
и цель, у которой есть задачи, получает тег `decomposed`. Оба случая печатаются
|
||||
поимённо.
|
||||
`--fix` правит **и файлы** — там, где источник ровно один и выбирать не из чего:
|
||||
тип переезжает из прежнего дома (тег `kind:`, префикс `[goal]`/`[idea]`) в поле
|
||||
меты, заголовок получает эмодзи, поле места — имя по типу, «зачем», оставшееся
|
||||
только в индексе, переезжает в мету, цель с задачами получает `decomposed`.
|
||||
Каждый случай печатается поимённо.
|
||||
|
||||
**Тип, который не выводится ниоткуда, `--fix` не угадывает.** `feature` от
|
||||
`chore` машина не отличает, и подставленное наугад значение врало бы ровно там,
|
||||
где по нему принимают решение. Такие записи идут в `НЕОДНОЗНАЧНО`, и тип им
|
||||
проставляет человек — `edit <слаг> --type …`.
|
||||
|
||||
**Что механизировано, а что нет.** У задачи, взятой в набор (`sprint take` и
|
||||
`check` по задачам спринта), проверяются три вещи, и у каждой своя глубина:
|
||||
`check` по задачам спринта), проверяется схема её типа, и у каждой части своя
|
||||
глубина:
|
||||
|
||||
- **критерии приёмки** — число пунктов жёстко (меньше двух отказ, больше пяти
|
||||
замечание), наличие оракула **эвристикой** по слову «оракул» в пункте;
|
||||
- **род работы** — жёстко: назван и из закрытого словаря;
|
||||
- **раздел «Затрагивает»** — только **наличие непустого**. Полнота перечня машине
|
||||
не видна: границу, которую забыли назвать, она от отсутствующей не отличает.
|
||||
- **тип** — жёстко: назван и из закрытого словаря;
|
||||
- **критерии приёмки** (`feature`, `fix`, `chore`) — число пунктов жёстко
|
||||
(меньше двух отказ, больше пяти замечание), наличие оракула **эвристикой** по
|
||||
слову «оракул» в пункте;
|
||||
- **прочие разделы схемы** (`Затрагивает`, `Воспроизведение`, `Вопрос`,
|
||||
`Куда ляжет ответ`, `Завершение`) — только **наличие непустого**. Содержимое
|
||||
машине не видно: границу, которую забыли назвать, она от отсутствующей не
|
||||
отличает, а шаги, по которым ничего не воспроизводится, — от годных.
|
||||
|
||||
Настоящий оракул от слова «оракул» машина тоже не отличает, поэтому эвристика
|
||||
даёт только замечание, и в докладе это называется как есть: «проверено число
|
||||
пунктов и наличие границ, годность оракулов и полнота границ — глазами».
|
||||
даёт только замечание, и в докладе это называется как есть: «проверено наличие
|
||||
разделов своего типа и число критериев, годность оракулов и полнота границ —
|
||||
глазами».
|
||||
|
||||
Формат файла, меты, слага, индексов и `REJECTED.md` —
|
||||
[references/task-format.md](references/task-format.md). Там же тест «готова к
|
||||
взятию», требования к критериям приёмки и раздел «Затрагивает».
|
||||
Формат записи, меты, слага, индексов и `REJECTED.md` —
|
||||
[references/task-format.md](references/task-format.md); там же тест «готова к
|
||||
взятию». Схема и алгоритм каждого типа — по файлу на тип:
|
||||
[goal](references/task-goal.md) · [feature](references/task-feature.md) ·
|
||||
[fix](references/task-fix.md) · [chore](references/task-chore.md) ·
|
||||
[research](references/task-research.md).
|
||||
|
||||
## Сценарии
|
||||
|
||||
### Завести задачу, идею или цель из диалога
|
||||
### Завести запись из диалога
|
||||
|
||||
1. **Фильтр.** Делаем прямо сейчас — не заводим. Не пожалеем о потере — не
|
||||
заводим. Родилось три кандидата — покажи их и спроси, какие заводить: молча
|
||||
@@ -444,30 +473,36 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
ту строку и что изменилось с момента отказа (`add` предупредит и сам, но
|
||||
молча заводить нельзя). Две задачи об одном — самая дорогая находка
|
||||
переоценки.
|
||||
3. **Тип по тесту готовности** (см. task-format): проходит — задача, не
|
||||
проходит — идея (`--type idea`). Не делается одним заходом — это не эпик, а
|
||||
несколько задач под одной целью: дроби сразу. Возможность приложения, а не
|
||||
шаг — цель (`--type goal`).
|
||||
4. **Цель задачи — если род её требует.** У `feature` должен быть
|
||||
`--goal <слаг>`: новая возможность и есть содержание цели. Подходящей нет —
|
||||
либо она заводится (`--type goal`), либо перед тобой не `feature`. У `fix`,
|
||||
`chore` и `research` цели может не быть вовсе, и придумывать её не надо. У
|
||||
идеи цель проставляется, когда идея становится задачей.
|
||||
5. **Род работы** — `--kind feature|fix|chore|research` (см. «Род работы»). Не
|
||||
подходит ни один — задача не одна, разбирай.
|
||||
6. `add …`, затем допиши тело редактором: одна фраза, **затрагиваемые границы**,
|
||||
критерии приёмки с оракулами, рамки. «Зачем» отвечает «зачем нужна эта
|
||||
задача» — состояние, остаток, боль, — а не пересказывает первый абзац, и
|
||||
пишется **для человека**: не «канонизация внутри транзакции», а «тело 40 МиБ
|
||||
держит блокировку 5 секунд, соседние доставки уходят в отказ».
|
||||
7. `check`.
|
||||
3. **Тип** — `--type` обязателен, и он же первое содержательное решение:
|
||||
|
||||
- возможность приложения, а не шаг к ней → `goal`;
|
||||
- снаружи появляется то, чего не было → `feature`;
|
||||
- поведение расходится с заявленным и **воспроизводится** → `fix`
|
||||
(не воспроизводится → `research`);
|
||||
- обслуживание, наблюдаемое поведение не меняется → `chore`;
|
||||
- исход — знание, а не изменение системы → `research`.
|
||||
|
||||
Не подходит ни один — в записи их два, разбирай. Не проходит тест готовности
|
||||
(см. task-format) — это **сырьё**: `--type research`, раздел «Вопрос» пока
|
||||
пуст, место в конце категории. Не делается одним заходом — это не эпик, а
|
||||
несколько задач под одной целью: дроби сразу.
|
||||
4. **Цель — если тип её требует.** У `feature` должен быть `--goal <слаг>`:
|
||||
новая возможность и есть содержание цели. Подходящей нет — либо она
|
||||
заводится (`--type goal`), либо перед тобой не `feature`. У `fix`, `chore` и
|
||||
`research` цели может не быть вовсе, и придумывать её не надо.
|
||||
5. `add …`, затем допиши тело редактором **по схеме своего типа** — шаблон её
|
||||
уже разложил, устав типа объясняет каждый раздел. «Зачем» отвечает «зачем
|
||||
нужна эта задача» — состояние, остаток, боль, — а не пересказывает первый
|
||||
абзац, и пишется **для человека**: не «канонизация внутри транзакции», а
|
||||
«тело 40 МиБ держит блокировку 5 секунд, соседние доставки уходят в отказ».
|
||||
6. `check`.
|
||||
|
||||
### Разобрать находки аудита или ревью
|
||||
|
||||
Ревью и аудиты — тоже источник задач, но с зеркальной диалогу опасностью: не
|
||||
пять файлов из одной мысли, а сорок файлов из сорока сырых находок. Защита та
|
||||
же, что в самом ревью: кластеризация по причине, дедуп против живых и
|
||||
`REJECTED.md`, находка без свидетельства → идея, а не задача, и карта кластеров
|
||||
`REJECTED.md`, находка без свидетельства → сырьё (`research`), а не задача, и карта кластеров
|
||||
пользователю до создания файлов. Порядок, отображение серьёзности и привязка к
|
||||
целям — [references/from-review.md](references/from-review.md).
|
||||
|
||||
@@ -481,7 +516,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
Если переводить надо не только задачи, а весь `docs/` — это скилл
|
||||
`av-dev-pm:canon`, и он зовёт этот сценарий сам на своём шаге.
|
||||
|
||||
### Декомпозиция и штурм идеи
|
||||
### Декомпозиция и штурм сырья
|
||||
|
||||
[references/split.md](references/split.md). Обе операции превращают одну запись в
|
||||
несколько, и у обеих есть проверяемый тест: части должны **мерджиться порознь** и
|
||||
@@ -551,10 +586,14 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
- **предписание процесса в теле** — «делать таким-то профилем ревью», «взять
|
||||
такой-то агент»: это второй дом для правила выбора и путь понизить требования
|
||||
решением, принятым до проектирования. Снимается;
|
||||
- **род, разошедшийся с задачей** — задача заводилась починкой, а после разбора
|
||||
- **тип, разошедшийся с задачей** — задача заводилась починкой, а после разбора
|
||||
оказалось, что поведение никогда и не было заявлено: это `feature`, а не `fix`.
|
||||
Правится `edit <slug> --kind …`; род, оставшийся от прошлой формулировки, врёт
|
||||
ровно там, где по нему отбирают;
|
||||
Правится `edit <slug> --type …`; тип, оставшийся от прошлой формулировки, врёт
|
||||
ровно там, где по нему отбирают, **и требует не тех разделов**: у брошенного
|
||||
`fix` останется «Воспроизведение», которого нечем заполнить;
|
||||
- **сырьё, у которого появился вопрос** — разведка обросла формулировкой, но
|
||||
раздел «Вопрос» так и пуст: она числится сырьём и в спринт не берётся.
|
||||
Записывается вопрос, и `check --fix` поднимает строку из конца категории;
|
||||
- **границы, названные вместо реализации** — «переписать хранилище на новый
|
||||
драйвер» в разделе «Затрагивает» это не граница, а замысел. Границы —
|
||||
`таблица points и её миграция`, `эндпоинт POST /ingest`, `формат отпечатка на
|
||||
@@ -619,7 +658,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
|
||||
- **Развилки — пользователю.** Через `AskUserQuestion`, с уже сформулированным
|
||||
предварительным суждением (**рекомендация — первым вариантом**). Что выкинуть,
|
||||
под какую цель отнести, какая рамка идеи верна — решение пользователя. Слаг,
|
||||
под какую цель отнести, какая рамка разведки верна — решение пользователя. Слаг,
|
||||
формулировка, порядок строк в индексе — механика, делаем сами.
|
||||
- **Не больше трёх вопросов за раз.** Пачка длиннее трёх тяжела для ответа;
|
||||
решений больше — веди **несколько итераций** диалога по ≤3, а не один
|
||||
|
||||
Reference in New Issue
Block a user