роадмап — состояние проекта, а не очередь работ
Основной инструмент владельца отвечал на половину своего вопроса. Оценка идёт по поведению: что приложение уже может и чего ещё не может, — а close --implemented удалял у достигнутой цели и файл, и строку, так что роадмап по построению показывал только «что осталось». Свидетельство лежало в самом роадмапе healthlog: секция «Что уже пройдено» на двадцать строк прозы, руками, с припиской «Эти звенья целями не заведены: закрытая цель записи не оставляет». Теперь строка с датой переезжает в секцию достигнутого, файл удаляется по-прежнему. Вторым домом поведения это не делает: нормативное поведение живёт в openspec/specs, роадмап отвечает, когда и в каком порядке оно появилось. Ссылки на файл в строке нет — файла больше нет, форма как в REJECTED.md. Цель стала возможностью приложения, задача — шагом к ней: - заголовок цели отвечает на «что приложение будет уметь»; свойство поведения («сообщает о своём состоянии», «исход не зависит от порядка») — тоже возможность и переформулировки не требует; - «Завершение» — списком, а не абзацем: задача ссылается на его строку, и это новая защита от «отрефакторить X» вместо прежнего «наблюдаемо снаружи». Заодно видно обратное: строка, к которой не относится ни одна задача, — незакрытая часть возможности; - работа над инструментом и процессом на этот вопрос не отвечает и живёт в отдельной секции. Цель обязательна не у всякой задачи. Прежнее «иначе она не попадёт ни в один спринт» было угрозой, а не аргументом, и заставляло операционную работу выдумывать себе направление. Граница по роду: feature без цели не бывает, fix, chore и research живут без неё и входят в набор помимо цели спринта. Тип [epic] упразднён: зонтиком стала цель, а слишком крупный шаг дробится под ней. Ноль употреблений на 97 записей двух живых проектов. Секции роадмапа — умеет / строим / направления / станок, четыре вместо двух; имена приняты как временные и запаркованы (TODO 7). Имя секции достигнутого знает скрипт — docs/.pm.json, ключ tasks.achieved_section. reopen цели снимает строку достигнутого, круг проверен вживую. Всё дописано в версию 3 канона: она ещё нигде не выкачена. DECISIONS 19, YYY–ГГГ и следствия 78–81. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# Декомпозиция и мозговой штурм
|
||||
|
||||
Обе операции превращают одну запись в несколько (или в ноль). Разница во входе:
|
||||
декомпозиция дробит **готовую задачу или эпик**, штурм прорабатывает **идею**,
|
||||
декомпозиция дробит **слишком крупную задачу**, штурм прорабатывает **идею**,
|
||||
которая ещё не задача.
|
||||
|
||||
## Тест декомпозиции
|
||||
@@ -11,10 +11,11 @@
|
||||
1. **Мерджатся независимо.** Часть Б не требует, чтобы часть А была уже влита.
|
||||
Есть порядок «сперва А, потом Б, иначе не собрать» → это не декомпозиция, а
|
||||
план реализации: шаги остаются **внутри одного файла**.
|
||||
2. **Каждая даёт видимую пользу.** Часть, полезная только в комплекте с другой,
|
||||
— не самостоятельная задача. Пользу проверяй тестом «готова к взятию»
|
||||
(task-format): что станет наблюдаемо иначе именно от этой части и какие у неё
|
||||
собственные критерии приёмки.
|
||||
2. **Каждая — самостоятельный шаг.** Часть, осмысленная только в комплекте с
|
||||
другой, — не задача. Проверяй тестом «готова к взятию» (task-format): какую
|
||||
строку «Завершения» цели двигает **именно эта часть** и какие у неё
|
||||
собственные критерии приёмки. У операционных частей (`fix`, `chore`,
|
||||
`research`) цели может не быть — тогда достаточно собственных критериев.
|
||||
|
||||
Не проходит хотя бы одно — **не дроби**. Ложная декомпозиция плодит файлы,
|
||||
которые нельзя взять поодиночке, и переоценка потом склеивает их обратно.
|
||||
@@ -55,21 +56,21 @@
|
||||
`REJECTED.md` здесь — не «выкинули», а именно тот след, что переживает запись:
|
||||
через квартал вопрос «куда делась задача X» отвечается строкой со ссылками на
|
||||
наследников, а не археологией git;
|
||||
- родитель осмыслен как зонтик → `edit <slug> --type epic`, тело — ссылки на
|
||||
задачи-части, своих шагов у него нет. **Эпик не берётся в спринт** и живёт
|
||||
ровно до тех пор, пока не закрыта последняя часть.
|
||||
- родитель осмыслен как **возможность**, а не как шаг → это цель. Тип на месте
|
||||
не меняется (цель живёт в другом индексе): заводится `[goal]` в `ROADMAP.md`,
|
||||
части получают `--goal <новый слаг>`, родитель закрывается с причиной-ссылкой.
|
||||
|
||||
Зонтик, который перестал быть временным и описывает направление, а не работу, —
|
||||
это уже **цель**, а не эпик. Тип на месте не меняется (цель живёт в другом
|
||||
индексе): заводится `[goal]` в `ROADMAP.md`, задачи получают `--goal <новый слаг>`,
|
||||
эпик закрывается с причиной-ссылкой.
|
||||
**Промежуточного зонтика между целью и задачей нет.** Тип `[epic]` упразднён:
|
||||
роль зонтика играет цель, а слишком крупный шаг дробится на шаги помельче под
|
||||
той же целью. Если частям нужен общий заголовок — значит у них общая
|
||||
возможность, и её надо назвать целью, а не заводить временный тип.
|
||||
|
||||
## Когда декомпозиция случается посреди спринта
|
||||
|
||||
Задача, которая **переросла в эпик**, распознаётся до того, как под неё заведено
|
||||
предложение об изменении: иначе его придётся выбрасывать. Она помечается
|
||||
`[epic]`, выходит из набора (`sprint drop … --reason "переросла в эпик"`), уходит
|
||||
на декомпозицию, а спринт продолжается остальными. Части заводятся сразу, но в
|
||||
Задача, которая **оказалась крупнее задачи**, распознаётся до того, как под неё
|
||||
заведено предложение об изменении: иначе его придётся выбрасывать. Она выходит
|
||||
из набора (`sprint drop … --reason "крупнее задачи"`), уходит на декомпозицию, а
|
||||
спринт продолжается остальными. Части заводятся сразу под той же целью, но в
|
||||
текущий набор **не добавляются** — набор заморожен.
|
||||
|
||||
## Мозговой штурм идеи
|
||||
@@ -100,7 +101,7 @@ Applicative-штурм («перечисли задачи, следующие и
|
||||
|
||||
- Идея/задача на входе, выбранная рамка (для штурма), задачи-наследники со
|
||||
слагами, целями и секциями.
|
||||
- Судьба родителя: удалён / стал эпиком / стал целью / выкинут с причиной.
|
||||
- Судьба родителя: удалён / стал целью / выкинут с причиной.
|
||||
- `tasks.py check` после правок.
|
||||
- Границы покрытия: какие постановки рассмотрены и какие сознательно отброшены —
|
||||
чтобы штурм не пришлось повторять с нуля.
|
||||
|
||||
Reference in New Issue
Block a user