журнал решений: разложен по теме на файл, метки решений стали номерами
- DECISIONS.md (4040 строк, 65 тем) → decisions/, файл на тему плюс указатель; - буквенные метки решений заменены сквозными Р1–Р234, следствия получили префикс С при прежних номерах: схема букв выродилась до пятибуквенных и сломалась — `АЕАКЛ` была занята и темой 53, и темой 65; - 42 перекрёстные ссылки переписаны под новые номера и стали живыми; где номер означал тему, а слово стояло «решение», формулировка исправлена.
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# 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. Правил стало пять, и нулевое — про смысл, а не про механику.** «Цель —
|
||||
возможность, задача — шаг к ней» стоит перед правилами о гниении беклога и
|
||||
производности индексов, потому что из него следует, зачем эти механики нужны.
|
||||
Reference in New Issue
Block a user