Files
dev-skills/decisions/19-roadmap-is-state-not-queue.md
T
av bf6a173115 журнал решений: разложен по теме на файл, метки решений стали номерами
- DECISIONS.md (4040 строк, 65 тем) → decisions/, файл на тему плюс указатель;
- буквенные метки решений заменены сквозными Р1–Р234, следствия получили
  префикс С при прежних номерах: схема букв выродилась до пятибуквенных и
  сломалась — `АЕАКЛ` была занята и темой 53, и темой 65;
- 42 перекрёстные ссылки переписаны под новые номера и стали живыми; где номер
  означал тему, а слово стояло «решение», формулировка исправлена.
2026-08-13 12:40:56 +03:00

102 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 19. Роадмап — состояние проекта, а не очередь работ (2026-08-04)
## Что было
Основной инструмент владельца — роадмап и набор целей: «на каком этапе проект,
что сделали и что осталось». Оценка идёт по **поведению**, а не по внутреннему
устройству: что приложение уже может делать и чего ещё не может. Отсюда
требование к формулировкам: цель отвечает на «что приложение будет делать»,
задача — на «что для этого нужно сделать».
Разбор показал, что инструмент отвечал ровно на половину этого вопроса.
## Решено
**Р77. Достигнутая цель из роадмапа не исчезает.** `close --implemented` удалял
у цели и файл, и строку — роадмап по построению показывал только «что осталось».
Свидетельство нашлось в самом роадмапе healthlog: там руками заведена секция
«Что уже пройдено» на двадцать строк прозы, и заканчивается она фразой «Эти
звенья целями не заведены: закрытая цель записи не оставляет, ей хватает коммита
и спеки». Обходной путь и его причина записаны рукой владельца. Теперь строка с
датой переезжает в секцию достигнутого; файл удаляется по-прежнему.
Вторым домом поведения это не делает: нормативное поведение живёт в
`openspec/specs/`, роадмап отвечает **когда и в каком порядке** оно появилось —
другой вопрос. Ссылки на файл в строке нет намеренно: файла больше нет, а битая
ссылка это законная ошибка `check`. Форма строки — как в `REJECTED.md`, и по той
же причине.
**Р78. Цель — возможность приложения, задача — шаг к ней.** Заголовок цели
отвечает на «что приложение будет уметь»: не «Работа со слиянием», а «Исход
слияния не зависит от порядка доставки». **Свойство поведения — тоже
возможность**: «сообщает о своём состоянии», «исход не зависит от порядка» —
законные цели, переформулировки в функцию не требуют. Единственный настоящий
чужак — работа над инструментом и процессом: на вопрос «что приложение будет
уметь» она не отвечает и живёт в отдельной секции роадмапа.
**Р79. Тест готовности задачи сменил защиту.** Требование «что станет наблюдаемо
иначе снаружи» переехало к цели. У задачи вместо него — **какую строку
«Завершения» своей цели она двигает**. «Отрефакторить X» проваливает тест не
потому, что невидим снаружи, а потому, что не находит строки, к которой
относится. Побочная выгода: видно и обратное — строка «Завершения», к которой не
относится ни одна задача, это незакрытая часть возможности. Отсюда требование к
«Завершению» быть **списком**, а не абзацем: на абзац не сошлёшься.
**Р80. Цель обязательна не у всякой задачи.** Прежнее правило — «у каждой задачи
должен быть `goal:`, иначе она не попадёт ни в один спринт» — было угрозой, а не
аргументом, и заставляло операционную работу выдумывать себе направление.
Граница проходит по роду работы: `feature` без цели не бывает (новая возможность
и есть содержание цели), `fix`, `chore` и `research` живут без цели законно и
входят в набор спринта помимо его цели. Это второй раз, когда род работы
окупается, — и первый, когда он что-то определяет за пределами отбора.
**Р81. Тип `[epic]` упразднён.** Зонтик между целью и задачами не нужен:
зонтиком стала цель, а слишком крупный шаг дробится на шаги помельче под ней.
Замер: ноль употреблений на 97 записей двух живых проектов, при том что тип
занимал место в словаре, тесте готовности, автомате переходов, `split.md` и трёх
местах `tasks.py`.
**Р82. Имена секций роадмапа — `Готово` / `Запланировано` / `Направления` /
`Разработка`.** Первый набор (`умеет` / `строим` / `станок`) прожил один заход и
был признан неудачным. Из четырёх предложенных имён отвергнуто одно, и по
проверяемой причине: **`окружение` уже занято** — в `architecture.md` это боевое
окружение приложения, «где работает, что рядом, кто перезапускает», и одно слово
в двух смыслах развело бы документы канона. Взято `Разработка`.
Принятый компромисс назван вслух: `Готово` слегка тянет обратно в трекерную рамку
«состояние работы», тогда как секция про **возможность**. Перевесила читаемость с
первого взгляда, а смысл несут заголовки целей внутри секции. Так же принято, что
цель в `Запланировано` может быть уже наполовину построена: это очередь, а не
«не начато», а «в работе» живёт в `SPRINT.md`.
**Р83. Секции роадмапа канонические, секции беклога — нет.** Разница выведена, а
не назначена: у секций роадмапа есть **семантика** (достигнутое, очередь,
долгое, не про продукт), в первую пишет сам `close`, и роадмап, названный
по-своему, читался бы только своим автором. Секции беклога (`Ядро`, `Инфра`)
семантики не несут — это полки. Поэтому `check` проверяет у роадмапа три вещи:
состав закреплён (чужая секция — ошибка), все четыре обязаны быть, язык один на
весь индекс; `--roadmap-sections` у `init` упразднён. Английский набор — `Done`
| `Planned` | `Directions` | `Tooling`.
Проверено на том самом случае, ради которого правило и заводилось: секция «Что
уже пройдено», которую healthlog вёл руками, теперь называется ошибкой поимённо.
## Что из этого следует
**С78. Ключа `tasks.achieved_section` не появилось.** Секция достигнутого
опознаётся по каноническому имени в любом из двух языков, и лишний knob не
заводится: канонический состав отвечает на тот же вопрос надёжнее конфига.
**С79. `reopen` цели снимает строку достигнутого.** Иначе роадмап продолжает
утверждать, что приложение умеет то, что вернулось в работу.
**С80. Прозаический раздел в индексе — дрейф.** Любой `##` проверка считает
секцией, поэтому «Что уже пройдено» и «Почему в таком порядке» в healthlog
формально были двумя лишними секциями, куда могла уехать задача. При повышении
они разбираются: звенья — строками в `Готово`, обоснование очереди — прозой
внутри `Запланировано`.
**С81. Правил стало пять, и нулевое — про смысл, а не про механику.** «Цель —
возможность, задача — шаг к ней» стоит перед правилами о гниении беклога и
производности индексов, потому что из него следует, зачем эти механики нужны.