канон 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:
@@ -1834,3 +1834,84 @@ ADR, запискам разведки и сообщениям коммитов
|
|||||||
100. **Версия канона отделяет состояния проектов, а не редакции текста** — и
|
100. **Версия канона отделяет состояния проектов, а не редакции текста** — и
|
||||||
ровно поэтому её нельзя не поднять, когда состояние хоть одного проекта
|
ровно поэтому её нельзя не поднять, когда состояние хоть одного проекта
|
||||||
уже зафиксировано.
|
уже зафиксировано.
|
||||||
|
|
||||||
|
## 27. Тип записи стал единственной осью и задаёт схему (2026-08-05)
|
||||||
|
|
||||||
|
Заметка просила «каждый тип задач сделать своей сущностью»: эмодзи на тип, тип
|
||||||
|
первым полем меты, категория вместо секции, описание типа с обязательными
|
||||||
|
разделами и алгоритмом, идеи в конец. Разбор показал, что первый шаг обязан быть
|
||||||
|
другим — не добавить типу свойств, а **сократить число осей**.
|
||||||
|
|
||||||
|
**ААББ. Осей было две, и ортогональность была фальшивой.** Тип записи
|
||||||
|
(`goal`/`idea`/`task`) и род работы (`kind:<род>` тегом) давали двенадцать клеток
|
||||||
|
произведения, из которых законны шесть: у цели род запрещён, у задачи обязателен,
|
||||||
|
у идеи пуст и на практике не ставится. Плюс «алгоритм работы над записью такого
|
||||||
|
типа» крепится не к `task`, а к `fix` и `research` — то есть к роду. Ось, к
|
||||||
|
которой пишется алгоритм, и была настоящим типом. Оси схлопнуты в одну из пяти
|
||||||
|
значений: `goal` | `feature` | `fix` | `chore` | `research`.
|
||||||
|
|
||||||
|
**ВВГГ. Тип `idea` упразднён: состояние не может быть типом.** Он значил не род
|
||||||
|
работы, а незаполненность — «первый, второй или третий вопрос теста готовности не
|
||||||
|
отвечается». Состояние меняется по мере того, как запись дописывают, а тип меняют
|
||||||
|
командой, и на этом расхождении `idea` и жила: её приходилось «понижать» и
|
||||||
|
«повышать» вручную. Теперь состояние выводится из заполненности — **`research`
|
||||||
|
без раздела «Вопрос» это сырьё**, — и различие держит та же машина, что и всё
|
||||||
|
остальное.
|
||||||
|
|
||||||
|
Цена решения названа сразу: `research` теперь вбирает и замер реальности, и
|
||||||
|
сырую функцию («Подсказка следующего хода»). Обосновано это тем, что у обоих
|
||||||
|
**один исход — записанный ответ, а не изменение системы**, и одна приёмка. Имя
|
||||||
|
`rnd` из заметки отклонено в пользу `research`: аббревиатура читается как
|
||||||
|
`random` и не расшифровывается тому, кто вернётся к беклогу через квартал, а
|
||||||
|
`research` уже стоял в файлах живых проектов — миграция тронула только бывшие
|
||||||
|
идеи.
|
||||||
|
|
||||||
|
**ДДЕЕ. Дом типа — поле меты, эмодзи производна.** Прежнее правило «отдельного
|
||||||
|
поля типа нет: два места для одного факта разъезжаются» отменено не потому, что
|
||||||
|
разонравилось, а потому, что его аргумент был против **префикса плюс поля**. При
|
||||||
|
переносе дома в мету дом остаётся один; из индекса тип при этом пропадал бы — там,
|
||||||
|
где принимают решение «брать или не брать», — и это чинит эмодзи. Она стоит в H1,
|
||||||
|
а не в строке индекса, чтобы инвариант «заголовок в индексе дословно» остался
|
||||||
|
нетронутым: одна проверка вместо двух.
|
||||||
|
|
||||||
|
**ЖЖЗЗ. Поле места назвали по типу, а не одним словом на всех.** «Категория»
|
||||||
|
вместо «Секции» — просьба заметки, но одинаковое переименование закрепило бы
|
||||||
|
конфляцию: у задачи поле называет полку домена, в которую она вернётся из
|
||||||
|
спринта, у цели — часть роадмапа, то есть состояние очереди. Разные имена
|
||||||
|
(`Категория` / `Секция`) выбраны именно потому, что **какое поле обязательно,
|
||||||
|
решает тип** — то самое, ради чего затевалась вся правка.
|
||||||
|
|
||||||
|
**ИИКК. Два новых обязательных раздела появились из уже записанных правил,
|
||||||
|
которые нечем было проверить.** «Не воспроизводится — это `research`, а не `fix`»
|
||||||
|
стояло в каноне и не проверялось: раздел `Воспроизведение` делает его
|
||||||
|
проверяемым. Приёмка разведки — «записанный ответ, а не изменённый код» — тоже
|
||||||
|
стояла, но `sprint take` требовал от `research` два-пять критериев с оракулами,
|
||||||
|
и они писались ради проверки; вместо них `Вопрос` и `Куда ляжет ответ`.
|
||||||
|
|
||||||
|
**ЛЛММ. Сортировка «по важности» отклонена, «сырьё в конец» взято.** Первая
|
||||||
|
требует, чтобы кто-то важность поддерживал, — это ровно тот приоритет, от
|
||||||
|
которого правило 4 отказалось сознательно. Вторая **выводится из типа и
|
||||||
|
заполненности**, а не назначается человеком, и потому проверяется машиной и
|
||||||
|
приоритетом не становится. Разрез прошёл по признаку «кто источник порядка», а не
|
||||||
|
по признаку «полезно ли».
|
||||||
|
|
||||||
|
### Что из этого следует
|
||||||
|
|
||||||
|
101. **Правило можно отменять его собственным аргументом.** «Отдельного поля типа
|
||||||
|
нет» держалось на «два места для одного факта»; перенос дома оставил одно
|
||||||
|
место, и правило перестало применяться. Проверять надо не запись правила, а
|
||||||
|
то, выполняется ли ещё его посылка.
|
||||||
|
102. **Схема, шаблон и проверка растут из одной таблицы.** `TYPE_SCHEMA` кормит и
|
||||||
|
`body_template`, и `schema_verdict`: иначе `add` кладёт то, на чём
|
||||||
|
`sprint take` потом откажет. Тот же приём, что нормализатор `spaced_sections`
|
||||||
|
для оформления индексов.
|
||||||
|
103. **`--fix` не угадывает того, чего нет.** Тип переносится из тега `kind:` и
|
||||||
|
префикса `[goal]`/`[idea]` детерминированно, но записи, заведённые до
|
||||||
|
появления рода работы, не несут ни того ни другого — `feature` от `chore`
|
||||||
|
машина не отличает. Они уходят в `НЕОДНОЗНАЧНО` поимённо, а не получают
|
||||||
|
значение по умолчанию, которое врало бы ровно там, где по нему принимают
|
||||||
|
решение.
|
||||||
|
104. **Мигрирующие шаги обязаны читать отложенный текст, а не диск.** Шагов,
|
||||||
|
правящих мету, стало пять, и второй, перечитавший файл, стёр бы правку
|
||||||
|
первого. Общий `stage()` поверх `files` снял целый класс отказов, который до
|
||||||
|
этого держался на том, что шагов было мало.
|
||||||
|
|||||||
@@ -191,3 +191,12 @@ jellybit 43. Шаги повышения — [changelog.md](av-dev-pm/skills/can
|
|||||||
`"canon": 4`
|
`"canon": 4`
|
||||||
- [ ] jellybit едет сразу на 4: `Готово` заводить **последней**, секцию
|
- [ ] jellybit едет сразу на 4: `Готово` заводить **последней**, секцию
|
||||||
сопровождения — сразу с новым именем, переставлять дважды не нужно
|
сопровождения — сразу с новым именем, переставлять дважды не нужно
|
||||||
|
- [ ] типы: `check --fix` переведёт `kind:`/`[goal]`/`[idea]` в поле «Тип», снимет
|
||||||
|
тег, поставит эмодзи, переименует «Секция» → «Категория» у задач и снесёт
|
||||||
|
сырьё в конец категорий — **за один проход, вместе с порядком секций**
|
||||||
|
- [ ] разобрать `НЕОДНОЗНАЧНО` после `--fix`: записи без типа (заведены до
|
||||||
|
появления рода работы) машина не угадывает — `edit <слаг> --type …`
|
||||||
|
- [ ] новые обязательные разделы — **не задним числом**: `Воспроизведение` у
|
||||||
|
каждого `fix` и `Вопрос` + `Куда ляжет ответ` у каждого `research` пишутся
|
||||||
|
по мере того, как задача идёт в набор (`sprint take` без них откажет).
|
||||||
|
Сколько записей готово к взятию, печатает блок здоровья `check`
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: task-form
|
name: task-form
|
||||||
description: "Проверка формы записи каталога задач по существу: форма заголовка по типу (цель — что приложение будет уметь, задача — что нужно сделать, идея — о чём она), «зачем», пересказывающее заголовок вместо состояния и боли, раздел «Затрагивает» с замыслом вместо границ, критерий приёмки с оракулом только на словах, предписание процесса в теле, и связь задачи со строкой «Завершения» её цели. Читает файл цели, на которую ссылается задача. Отдаёт готовые формулировки на замену и ничего не правит сам. Язык текста (залог, оценки, стоп-слова, англицизмы) смотрит отдельный агент doc-wording. Использовать после заведения или разбора пачки записей, до взятия в спринт и на переоценке. Только чтение."
|
description: "Проверка формы записи каталога задач по существу: тип, разошедшийся с содержанием записи, форма заголовка по типу (цель — что приложение будет уметь, задача — что нужно сделать, разведка — о чём она), «зачем», пересказывающее заголовок вместо состояния и боли, раздел «Затрагивает» с замыслом вместо границ, критерий приёмки с оракулом только на словах, предписание процесса в теле, и связь задачи со строкой «Завершения» её цели. Читает файл цели, на которую ссылается задача. Отдаёт готовые формулировки на замену и ничего не правит сам. Язык текста (залог, оценки, стоп-слова, англицизмы) смотрит отдельный агент doc-wording. Использовать после заведения или разбора пачки записей, до взятия в спринт и на переоценке. Только чтение."
|
||||||
tools: Read, Grep, Glob
|
tools: Read, Grep, Glob
|
||||||
model: opus
|
model: opus
|
||||||
color: yellow
|
color: yellow
|
||||||
@@ -29,7 +29,7 @@ color: yellow
|
|||||||
|
|
||||||
Список файлов записей (`docs/tasks/items/<slug>.md`) или каталог задач целиком.
|
Список файлов записей (`docs/tasks/items/<slug>.md`) или каталог задач целиком.
|
||||||
Каталог тебе нужен и сам по себе: задача несёт тег `goal:<слаг>`, и **файл цели
|
Каталог тебе нужен и сам по себе: задача несёт тег `goal:<слаг>`, и **файл цели
|
||||||
ты открываешь**, иначе шестое правило не проверить.
|
ты открываешь**, иначе седьмое правило не проверить.
|
||||||
|
|
||||||
Документы проекта — паспорт, архитектура, конвенции — если зовущий их назвал.
|
Документы проекта — паспорт, архитектура, конвенции — если зовущий их назвал.
|
||||||
По ним видно, названа ли граница именем, которое в проекте существует.
|
По ним видно, названа ли граница именем, которое в проекте существует.
|
||||||
@@ -38,11 +38,14 @@ color: yellow
|
|||||||
|
|
||||||
1. **Заголовок отвечает на вопрос своего типа.**
|
1. **Заголовок отвечает на вопрос своего типа.**
|
||||||
|
|
||||||
|
Тип стоит первым полем меты — `- **Тип:** …`, — а в заголовке ему
|
||||||
|
соответствует эмодзи.
|
||||||
|
|
||||||
| Тип | Отвечает на | Форма |
|
| Тип | Отвечает на | Форма |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `[goal]` | что приложение будет уметь | утверждение о возможности: «Соперником может быть компьютер» |
|
| 🎯 `goal` | что приложение будет уметь | утверждение о возможности: «Соперником может быть компьютер» |
|
||||||
| задача | что нужно сделать | глагол в неопределённой форме, допускается «не» перед ним: «Печатать поле одним куском кода» |
|
| ✨ `feature`, 🐞 `fix`, 🧹 `chore` | что нужно сделать | глагол в неопределённой форме, допускается «не» перед ним: «Печатать поле одним куском кода» |
|
||||||
| `[idea]` | о чём она | назывное, без обещания: «Подсказка следующего хода» |
|
| 🔬 `research` | о чём разведка | назывное, без обещания: «Подсказка следующего хода» |
|
||||||
|
|
||||||
Описательный заголовок задачи («Лишние символы молча отбрасываются») называет
|
Описательный заголовок задачи («Лишние символы молча отбрасываются») называет
|
||||||
**состояние** и одинаково читается как жалоба и как задание. Заголовок цели в
|
**состояние** и одинаково читается как жалоба и как задание. Заголовок цели в
|
||||||
@@ -55,12 +58,32 @@ color: yellow
|
|||||||
законная возможность**: «исход слияния не зависит от порядка доставки» — цель,
|
законная возможность**: «исход слияния не зависит от порядка доставки» — цель,
|
||||||
а не абстракция.
|
а не абстракция.
|
||||||
|
|
||||||
2. **«Зачем» отвечает на «зачем нужна эта задача»** — состояние, остаток, боль,
|
2. **Тип сходится с тем, что в записи написано.** Тип — первое поле меты, и он
|
||||||
|
решает, каких разделов запись требует; разошедшийся тип врёт ровно там, где
|
||||||
|
по нему принимают решение. Проверяемые расхождения:
|
||||||
|
|
||||||
|
- **`fix`, у которого нечего воспроизвести**, — расхождение приняли на слово.
|
||||||
|
Либо это `research` («при каких условиях проявляется»), либо `feature`:
|
||||||
|
поведение никогда и не было заявлено, и чинить нечего;
|
||||||
|
- **`feature`, после которой снаружи ничего не меняется**, — это `chore`, и
|
||||||
|
сказать это честно дешевле, чем выдумывать пользовательскую пользу;
|
||||||
|
- **`chore`, меняющий наблюдаемое поведение**, — это `feature` или `fix`, и у
|
||||||
|
них другие требования (цель, воспроизведение);
|
||||||
|
- **`research`, у которого «Вопрос» — это тема, а не вопрос.** «Разобраться с
|
||||||
|
выводом в терминалах» вопросом не является: на него нельзя ответить. Пока
|
||||||
|
вопроса нет, запись остаётся сырьём — и это законное состояние, но назови
|
||||||
|
его.
|
||||||
|
|
||||||
|
Раздел не из схемы своего типа (`Воспроизведение` у `chore`, критерии у
|
||||||
|
`research`) — сигнал того же расхождения, и `check` о нём говорит замечанием.
|
||||||
|
Твоя работа — сказать, **какой тип верен**, а не только что текущий не сходится.
|
||||||
|
|
||||||
|
3. **«Зачем» отвечает на «зачем нужна эта задача»** — состояние, остаток, боль,
|
||||||
— а не пересказывает заголовок. «Починить разбор хода» при заголовке «Не
|
— а не пересказывает заголовок. «Починить разбор хода» при заголовке «Не
|
||||||
отбрасывать молча лишние символы» — пересказ: читающий узнаёт то же самое
|
отбрасывать молча лишние символы» — пересказ: читающий узнаёт то же самое
|
||||||
дважды и по-прежнему не знает, почему это лежит в беклоге.
|
дважды и по-прежнему не знает, почему это лежит в беклоге.
|
||||||
|
|
||||||
3. **«Затрагивает» перечисляет границы, а не замысел.** Граница — то, у чего есть
|
4. **«Затрагивает» перечисляет границы, а не замысел.** Граница — то, у чего есть
|
||||||
внешняя сторона: команда и её аргументы, эндпоинт, таблица и миграция, формат
|
внешняя сторона: команда и её аргументы, эндпоинт, таблица и миграция, формат
|
||||||
на диске, публичный тип пакета, внешний сервис. «Переписать хранилище на новый
|
на диске, публичный тип пакета, внешний сервис. «Переписать хранилище на новый
|
||||||
драйвер» — замысел; проверяется вопросом «это можно назвать до того, как
|
драйвер» — замысел; проверяется вопросом «это можно назвать до того, как
|
||||||
@@ -72,17 +95,17 @@ color: yellow
|
|||||||
становится двумя» вместо «выбор источника хода в модуле партии») — это уже
|
становится двумя» вместо «выбор источника хода в модуле партии») — это уже
|
||||||
решение о том, как делать.
|
решение о том, как делать.
|
||||||
|
|
||||||
4. **У критерия назван оракул, и оракул проверяем.** «Оракул: глазами» на
|
5. **У критерия назван оракул, и оракул проверяем.** «Оракул: глазами» на
|
||||||
утверждение, которого глазами не проверить («компьютер не проигрывает ни в
|
утверждение, которого глазами не проверить («компьютер не проигрывает ни в
|
||||||
одной партии»), — находка: слово стоит, проверки нет. Число критериев считает
|
одной партии»), — находка: слово стоит, проверки нет. Число критериев считает
|
||||||
`tasks.py check`, тебе оно неинтересно.
|
`tasks.py check`, тебе оно неинтересно.
|
||||||
|
|
||||||
5. **Предписания процесса в теле нет.** «Делать профилем standard», «взять
|
6. **Предписания процесса в теле нет.** «Делать профилем standard», «взять
|
||||||
такой-то агент» — это выбор, который делают, увидев изменение, а не при
|
такой-то агент» — это выбор, который делают, увидев изменение, а не при
|
||||||
постановке. Он же путь понизить требования решением, принятым до
|
постановке. Он же путь понизить требования решением, принятым до
|
||||||
проектирования.
|
проектирования.
|
||||||
|
|
||||||
6. **Задача называет, какую строку «Завершения» своей цели она двигает.**
|
7. **Задача называет, какую строку «Завершения» своей цели она двигает.**
|
||||||
Открой файл цели из тега `goal:<слаг>` и сверь. Три исхода, и все три —
|
Открой файл цели из тега `goal:<слаг>` и сверь. Три исхода, и все три —
|
||||||
разные находки:
|
разные находки:
|
||||||
|
|
||||||
@@ -94,8 +117,8 @@ color: yellow
|
|||||||
это незакрытая часть возможности. Скажи о ней отдельно, вне списка находок
|
это незакрытая часть возможности. Скажи о ней отдельно, вне списка находок
|
||||||
по файлам: это про набор, а не про запись.
|
по файлам: это про набор, а не про запись.
|
||||||
|
|
||||||
У задачи **без цели** (`kind:fix`, `chore`, `research`) правило не
|
У задачи **без цели** (`fix`, `chore`, `research`) правило не применяется
|
||||||
применяется вовсе — они служат работоспособности, а не направлению.
|
вовсе — они служат работоспособности, а не направлению.
|
||||||
|
|
||||||
## Чего ты не проверяешь
|
## Чего ты не проверяешь
|
||||||
|
|
||||||
@@ -113,7 +136,7 @@ color: yellow
|
|||||||
одного правила.
|
одного правила.
|
||||||
|
|
||||||
**Содержание работы**: нужна ли задача, верно ли выбрана цель, не крупна ли она,
|
**Содержание работы**: нужна ли задача, верно ли выбрана цель, не крупна ли она,
|
||||||
достаточна ли декомпозиция. Шестое правило подходит к этому близко и
|
достаточна ли декомпозиция. Седьмое правило подходит к этому близко и
|
||||||
останавливается там, где кончается сверка с текстом цели. Об этом молчи.
|
останавливается там, где кончается сверка с текстом цели. Об этом молчи.
|
||||||
|
|
||||||
## Порог вмешательства
|
## Порог вмешательства
|
||||||
|
|||||||
@@ -240,18 +240,30 @@ kebab-case.
|
|||||||
становится: нормативное поведение живёт в `openspec/specs/`, роадмап отвечает,
|
становится: нормативное поведение живёт в `openspec/specs/`, роадмап отвечает,
|
||||||
**когда и в каком порядке** оно появилось.
|
**когда и в каком порядке** оно появилось.
|
||||||
|
|
||||||
Плюс два требования к записи задачи, потому что от них зависит, можно ли её
|
**У каждой записи есть тип, и тип решает, что с ней можно делать.** Дом типа —
|
||||||
оценить:
|
поле меты `Тип` первой строкой; эмодзи в заголовке от него производна. Словарь
|
||||||
|
закрыт:
|
||||||
|
|
||||||
- **род работы** тегом `kind:<род>` из закрытого словаря `feature` | `fix` |
|
| Тип | Что это | Обязательные разделы | Цель |
|
||||||
`chore` | `research` — у задачи обязателен, у цели запрещён. Он же решает,
|
| --- | --- | --- | --- |
|
||||||
нужна ли цель: у `feature` обязательна, у остальных нет;
|
| 🎯 `goal` | возможность приложения | `Завершение` | — |
|
||||||
- **раздел «Затрагивает»** в теле задачи — границы, которых изменение касается
|
| ✨ `feature` | снаружи появляется то, чего не было | `Затрагивает`, `Критерии приёмки` | обязательна |
|
||||||
(эндпоинт, таблица и миграция, формат на диске, публичный тип пакета).
|
| 🐞 `fix` | поведение расходится с заявленным | `Воспроизведение`, `Затрагивает`, `Критерии приёмки` | нет |
|
||||||
|
| 🧹 `chore` | обслуживание, поведение не меняется | `Затрагивает`, `Критерии приёмки` | нет |
|
||||||
|
| 🔬 `research` | исход — знание, а не изменение | `Вопрос`, `Куда ляжет ответ` | нет |
|
||||||
|
|
||||||
Оба требуются **к взятию в спринт**, а не к заведению: беклог пополняется чаще,
|
Схема требуется **к взятию в спринт**, а не к заведению: беклог пополняется чаще,
|
||||||
чем разбирается, и требование на входе выгоняло бы в заметки то, что должно
|
чем разбирается, и требование на входе выгоняло бы в заметки то, что должно
|
||||||
лежать задачей.
|
лежать задачей. Запись, не собравшая разделы своего типа, — законное состояние
|
||||||
|
беклога; невзятой её делает `sprint take`.
|
||||||
|
|
||||||
|
Отдельного типа для незаполненной записи нет: «ещё не описано» — состояние, а не
|
||||||
|
род работы, и называется оно **`research` без раздела «Вопрос»**. Такая запись в
|
||||||
|
спринт не берётся и лежит в конце своей категории.
|
||||||
|
|
||||||
|
Раскладку, форму записи и алгоритм работы над каждым типом держит скилл `tasks`
|
||||||
|
(`references/task-<тип>.md`); канон фиксирует только словарь типов и то, от чего
|
||||||
|
зависит, читается ли проект как продукт.
|
||||||
|
|
||||||
### `CLAUDE.md`
|
### `CLAUDE.md`
|
||||||
|
|
||||||
@@ -324,7 +336,7 @@ kebab-case.
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `docs/review-brief.md` | документы канона и есть бриф; остаток — в `review.md` |
|
| `docs/review-brief.md` | документы канона и есть бриф; остаток — в `review.md` |
|
||||||
| `docs/specs/` | `openspec/specs/` (поведение) и `architecture.md` (обзор) |
|
| `docs/specs/` | `openspec/specs/` (поведение) и `architecture.md` (обзор) |
|
||||||
| `docs/drafts/` | идея → задача `[idea]`; отказ → ADR; порядок → `ROADMAP.md`; размышление → `opsx:explore` |
|
| `docs/drafts/` | идея → запись `research`; отказ → ADR; порядок → `ROADMAP.md`; размышление → `opsx:explore` |
|
||||||
| `docs/plan.md` | `docs/tasks/ROADMAP.md` |
|
| `docs/plan.md` | `docs/tasks/ROADMAP.md` |
|
||||||
| `BRIEF.md` | `passport.md` |
|
| `BRIEF.md` | `passport.md` |
|
||||||
| `docs/backlog/` | `docs/tasks/` |
|
| `docs/backlog/` | `docs/tasks/` |
|
||||||
@@ -364,10 +376,14 @@ kebab-case.
|
|||||||
`database.md`. `tasks` — настройки каталога задач, переехавшие сюда из прежнего
|
`database.md`. `tasks` — настройки каталога задач, переехавшие сюда из прежнего
|
||||||
`<tasks>/.tasks.json`: **один конфиг на весь канон, а не по одному на каталог**.
|
`<tasks>/.tasks.json`: **один конфиг на весь канон, а не по одному на каталог**.
|
||||||
Внутри `tasks` — **только имена файлов и заголовков** (`items`, `backlog`,
|
Внутри `tasks` — **только имена файлов и заголовков** (`items`, `backlog`,
|
||||||
`plan`, `sprint`, `rejected`, `sprint_section`, `questions_heading`,
|
`roadmap`, `sprint`, `rejected`, `sprint_section`, `oracle_word` и заголовки
|
||||||
`criteria_heading`, `oracle_word`), и ключ пишется, лишь когда имя отличается от
|
разделов тела: `criteria_heading`, `surface_heading`, `questions_heading`,
|
||||||
умолчания. **Секций беклога здесь нет:** их дом — заголовки `##` самого индекса,
|
`completion_heading`, `repro_heading`, `question_heading`, `answer_heading`,
|
||||||
и второй список сразу разошёлся бы с первым. Неизвестный ключ `tasks.py`
|
`scope_heading`), и ключ пишется, лишь когда имя отличается от умолчания.
|
||||||
|
**Словаря типов здесь нет** — он закрыт каноном, а не настраивается проектом:
|
||||||
|
настраиваемый словарь типов разъехался бы на синонимах ровно так же, как
|
||||||
|
открытый. **Категорий беклога здесь тоже нет:** их дом — заголовки `##` самого
|
||||||
|
индекса, и второй список сразу разошёлся бы с первым. Неизвестный ключ `tasks.py`
|
||||||
отвергает кодом 3, поэтому лишнее слово в этом объекте останавливает работу с
|
отвергает кодом 3, поэтому лишнее слово в этом объекте останавливает работу с
|
||||||
задачами целиком.
|
задачами целиком.
|
||||||
|
|
||||||
|
|||||||
@@ -13,17 +13,25 @@ upgrade` идёт по записям снизу вверх от версии п
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Версия 4 — 2026-08-04
|
## Версия 4 — 2026-08-05
|
||||||
|
|
||||||
Одна секция роадмапа переименована, и вместе с именем расширен её смысл;
|
Две правки, обе про то, как читается каталог задач. Первая — секция роадмапа
|
||||||
достигнутое переехало вниз. Плюс общий словарь для трёх мест канона, которые
|
переименована, и вместе с именем расширен её смысл; достигнутое переехало вниз.
|
||||||
говорят про одну тему разными словами. Раскладка не меняется, файлов не
|
Вторая — **у каждой записи появился тип, и тип определяет, что с записью можно
|
||||||
прибавляется.
|
делать**. Раскладка не меняется, файлов канона не прибавляется.
|
||||||
|
|
||||||
**Что переехало:** секция роадмапа `Разработка` → **`Сопровождение`** (англ.
|
**Что переехало:**
|
||||||
`Tooling` → **`Operations`**). Прежнее имя называло слишком много: роадмап
|
|
||||||
**весь** про разработку, и секция с таким именем не отличалась от остальных
|
- секция роадмапа `Разработка` → **`Сопровождение`** (англ. `Tooling` →
|
||||||
ничем.
|
**`Operations`**). Прежнее имя называло слишком много: роадмап **весь** про
|
||||||
|
разработку, и секция с таким именем не отличалась от остальных ничем;
|
||||||
|
- **тип записи** — из префикса заголовка (`[goal]`/`[idea]`) и тега
|
||||||
|
`kind:<род>` в **поле меты `Тип`** первой строкой. Эмодзи в заголовке от него
|
||||||
|
производна;
|
||||||
|
- **поле места** у задачи: `Секция` → **`Категория`**. У цели остаётся `Секция`:
|
||||||
|
у задачи поле называет полку домена, в которую она вернётся из спринта, у цели
|
||||||
|
— часть роадмапа, то есть состояние очереди. Одно имя на два смысла было
|
||||||
|
конфляцией.
|
||||||
|
|
||||||
**Что добавилось:**
|
**Что добавилось:**
|
||||||
|
|
||||||
@@ -51,6 +59,28 @@ upgrade` идёт по записям снизу вверх от версии п
|
|||||||
5. **Заголовок секции отбивается пустой строкой с обеих сторон.** Прежде
|
5. **Заголовок секции отбивается пустой строкой с обеих сторон.** Прежде
|
||||||
проверялась только строка после заголовка; перестановка секций двигает целые
|
проверялась только строка после заголовка; перестановка секций двигает целые
|
||||||
блоки, и два заголовка оказываются вплотную. Правит `check --fix`.
|
блоки, и два заголовка оказываются вплотную. Правит `check --fix`.
|
||||||
|
6. **Тип — единственная ось записи, закрытый словарь из пяти значений:**
|
||||||
|
`goal` | `feature` | `fix` | `chore` | `research`. Осей было две — тип записи
|
||||||
|
(`goal`/`idea`/`task`) и род работы (`kind:` тегом), — но из двенадцати
|
||||||
|
клеток произведения законны были шесть, а алгоритм работы крепится к роду, а
|
||||||
|
не к типу. Оси схлопнуты.
|
||||||
|
7. **Тип задаёт схему тела:** какие разделы обязательны, какие допустимы, нужна
|
||||||
|
ли цель, берётся ли запись в спринт. Проверяет `sprint take`, замечания даёт
|
||||||
|
`check`. Два раздела новые: **`Воспроизведение`** у `fix` (не
|
||||||
|
воспроизводится — это `research`, а не `fix`; правило было записано и не
|
||||||
|
проверялось) и **`Вопрос` + `Куда ляжет ответ`** у `research` вместо
|
||||||
|
критериев приёмки (приёмка разведки — записанный ответ, и критерии в форме
|
||||||
|
«оракул: тест» ей натянуты).
|
||||||
|
8. **Тип `idea` упразднён.** Он значил не род работы, а состояние
|
||||||
|
незаполненности, а состояние типом быть не может. Теперь оно называется
|
||||||
|
честно: `research` без раздела «Вопрос» — **сырьё**. В спринт не берётся, как
|
||||||
|
и прежняя идея, лежит **в конце своей категории** (проверяет `check`,
|
||||||
|
переставляет `--fix`) и отбирается `list --raw`. Порядка «по важности» в
|
||||||
|
беклоге по-прежнему нет: этот порядок производен от типа, а не назначен
|
||||||
|
человеком.
|
||||||
|
9. **Алгоритм работы над каждым типом** — отдельным файлом,
|
||||||
|
`skills/tasks/references/task-<тип>.md`: схема, что проверяет машина, что
|
||||||
|
человек, и порядок шагов.
|
||||||
|
|
||||||
**Что сделать проекту:**
|
**Что сделать проекту:**
|
||||||
|
|
||||||
@@ -63,10 +93,22 @@ upgrade` идёт по записям снизу вверх от версии п
|
|||||||
docs/tasks` покажет расхождение поимённо.
|
docs/tasks` покажет расхождение поимённо.
|
||||||
3. Перечитать состав секции: цели про выкладку, метрики, логи и инфраструктуру,
|
3. Перечитать состав секции: цели про выкладку, метрики, логи и инфраструктуру,
|
||||||
если они лежали в `Направлениях` за неимением места, переезжают сюда.
|
если они лежали в `Направлениях` за неимением места, переезжают сюда.
|
||||||
4. Прогнать `python3 tasks.py check --dir docs/tasks --fix`: он переставит
|
4. Прогнать `python3 tasks.py check --dir docs/tasks --fix`. За один проход он
|
||||||
секции роадмапа в канонический порядок (`Готово` уедет вниз вместе со всем
|
переставит секции роадмапа в канонический порядок (`Готово` уедет вниз вместе
|
||||||
содержимым) и поправит отбивку заголовков.
|
со всем содержимым), поправит отбивку заголовков и **переведёт записи на
|
||||||
5. `docs/.pm.json`: `"canon": 4`.
|
типы**: перенесёт значение из тега `kind:` и префикса `[goal]`/`[idea]` в поле
|
||||||
|
`Тип`, снимет тег, поставит эмодзи в заголовок, переименует `Секция` →
|
||||||
|
`Категория` у задач и снесёт сырьё в конец категорий.
|
||||||
|
5. Разобрать то, что `--fix` вернул пометкой `НЕОДНОЗНАЧНО`. Главный случай —
|
||||||
|
**записи без типа**: заведённые до появления рода работы, они не несут ни
|
||||||
|
тега, ни префикса, и машина их не угадывает (`feature` от `chore` не
|
||||||
|
отличает). Проставить руками: `edit <слаг> --type …`.
|
||||||
|
6. Дописать новые обязательные разделы у задач, которые собираются в спринт:
|
||||||
|
`Воспроизведение` у каждого `fix`, `Вопрос` и `Куда ляжет ответ` у каждого
|
||||||
|
`research`. Не «заодно по всему беклогу», а порциями переоценки: `check`
|
||||||
|
ошибкой это не считает, отказывает только `sprint take`. Сколько задач готово
|
||||||
|
к взятию, печатает блок здоровья `check`.
|
||||||
|
7. `docs/.pm.json`: `"canon": 4`.
|
||||||
|
|
||||||
## Версия 3 — 2026-08-04
|
## Версия 3 — 2026-08-04
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ RETIRED = {
|
|||||||
"local-research.md": "→ docs/research/",
|
"local-research.md": "→ docs/research/",
|
||||||
"research.md": "→ docs/research/",
|
"research.md": "→ docs/research/",
|
||||||
"specs": "поведение → openspec/specs/, обзор → docs/architecture.md",
|
"specs": "поведение → openspec/specs/, обзор → docs/architecture.md",
|
||||||
"drafts": "идея → задача [idea], отказ → ADR, порядок → ROADMAP.md",
|
"drafts": "идея → запись research, отказ → ADR, порядок → ROADMAP.md",
|
||||||
"backlog": "→ docs/tasks/",
|
"backlog": "→ docs/tasks/",
|
||||||
"review": "→ docs/review.md",
|
"review": "→ docs/review.md",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ description: "Ритуал между спринтами и ведение са
|
|||||||
|
|
||||||
## Единицы
|
## Единицы
|
||||||
|
|
||||||
- **Цель** — то, ради чего набирается спринт. Файл `[goal]`, перечисленный в
|
- **Цель** — то, ради чего набирается спринт. Файл типа `goal` (🎯),
|
||||||
`ROADMAP.md`. Цель постоянна: живёт, пока живёт направление.
|
перечисленный в `ROADMAP.md`. Цель постоянна: живёт, пока живёт направление.
|
||||||
- **Задача** — то, что мерджится целиком и даёт видимую пользу.
|
- **Задача** — то, что мерджится целиком и даёт видимую пользу.
|
||||||
- **Вопрос** — решение человека. Не останавливает начатую работу, но **блокирует
|
- **Вопрос** — решение человека. Не останавливает начатую работу, но **блокирует
|
||||||
взятие** задачи в спринт. Живёт внутри файла задачи разделом «Вопросы» и тегом
|
взятие** задачи в спринт. Живёт внутри файла задачи разделом «Вопросы» и тегом
|
||||||
|
|||||||
@@ -105,11 +105,13 @@
|
|||||||
4. **Пере-кластеризуй по общей причине.** Несколько задач, оказавшихся симптомами
|
4. **Пере-кластеризуй по общей причине.** Несколько задач, оказавшихся симптомами
|
||||||
одного дефекта, сливаются в одну — это находка, которую интейк дать не мог.
|
одного дефекта, сливаются в одну — это находка, которую интейк дать не мог.
|
||||||
5. **Гигиена полей** — протухшее «зачем», вопрос в прозе, снятый ответ, свойство
|
5. **Гигиена полей** — протухшее «зачем», вопрос в прозе, снятый ответ, свойство
|
||||||
репозитория в рамках, предписание процесса в теле, род работы, разошедшийся с
|
репозитория в рамках, предписание процесса в теле, тип, разошедшийся с
|
||||||
задачей, границы вместо реализации в разделе «Затрагивает». Список и правила —
|
задачей, границы вместо реализации в разделе «Затрагивает». Список и правила —
|
||||||
в скилле `tasks`. **Переоценка — то самое место, где беклог добирает род
|
в скилле `tasks`. **Переоценка — то самое место, где беклог добирает тип и
|
||||||
работы и границы:** требовать их на входе значило бы выгонять в заметки то,
|
разделы его схемы:** требовать их на входе значило бы выгонять в заметки то,
|
||||||
что должно лежать задачей, а к взятию в спринт они уже обязательны.
|
что должно лежать задачей, а к взятию в спринт они уже обязательны. Сколько
|
||||||
|
записей готово к взятию, печатает блок здоровья `check`, — по этому числу и
|
||||||
|
видно, добрала переоценка или нет.
|
||||||
|
|
||||||
Затем — то, что решает пользователь:
|
Затем — то, что решает пользователь:
|
||||||
|
|
||||||
@@ -122,8 +124,9 @@
|
|||||||
заказывал. Операционной задаче (`fix`, `chore`, `research`) цель не нужна, и
|
заказывал. Операционной задаче (`fix`, `chore`, `research`) цель не нужна, и
|
||||||
выдумывать её здесь не надо.
|
выдумывать её здесь не надо.
|
||||||
8. **Задача ли это по-прежнему.** Не проходит тест «готова к взятию» → `edit
|
8. **Задача ли это по-прежнему.** Не проходит тест «готова к взятию» → `edit
|
||||||
<slug> --type idea`, дальше штурм. Разрослась → это несколько задач под той
|
<slug> --type research` и опустошённый раздел «Вопрос», то есть сырьё; дальше
|
||||||
же целью, дальше декомпозиция.
|
штурм. Разрослась → это несколько задач под той же целью, дальше
|
||||||
|
декомпозиция.
|
||||||
9. **Переоценка по измеренному.** Спринт производит числа — сколько на самом
|
9. **Переоценка по измеренному.** Спринт производит числа — сколько на самом
|
||||||
деле стоит такая работа, что оказалось дороже ожидания. Эти числа меняют цену
|
деле стоит такая работа, что оказалось дороже ожидания. Эти числа меняют цену
|
||||||
**других** задач, и именно здесь это применяется: задача, чья цена выросла
|
**других** задач, и именно здесь это применяется: задача, чья цена выросла
|
||||||
@@ -167,7 +170,7 @@
|
|||||||
> - Взять в ближайший набор — без бэкапа ретеншн опасен
|
> - Взять в ближайший набор — без бэкапа ретеншн опасен
|
||||||
> - Выкинуть
|
> - Выкинуть
|
||||||
> 3. `guessit-sputnik` — вынести распознавание в сервис-спутник
|
> 3. `guessit-sputnik` — вынести распознавание в сервис-спутник
|
||||||
> - Понизить до `[idea]` *(рекомендую)* — не проходит тест «готова к взятию»
|
> - Понизить до сырья (`--type research`) *(рекомендую)* — не проходит тест «готова к взятию»
|
||||||
> - Оставить задачей
|
> - Оставить задачей
|
||||||
|
|
||||||
Каждый вариант несёт причину — ту самую, что уедет в `--reason`. Ответы применяй
|
Каждый вариант несёт причину — ту самую, что уедет в `--reason`. Ответы применяй
|
||||||
@@ -184,15 +187,16 @@
|
|||||||
2. **Цель называет человек.** Это продуктовое решение, а не механика: агент
|
2. **Цель называет человек.** Это продуктовое решение, а не механика: агент
|
||||||
предлагает и объясняет, но не выбирает.
|
предлагает и объясняет, но не выбирает.
|
||||||
3. **Набор собирает агент** — `sprint start --goal <слаг>`, затем `sprint take
|
3. **Набор собирает агент** — `sprint start --goal <слаг>`, затем `sprint take
|
||||||
…`. Скрипт не даст взять цель, идею, задачу с чужой целью, с открытым
|
…`. Скрипт не даст взять цель, задачу с чужой целью, с открытым вопросом, без
|
||||||
вопросом, без критериев приёмки, без рода работы или без раздела
|
типа и **без разделов, которых требует её тип** (у `fix` это в том числе
|
||||||
«Затрагивает». Задача без цели вовсе (`fix`, `chore`, `research`) берётся
|
`Воспроизведение`, у `research` — `Вопрос` и `Куда ляжет ответ`, и сырьё
|
||||||
свободно — операционная работа входит в набор помимо его цели.
|
поэтому не берётся вовсе). Задача без цели (`fix`, `chore`, `research`)
|
||||||
|
берётся свободно — операционная работа входит в набор помимо его цели.
|
||||||
4. **Набор показывается человеку до старта работ.** Показ — это и есть момент
|
4. **Набор показывается человеку до старта работ.** Показ — это и есть момент
|
||||||
заморозки: после него набор не двигается. **В показе называется состав по
|
заморозки: после него набор не двигается. **В показе называется состав по
|
||||||
роду работы** — три `fix` и ни одной `feature` под целью развития это
|
типам** — три `fix` и ни одной `feature` под целью развития это разговор про
|
||||||
разговор про цель, а не про набор, и увидеть его надо до заморозки, а не в
|
цель, а не про набор, и увидеть его надо до заморозки, а не в докладе по
|
||||||
докладе по итогам.
|
итогам.
|
||||||
|
|
||||||
Здесь же последний дешёвый момент заметить **разнородную задачу**: раздел
|
Здесь же последний дешёвый момент заметить **разнородную задачу**: раздел
|
||||||
«Затрагивает» показывает границы до того, как заведено предложение об
|
«Затрагивает» показывает границы до того, как заведено предложение об
|
||||||
@@ -200,10 +204,9 @@
|
|||||||
перечня, — кандидат на разрез (шов — в `tasks`, `references/split.md`).
|
перечня, — кандидат на разрез (шов — в `tasks`, `references/split.md`).
|
||||||
Замеченная здесь, она стоит одного `edit`; замеченная на ревью — выброшенного
|
Замеченная здесь, она стоит одного `edit`; замеченная на ревью — выброшенного
|
||||||
предложения.
|
предложения.
|
||||||
5. Задача, которой для взятия не хватает только критериев приёмки, границ или
|
5. Задача, которой для взятия не хватает только разделов её типа, дописывается
|
||||||
рода, дописывается здесь же — 2–5 утверждений с оракулами, перечень
|
здесь же — критерии с оракулами, перечень границ, шаги воспроизведения. Но
|
||||||
затрагиваемых границ, `--kind`. Но если для этого нужен ответ человека, это
|
если для этого нужен ответ человека, это вопрос, и задача в набор не идёт.
|
||||||
вопрос, и задача в набор не идёт.
|
|
||||||
|
|
||||||
**Размер — ориентир, а не закон:** 5–8 задач. Можно взять больше, можно меньше —
|
**Размер — ориентир, а не закон:** 5–8 задач. Можно взять больше, можно меньше —
|
||||||
набор под цель важнее круглого числа; одна крупная задача спринтом тоже бывает.
|
набор под цель важнее круглого числа; одна крупная задача спринтом тоже бывает.
|
||||||
@@ -214,8 +217,8 @@
|
|||||||
- Вопросы: разобрано N, из них отвечено без человека N, снято тегов N.
|
- Вопросы: разобрано N, из них отвечено без человека N, снято тегов N.
|
||||||
- Разбор процесса: что записано и куда.
|
- Разбор процесса: что записано и куда.
|
||||||
- Изменения списком: удалено как реализованное (со ссылками), ушло без
|
- Изменения списком: удалено как реализованное (со ссылками), ушло без
|
||||||
реализации (с причинами), понижено до идей, слито, сменило цель.
|
реализации (с причинами), понижено до сырья, слито, сменило тип или цель.
|
||||||
- Новый спринт: цель, набор со слагами, дата, состав по роду работы.
|
- Новый спринт: цель, набор со слагами, дата, состав по типам.
|
||||||
- **Границы покрытия**: сколько задач не трогали и какие именно секции, теги или
|
- **Границы покрытия**: сколько задач не трогали и какие именно секции, теги или
|
||||||
цели остались — иначе доклад читается как «беклог разобран».
|
цели остались — иначе доклад читается как «беклог разобран».
|
||||||
- `tasks.py check` после правок — результат строкой.
|
- `tasks.py check` после правок — результат строкой.
|
||||||
|
|||||||
+153
-114
@@ -1,19 +1,19 @@
|
|||||||
---
|
---
|
||||||
name: tasks
|
name: tasks
|
||||||
description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). Заведение задачи, идеи или цели из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, мозговой штурм идеи, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Ритуал между спринтами — скилл session. Не реализует задачи — этим занимается пайплайн проекта.
|
description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). У каждой записи есть тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение записи из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, штурм сырья, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Ритуал между спринтами — скилл session. Не реализует задачи — этим занимается пайплайн проекта.
|
||||||
---
|
---
|
||||||
|
|
||||||
# Задачи
|
# Задачи
|
||||||
|
|
||||||
Задачи — каталог markdown-файлов. Одна запись = один файл `items/<slug>.md` плюс
|
Задачи — каталог markdown-файлов. Одна запись = один файл `items/<slug>.md` плюс
|
||||||
строка **ровно в одном** индексе. Скилл владеет **форматом и содержимым**:
|
строка **ровно в одном** индексе. Скилл владеет **форматом и содержимым**:
|
||||||
заводит, редактирует, закрывает, разбирает находки ревью, дробит, штурмует идеи.
|
заводит, редактирует, закрывает, разбирает находки ревью, дробит, штурмует сырьё.
|
||||||
|
|
||||||
Чем он **не** владеет: ритуалом между спринтами (разбор вопросов → разбор
|
Чем он **не** владеет: ритуалом между спринтами (разбор вопросов → разбор
|
||||||
прошедшего спринта → переоценка → выбор цели и набор) — это скилл `session`; и
|
прошедшего спринта → переоценка → выбор цели и набор) — это скилл `session`; и
|
||||||
выполнением задачи — это пайплайн проекта.
|
выполнением задачи — это пайплайн проекта.
|
||||||
|
|
||||||
## Пять правил, из которых всё следует
|
## Шесть правил, из которых всё следует
|
||||||
|
|
||||||
Ситуация не покрыта инструкцией — решай по ним.
|
Ситуация не покрыта инструкцией — решай по ним.
|
||||||
|
|
||||||
@@ -43,10 +43,20 @@ description: Ведение задач и целей как каталога mar
|
|||||||
4. **Порядка нет, есть цель — но цель есть не у всякой задачи.** Приоритетов,
|
4. **Порядка нет, есть цель — но цель есть не у всякой задачи.** Приоритетов,
|
||||||
«повысить» и «встать раньше» нет: «что делать дальше» отвечает набор спринта,
|
«повысить» и «встать раньше» нет: «что делать дальше» отвечает набор спринта,
|
||||||
а между спринтами порядок не нужен никому. Цель обязательна там, где она и
|
а между спринтами порядок не нужен никому. Цель обязательна там, где она и
|
||||||
есть содержание работы, — у **новой возможности** (`kind:feature`). Починка,
|
есть содержание работы, — у **новой возможности** (`feature`). Починка,
|
||||||
техдолг и разведка служат работоспособности, а не направлению, и живут без
|
техдолг и разведка служат работоспособности, а не направлению, и живут без
|
||||||
цели законно; в набор спринта они входят помимо его цели. Придуманная им цель
|
цели законно; в набор спринта они входят помимо его цели. Придуманная им цель
|
||||||
— то же враньё, от которого спасает род работы.
|
— то же враньё, от которого спасает тип.
|
||||||
|
|
||||||
|
Единственный порядок, который в беклоге всё-таки есть, **производен от типа**,
|
||||||
|
а не назначен человеком: **сырьё** (`research` без раздела «Вопрос») стоит в
|
||||||
|
конце своей категории. Его не берут, и между берущимся оно каждый раз требует
|
||||||
|
открыть файл, чтобы это понять. Раз порядок выводится, его проверяет машина —
|
||||||
|
и приоритетом он не становится.
|
||||||
|
5. **Тип решает, что с записью можно делать.** Тип — единственная ось и первое
|
||||||
|
поле меты: от него зависят обязательные разделы тела, нужна ли цель, берётся
|
||||||
|
ли запись в спринт и в каком индексе живёт её строка. Словарь закрыт; ни один
|
||||||
|
тип не подошёл — значит, в записи их два, и её надо разделить.
|
||||||
|
|
||||||
## Раскладка
|
## Раскладка
|
||||||
|
|
||||||
@@ -82,10 +92,12 @@ docs/tasks/
|
|||||||
открывают чаще всего, — что делается сейчас и что дальше. Порядок проверяет
|
открывают чаще всего, — что делается сейчас и что дальше. Порядок проверяет
|
||||||
`check`, переставляет `check --fix`.
|
`check`, переставляет `check --fix`.
|
||||||
|
|
||||||
**Секции роадмапа канонические, секции беклога — нет**, и разница не в любви к
|
**Секции роадмапа канонические, категории беклога — нет**, и разница не в любви к
|
||||||
единообразию. У каждой секции роадмапа свой смысл, в достигнутое пишет сам `close`, и
|
единообразию. У каждой секции роадмапа свой смысл, в достигнутое пишет сам `close`, и
|
||||||
роадмап, названный по-своему, читался бы только своим автором. Секции беклога
|
роадмап, названный по-своему, читался бы только своим автором. Категории беклога
|
||||||
(`Ядро`, `Инфра`) смысла не несут — это полки, и остаются делом проекта.
|
(`Ядро`, `Инфра`) смысла не несут — это полки домена, и остаются делом проекта.
|
||||||
|
Отсюда и разные имена поля меты: у цели **Секция** (часть роадмапа — состояние
|
||||||
|
очереди), у задачи **Категория** (полка, в которую она вернётся из спринта).
|
||||||
|
|
||||||
Отсюда четыре правила, которые проверяет `tasks.py check`: **состав закреплён**
|
Отсюда четыре правила, которые проверяет `tasks.py check`: **состав закреплён**
|
||||||
(чужая секция — ошибка, а не вольность), **все четыре обязаны быть** (нет
|
(чужая секция — ошибка, а не вольность), **все четыре обязаны быть** (нет
|
||||||
@@ -93,7 +105,7 @@ docs/tasks/
|
|||||||
канонический**. `--roadmap-sections` у `init` нет: выбирать нечего.
|
канонический**. `--roadmap-sections` у `init` нет: выбирать нечего.
|
||||||
|
|
||||||
**Заголовок секции отбит пустой строкой с обеих сторон и написан с прописной.**
|
**Заголовок секции отбит пустой строкой с обеих сторон и написан с прописной.**
|
||||||
Во всех индексах одинаково, включая секции беклога, которые проект называет сам.
|
Во всех индексах одинаково, включая категории беклога, которые проект называет сам.
|
||||||
Написание канонических секций правит `check --fix` (заодно и ссылку на секцию в
|
Написание канонических секций правит `check --fix` (заодно и ссылку на секцию в
|
||||||
мете файлов: имя секции принадлежит заголовку индекса, файл на неё только
|
мете файлов: имя секции принадлежит заголовку индекса, файл на неё только
|
||||||
ссылается); отбивку и порядок он правит везде.
|
ссылается); отбивку и порядок он правит везде.
|
||||||
@@ -143,10 +155,10 @@ stateDiagram-v2
|
|||||||
state "записи нет — реализована" as D
|
state "записи нет — реализована" as D
|
||||||
state "ROADMAP.md, «умеет» — цель достигнута" as A
|
state "ROADMAP.md, «умеет» — цель достигнута" as A
|
||||||
|
|
||||||
[*] --> B: add
|
[*] --> B: add --type feature|fix|chore|research
|
||||||
[*] --> P: add --type goal
|
[*] --> P: add --type goal
|
||||||
B --> P: edit --type goal --section
|
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
|
B --> S: sprint take
|
||||||
S --> B: sprint drop --reason
|
S --> B: sprint drop --reason
|
||||||
S --> D: close --implemented
|
S --> D: close --implemented
|
||||||
@@ -169,7 +181,7 @@ stateDiagram-v2
|
|||||||
|
|
||||||
## Цели
|
## Цели
|
||||||
|
|
||||||
**Цель — возможность приложения.** Такой же файл в `items/`, тип `[goal]`,
|
**Цель — возможность приложения.** Такой же файл в `items/`, тип `goal` (🎯),
|
||||||
перечисленный в `ROADMAP.md`. Формулируется ответом на вопрос **«что приложение
|
перечисленный в `ROADMAP.md`. Формулируется ответом на вопрос **«что приложение
|
||||||
будет уметь»**, а не названием области работ: не «Работа с чтением», а «Чтение
|
будет уметь»**, а не названием области работ: не «Работа с чтением», а «Чтение
|
||||||
данных клиентами»; не «Рефакторинг слияния», а «Исход слияния не зависит от
|
данных клиентами»; не «Рефакторинг слияния», а «Исход слияния не зависит от
|
||||||
@@ -226,52 +238,51 @@ stateDiagram-v2
|
|||||||
проектов. Встретился в чужом беклоге — это цель либо набор задач, и `check`
|
проектов. Встретился в чужом беклоге — это цель либо набор задач, и `check`
|
||||||
назовёт его неизвестным типом.
|
назовёт его неизвестным типом.
|
||||||
|
|
||||||
## Род работы
|
## Тип записи
|
||||||
|
|
||||||
**Тип записи и род работы — две оси, и путать их нельзя.** Тип отвечает «что это
|
**Тип — единственная ось, и он решает, что с записью можно делать.** Дом типа —
|
||||||
за запись» (цель, идея, задача), род — «какого рода работа»: `feature`, `fix`,
|
**поле меты `Тип` первой строкой**; эмодзи в заголовке H1 от него производна, её
|
||||||
`chore`, `research`. Одним значением на оба вопроса не ответить: идея бывает
|
ставит `add` и чинит `check --fix`.
|
||||||
*про* функцию, а цель функцией *и является*.
|
|
||||||
|
|
||||||
- **`feature`** — снаружи появляется или меняется то, чего раньше не было.
|
| Тип | Обязательные разделы | Цель | В спринт | Устав |
|
||||||
- **`fix`** — поведение расходится с заявленным, и расхождение воспроизводится.
|
| --- | --- | --- | --- | --- |
|
||||||
Не воспроизводится — это `research`, а не `fix`.
|
| 🎯 `goal` | `Завершение` | — | нет | [task-goal.md](references/task-goal.md) |
|
||||||
- **`chore`** — обслуживание: зависимости, сборка, перенос, чистка. Наблюдаемое
|
| ✨ `feature` | `Затрагивает`, `Критерии приёмки` | **обязательна** | да | [task-feature.md](references/task-feature.md) |
|
||||||
поведение не меняется, и в этом всё дело: **у `chore` тест готовности слабее
|
| 🐞 `fix` | `Воспроизведение`, `Затрагивает`, `Критерии приёмки` | необязательна | да | [task-fix.md](references/task-fix.md) |
|
||||||
честно**, а не молча. «Что станет наблюдаемо иначе» здесь отвечается
|
| 🧹 `chore` | `Затрагивает`, `Критерии приёмки` | нет | да | [task-chore.md](references/task-chore.md) |
|
||||||
разработчику («перестанет собираться два раза», «уедет последний вызов
|
| 🔬 `research` | `Вопрос`, `Куда ляжет ответ` | нет | да | [task-research.md](references/task-research.md) |
|
||||||
устаревшего API»), а не пользователю. Пока рода не было, такие задачи либо не
|
|
||||||
заводились, либо формулировались как выдуманная польза.
|
|
||||||
- **`research`** — исход работы знание, а не изменение системы: ответ на вопрос,
|
|
||||||
замер, разведка. Приёмка — записанный ответ (`docs/research/`, ADR, тело
|
|
||||||
задачи), а не изменённый код.
|
|
||||||
|
|
||||||
Дом рода — **тег `kind:<род>`**, а не префикс заголовка и не поле меты: теги
|
Сверх обязательных у любой задачи допустимы `Рамки` и `Вопросы`. Раздел не из
|
||||||
здесь единственный механизм разметки, и `list --kind fix` работает даром. Цена
|
схемы своего типа — **замечание, а не ошибка**: свой раздел законная вольность
|
||||||
известна: в строку индекса род не попадает (индексы производны), и «в наборе одни
|
проекта, но `Воспроизведение` у `chore` почти всегда значит, что тип проставлен
|
||||||
починки» видно командой, а не глазами по `SPRINT.md`.
|
не тот, и сказать об этом стоит, не запрещая.
|
||||||
|
|
||||||
|
**Осей было две, и ортогональность у них была фальшивой.** Тип записи
|
||||||
|
(`goal`/`idea`/`task`) и род работы (`kind:<род>` тегом) давали двенадцать клеток
|
||||||
|
произведения, из которых законны были шесть: у цели род запрещён, у задачи
|
||||||
|
обязателен, у идеи пуст. Плюс алгоритм работы крепится не к `task`, а к `fix` и
|
||||||
|
`research` — то есть к роду. Оси схлопнуты, тег `kind:` упразднён.
|
||||||
|
|
||||||
|
**Тип `idea` упразднён вместе с ними.** Он значил не род работы, а **состояние
|
||||||
|
незаполненности** — «первый, второй или третий вопрос теста готовности не
|
||||||
|
отвечается», — а состояние типом быть не может: оно меняется по мере того, как
|
||||||
|
запись дописывают, а тип меняют командой. Теперь это состояние называется честно:
|
||||||
|
`research` без раздела «Вопрос» — **сырьё**. В спринт не берётся ровно как
|
||||||
|
прежняя идея, лежит в конце своей категории и отбирается `list --raw`.
|
||||||
|
|
||||||
Словарь **закрыт**. Открытый разъедется на синонимах — `bug`, `bugfix`, `fix`,
|
Словарь **закрыт**. Открытый разъедется на синонимах — `bug`, `bugfix`, `fix`,
|
||||||
`defect`, — и отбор по роду перестанет отвечать на свой единственный вопрос. Ни
|
`defect`, — и отбор по типу перестанет отвечать на свой единственный вопрос. Ни
|
||||||
один род не подходит — это сигнал, что в задаче их два и её надо разделить.
|
один тип не подходит — это сигнал, что в задаче их два и её надо разделить.
|
||||||
|
|
||||||
**Род обязателен у задачи, у цели запрещён, у идеи необязателен** — идея получает
|
**Требуется тип там, где по нему принимают решение:** `sprint take` без типа
|
||||||
его, когда становится задачей. Требуется он там, где по нему принимают решение:
|
откажет, потому что не знает, каких разделов требовать. `check` о пропаже только
|
||||||
`sprint take` без рода откажет. `check` о пропаже только **напоминает** — беклог,
|
**напоминает** — беклог, заведённый до появления типа, законен, и переоформлять
|
||||||
заведённый до появления рода, законен, и переоформлять его «заодно» здесь не
|
его «заодно» здесь не просят.
|
||||||
просят.
|
|
||||||
|
|
||||||
**Род решает и то, обязательна ли цель.** `feature` без цели не бывает: новая
|
**Тип не выбирает профиль ревью и вообще ничего не предписывает пайплайну.**
|
||||||
возможность и есть содержание цели, и если подходящей нет — либо она заводится,
|
Профиль выбирается по факту изменения, а не по типу задачи: `chore` бывает
|
||||||
либо это не `feature`. `fix`, `chore` и `research` живут без цели законно, и
|
|
||||||
`check` о них молчит: они служат работоспособности, а не направлению. Это
|
|
||||||
единственный случай, когда род что-то определяет за пределами отбора, — и
|
|
||||||
определяет он учёт, а не процесс проверки.
|
|
||||||
|
|
||||||
**Род не выбирает профиль ревью и вообще ничего не предписывает пайплайну.**
|
|
||||||
Профиль выбирается по факту изменения, а не по роду задачи: `chore` бывает
|
|
||||||
миграцией схемы, `fix` — правкой публичного контракта. Правило «предписание
|
миграцией схемы, `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 # согласованность индексов + здоровье
|
||||||
python3 $tk check --dir D --fix # + починить дрейф (секция, заголовок, дубли, «зачем», форма меты)
|
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 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|idea] [--section S] [--goal G] [--kind K] [--why «зачем»] [--tag a,b]
|
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] [--kind K] [--add-tag a,b] [--rm-tag c]
|
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 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 --reason R # в REJECTED.md + удалить (ушла без реализации)
|
||||||
python3 $tk close S --dir D --implemented # просто удалить (реализована и закоммичена)
|
python3 $tk close S --dir D --implemented # просто удалить (реализована и закоммичена)
|
||||||
@@ -375,20 +387,22 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
|||||||
Различать 1 и 3 обязательно: «дрейф в беклоге» — рабочая ситуация, «каталога
|
Различать 1 и 3 обязательно: «дрейф в беклоге» — рабочая ситуация, «каталога
|
||||||
нет» — нерабочая, и одинаковая реакция на них была бы неверна в обоих случаях.
|
нет» — нерабочая, и одинаковая реакция на них была бы неверна в обоих случаях.
|
||||||
|
|
||||||
Тип — английское ключевое слово `goal` / `idea` / `task` (как и прочие токены
|
Тип — английское ключевое слово `goal` / `feature` / `fix` / `chore` /
|
||||||
команд); `task` префикса не несёт, остальные кодируются `[goal]`/`[idea]` в
|
`research` (как и прочие токены команд), у `add` **обязательное**: без него
|
||||||
заголовке. Текст задачи при этом русский.
|
неизвестно, какой шаблон тела класть. Текст задачи при этом русский, а эмодзи в
|
||||||
|
заголовке ставит скрипт.
|
||||||
|
|
||||||
**Мутации правят файл и индексы заодно** — руками строку индекса или мету
|
**Мутации правят файл и индексы заодно** — руками строку индекса или мету
|
||||||
не пиши, зови `add`/`edit`/`move`/`close`/`sprint`. Смена заголовка, «зачем», типа,
|
не пиши, зови `add`/`edit`/`move`/`close`/`sprint`. Смена заголовка, «зачем», типа,
|
||||||
цели, рода работы и **тегов** — это `edit`: он держит H1, мету и индекс в синхроне.
|
цели и **тегов** — это `edit`: он держит H1 (вместе с эмодзи), мету и индекс в
|
||||||
Снятие тега — `--rm-tag` (после ответа на вопрос снимается `question`), смена
|
синхроне. Снятие тега — `--rm-tag` (после ответа на вопрос снимается
|
||||||
цели — `--goal`, рода — `--kind`; оба заменяют прежнее значение, а не добавляют
|
`question`), смена цели — `--goal`, типа — `--type`; оба заменяют прежнее
|
||||||
второе.
|
значение, а не добавляют второе.
|
||||||
|
|
||||||
**Переезд между индексами — следствие смены типа, а не отдельная команда.**
|
**Переезд между индексами — следствие смены типа, а не отдельная команда.**
|
||||||
`edit <slug> --type goal --section <часть роадмапа>` переносит строку из
|
`edit <slug> --type goal --section <часть роадмапа>` переносит строку из
|
||||||
`BACKLOG.md` в `ROADMAP.md` (и обратно `--type task --section <секция беклога>`);
|
`BACKLOG.md` в `ROADMAP.md` (и обратно — задачным типом плюс
|
||||||
|
`--section <категория беклога>`);
|
||||||
`move` двигает только внутри одного индекса и пишет причину. `--section` у
|
`move` двигает только внутри одного индекса и пишет причину. `--section` у
|
||||||
`edit` работает **только** при таком переезде — иначе он отсылает к `move`,
|
`edit` работает **только** при таком переезде — иначе он отсылает к `move`,
|
||||||
потому что смена секции без причины и есть тот дрейф, который потом никто не
|
потому что смена секции без причины и есть тот дрейф, который потом никто не
|
||||||
@@ -401,39 +415,54 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
|||||||
`check` — единственный судья согласованности; что именно он ловит, скажет его
|
`check` — единственный судья согласованности; что именно он ловит, скажет его
|
||||||
вывод, здесь не пересказываем. Гоняй его **в начале сессии** и **после каждой
|
вывод, здесь не пересказываем. Гоняй его **в начале сессии** и **после каждой
|
||||||
правки**, даже если правил мутациями: дрейф мог накопиться раньше. Накопившееся
|
правки**, даже если правил мутациями: дрейф мог накопиться раньше. Накопившееся
|
||||||
чини `check --fix` — он детерминированно правит то, где истина однозначна
|
чини `check --fix` — он детерминированно правит то, где истина однозначна (тип в
|
||||||
(секция, заголовок, дубли, «зачем» из индекса в файл, старая форма меты,
|
своё поле, эмодзи заголовка, имя поля места, секция, заголовок, дубли, «зачем» из
|
||||||
пометка `decomposed` у цели с задачами), а неоднозначное (задача сразу в двух
|
индекса в файл, старая форма меты, пометка `decomposed` у цели с задачами, сырьё
|
||||||
индексах, нечего восстанавливать) печатает отдельной пометкой `НЕОДНОЗНАЧНО` —
|
в конец категории), а неоднозначное (задача сразу в двух индексах, нечего
|
||||||
это тебе, и это идёт строкой доклада. **Ссылка на исчезнувший файл в пометку не
|
восстанавливать, **тип, которого неоткуда взять**) печатает отдельной пометкой
|
||||||
попадает:** `--fix` её просто не трогает, и она остаётся `ОШИБКА` обычного
|
`НЕОДНОЗНАЧНО` — это тебе, и это идёт строкой доклада. **Ссылка на исчезнувший
|
||||||
`check` — то есть видна, но в докладе её надо назвать отдельно.
|
файл в пометку не попадает:** `--fix` её просто не трогает, и она остаётся
|
||||||
|
`ОШИБКА` обычного `check` — то есть видна, но в докладе её надо назвать отдельно.
|
||||||
|
|
||||||
`--fix` правит **и файлы** — ровно в двух местах, где источник ровно один и
|
`--fix` правит **и файлы** — там, где источник ровно один и выбирать не из чего:
|
||||||
выбирать не из чего: «зачем», оставшееся только в индексе, переезжает в мету,
|
тип переезжает из прежнего дома (тег `kind:`, префикс `[goal]`/`[idea]`) в поле
|
||||||
и цель, у которой есть задачи, получает тег `decomposed`. Оба случая печатаются
|
меты, заголовок получает эмодзи, поле места — имя по типу, «зачем», оставшееся
|
||||||
поимённо.
|
только в индексе, переезжает в мету, цель с задачами получает `decomposed`.
|
||||||
|
Каждый случай печатается поимённо.
|
||||||
|
|
||||||
|
**Тип, который не выводится ниоткуда, `--fix` не угадывает.** `feature` от
|
||||||
|
`chore` машина не отличает, и подставленное наугад значение врало бы ровно там,
|
||||||
|
где по нему принимают решение. Такие записи идут в `НЕОДНОЗНАЧНО`, и тип им
|
||||||
|
проставляет человек — `edit <слаг> --type …`.
|
||||||
|
|
||||||
**Что механизировано, а что нет.** У задачи, взятой в набор (`sprint take` и
|
**Что механизировано, а что нет.** У задачи, взятой в набор (`sprint take` и
|
||||||
`check` по задачам спринта), проверяются три вещи, и у каждой своя глубина:
|
`check` по задачам спринта), проверяется схема её типа, и у каждой части своя
|
||||||
|
глубина:
|
||||||
|
|
||||||
- **критерии приёмки** — число пунктов жёстко (меньше двух отказ, больше пяти
|
- **тип** — жёстко: назван и из закрытого словаря;
|
||||||
замечание), наличие оракула **эвристикой** по слову «оракул» в пункте;
|
- **критерии приёмки** (`feature`, `fix`, `chore`) — число пунктов жёстко
|
||||||
- **род работы** — жёстко: назван и из закрытого словаря;
|
(меньше двух отказ, больше пяти замечание), наличие оракула **эвристикой** по
|
||||||
- **раздел «Затрагивает»** — только **наличие непустого**. Полнота перечня машине
|
слову «оракул» в пункте;
|
||||||
не видна: границу, которую забыли назвать, она от отсутствующей не отличает.
|
- **прочие разделы схемы** (`Затрагивает`, `Воспроизведение`, `Вопрос`,
|
||||||
|
`Куда ляжет ответ`, `Завершение`) — только **наличие непустого**. Содержимое
|
||||||
|
машине не видно: границу, которую забыли назвать, она от отсутствующей не
|
||||||
|
отличает, а шаги, по которым ничего не воспроизводится, — от годных.
|
||||||
|
|
||||||
Настоящий оракул от слова «оракул» машина тоже не отличает, поэтому эвристика
|
Настоящий оракул от слова «оракул» машина тоже не отличает, поэтому эвристика
|
||||||
даёт только замечание, и в докладе это называется как есть: «проверено число
|
даёт только замечание, и в докладе это называется как есть: «проверено наличие
|
||||||
пунктов и наличие границ, годность оракулов и полнота границ — глазами».
|
разделов своего типа и число критериев, годность оракулов и полнота границ —
|
||||||
|
глазами».
|
||||||
|
|
||||||
Формат файла, меты, слага, индексов и `REJECTED.md` —
|
Формат записи, меты, слага, индексов и `REJECTED.md` —
|
||||||
[references/task-format.md](references/task-format.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. **Фильтр.** Делаем прямо сейчас — не заводим. Не пожалеем о потере — не
|
1. **Фильтр.** Делаем прямо сейчас — не заводим. Не пожалеем о потере — не
|
||||||
заводим. Родилось три кандидата — покажи их и спроси, какие заводить: молча
|
заводим. Родилось три кандидата — покажи их и спроси, какие заводить: молча
|
||||||
@@ -444,30 +473,36 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
|||||||
ту строку и что изменилось с момента отказа (`add` предупредит и сам, но
|
ту строку и что изменилось с момента отказа (`add` предупредит и сам, но
|
||||||
молча заводить нельзя). Две задачи об одном — самая дорогая находка
|
молча заводить нельзя). Две задачи об одном — самая дорогая находка
|
||||||
переоценки.
|
переоценки.
|
||||||
3. **Тип по тесту готовности** (см. task-format): проходит — задача, не
|
3. **Тип** — `--type` обязателен, и он же первое содержательное решение:
|
||||||
проходит — идея (`--type idea`). Не делается одним заходом — это не эпик, а
|
|
||||||
несколько задач под одной целью: дроби сразу. Возможность приложения, а не
|
- возможность приложения, а не шаг к ней → `goal`;
|
||||||
шаг — цель (`--type goal`).
|
- снаружи появляется то, чего не было → `feature`;
|
||||||
4. **Цель задачи — если род её требует.** У `feature` должен быть
|
- поведение расходится с заявленным и **воспроизводится** → `fix`
|
||||||
`--goal <слаг>`: новая возможность и есть содержание цели. Подходящей нет —
|
(не воспроизводится → `research`);
|
||||||
либо она заводится (`--type goal`), либо перед тобой не `feature`. У `fix`,
|
- обслуживание, наблюдаемое поведение не меняется → `chore`;
|
||||||
`chore` и `research` цели может не быть вовсе, и придумывать её не надо. У
|
- исход — знание, а не изменение системы → `research`.
|
||||||
идеи цель проставляется, когда идея становится задачей.
|
|
||||||
5. **Род работы** — `--kind feature|fix|chore|research` (см. «Род работы»). Не
|
Не подходит ни один — в записи их два, разбирай. Не проходит тест готовности
|
||||||
подходит ни один — задача не одна, разбирай.
|
(см. task-format) — это **сырьё**: `--type research`, раздел «Вопрос» пока
|
||||||
6. `add …`, затем допиши тело редактором: одна фраза, **затрагиваемые границы**,
|
пуст, место в конце категории. Не делается одним заходом — это не эпик, а
|
||||||
критерии приёмки с оракулами, рамки. «Зачем» отвечает «зачем нужна эта
|
несколько задач под одной целью: дроби сразу.
|
||||||
задача» — состояние, остаток, боль, — а не пересказывает первый абзац, и
|
4. **Цель — если тип её требует.** У `feature` должен быть `--goal <слаг>`:
|
||||||
пишется **для человека**: не «канонизация внутри транзакции», а «тело 40 МиБ
|
новая возможность и есть содержание цели. Подходящей нет — либо она
|
||||||
держит блокировку 5 секунд, соседние доставки уходят в отказ».
|
заводится (`--type goal`), либо перед тобой не `feature`. У `fix`, `chore` и
|
||||||
7. `check`.
|
`research` цели может не быть вовсе, и придумывать её не надо.
|
||||||
|
5. `add …`, затем допиши тело редактором **по схеме своего типа** — шаблон её
|
||||||
|
уже разложил, устав типа объясняет каждый раздел. «Зачем» отвечает «зачем
|
||||||
|
нужна эта задача» — состояние, остаток, боль, — а не пересказывает первый
|
||||||
|
абзац, и пишется **для человека**: не «канонизация внутри транзакции», а
|
||||||
|
«тело 40 МиБ держит блокировку 5 секунд, соседние доставки уходят в отказ».
|
||||||
|
6. `check`.
|
||||||
|
|
||||||
### Разобрать находки аудита или ревью
|
### Разобрать находки аудита или ревью
|
||||||
|
|
||||||
Ревью и аудиты — тоже источник задач, но с зеркальной диалогу опасностью: не
|
Ревью и аудиты — тоже источник задач, но с зеркальной диалогу опасностью: не
|
||||||
пять файлов из одной мысли, а сорок файлов из сорока сырых находок. Защита та
|
пять файлов из одной мысли, а сорок файлов из сорока сырых находок. Защита та
|
||||||
же, что в самом ревью: кластеризация по причине, дедуп против живых и
|
же, что в самом ревью: кластеризация по причине, дедуп против живых и
|
||||||
`REJECTED.md`, находка без свидетельства → идея, а не задача, и карта кластеров
|
`REJECTED.md`, находка без свидетельства → сырьё (`research`), а не задача, и карта кластеров
|
||||||
пользователю до создания файлов. Порядок, отображение серьёзности и привязка к
|
пользователю до создания файлов. Порядок, отображение серьёзности и привязка к
|
||||||
целям — [references/from-review.md](references/from-review.md).
|
целям — [references/from-review.md](references/from-review.md).
|
||||||
|
|
||||||
@@ -481,7 +516,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
|||||||
Если переводить надо не только задачи, а весь `docs/` — это скилл
|
Если переводить надо не только задачи, а весь `docs/` — это скилл
|
||||||
`av-dev-pm:canon`, и он зовёт этот сценарий сам на своём шаге.
|
`av-dev-pm:canon`, и он зовёт этот сценарий сам на своём шаге.
|
||||||
|
|
||||||
### Декомпозиция и штурм идеи
|
### Декомпозиция и штурм сырья
|
||||||
|
|
||||||
[references/split.md](references/split.md). Обе операции превращают одну запись в
|
[references/split.md](references/split.md). Обе операции превращают одну запись в
|
||||||
несколько, и у обеих есть проверяемый тест: части должны **мерджиться порознь** и
|
несколько, и у обеих есть проверяемый тест: части должны **мерджиться порознь** и
|
||||||
@@ -551,10 +586,14 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
|||||||
- **предписание процесса в теле** — «делать таким-то профилем ревью», «взять
|
- **предписание процесса в теле** — «делать таким-то профилем ревью», «взять
|
||||||
такой-то агент»: это второй дом для правила выбора и путь понизить требования
|
такой-то агент»: это второй дом для правила выбора и путь понизить требования
|
||||||
решением, принятым до проектирования. Снимается;
|
решением, принятым до проектирования. Снимается;
|
||||||
- **род, разошедшийся с задачей** — задача заводилась починкой, а после разбора
|
- **тип, разошедшийся с задачей** — задача заводилась починкой, а после разбора
|
||||||
оказалось, что поведение никогда и не было заявлено: это `feature`, а не `fix`.
|
оказалось, что поведение никогда и не было заявлено: это `feature`, а не `fix`.
|
||||||
Правится `edit <slug> --kind …`; род, оставшийся от прошлой формулировки, врёт
|
Правится `edit <slug> --type …`; тип, оставшийся от прошлой формулировки, врёт
|
||||||
ровно там, где по нему отбирают;
|
ровно там, где по нему отбирают, **и требует не тех разделов**: у брошенного
|
||||||
|
`fix` останется «Воспроизведение», которого нечем заполнить;
|
||||||
|
- **сырьё, у которого появился вопрос** — разведка обросла формулировкой, но
|
||||||
|
раздел «Вопрос» так и пуст: она числится сырьём и в спринт не берётся.
|
||||||
|
Записывается вопрос, и `check --fix` поднимает строку из конца категории;
|
||||||
- **границы, названные вместо реализации** — «переписать хранилище на новый
|
- **границы, названные вместо реализации** — «переписать хранилище на новый
|
||||||
драйвер» в разделе «Затрагивает» это не граница, а замысел. Границы —
|
драйвер» в разделе «Затрагивает» это не граница, а замысел. Границы —
|
||||||
`таблица points и её миграция`, `эндпоинт POST /ingest`, `формат отпечатка на
|
`таблица points и её миграция`, `эндпоинт POST /ingest`, `формат отпечатка на
|
||||||
@@ -619,7 +658,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
|||||||
|
|
||||||
- **Развилки — пользователю.** Через `AskUserQuestion`, с уже сформулированным
|
- **Развилки — пользователю.** Через `AskUserQuestion`, с уже сформулированным
|
||||||
предварительным суждением (**рекомендация — первым вариантом**). Что выкинуть,
|
предварительным суждением (**рекомендация — первым вариантом**). Что выкинуть,
|
||||||
под какую цель отнести, какая рамка идеи верна — решение пользователя. Слаг,
|
под какую цель отнести, какая рамка разведки верна — решение пользователя. Слаг,
|
||||||
формулировка, порядок строк в индексе — механика, делаем сами.
|
формулировка, порядок строк в индексе — механика, делаем сами.
|
||||||
- **Не больше трёх вопросов за раз.** Пачка длиннее трёх тяжела для ответа;
|
- **Не больше трёх вопросов за раз.** Пачка длиннее трёх тяжела для ответа;
|
||||||
решений больше — веди **несколько итераций** диалога по ≤3, а не один
|
решений больше — веди **несколько итераций** диалога по ≤3, а не один
|
||||||
|
|||||||
@@ -23,8 +23,11 @@
|
|||||||
- **Находка со свидетельством**, отложенная к исполнению → **задача**.
|
- **Находка со свидетельством**, отложенная к исполнению → **задача**.
|
||||||
Свидетельство и последствие переносим в тело — это её «почему», то самое, что
|
Свидетельство и последствие переносим в тело — это её «почему», то самое, что
|
||||||
переживает запись.
|
переживает запись.
|
||||||
- **Находка без свидетельства / низкой уверенности** → **идея** (`[idea]`), а не
|
- **Находка без свидетельства / низкой уверенности** → **сырьё**: `research`, у
|
||||||
задача. Её судьба — штурм, где либо найдётся подтверждение, либо она уедет в
|
которого раздел «Вопрос» и есть недостающее свидетельство («при каких условиях
|
||||||
|
это воспроизводится»). Не `fix`: без `Воспроизведения` его в спринт не
|
||||||
|
возьмут, и правильно — чинить нечего, пока непонятно, что ломается. Судьба
|
||||||
|
сырья — штурм, где либо найдётся подтверждение, либо оно уедет в
|
||||||
`REJECTED.md`.
|
`REJECTED.md`.
|
||||||
- **Уже починено по ходу ревью** → **ничего**. Починенное не заводим.
|
- **Уже починено по ходу ревью** → **ничего**. Починенное не заводим.
|
||||||
- **Развилка, решённая при ревью** → ничего; решённая «потом» → задача с
|
- **Развилка, решённая при ревью** → ничего; решённая «потом» → задача с
|
||||||
@@ -44,13 +47,13 @@
|
|||||||
4. **Разложи по целям — там, где цель нужна.** Большинство находок ревью это
|
4. **Разложи по целям — там, где цель нужна.** Большинство находок ревью это
|
||||||
`fix` и `chore`, и **цель им не требуется**: они служат работоспособности, а
|
`fix` и `chore`, и **цель им не требуется**: они служат работоспособности, а
|
||||||
не направлению, и в спринт входят помимо его цели. Придуманная им цель —
|
не направлению, и в спринт входят помимо его цели. Придуманная им цель —
|
||||||
ровно то враньё, от которого спасает род работы.
|
ровно то враньё, от которого спасает тип.
|
||||||
|
|
||||||
Цель обязательна у находки, которая оказалась **новой возможностью**
|
Цель обязательна у находки, которая оказалась **новой возможностью**
|
||||||
(`kind:feature`): нашлось поведение, которого никто не заказывал, и его надо
|
(`feature`): нашлось поведение, которого никто не заказывал, и его надо
|
||||||
либо заказать целью, либо убрать. Подходящей цели нет — заведи её
|
либо заказать целью, либо убрать. Подходящей цели нет — заведи её
|
||||||
(`add --type goal --section Направления`) в том же проходе.
|
(`add --type goal --section Направления`) в том же проходе.
|
||||||
5. **Покажи карту до создания файлов.** Кластер → задача / идея / строка в
|
5. **Покажи карту до создания файлов.** Кластер → задача / сырьё / строка в
|
||||||
пакетный файл / уже заведено / отброшено, и под какую цель — пачкой через
|
пакетный файл / уже заведено / отброшено, и под какую цель — пачкой через
|
||||||
`AskUserQuestion`. Это тот же барьер, что и «три кандидата» в интейке из
|
`AskUserQuestion`. Это тот же барьер, что и «три кандидата» в интейке из
|
||||||
диалога: массовое заведение файлов без подтверждения — ровно тот отказ, ради
|
диалога: массовое заведение файлов без подтверждения — ровно тот отказ, ради
|
||||||
@@ -60,11 +63,12 @@
|
|||||||
6. **Заводи утверждённое** через `tasks.py add`, с тремя добавками:
|
6. **Заводи утверждённое** через `tasks.py add`, с тремя добавками:
|
||||||
- **тег партии** — `--tag review-ГГГГ-ММ-ДД` (или `audit-<тема>`), чтобы весь
|
- **тег партии** — `--tag review-ГГГГ-ММ-ДД` (или `audit-<тема>`), чтобы весь
|
||||||
заход разбора поднимался одной командой `list --tag …`;
|
заход разбора поднимался одной командой `list --tag …`;
|
||||||
- **род работы** — `--kind`. У находок ревью он **не по умолчанию `fix`**:
|
- **тип** — `--type`, и он **не по умолчанию `fix`**: починкой считается
|
||||||
починкой считается расхождение с заявленным поведением, а находка «этого
|
расхождение с заявленным поведением, а находка «этого свойства никто не
|
||||||
свойства никто не заказывал» — это `feature`, находка «не знаем, как
|
заказывал» — это `feature`, находка «не знаем, как поведёт себя драйвер» —
|
||||||
поведёт себя драйвер» — `research`. Род, розданный оптом, врёт ровно там,
|
`research`. Тип, розданный оптом, врёт ровно там, где по нему потом
|
||||||
где по нему потом отбирают;
|
отбирают, **и требует не тех разделов**: каждому `fix` придётся заполнить
|
||||||
|
`Воспроизведение`, а у находки без свидетельства его нет;
|
||||||
- **провенанс в теле** — кто нашёл, каким проходом, с каким свидетельством.
|
- **провенанс в теле** — кто нашёл, каким проходом, с каким свидетельством.
|
||||||
Без него через месяц не отличить проверенную находку от догадки.
|
Без него через месяц не отличить проверенную находку от догадки.
|
||||||
7. `tasks.py check`.
|
7. `tasks.py check`.
|
||||||
|
|||||||
@@ -57,10 +57,10 @@
|
|||||||
через квартал вопрос «куда делась задача X» отвечается строкой со ссылками на
|
через квартал вопрос «куда делась задача X» отвечается строкой со ссылками на
|
||||||
наследников, а не археологией git;
|
наследников, а не археологией git;
|
||||||
- родитель осмыслен как **возможность**, а не как шаг → это цель. Тип на месте
|
- родитель осмыслен как **возможность**, а не как шаг → это цель. Тип на месте
|
||||||
не меняется (цель живёт в другом индексе): заводится `[goal]` в `ROADMAP.md`,
|
не меняется (цель живёт в другом индексе): заводится `--type goal` в `ROADMAP.md`,
|
||||||
части получают `--goal <новый слаг>`, родитель закрывается с причиной-ссылкой.
|
части получают `--goal <новый слаг>`, родитель закрывается с причиной-ссылкой.
|
||||||
|
|
||||||
**Промежуточного зонтика между целью и задачей нет.** Тип `[epic]` упразднён:
|
**Промежуточного зонтика между целью и задачей нет.** Тип `epic` упразднён:
|
||||||
роль зонтика играет цель, а слишком крупный шаг дробится на шаги помельче под
|
роль зонтика играет цель, а слишком крупный шаг дробится на шаги помельче под
|
||||||
той же целью. Если частям нужен общий заголовок — значит у них общая
|
той же целью. Если частям нужен общий заголовок — значит у них общая
|
||||||
возможность, и её надо назвать целью, а не заводить временный тип.
|
возможность, и её надо назвать целью, а не заводить временный тип.
|
||||||
@@ -73,10 +73,15 @@
|
|||||||
спринт продолжается остальными. Части заводятся сразу под той же целью, но в
|
спринт продолжается остальными. Части заводятся сразу под той же целью, но в
|
||||||
текущий набор **не добавляются** — набор заморожен.
|
текущий набор **не добавляются** — набор заморожен.
|
||||||
|
|
||||||
## Мозговой штурм идеи
|
## Мозговой штурм сырья
|
||||||
|
|
||||||
Идея (`[idea]`) не проходит тест «готова к взятию»: неясно, что именно делаем.
|
Сырьё — запись типа `research`, у которой раздел «Вопрос» пуст: она не проходит
|
||||||
Штурм проясняет — и это **generative-операция, а не applicative**.
|
тест «готова к взятию», потому что неясно, что именно делаем. Штурм проясняет —
|
||||||
|
и это **generative-операция, а не applicative**.
|
||||||
|
|
||||||
|
Исход штурма и есть заполненный «Вопрос» (тогда разведку можно брать в спринт)
|
||||||
|
или набор задач с типами, которые из ответа следуют. Третий законный исход —
|
||||||
|
`close --reason`.
|
||||||
|
|
||||||
Applicative-штурм («перечисли задачи, следующие из идеи») выдаёт очевидное:
|
Applicative-штурм («перечисли задачи, следующие из идеи») выдаёт очевидное:
|
||||||
перечисляется то, что уже видно в формулировке. Ценное — на уровень выше.
|
перечисляется то, что уже видно в формулировке. Ценное — на уровень выше.
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
# 🧹 `chore` — обслуживание, наблюдаемое поведение не меняется
|
||||||
|
|
||||||
|
Зависимости, сборка, перенос, чистка, оснастка. Отвечает на **«что нужно
|
||||||
|
сделать»**, глаголом в неопределённой форме.
|
||||||
|
|
||||||
|
Общая форма записи (мета, слаг, строка индекса) — [task-format.md](task-format.md).
|
||||||
|
Здесь только то, что у этого типа своё.
|
||||||
|
|
||||||
|
## Схема
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| --- | --- |
|
||||||
|
| Заголовок отвечает на | что нужно сделать |
|
||||||
|
| Обязательные разделы | `Затрагивает`, `Критерии приёмки` |
|
||||||
|
| Допустимые сверх того | `Рамки`, `Вопросы` |
|
||||||
|
| Поле места | **Категория** — полка домена беклога |
|
||||||
|
| Цель (`goal:<слаг>`) | нет: цель — это возможность, а здесь её не появляется |
|
||||||
|
| Индекс | `BACKLOG.md` → `SPRINT.md` |
|
||||||
|
| Берётся в спринт | да |
|
||||||
|
|
||||||
|
## Адресат — разработчик, и это законно
|
||||||
|
|
||||||
|
Тест готовности спрашивает «что станет наблюдаемо иначе». У `chore` ответ
|
||||||
|
адресован **разработчику**, а не пользователю: «перестанет собираться два раза»,
|
||||||
|
«уедет последний вызов устаревшего API», «проверки гоняются одной командой».
|
||||||
|
Это ответ, а не отговорка.
|
||||||
|
|
||||||
|
**У `chore` тест готовности слабее честно, а не молча.** Пока типа не было,
|
||||||
|
такие задачи либо не заводились вовсе, либо формулировались как выдуманная
|
||||||
|
пользовательская польза — и то и другое хуже, чем сказать прямо, для кого работа.
|
||||||
|
|
||||||
|
Отсюда же граница: если после задачи меняется то, что видит пользователь, — это
|
||||||
|
не `chore`. Тип, оставшийся от первой формулировки, врёт ровно там, где по нему
|
||||||
|
отбирают.
|
||||||
|
|
||||||
|
## Алгоритм
|
||||||
|
|
||||||
|
1. **Проверить, что поведение не меняется.** Меняется — это `feature` или `fix`,
|
||||||
|
и у неё другие требования (цель, воспроизведение).
|
||||||
|
2. **Назвать, что перестанет мешать** — одной фразой, адресуясь разработчику.
|
||||||
|
«Прибраться в модуле X» ответом не является: непонятно, что изменится.
|
||||||
|
3. **Назвать границы** в `Затрагивает`. У обслуживания они часто не в коде:
|
||||||
|
конфиг и его образцы, версия зависимости, команда сборки, файл CI. Границей
|
||||||
|
считается то, у чего есть внешняя сторона и цена изменения.
|
||||||
|
4. **Написать критерии приёмки** — 2–5 утверждений с оракулами. У `chore`
|
||||||
|
оракул обычно самый дешёвый из всех типов: команда, которая раньше падала
|
||||||
|
или требовала трёх шагов, теперь отрабатывает одним.
|
||||||
|
5. **Проверить, что это не «заодно».** Обслуживание любит склеиваться в пачку
|
||||||
|
(«обновить зависимости и переписать сборку и убрать мёртвый код»). Не
|
||||||
|
мерджится порознь — это несколько задач ([split.md](split.md)).
|
||||||
|
6. **Цель не проставлять.** `chore` служит работоспособности, а не направлению,
|
||||||
|
и в набор спринта входит помимо его цели. Работа по сопровождению проекта
|
||||||
|
при этом видна в роадмапе — секцией `Сопровождение`, но целью не становится.
|
||||||
|
|
||||||
|
## Что видит машина, а что человек
|
||||||
|
|
||||||
|
`check` и `sprint take` смотрят на **наличие непустого** `Затрагивает` и на
|
||||||
|
**число** критериев — ровно то же, что у `feature`. Разница между типами здесь не
|
||||||
|
в строгости проверки, а в том, **кому адресован ответ** на «что станет
|
||||||
|
наблюдаемо иначе», — и это судит человек.
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
# ✨ `feature` — снаружи появляется то, чего не было
|
||||||
|
|
||||||
|
Задача, после которой наблюдаемое поведение меняется в сторону новой
|
||||||
|
возможности. Отвечает на **«что нужно сделать»** и пишется глаголом в
|
||||||
|
неопределённой форме.
|
||||||
|
|
||||||
|
Общая форма записи (мета, слаг, строка индекса) — [task-format.md](task-format.md).
|
||||||
|
Здесь только то, что у этого типа своё.
|
||||||
|
|
||||||
|
## Схема
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| --- | --- |
|
||||||
|
| Заголовок отвечает на | что нужно сделать («Печатать поле одним куском кода») |
|
||||||
|
| Обязательные разделы | `Затрагивает`, `Критерии приёмки` |
|
||||||
|
| Допустимые сверх того | `Рамки`, `Вопросы` |
|
||||||
|
| Поле места | **Категория** — полка домена беклога |
|
||||||
|
| Цель (`goal:<слаг>`) | **обязательна** |
|
||||||
|
| Индекс | `BACKLOG.md` → `SPRINT.md` |
|
||||||
|
| Берётся в спринт | да |
|
||||||
|
|
||||||
|
**Цель обязательна, и это единственный тип, у которого так.** Новая возможность
|
||||||
|
и есть содержание цели: подходящей нет — либо она заводится, либо перед тобой не
|
||||||
|
`feature`. `sprint take` без цели откажет.
|
||||||
|
|
||||||
|
## Алгоритм
|
||||||
|
|
||||||
|
1. **Найти цель или завести её.** Задача без цели, названная функцией, — самый
|
||||||
|
частый способ пронести в беклог работу, которой никто не заказывал.
|
||||||
|
2. **Назвать границы** в разделе `Затрагивает`: эндпоинт или команда, таблица и
|
||||||
|
миграция, формат на диске, публичный тип пакета, внешний сервис. Названы
|
||||||
|
**границы, а не замысел**: «переписать хранилище на новый драйвер» — замысел,
|
||||||
|
`таблица points и её миграция` — граница. Проверяется вопросом «это можно
|
||||||
|
назвать до того, как решено *как* делать?».
|
||||||
|
3. **Написать критерии приёмки** — 2–5 проверяемых утверждений списком, у
|
||||||
|
каждого назван оракул. Не «работает корректно», а «повторный прогон даёт тот
|
||||||
|
же отпечаток — оракул: команда сверки».
|
||||||
|
4. **Сказать, какую строку «Завершения» цели задача двигает.** Одной строкой в
|
||||||
|
теле. Это защита от задачи «отрефакторить X»: она проваливается не потому,
|
||||||
|
что невидима снаружи, а потому, что не находит строки, к которой относится.
|
||||||
|
5. **Проверить, что задача одна.** Отвечается всё, но задача не делается одним
|
||||||
|
заходом и не мерджится целиком — это несколько задач под одной целью, дроби
|
||||||
|
сразу ([split.md](split.md)). Промежуточного зонтика между целью и задачей
|
||||||
|
нет.
|
||||||
|
6. **Реализация** — дело пайплайна проекта, не этого скилла. Закрывается
|
||||||
|
`close <слаг> --implemented`: файл и строка удаляются, суть переезжает в
|
||||||
|
`openspec/specs/` и документацию.
|
||||||
|
|
||||||
|
## Что видит машина, а что человек
|
||||||
|
|
||||||
|
`check` и `sprint take` смотрят на **наличие непустого** раздела `Затрагивает`,
|
||||||
|
на **число** критериев (меньше двух — отказ, больше пяти — замечание) и на цель.
|
||||||
|
Наличие оракула проверяется **эвристикой** — словом «оракул» в пункте.
|
||||||
|
|
||||||
|
Полнота перечня границ машине не видна: границу, которую забыли назвать, она от
|
||||||
|
отсутствующей не отличает. Настоящий оракул от слова «оракул» тоже не отличает.
|
||||||
|
Поэтому в докладе это называется как есть: «проверено число пунктов и наличие
|
||||||
|
границ, годность оракулов и полнота границ — глазами».
|
||||||
|
|
||||||
|
**Критерии — пол, но расхождение с ними есть дефект критериев.** Видишь, что
|
||||||
|
критерии закрыты, а суть задачи не достигнута — **правь критерии и возвращай
|
||||||
|
задачу**, а не держи невидимое сверх-требование: иначе исполнитель никогда не
|
||||||
|
знает, закончил ли, и мотивирован занижать критерии заранее.
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# 🐞 `fix` — поведение расходится с заявленным
|
||||||
|
|
||||||
|
Задача о расхождении между тем, что система делает, и тем, что про неё заявлено
|
||||||
|
— в спеке, в инварианте `CLAUDE.md`, в критериях закрытой задачи. Отвечает на
|
||||||
|
**«что нужно сделать»**, глаголом в неопределённой форме, перед ним допускается
|
||||||
|
«не»: «Не отбрасывать молча лишние символы в ходе».
|
||||||
|
|
||||||
|
Общая форма записи (мета, слаг, строка индекса) — [task-format.md](task-format.md).
|
||||||
|
Здесь только то, что у этого типа своё.
|
||||||
|
|
||||||
|
## Схема
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| --- | --- |
|
||||||
|
| Заголовок отвечает на | что нужно сделать |
|
||||||
|
| Обязательные разделы | **`Воспроизведение`**, `Затрагивает`, `Критерии приёмки` |
|
||||||
|
| Допустимые сверх того | `Рамки`, `Вопросы` |
|
||||||
|
| Поле места | **Категория** — полка домена беклога |
|
||||||
|
| Цель (`goal:<слаг>`) | необязательна |
|
||||||
|
| Индекс | `BACKLOG.md` → `SPRINT.md` |
|
||||||
|
| Берётся в спринт | да |
|
||||||
|
|
||||||
|
## `Воспроизведение` — раздел, которого нет у других типов
|
||||||
|
|
||||||
|
**Не воспроизводится — это `research`, а не `fix`.** Правило было записано и
|
||||||
|
раньше, но проверять его было нечем, и «починки» без единого шага повторения
|
||||||
|
уходили в спринт наравне с остальными. Раздел делает правило проверяемым: он
|
||||||
|
называет, **что сделать, чтобы расхождение проявилось, и что при этом видно
|
||||||
|
вместо ожидаемого**.
|
||||||
|
|
||||||
|
Пишется двумя частями, обе обязательны по смыслу:
|
||||||
|
|
||||||
|
- **шаги или вход** — команда, запрос, файл, последовательность действий;
|
||||||
|
- **что видно и что ожидалось** — «ввод `а1б2` ходит в `a1`, а должен быть
|
||||||
|
отвергнут с ошибкой».
|
||||||
|
|
||||||
|
Это не критерии приёмки и не дублирует их: воспроизведение описывает **сегодня**,
|
||||||
|
критерии — **завтра**. Пропущенное воспроизведение чаще всего означает одно из
|
||||||
|
двух: расхождение приняли на слово, или его вообще нет, а есть недовольство
|
||||||
|
поведением — и тогда это `feature`, а не `fix`.
|
||||||
|
|
||||||
|
## Алгоритм
|
||||||
|
|
||||||
|
1. **Воспроизвести.** Не удаётся — это `research`: заведи вопрос «при каких
|
||||||
|
условиях проявляется» и не притворяйся, что чинить есть что.
|
||||||
|
2. **Найти, чему поведение противоречит.** Спека, инвариант, критерий закрытой
|
||||||
|
задачи. Не противоречит ничему — это `feature`: поведение никогда и не было
|
||||||
|
заявлено, а тип, оставшийся от первой формулировки, врёт ровно там, где по
|
||||||
|
нему отбирают.
|
||||||
|
3. **Записать воспроизведение** — шаги и наблюдаемое против ожидаемого.
|
||||||
|
4. **Назвать границы** в `Затрагивает`: починка часто трогает больше, чем
|
||||||
|
кажется по объёму текста, и оценка систематически занижена именно здесь.
|
||||||
|
5. **Написать критерии приёмки** — 2–5 утверждений с оракулами. У починки
|
||||||
|
почти всегда есть парный критерий: **прежнее поведение не сломалось**
|
||||||
|
(«ввод `а1` принимается по-прежнему»). Без него починка чинит одно и ломает
|
||||||
|
соседнее.
|
||||||
|
6. **Цель не выдумывать.** `fix` служит работоспособности, а не направлению, и в
|
||||||
|
набор спринта входит помимо его цели. Придуманная цель — то же враньё, от
|
||||||
|
которого спасает тип.
|
||||||
|
7. **Записать дефект в журнал** `docs/review.md` с пометкой «проскочил / пойман
|
||||||
|
ревью». Проскочившие — эвал-сет для калибровки конвейера; пойманные с
|
||||||
|
оракулом — лучшая опора для прохода ревью: проектные, воспроизводимые,
|
||||||
|
однажды оказавшиеся правдой.
|
||||||
|
|
||||||
|
## Что видит машина, а что человек
|
||||||
|
|
||||||
|
`check` и `sprint take` смотрят на **наличие непустого** `Воспроизведения` и
|
||||||
|
`Затрагивает` и на **число** критериев. Годность воспроизведения — человеку:
|
||||||
|
шаги, по которым ничего не воспроизводится, машина от годных не отличает, и
|
||||||
|
делать вид, что проверено больше проверенного, хуже, чем не проверять вовсе.
|
||||||
@@ -1,78 +1,125 @@
|
|||||||
# Формат задач, целей и индексов
|
# Формат записей и индексов
|
||||||
|
|
||||||
Заголовок, мета-блок и строку индекса ставит `tasks.py add` — руками их не
|
Заголовок, мета-блок и строку индекса ставит `tasks.py add` — руками их не
|
||||||
пишут. Этот файл описывает, что именно скрипт создаёт и что проверяет `check`;
|
пишут. Этот файл описывает **общую форму** любой записи и то, что проверяет
|
||||||
тело задачи (одну фразу, критерии, рамки, контекст) дописывает агент.
|
`check`; тело дописывает агент.
|
||||||
|
|
||||||
## Файл задачи
|
Чем разделы тела отличаются от типа к типу, какой алгоритм у каждого типа и что
|
||||||
|
у него обязательно — **отдельным файлом на тип**:
|
||||||
|
|
||||||
|
| Тип | Файл | Одной строкой |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 🎯 `goal` | [task-goal.md](task-goal.md) | возможность приложения |
|
||||||
|
| ✨ `feature` | [task-feature.md](task-feature.md) | снаружи появляется то, чего не было |
|
||||||
|
| 🐞 `fix` | [task-fix.md](task-fix.md) | поведение расходится с заявленным |
|
||||||
|
| 🧹 `chore` | [task-chore.md](task-chore.md) | обслуживание, поведение не меняется |
|
||||||
|
| 🔬 `research` | [task-research.md](task-research.md) | исход — знание, а не изменение |
|
||||||
|
|
||||||
|
## Файл записи
|
||||||
|
|
||||||
`items/<slug>.md`:
|
`items/<slug>.md`:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# Тай-брейк при равной полноте
|
# 🐞 Не отбрасывать молча лишние символы в ходе
|
||||||
|
|
||||||
- **Секция:** Ядро — вышла из спринта: остаток писал нерешённое в журнал
|
- **Тип:** fix
|
||||||
- **Зачем:** порядок канонических форм берёт меньшее в 96% случаев — для накопительных это систематический недосчёт
|
- **Категория:** Ядро — вышла из спринта: остаток писал нерешённое в журнал
|
||||||
- **Теги:** goal:merge-robustness, kind:fix, sprint:2026-08-03
|
- **Зачем:** ввод «а1б2» ходит в a1 — игрок не видит, что ошибся, и винит игру
|
||||||
|
- **Теги:** goal:merge-robustness, sprint:2026-08-03
|
||||||
|
|
||||||
При столкновении точек выигрывает более полная, но при равной полноте побеждает
|
Разбор хода читает первые два символа и молча выбрасывает остаток строки.
|
||||||
последняя доставка — а она систематически беднее первой.
|
|
||||||
|
## Воспроизведение
|
||||||
|
|
||||||
|
Ввести `а1б2` в свой ход: программа ходит в `a1` и ничего не сообщает.
|
||||||
|
Ожидалось — отказ с ошибкой разбора.
|
||||||
|
|
||||||
## Затрагивает
|
## Затрагивает
|
||||||
|
|
||||||
Таблица `points` и её миграция; правило слияния в приёме доставки; формат
|
Разбор строки хода; текст ошибки в выводе партии. Формат сохранения партии
|
||||||
отпечатка состояния на диске. Публичного контракта не трогает.
|
не трогается.
|
||||||
|
|
||||||
## Критерии приёмки
|
## Критерии приёмки
|
||||||
|
|
||||||
- повторный прогон свёртки даёт тот же отпечаток состояния — оракул: команда сверки
|
- ввод «а1б2» отвергается с ошибкой — оракул: тест разбора
|
||||||
- накопительная метрика за сутки не уменьшается после повторной доставки — оракул: тест
|
- ввод «а1» принимается по-прежнему — оракул: тест разбора
|
||||||
- в логе видно, какая из двух точек выиграла и почему — оракул: глазами по логу прогона
|
|
||||||
|
|
||||||
## Рамки
|
## Рамки
|
||||||
|
|
||||||
Схема не трогается; данные только читаются; перезапуск сервиса допустим.
|
Схема не трогается; данные только читаются; перезапуск допустим.
|
||||||
|
|
||||||
Связано: решение о канонической форме содержимого.
|
Связано: решение о канонической форме содержимого.
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Заголовок H1** — он же заголовок строки в индексе, дословно. Тип кодируется
|
- **Заголовок H1** — он же заголовок строки в индексе, дословно. Начинается
|
||||||
префиксом `[goal]` / `[idea]`; обычная задача — без префикса.
|
**эмодзи типа**, и она **производна**: её ставит `add` и чинит `check --fix`
|
||||||
Отдельного поля типа **нет**: два места для одного факта разъезжаются, а
|
по полю меты. Второго дома у типа нет — эмодзи это его отображение, как
|
||||||
префикс виден прямо в индексе, где и принимается решение «брать или не брать».
|
строка индекса это отображение файла.
|
||||||
- **Форма заголовка — по типу записи.** Задача отвечает на «что нужно сделать»
|
- **Форма заголовка — по типу.** Цель отвечает на «что приложение будет уметь»;
|
||||||
и пишется глаголом в неопределённой форме («Печатать поле одним куском кода»,
|
`feature`, `fix` и `chore` — на «что нужно сделать», глаголом в неопределённой
|
||||||
«Не отбрасывать молча лишние символы»); цель — на «что приложение будет
|
форме, перед ним допускается «не»; `research` называет предмет разведки и
|
||||||
уметь»; идея просто называет, о чём она. Почему так — SKILL.md, «Как написана
|
формы действия **не несёт намеренно**. Почему так — SKILL.md, «Как написана
|
||||||
задача». `check` считает заголовки не в форме действия и печатает число в
|
задача». `check` считает заголовки не в форме действия и печатает число в
|
||||||
здоровье; годность формулировки смотрит агент `task-form`.
|
здоровье; годность формулировки смотрит агент `task-form`.
|
||||||
- **Мета-блок** — список сразу после заголовка, **поле на строку**. Обязательна
|
- **Мета-блок** — список сразу после заголовка, **поле на строку**. Обязательны
|
||||||
секция, причина после тире желательна (именно она объясняет, почему задача
|
**тип** и **место**, причина после тире желательна (именно она объясняет,
|
||||||
здесь оказалась — в том числе «вышла из спринта: …»), «зачем» и теги
|
почему задача здесь оказалась — в том числе «вышла из спринта: …»), «зачем» и
|
||||||
опциональны. Порядок свободный, поле в одну строку. Нераспознанные поля
|
теги опциональны. Нераспознанные поля сохраняются: скрипт правит свои и не
|
||||||
сохраняются: скрипт правит свои и не трогает чужие.
|
трогает чужие.
|
||||||
|
- **Тип — первым полем.** Он решает, что у записи вообще может быть: какие
|
||||||
|
разделы обязательны, нужна ли цель, берётся ли она в спринт, — и читается
|
||||||
|
раньше всего остального. Словарь **закрыт**: `goal` | `feature` | `fix` |
|
||||||
|
`chore` | `research`. Не подходит ни один — это сигнал, что в записи их два и
|
||||||
|
её надо разделить.
|
||||||
- **«Зачем» отвечает на «зачем нужна эта задача»** — состояние, остаток, боль.
|
- **«Зачем» отвечает на «зачем нужна эта задача»** — состояние, остаток, боль.
|
||||||
Не пересказ задачи: пересказ уже есть по ссылке. Живёт здесь, а не только в
|
Не пересказ задачи: пересказ уже есть по ссылке. Живёт здесь, а не только в
|
||||||
индексе: строка индекса его повторяет и производна от него, `check` сверяет,
|
индексе: строка индекса его повторяет и производна от него, `check` сверяет,
|
||||||
`check --fix` восстанавливает пропавшую строку **вместе с ним**. Пока поле
|
`check --fix` восстанавливает пропавшую строку **вместе с ним**. Пока поле
|
||||||
лежало только в индексе, штатная починка дрейфа теряла его молча и
|
лежало только в индексе, штатная починка дрейфа теряла его молча и
|
||||||
навсегда — а это единственное, по чему задачу выбирают, не открывая.
|
навсегда — а это единственное, по чему задачу выбирают, не открывая.
|
||||||
|
- **Тело** — одна фраза «что станет наблюдаемо иначе», дальше разделы по схеме
|
||||||
- **Тело** — одна фраза «что станет наблюдаемо иначе», затрагиваемые границы,
|
типа. Пишется на языке документации проекта: предметно, без англицизмов, у
|
||||||
критерии приёмки, рамки, контекст, ссылки. Пишется на языке документации
|
которых есть русское слово, и без терминов, которых нет ни в паспорте, ни в
|
||||||
проекта: предметно, без англицизмов, у которых есть русское слово, и без
|
архитектуре, ни в конвенциях (правило и его причина — в SKILL.md, раздел «Как
|
||||||
терминов, которых нет ни в паспорте, ни в архитектуре, ни в конвенциях
|
написана задача»).
|
||||||
(правило и его причина — в SKILL.md, раздел «Как написана задача»).
|
|
||||||
|
|
||||||
Мета **одной строкой через `·`** — прежняя форма. Она читается по-прежнему,
|
|
||||||
`check` называет её дрейфом, `check --fix` переписывает списком; поле `Хук`
|
|
||||||
при этом становится `Зачем`. Причина отказа от строки простая: с тремя полями
|
|
||||||
и длинным «зачем» строка уезжала за экран, а `·` приходилось запрещать в тексте
|
|
||||||
причины и самого «зачем».
|
|
||||||
|
|
||||||
Тело — не план реализации и не спецификация: принятое и реализованное переезжает
|
Тело — не план реализации и не спецификация: принятое и реализованное переезжает
|
||||||
в документацию проекта, а файл задачи удаляется.
|
в документацию проекта, а файл задачи удаляется.
|
||||||
|
|
||||||
|
### Поле места: «Категория» и «Секция»
|
||||||
|
|
||||||
|
Поле называет, **где числится строка**, и имя у него **зависит от типа**:
|
||||||
|
|
||||||
|
| Тип | Поле | Значения | Что это |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `goal` | **Секция** | `Запланировано`, `Направления`, `Сопровождение` | часть роадмапа: состояние очереди |
|
||||||
|
| прочие | **Категория** | секции беклога проекта (`Ядро`, `Инфра`, …) | полка домена, в которую задача вернётся из спринта |
|
||||||
|
|
||||||
|
Разные имена потому, что это **разные вещи**. У задачи поле переживает спринт:
|
||||||
|
`sprint drop` возвращает её именно туда. У цели оно называет не полку, а место в
|
||||||
|
очереди работ. Одно имя на два смысла и было конфляцией; `check` называет
|
||||||
|
несовпадение дрейфом, `check --fix` переименовывает.
|
||||||
|
|
||||||
|
Имя самого места принадлежит **заголовку индекса** — файл на него лишь
|
||||||
|
ссылается, и принадлежность сверяется по нижнему регистру.
|
||||||
|
|
||||||
|
### Прежние формы, которые читаются, но не пишутся
|
||||||
|
|
||||||
|
Всё это `check` называет дрейфом, а `check --fix` переписывает:
|
||||||
|
|
||||||
|
| Было | Стало |
|
||||||
|
| --- | --- |
|
||||||
|
| префикс `[goal]` / `[idea]` в H1 | поле **Тип** + эмодзи в H1; `[idea]` → `research` |
|
||||||
|
| тег `kind:<род>` | поле **Тип** (род работы стал типом) |
|
||||||
|
| поле **Секция** у задачи | поле **Категория** |
|
||||||
|
| поле **Хук** | поле **Зачем** |
|
||||||
|
| мета одной строкой через `·` | мета списком, поле на строку |
|
||||||
|
|
||||||
|
Единственное, чего `--fix` не делает сам, — **проставить тип записи, у которой
|
||||||
|
его неоткуда взять**: `feature` от `chore` машина не отличает, и подставленное
|
||||||
|
наугад значение врало бы ровно там, где по нему принимают решение. Такие записи
|
||||||
|
он называет поимённо пометкой `НЕОДНОЗНАЧНО`.
|
||||||
|
|
||||||
### Затрагивает
|
### Затрагивает
|
||||||
|
|
||||||
Перечень **границ**, которых изменение касается. Границей считается то, у чего
|
Перечень **границ**, которых изменение касается. Границей считается то, у чего
|
||||||
@@ -100,8 +147,8 @@
|
|||||||
забыли назвать, она от отсутствующей не отличает. Раздела нет — отказ во взятии:
|
забыли назвать, она от отсутствующей не отличает. Раздела нет — отказ во взятии:
|
||||||
оценивать нечем.
|
оценивать нечем.
|
||||||
|
|
||||||
**У идей раздела нет** — как и критериев: границы становятся известны, когда идея
|
**У `goal` и `research` раздела нет** — у первой границы называют её задачи, у
|
||||||
превращается в задачу.
|
второй они становятся известны, когда из разведки родятся задачи.
|
||||||
|
|
||||||
### Критерии приёмки
|
### Критерии приёмки
|
||||||
|
|
||||||
@@ -118,7 +165,9 @@
|
|||||||
замечание: настоящий оракул от слова «оракул» машина не отличает, и делать вид,
|
замечание: настоящий оракул от слова «оракул» машина не отличает, и делать вид,
|
||||||
что проверено больше проверенного, хуже, чем не проверять вовсе.
|
что проверено больше проверенного, хуже, чем не проверять вовсе.
|
||||||
|
|
||||||
**У идей критериев нет — именно поэтому они идеи.**
|
**У `research` критериев нет** — её приёмка это записанный ответ, и описывается
|
||||||
|
она разделами «Вопрос» и «Куда ляжет ответ». **У `goal` их заменяет
|
||||||
|
«Завершение».**
|
||||||
|
|
||||||
**Критерии — пол, но расхождение с ними есть дефект критериев.** Если приёмщик
|
**Критерии — пол, но расхождение с ними есть дефект критериев.** Если приёмщик
|
||||||
видит, что критерии закрыты, а суть задачи не достигнута, он **правит критерии и
|
видит, что критерии закрыты, а суть задачи не достигнута, он **правит критерии и
|
||||||
@@ -129,16 +178,21 @@
|
|||||||
### Рамки
|
### Рамки
|
||||||
|
|
||||||
Одна строка: чего касаться нельзя, что перезапускается, что считается
|
Одна строка: чего касаться нельзя, что перезапускается, что считается
|
||||||
необратимым, трогается ли схема данных. **Свойства репозитория сюда не пишутся**
|
необратимым, трогается ли схема данных. Раздел **допустим у любого типа задачи и
|
||||||
— номер последней миграции, версия зависимости, хеш: в лежалой задаче они
|
ни у одного не обязателен**. **Свойства репозитория сюда не пишутся** — номер
|
||||||
протухают молча и становятся ложной рамкой. Снимок берётся при постановке, а не
|
последней миграции, версия зависимости, хеш: в лежалой задаче они протухают
|
||||||
при заведении.
|
молча и становятся ложной рамкой. Снимок берётся при постановке, а не при
|
||||||
|
заведении.
|
||||||
|
|
||||||
### Вопросы
|
### Вопросы
|
||||||
|
|
||||||
Неразобранное решение человека живёт разделом `## Вопросы` **плюс тегом
|
Неразобранное решение человека живёт разделом `## Вопросы` **плюс тегом
|
||||||
`question`**. Раздел без тега или тег без раздела — дрейф, `check` о нём скажет.
|
`question`**. Раздел без тега или тег без раздела — дрейф, `check` о нём скажет.
|
||||||
|
|
||||||
|
Раздел `Вопросы` (о решении человека) и раздел `Вопрос` у `research` (предмет
|
||||||
|
разведки) — **разные вещи и разные слова**: первый блокирует взятие, второй его
|
||||||
|
разрешает.
|
||||||
|
|
||||||
**Судит факт, а не метка.** Отказ во взятии даёт **непустой раздел «Вопросы»**,
|
**Судит факт, а не метка.** Отказ во взятии даёт **непустой раздел «Вопросы»**,
|
||||||
независимо от того, стоит ли тег: иначе забывший тег проходил бы, а поставивший
|
независимо от того, стоит ли тег: иначе забывший тег проходил бы, а поставивший
|
||||||
спотыкался — стимул ровно обратный записанному правилу. Тег производен: он нужен
|
спотыкался — стимул ровно обратный записанному правилу. Тег производен: он нужен
|
||||||
@@ -158,13 +212,12 @@
|
|||||||
|
|
||||||
## Файл цели
|
## Файл цели
|
||||||
|
|
||||||
**Заголовок цели отвечает на «что приложение будет уметь».** Не область работ и
|
Форма та же, разделы и алгоритм — [task-goal.md](task-goal.md).
|
||||||
не имя подсистемы: не «Работа со слиянием», а «Исход слияния не зависит от
|
|
||||||
порядка доставки». Свойство поведения — тоже возможность.
|
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# [goal] Исход слияния не зависит от порядка доставки
|
# 🎯 Исход слияния не зависит от порядка доставки
|
||||||
|
|
||||||
|
- **Тип:** goal
|
||||||
- **Секция:** Направления
|
- **Секция:** Направления
|
||||||
- **Теги:** decomposed
|
- **Теги:** decomposed
|
||||||
|
|
||||||
@@ -181,10 +234,6 @@
|
|||||||
- **Задачи цели здесь не перечисляются.** Перечень даёт
|
- **Задачи цели здесь не перечисляются.** Перечень даёт
|
||||||
`tasks.py list --goal <слаг>`; хранимый список стал бы третьим индексом и
|
`tasks.py list --goal <слаг>`; хранимый список стал бы третьим индексом и
|
||||||
поехал бы на первой же закрытой задаче.
|
поехал бы на первой же закрытой задаче.
|
||||||
- **Раздел «Завершение» — списком, а не абзацем.** Это признаки того, что
|
|
||||||
приложение уже умеет; **на строку «Завершения» ссылается задача**, объясняя,
|
|
||||||
какую часть возможности она двигает (см. тест готовности). Абзацем такая
|
|
||||||
ссылка не берётся, поэтому список.
|
|
||||||
- **Тег `decomposed`** отличает «цель ещё не разобрана» от «все её задачи
|
- **Тег `decomposed`** отличает «цель ещё не разобрана» от «все её задачи
|
||||||
закрыты» — два состояния, у которых снаружи один и тот же признак: задач нет.
|
закрыты» — два состояния, у которых снаружи один и тот же признак: задач нет.
|
||||||
Пометка именно **тегом**, а не строкой в теле: только так она проверяется.
|
Пометка именно **тегом**, а не строкой в теле: только так она проверяется.
|
||||||
@@ -217,16 +266,18 @@
|
|||||||
Строка везде одной формы:
|
Строка везде одной формы:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
- [Заголовок дословно](items/slug.md) — зачем
|
- [🐞 Заголовок дословно](items/slug.md) — зачем
|
||||||
```
|
```
|
||||||
|
|
||||||
«Зачем» отвечает на «зачем нужна эта задача» одним предложением: состояние,
|
«Зачем» отвечает на «зачем нужна эта задача» одним предложением: состояние,
|
||||||
остаток, боль. Пересказ первого абзаца бесполезен — он уже есть по ссылке.
|
остаток, боль. Пересказ первого абзаца бесполезен — он уже есть по ссылке.
|
||||||
|
Эмодзи внутри квадратных скобок не украшение: заголовок копируется **дословно**,
|
||||||
|
и тип виден там, где решают «брать или не брать».
|
||||||
|
|
||||||
| Файл | Что отвечает | Секции |
|
| Файл | Что отвечает | Секции |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `ROADMAP.md` | что приложение уже умеет и чего ещё не умеет | канонические и в этом порядке: `Запланировано`, `Направления`, `Сопровождение`, `Готово` (англ. `Planned`, `Directions`, `Operations`, `Done`) |
|
| `ROADMAP.md` | что приложение уже умеет и чего ещё не умеет | канонические и в этом порядке: `Запланировано`, `Направления`, `Сопровождение`, `Готово` (англ. `Planned`, `Directions`, `Operations`, `Done`) |
|
||||||
| `BACKLOG.md` | что **можно взять** — только задачи | секции проекта (по умолчанию Ядро/Инфра) |
|
| `BACKLOG.md` | что **можно взять** — только задачи | категории проекта (по умолчанию Ядро/Инфра) |
|
||||||
| `SPRINT.md` | какая цель и какой набор под неё | одна: «Набор» |
|
| `SPRINT.md` | какая цель и какой набор под неё | одна: «Набор» |
|
||||||
| `REJECTED.md` | что ушло без реализации и почему | — |
|
| `REJECTED.md` | что ушло без реализации и почему | — |
|
||||||
|
|
||||||
@@ -237,8 +288,15 @@
|
|||||||
следующем `sprint start` и очищается на `sprint close`.
|
следующем `sprint start` и очищается на `sprint close`.
|
||||||
|
|
||||||
Секции — **единственные заголовки `##` в индексе**: любой другой `##` в
|
Секции — **единственные заголовки `##` в индексе**: любой другой `##` в
|
||||||
преамбуле проверка сочтёт секцией. Внутри секции беклога порядок значения не
|
преамбуле проверка сочтёт секцией.
|
||||||
имеет — порядка в беклоге нет вовсе.
|
|
||||||
|
**Порядка «по важности» внутри секции беклога нет** — «что делать дальше»
|
||||||
|
отвечает набор спринта. Единственный порядок, который есть, **производен от типа
|
||||||
|
и заполненности**: **сырьё** (`research` без раздела «Вопрос») стоит в конце
|
||||||
|
своей секции, потому что его не берут, и между берущимся оно каждый раз требует
|
||||||
|
открыть файл, чтобы это понять. Проверяет `check`, переставляет `check --fix`,
|
||||||
|
и человек этот порядок не назначает — иначе он был бы приоритетом, которого
|
||||||
|
здесь нет.
|
||||||
|
|
||||||
**Секции «блокеры» среди них нет.** Блокер — состояние, а не полка: он живёт до
|
**Секции «блокеры» среди них нет.** Блокер — состояние, а не полка: он живёт до
|
||||||
ответа человека, а следы остаются вопросами в файлах задач распущенного спринта.
|
ответа человека, а следы остаются вопросами в файлах задач распущенного спринта.
|
||||||
@@ -251,15 +309,14 @@
|
|||||||
`REJECTED.md`, и по той же причине (файла уже нет, ссылаться некуда).
|
`REJECTED.md`, и по той же причине (файла уже нет, ссылаться некуда).
|
||||||
|
|
||||||
**Секции роадмапа закреплены** — состав, полнота, единство языка и **порядок**
|
**Секции роадмапа закреплены** — состав, полнота, единство языка и **порядок**
|
||||||
проверяются `check`; секции беклога проект называет сам. Почему так — SKILL.md.
|
проверяются `check`; категории беклога проект называет сам. Почему так —
|
||||||
Порядок закреплён потому, что `Готово` копится: стоя первым, достигнутое
|
SKILL.md. Порядок закреплён потому, что `Готово` копится: стоя первым,
|
||||||
отодвигает за экран то, ради чего роадмап открывают чаще всего.
|
достигнутое отодвигает за экран то, ради чего роадмап открывают чаще всего.
|
||||||
|
|
||||||
**Заголовок секции пишется с прописной и отбивается пустой строкой с обеих
|
**Заголовок секции пишется с прописной и отбивается пустой строкой с обеих
|
||||||
сторон** — во всех индексах, включая секции беклога, имена которых выбирает проект. Написание
|
сторон** — во всех индексах, включая категории беклога, имена которых выбирает
|
||||||
канонических секций и отбивку правит `check --fix`; он же сводит написание
|
проект. Написание канонических секций и отбивку правит `check --fix`; он же
|
||||||
секции в мете файла с заголовком индекса — **имя секции принадлежит заголовку**,
|
сводит написание места в мете файла с заголовком индекса.
|
||||||
файл на неё лишь ссылается, и принадлежность сверяется по нижнему регистру.
|
|
||||||
|
|
||||||
Индексы **производны**: расходятся с файлом — правим индексы (`check --fix`).
|
Индексы **производны**: расходятся с файлом — правим индексы (`check --fix`).
|
||||||
Строку руками не пишут.
|
Строку руками не пишут.
|
||||||
@@ -295,19 +352,13 @@
|
|||||||
|
|
||||||
## Теги
|
## Теги
|
||||||
|
|
||||||
Единственный механизм разметки, потому что `list --tag` уже умеет отбирать по
|
Разметка сверх типа. Тип полем, потому что он один и обязателен; теги — потому
|
||||||
ним порцию разбора. Отдельных полей меты под это не заводим.
|
что их много и `list --tag` уже умеет отбирать по ним порцию разбора.
|
||||||
|
|
||||||
- `goal:<слаг>` — цель, которой служит задача. Обязателен **у `kind:feature`**:
|
- `goal:<слаг>` — цель, которой служит задача. Обязателен **у `feature`**:
|
||||||
новая возможность и есть содержание цели. У `fix`, `chore` и `research` его
|
новая возможность и есть содержание цели. У `fix`, `chore` и `research` его
|
||||||
может не быть — они служат работоспособности, а не направлению, и в набор
|
может не быть — они служат работоспособности, а не направлению, и в набор
|
||||||
спринта входят помимо его цели.
|
спринта входят помимо его цели.
|
||||||
- `kind:<род>` — род работы: `feature` | `fix` | `chore` | `research`. Словарь
|
|
||||||
**закрыт**, значение ровно одно. Обязателен у задачи (без него `sprint take`
|
|
||||||
откажет), у цели запрещён, у идеи необязателен. Ставится
|
|
||||||
`add --kind` / `edit --kind`; `--kind` заменяет прежнее значение, а не
|
|
||||||
добавляет второе. Смысл рода и почему он тегом, а не префиксом — в SKILL.md,
|
|
||||||
раздел «Род работы».
|
|
||||||
- `question` — в файле есть неразобранный раздел «Вопросы».
|
- `question` — в файле есть неразобранный раздел «Вопросы».
|
||||||
- `sprint:<слаг>` — задача заведена в этом спринте; по нему отбирается первая
|
- `sprint:<слаг>` — задача заведена в этом спринте; по нему отбирается первая
|
||||||
порция разбора («урожай спринта»). **Ставится сам**: слаг спринта заводит
|
порция разбора («урожай спринта»). **Ставится сам**: слаг спринта заводит
|
||||||
@@ -317,6 +368,9 @@
|
|||||||
разбора — урожай прошедшего спринта».
|
разбора — урожай прошедшего спринта».
|
||||||
- `decomposed` — на цели: разложена на задачи (см. «Файл цели»).
|
- `decomposed` — на цели: разложена на задачи (см. «Файл цели»).
|
||||||
|
|
||||||
|
Тега `kind:<род>` больше нет: род работы стал типом. Оставшийся в файле `check`
|
||||||
|
называет дрейфом, а `check --fix` снимает, перенеся значение в поле «Тип».
|
||||||
|
|
||||||
Отбор — `list --tag a,b`: перечисленные через запятую теги требуются **все
|
Отбор — `list --tag a,b`: перечисленные через запятую теги требуются **все
|
||||||
сразу** (это И, не ИЛИ). Тег, которого нет ни у одной задачи, `list` называет
|
сразу** (это И, не ИЛИ). Тег, которого нет ни у одной задачи, `list` называет
|
||||||
вслух: молчаливый ноль читается как «таких задач нет», а чаще это опечатка.
|
вслух: молчаливый ноль читается как «таких задач нет», а чаще это опечатка.
|
||||||
@@ -327,17 +381,20 @@
|
|||||||
|
|
||||||
## Тест «готова к взятию»
|
## Тест «готова к взятию»
|
||||||
|
|
||||||
Задача готова, если из файла отвечаются четыре вопроса:
|
Задача готова, если из файла отвечаются четыре вопроса. Первый и четвёртый —
|
||||||
|
общие, второй и третий у каждого типа свои и перечислены в его файле.
|
||||||
|
|
||||||
1. **Что станет наблюдаемо иначе**, когда она сделана — снаружи: пользователю,
|
1. **Что станет наблюдаемо иначе**, когда она сделана — снаружи: пользователю,
|
||||||
владельцу сервиса или разработчику. «Отрефакторить X» — не ответ; «перестанет
|
владельцу сервиса или разработчику. «Отрефакторить X» — не ответ; «перестанет
|
||||||
ломаться Y при Z» — ответ. **У `kind:chore` адресат — разработчик, и это
|
ломаться Y при Z» — ответ. **У `chore` адресат — разработчик, и это
|
||||||
законно**: «уедет последний вызов устаревшего API» — ответ, а не отговорка.
|
законно**: «уедет последний вызов устаревшего API» — ответ, а не отговорка.
|
||||||
Род объявлен как раз затем, чтобы такие задачи не выдумывали себе
|
Тип объявлен как раз затем, чтобы такие задачи не выдумывали себе
|
||||||
пользовательскую пользу.
|
пользовательскую пользу.
|
||||||
2. **Каких границ это касается** — раздел «Затрагивает». Без него задачу нельзя
|
2. **Что известно про сегодня** — то, что тип требует знать до работы:
|
||||||
оценить: остаётся судить по длине текста.
|
у `fix` это `Воспроизведение`, у `research` — `Вопрос`, у `feature` и
|
||||||
3. **По чему видно, что закончено** — критерии приёмки с оракулами.
|
`chore` — `Затрагивает`.
|
||||||
|
3. **По чему видно, что закончено** — критерии приёмки с оракулами;
|
||||||
|
у `research` вместо них `Куда ляжет ответ`.
|
||||||
4. **Какую часть «Завершения» своей цели она двигает** — у задачи с целью.
|
4. **Какую часть «Завершения» своей цели она двигает** — у задачи с целью.
|
||||||
Строкой: «двигает пункт 2 «Завершения» — накопительная метрика перестаёт
|
Строкой: «двигает пункт 2 «Завершения» — накопительная метрика перестаёт
|
||||||
уменьшаться». Это и есть защита от задачи «отрефакторить X»: она проваливает
|
уменьшаться». Это и есть защита от задачи «отрефакторить X»: она проваливает
|
||||||
@@ -349,9 +406,10 @@
|
|||||||
**У задачи без цели** (`fix`, `chore`, `research`) вопрос не задаётся: они
|
**У задачи без цели** (`fix`, `chore`, `research`) вопрос не задаётся: они
|
||||||
служат работоспособности, а не направлению.
|
служат работоспособности, а не направлению.
|
||||||
|
|
||||||
Не отвечается первый, второй или третий вопрос → это **идея** (`[idea]`), её
|
Не отвечается первый, второй или третий вопрос → это ещё не задача, а **сырьё**:
|
||||||
место в штурме. Не отвечается четвёртый у `feature` → либо цель есть и не
|
тип `research` без раздела «Вопрос», место — конец секции, работа над ним —
|
||||||
проставлена, либо это не новая возможность.
|
штурм. Не отвечается четвёртый у `feature` → либо цель есть и не проставлена,
|
||||||
|
либо это не новая возможность.
|
||||||
|
|
||||||
Отвечается всё, но задача не делается одним заходом и не мерджится целиком →
|
Отвечается всё, но задача не делается одним заходом и не мерджится целиком →
|
||||||
это **несколько задач под одной целью**, дроби сразу. Промежуточного зонтика
|
это **несколько задач под одной целью**, дроби сразу. Промежуточного зонтика
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
# 🎯 `goal` — возможность приложения
|
||||||
|
|
||||||
|
Цель отвечает на **«что приложение будет уметь»**. Не область работ и не имя
|
||||||
|
подсистемы: не «Работа со слиянием», а «Исход слияния не зависит от порядка
|
||||||
|
доставки». Свойство поведения — тоже возможность.
|
||||||
|
|
||||||
|
Общая форма записи (мета, слаг, строка индекса) — [task-format.md](task-format.md).
|
||||||
|
Здесь только то, что у этого типа своё.
|
||||||
|
|
||||||
|
## Схема
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| --- | --- |
|
||||||
|
| Заголовок отвечает на | что приложение будет уметь |
|
||||||
|
| Обязательные разделы | `Завершение` |
|
||||||
|
| Допустимые сверх того | — |
|
||||||
|
| Поле места | **Секция** — часть роадмапа |
|
||||||
|
| Цель (`goal:<слаг>`) | запрещена: цель и есть цель |
|
||||||
|
| Индекс | `ROADMAP.md`, и никогда `BACKLOG.md` или `SPRINT.md` |
|
||||||
|
| Берётся в спринт | нет — берутся её задачи |
|
||||||
|
|
||||||
|
Поле места у цели называется **«Секция»**, а не «Категория», и это не разнобой:
|
||||||
|
у задачи оно называет полку домена, в которую она вернётся из спринта, а у цели
|
||||||
|
— часть роадмапа, то есть состояние очереди. Одно имя на два смысла и было
|
||||||
|
конфляцией.
|
||||||
|
|
||||||
|
## «Завершение» — списком, а не абзацем
|
||||||
|
|
||||||
|
Это признаки того, что приложение **уже умеет**, и на строки этого раздела
|
||||||
|
ссылаются задачи цели: «двигает пункт 2 «Завершения» — накопительная метрика
|
||||||
|
перестаёт уменьшаться». Абзацем такая ссылка не берётся, поэтому список.
|
||||||
|
|
||||||
|
Отсюда же читается обратное и более полезное: **строка «Завершения», к которой
|
||||||
|
не относится ни одна задача, — незакрытая часть возможности**. Достаточность
|
||||||
|
набора задач видна из самой цели, а не из чьей-то памяти.
|
||||||
|
|
||||||
|
## Алгоритм
|
||||||
|
|
||||||
|
1. **Проверить, что это возможность, а не работа.** Сборка, проверки, выкладка,
|
||||||
|
мониторинг, дежурство на вопрос «что приложение будет уметь» не отвечают. Им
|
||||||
|
отведена секция `Сопровождение` — там они видны в том же экране и не читаются
|
||||||
|
как обещание продукта. Граница проходит по тому, **кто наблюдает**:
|
||||||
|
«приложение сообщает о своём состоянии» — возможность, «дежурный видит
|
||||||
|
состояние на одном экране» — сопровождение.
|
||||||
|
2. **Выбрать секцию.** Очередь значима и обоснована прозой — `Запланировано`;
|
||||||
|
тянется долго и очереди не имеет — `Направления`; про то, чем держат проект,
|
||||||
|
— `Сопровождение`. В `Готово` кладёт сам `close`.
|
||||||
|
3. **Написать «Завершение»** — 2–5 наблюдаемых признаков списком. Пишутся до
|
||||||
|
декомпозиции: иначе задачи придумают себе цель задним числом.
|
||||||
|
4. **Разложить на задачи** и проставить им `goal:<слаг>`. Перечень задач в теле
|
||||||
|
цели **не хранится** — он был бы третьим индексом и поехал бы на первой же
|
||||||
|
закрытой задаче; выводит `tasks.py list --goal <слаг>`.
|
||||||
|
5. **Пометить `decomposed`.** Тег отличает «ещё не разобрана» от «все задачи
|
||||||
|
закрыты» — два состояния с одним внешним признаком. `check --fix` ставит его
|
||||||
|
сам цели, у которой задачи есть.
|
||||||
|
6. **Закрыть достигнутой** — `close <слаг> --implemented`, когда не осталось
|
||||||
|
открытых задач. Файл удаляется, строка с датой переезжает в `Готово`. Скрипт
|
||||||
|
откажет, если задачи ещё живы.
|
||||||
|
|
||||||
|
## Что видит машина, а что человек
|
||||||
|
|
||||||
|
`check` считает цели, различает разобранные и пустые, ставит `decomposed`,
|
||||||
|
запрещает закрыть цель с живыми задачами и держит `Секцию` в согласии с
|
||||||
|
заголовком роадмапа. **Годность формулировки — не машине**: «возможность это или
|
||||||
|
область работ» решает [агент вычитки](../SKILL.md#вычитка-два-прохода-а-не-один).
|
||||||
|
|
||||||
|
Достигнутая цель **не исчезает**: «что приложение умеет» — половина вопроса, ради
|
||||||
|
которого роадмап открывают. Вторым домом поведения роадмап при этом не
|
||||||
|
становится: нормативное поведение живёт в `openspec/specs/`, роадмап отвечает,
|
||||||
|
**когда и в каком порядке** оно появилось.
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# 🔬 `research` — исход работы знание, а не изменение системы
|
||||||
|
|
||||||
|
Ответ на вопрос, замер, разведка, проработка сырой мысли. Приёмка — **записанный
|
||||||
|
ответ**, а не изменённый код.
|
||||||
|
|
||||||
|
Общая форма записи (мета, слаг, строка индекса) — [task-format.md](task-format.md).
|
||||||
|
Здесь только то, что у этого типа своё.
|
||||||
|
|
||||||
|
## Схема
|
||||||
|
|
||||||
|
| | |
|
||||||
|
| --- | --- |
|
||||||
|
| Заголовок отвечает на | о чём разведка (предмет, а не действие) |
|
||||||
|
| Обязательные разделы | `Вопрос`, `Куда ляжет ответ` |
|
||||||
|
| Допустимые сверх того | `Рамки`, `Вопросы` |
|
||||||
|
| Поле места | **Категория** — полка домена беклога |
|
||||||
|
| Цель (`goal:<слаг>`) | нет |
|
||||||
|
| Индекс | `BACKLOG.md` → `SPRINT.md` |
|
||||||
|
| Берётся в спринт | да — **но только с заполненным «Вопросом»** |
|
||||||
|
|
||||||
|
**Критериев приёмки у `research` нет, и это не поблажка.** Критерии в форме
|
||||||
|
«оракул: тест» разведке натянуты: проверять нечего, пока ответа нет. Её приёмка
|
||||||
|
описывается раздельно — вопрос, на который отвечаем, и место, куда ляжет ответ.
|
||||||
|
|
||||||
|
**Заголовок формы действия не несёт намеренно.** Что делать, ещё неизвестно, и
|
||||||
|
заголовок-действие обещал бы решённость, которой нет. «Подсказка следующего
|
||||||
|
хода», а не «Сделать подсказку следующего хода».
|
||||||
|
|
||||||
|
## Этот тип вобрал прежний `[idea]`
|
||||||
|
|
||||||
|
Тип `idea` упразднён. Он значил не род работы, а **состояние незаполненности** —
|
||||||
|
«первый, второй или третий вопрос теста готовности не отвечается», — а состояние
|
||||||
|
типом быть не может: оно меняется по мере того, как запись дописывают, а тип
|
||||||
|
меняют командой.
|
||||||
|
|
||||||
|
Теперь это состояние называется честно: **`research` без раздела «Вопрос» — это
|
||||||
|
сырьё**.
|
||||||
|
|
||||||
|
| | сырьё | разведка |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Раздел `Вопрос` | пуст или отсутствует | заполнен |
|
||||||
|
| `sprint take` | отказ | берёт |
|
||||||
|
| Место в секции беклога | **конец**, `check --fix` сносит туда сам | среди прочих |
|
||||||
|
| `tasks.py list --raw` | показывает | нет |
|
||||||
|
|
||||||
|
Порядка «по важности» в беклоге по-прежнему нет. Этот порядок **производен от
|
||||||
|
типа и заполненности**, а не назначен человеком, — потому его и проверяет машина,
|
||||||
|
и потому он не противоречит правилу «порядка нет, есть цель».
|
||||||
|
|
||||||
|
Сырьём заводится и **сырая функция**: «Подсказка следующего хода» — ещё не
|
||||||
|
`feature`, потому что неизвестно, что именно делать. Работа над ней — думание, и
|
||||||
|
её исход — либо задачи, либо отказ.
|
||||||
|
|
||||||
|
## Алгоритм
|
||||||
|
|
||||||
|
1. **Записать вопрос одной фразой.** Не тему, а вопрос: не «Разобраться с
|
||||||
|
выводом в терминалах», а «Какими символами рамки печатаются одинаково в
|
||||||
|
Терминале, iTerm и `tmux`». Вопроса ещё нет — запись заводится сырьём и
|
||||||
|
лежит в конце секции, пока вопрос не появится.
|
||||||
|
2. **Назвать, куда ляжет ответ**: `docs/research/<тема>.md`, ADR, тело этой
|
||||||
|
задачи. Место называется **заранее**, иначе ответ остаётся в переписке, а
|
||||||
|
через квартал разведку заказывают заново.
|
||||||
|
3. **Ограничить рамками**, если разведка может утечь: сколько времени, какие
|
||||||
|
источники, что заведомо вне.
|
||||||
|
4. **Провести разведку** и **записать ответ по названному адресу**. Числа — с
|
||||||
|
провенансом: с командой или условиями, которыми получены. Число без источника
|
||||||
|
проход ревью обязан читать как условие, а не как замер.
|
||||||
|
5. **Разложить исход на задачи** — если он их родил. Разведка кончается одним из
|
||||||
|
трёх: заведены задачи, записано знание, отказ. **Отказ — полноправный исход**:
|
||||||
|
«проверили, не проблема» экономит спринт.
|
||||||
|
6. **Закрыть** — `close <слаг> --implemented`, когда ответ записан. Файл
|
||||||
|
удаляется: запись ответа и есть след, второго не нужно. Ушла без ответа —
|
||||||
|
`close --reason`, и строка уезжает в `REJECTED.md`.
|
||||||
|
|
||||||
|
## Что видит машина, а что человек
|
||||||
|
|
||||||
|
`check` и `sprint take` смотрят на **наличие непустых** разделов `Вопрос` и
|
||||||
|
`Куда ляжет ответ`, считают сырьё отдельной строкой здоровья и держат его в конце
|
||||||
|
секции. Годность вопроса — человеку: «вопрос это или тема» машина не различает,
|
||||||
|
и `check` о годности молчит намеренно.
|
||||||
|
|
||||||
|
Штурм сырья, дробление исхода на задачи и тест «части мерджатся порознь» —
|
||||||
|
[split.md](split.md).
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user