роадмап — состояние проекта, а не очередь работ

Основной инструмент владельца отвечал на половину своего вопроса. Оценка идёт
по поведению: что приложение уже может и чего ещё не может, — а 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:
av
2026-08-04 17:43:55 +03:00
co-authored by Claude Opus 5
parent 5bf599a767
commit e847bfa0ea
13 changed files with 453 additions and 136 deletions
+16 -5
View File
@@ -200,13 +200,24 @@ kebab-case.
### `tasks/`
Раскладку, форму записи и команды держит скилл `tasks` — канон фиксирует только
имена файлов (`items/`, `ROADMAP.md`, `BACKLOG.md`, `SPRINT.md`, `REJECTED.md`) и
два требования к самой записи, потому что от них зависит, можно ли задачу
Раскладку, форму записи и команды держит скилл `tasks` — канон фиксирует имена
файлов (`items/`, `ROADMAP.md`, `BACKLOG.md`, `SPRINT.md`, `REJECTED.md`) и то,
от чего зависит, читается ли проект как продукт.
**`ROADMAP.md` отвечает на «что приложение уже умеет и чего ещё не умеет».** Это
не очередь работ: цель — **возможность приложения**, задача — шаг к ней.
Достигнутая цель из роадмапа **не исчезает** — строка с датой переезжает в
секцию достигнутого, потому что «что умеет» и есть половина вопроса, ради
которого документ открывают. Вторым домом поведения роадмап при этом не
становится: нормативное поведение живёт в `openspec/specs/`, роадмап отвечает,
**когда и в каком порядке** оно появилось.
Плюс два требования к записи задачи, потому что от них зависит, можно ли её
оценить:
- **род работы** тегом `kind:<род>` из закрытого словаря `feature` | `fix` |
`chore` | `research` — у задачи обязателен, у цели запрещён;
`chore` | `research` — у задачи обязателен, у цели запрещён. Он же решает,
нужна ли цель: у `feature` обязательна, у остальных нет;
- **раздел «Затрагивает»** в теле задачи — границы, которых изменение касается
(эндпоинт, таблица и миграция, формат на диске, публичный тип пакета).
@@ -252,7 +263,7 @@ kebab-case.
| почему решено так | `adr/`, источник — архивный `design.md` |
| граница домена, «чем не является» | `passport.md` |
| инвариант и его severity | `CLAUDE.md` |
| порядок работ и его обоснование | `docs/tasks/ROADMAP.md` |
| что приложение умеет и чего не умеет; порядок работ | `docs/tasks/ROADMAP.md` |
| измеренное число | `research/` |
| настройка с числовым значением | `database.md` |
| периметр и модель угроз | `security.md` |
+31 -8
View File
@@ -15,10 +15,11 @@ upgrade` идёт по записям снизу вверх от версии п
## Версия 3 — 2026-08-04
Оглавление целей переименовано, у задач появился род работы и раздел
«Затрагивает», сменилось умолчание профиля ревью. Раскладка меняется в одном
файле, но переименование тянет за собой ссылки, поэтому шаги делаются одним
заходом.
Роадмап стал **состоянием проекта**, а не очередью работ: цель — возможность
приложения, задача — шаг к ней, достигнутое из роадмапа не исчезает. Плюс род
работы, раздел «Затрагивает» и новое умолчание профиля ревью. Раскладка меняется
в одном файле, но переименование и смена секций тянут за собой ссылки, поэтому
шаги делаются одним заходом.
**Что добавилось:**
@@ -30,20 +31,30 @@ upgrade` идёт по записям снизу вверх от версии п
2. **Раздел «Затрагивает»** в теле задачи — перечень границ, которых изменение
касается (эндпоинт, таблица и миграция, формат на диске, публичный тип). Как
и критерии приёмки, требуется к взятию в спринт, а не к заведению.
3. **Умолчание профиля ревью сменилось** — это не раскладка, но проектный текст
3. **Секции роадмапа** — четыре вместо двух: `умеет` (достигнутые цели строкой
с датой, без ссылки на файл), `строим` (очередь значима), `направления`
(очереди нет), `станок` (инструмент и процесс, не возможности приложения).
Имя секции достигнутого скрипт знает по конфигу — `tasks.achieved_section`.
Имена **временные** и будут пересмотрены (DECISIONS, тема 19).
4. **Умолчание профиля ревью сменилось** — это не раскладка, но проектный текст
под него уже написан. `standard` стал рабочим умолчанием: миграция схемы,
публичный контракт и инвариант ступень больше **не** поднимают, `wide`
означает новое понятие или структурную единицу. Подраздел «Триггеры профиля»
в `docs/review.md` остаётся на месте, но его содержимое надо перечитать.
**Что переехало:** `docs/tasks/PLAN.md``docs/tasks/ROADMAP.md`. Вместе с
**Что переехало:** `docs/tasks/PLAN.md``docs/tasks/ROADMAP.md`; достигнутая
цель — из небытия в секцию `умеет`: `close <цель> --implemented` удаляет файл, но
**оставляет строку с датой**. Прежде роадмап отвечал только «что осталось», и
половину его вопроса вели прозой руками. Вместе с
файлом переименован ключ конфига `tasks.plan``tasks.roadmap` и токены
команд: `--index plan``--index roadmap`, `init --plan-sections`
`--roadmap-sections`, `init --plan``--roadmap`. Старый ключ в
`docs/.pm.json` не игнорируется молча — `tasks.py` останавливается и называет
переименование.
**Что удалено:** ничего.
**Что удалено:** тип `[epic]`. Он был зонтиком между целью и задачами; зонтиком
стала цель, а слишком крупный шаг дробится на шаги помельче под ней. Ноль
употреблений на 97 записей двух живых проектов.
**Что сделать проекту:**
@@ -63,7 +74,19 @@ upgrade` идёт по записям снизу вверх от версии п
что для этого проекта считается **новым понятием** и **правилом
идентичности**, — и убрать остальное, иначе проект возвращает себе прежнюю
частоту полного набора уточнением.
7. `docs/.pm.json`: `"canon": 3`.
7. Переименовать секции роадмапа: `порядок``строим`, `темы`
`направления`; завести `умеет` **первой** и `станок` последней. Прозаические
разделы вроде «Что уже пройдено», которые велись руками, разложить: звенья —
строками в `умеет` (дата, слаг, что стало возможно), обоснование очереди
оставить прозой в `строим`. Любой `##` в индексе проверка считает секцией,
поэтому прозаический заголовок здесь — дрейф.
8. Переформулировать цели ответом на **«что приложение будет уметь»**: не
«Работа со слиянием», а «Исход слияния не зависит от порядка доставки».
Свойство поведения — законная цель. Цель, которая не про приложение
(процесс, инструмент), переезжает в `станок`.
9. `[epic]`, если он в проекте заводился: это либо цель, либо набор задач под
общей целью. `check` назовёт его неизвестным типом.
10. `docs/.pm.json`: `"canon": 3`.
## Версия 2 — 2026-08-03