канон 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:
@@ -240,18 +240,30 @@ kebab-case.
|
||||
становится: нормативное поведение живёт в `openspec/specs/`, роадмап отвечает,
|
||||
**когда и в каком порядке** оно появилось.
|
||||
|
||||
Плюс два требования к записи задачи, потому что от них зависит, можно ли её
|
||||
оценить:
|
||||
**У каждой записи есть тип, и тип решает, что с ней можно делать.** Дом типа —
|
||||
поле меты `Тип` первой строкой; эмодзи в заголовке от него производна. Словарь
|
||||
закрыт:
|
||||
|
||||
- **род работы** тегом `kind:<род>` из закрытого словаря `feature` | `fix` |
|
||||
`chore` | `research` — у задачи обязателен, у цели запрещён. Он же решает,
|
||||
нужна ли цель: у `feature` обязательна, у остальных нет;
|
||||
- **раздел «Затрагивает»** в теле задачи — границы, которых изменение касается
|
||||
(эндпоинт, таблица и миграция, формат на диске, публичный тип пакета).
|
||||
| Тип | Что это | Обязательные разделы | Цель |
|
||||
| --- | --- | --- | --- |
|
||||
| 🎯 `goal` | возможность приложения | `Завершение` | — |
|
||||
| ✨ `feature` | снаружи появляется то, чего не было | `Затрагивает`, `Критерии приёмки` | обязательна |
|
||||
| 🐞 `fix` | поведение расходится с заявленным | `Воспроизведение`, `Затрагивает`, `Критерии приёмки` | нет |
|
||||
| 🧹 `chore` | обслуживание, поведение не меняется | `Затрагивает`, `Критерии приёмки` | нет |
|
||||
| 🔬 `research` | исход — знание, а не изменение | `Вопрос`, `Куда ляжет ответ` | нет |
|
||||
|
||||
Оба требуются **к взятию в спринт**, а не к заведению: беклог пополняется чаще,
|
||||
Схема требуется **к взятию в спринт**, а не к заведению: беклог пополняется чаще,
|
||||
чем разбирается, и требование на входе выгоняло бы в заметки то, что должно
|
||||
лежать задачей.
|
||||
лежать задачей. Запись, не собравшая разделы своего типа, — законное состояние
|
||||
беклога; невзятой её делает `sprint take`.
|
||||
|
||||
Отдельного типа для незаполненной записи нет: «ещё не описано» — состояние, а не
|
||||
род работы, и называется оно **`research` без раздела «Вопрос»**. Такая запись в
|
||||
спринт не берётся и лежит в конце своей категории.
|
||||
|
||||
Раскладку, форму записи и алгоритм работы над каждым типом держит скилл `tasks`
|
||||
(`references/task-<тип>.md`); канон фиксирует только словарь типов и то, от чего
|
||||
зависит, читается ли проект как продукт.
|
||||
|
||||
### `CLAUDE.md`
|
||||
|
||||
@@ -324,7 +336,7 @@ kebab-case.
|
||||
| --- | --- |
|
||||
| `docs/review-brief.md` | документы канона и есть бриф; остаток — в `review.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` |
|
||||
| `BRIEF.md` | `passport.md` |
|
||||
| `docs/backlog/` | `docs/tasks/` |
|
||||
@@ -364,10 +376,14 @@ kebab-case.
|
||||
`database.md`. `tasks` — настройки каталога задач, переехавшие сюда из прежнего
|
||||
`<tasks>/.tasks.json`: **один конфиг на весь канон, а не по одному на каталог**.
|
||||
Внутри `tasks` — **только имена файлов и заголовков** (`items`, `backlog`,
|
||||
`plan`, `sprint`, `rejected`, `sprint_section`, `questions_heading`,
|
||||
`criteria_heading`, `oracle_word`), и ключ пишется, лишь когда имя отличается от
|
||||
умолчания. **Секций беклога здесь нет:** их дом — заголовки `##` самого индекса,
|
||||
и второй список сразу разошёлся бы с первым. Неизвестный ключ `tasks.py`
|
||||
`roadmap`, `sprint`, `rejected`, `sprint_section`, `oracle_word` и заголовки
|
||||
разделов тела: `criteria_heading`, `surface_heading`, `questions_heading`,
|
||||
`completion_heading`, `repro_heading`, `question_heading`, `answer_heading`,
|
||||
`scope_heading`), и ключ пишется, лишь когда имя отличается от умолчания.
|
||||
**Словаря типов здесь нет** — он закрыт каноном, а не настраивается проектом:
|
||||
настраиваемый словарь типов разъехался бы на синонимах ровно так же, как
|
||||
открытый. **Категорий беклога здесь тоже нет:** их дом — заголовки `##` самого
|
||||
индекса, и второй список сразу разошёлся бы с первым. Неизвестный ключ `tasks.py`
|
||||
отвергает кодом 3, поэтому лишнее слово в этом объекте останавливает работу с
|
||||
задачами целиком.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user