задачи: цель упразднена, у проекта появилась стадия
Тип goal и индекс ROADMAP.md убраны: цель — зонтик над параллельными направлениями, а у проекта на одного человека список работ линеен. Роадмап при этом наполовину дублировал беклог, а «что уже умеет» отвечают спеки и git log индекса. Секция «Готово» удалена, а не перенесена. Вместо цели — ось «стадия проекта»: build (беклог это план стройки, порядок строк значит зависимость, секция одна) и support (очередь правок, порядок значит важность, секции — полки домена). Стадия объявляется ключом [tasks] stage, меняется командой stage, без неё check отказывает: порядок строк нечем прочитать. Ушли теги goal:/decomposed, поле «Секция», раздел «Завершение», флаги --goal и edit --section. Версия раскладки 2 → 3, перевод проекта расписан записью журнала.
This commit is contained in:
@@ -46,8 +46,9 @@
|
||||
|
||||
**Учёт работ.** Владеет каталогом задач.
|
||||
|
||||
- `task-track` — задачи и цели каталогом markdown-файлов, у каждой записи тип
|
||||
(`goal`, `feature`, `fix`, `chore`, `research`), и тип задаёт её схему;
|
||||
- `task-track` — задачи каталогом markdown-файлов: у каждой тип (`feature`,
|
||||
`fix`, `chore`, `research`), задающий её схему, а у проекта — стадия (`build`
|
||||
или `support`), решающая, что значит порядок строк беклога;
|
||||
вычитывают их два отдельных прохода: `task-form` (форма записи) и
|
||||
`task-wording` (язык записей);
|
||||
- `task-groom` — груминг беклога: что сейчас самое важное и что перестало быть
|
||||
@@ -472,7 +473,7 @@ python3 scripts/resync.py # переписать тела всех разо
|
||||
## Проверка адресов документов
|
||||
|
||||
Адрес документа принадлежит одному плагину, а называют его все: `docs/*` стоит
|
||||
примерно в сорока местах конвейера, `tasks/ROADMAP.md` — в четырёх местах канона.
|
||||
примерно в сорока местах конвейера, `tasks/BACKLOG.md` — в нескольких местах канона.
|
||||
Переименование в каноне до этих мест само не доходит.
|
||||
|
||||
```
|
||||
|
||||
@@ -27,7 +27,7 @@ color: yellow
|
||||
| почему решено так | `adr/`, источник — архивный `design.md` либо записка разведки |
|
||||
| граница домена, «чем не является» | `passport.md` |
|
||||
| инвариант и его severity | `CLAUDE.md` |
|
||||
| что приложение умеет и чего не умеет; порядок работ | `tasks/ROADMAP.md` |
|
||||
| что осталось сделать и в каком порядке | `tasks/BACKLOG.md` |
|
||||
| измеренное число | `research/` |
|
||||
| настройка с числовым значением | `database.md` |
|
||||
| периметр и модель угроз | `security.md` |
|
||||
|
||||
+19
-43
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: task-form
|
||||
description: "Проверка формы записи каталога задач по существу: тип, разошедшийся с содержанием записи, форма заголовка по типу (цель — что приложение будет уметь, задача — что нужно сделать, разведка — о чём она), «зачем», пересказывающее заголовок вместо состояния и боли, раздел «Затрагивает» с замыслом вместо границ, критерий приёмки с оракулом только на словах, предписание процесса в теле, и связь задачи со строкой «Завершения» её цели. Читает файл цели, на которую ссылается задача. Отдаёт готовые формулировки на замену и ничего не правит сам. Язык текста (залог, оценки, стоп-слова, англицизмы) смотрит отдельный агент task-wording. Использовать после заведения или разбора пачки записей, при проверке готовности перед взятием в работу (tasks.py ready) и на груминге. Только чтение."
|
||||
description: "Проверка формы записи каталога задач по существу: тип, разошедшийся с содержанием записи, форма заголовка по типу (задача — что нужно сделать, разведка — о чём она), «зачем», пересказывающее заголовок вместо состояния и боли, раздел «Затрагивает» с замыслом вместо границ, критерий приёмки с оракулом только на словах, предписание процесса в теле. Отдаёт готовые формулировки на замену и ничего не правит сам. Язык текста (залог, оценки, стоп-слова, англицизмы) смотрит отдельный агент task-wording. Использовать после заведения или разбора пачки записей, при проверке готовности перед взятием в работу (tasks.py ready) и на груминге. Только чтение."
|
||||
tools: Read, Grep, Glob
|
||||
model: sonnet
|
||||
color: green
|
||||
@@ -11,8 +11,8 @@ color: green
|
||||
открывая код.
|
||||
|
||||
Оптика — смысл записи в её собственных рамках. Ты **не** судишь, нужна ли
|
||||
задача, верно ли выбрана цель и не крупна ли она: это разбор, и его ведёт
|
||||
человек со скиллом `task-track`.
|
||||
задача и не крупна ли она: это разбор, и его ведёт человек со скиллом
|
||||
`task-track`.
|
||||
|
||||
Границу с языком держи твёрдо. **Залог, оценки, стоп-слова, англицизмы, жаргон**
|
||||
— у агента `task-wording`, и тебе они не поручены даже там, где бросаются в
|
||||
@@ -28,8 +28,6 @@ color: green
|
||||
## Что тебе дают
|
||||
|
||||
Список файлов записей (`tasks/items/<slug>.md`) или каталог задач целиком.
|
||||
Каталог тебе нужен и сам по себе: задача несёт тег `goal:<слаг>`, и **файл цели
|
||||
ты открываешь**, иначе седьмое правило не проверить.
|
||||
|
||||
Документы проекта — паспорт, архитектура, конвенции — если зовущий их назвал.
|
||||
По ним видно, названа ли граница именем, которое в проекте существует.
|
||||
@@ -43,20 +41,15 @@ color: green
|
||||
|
||||
| Тип | Отвечает на | Форма |
|
||||
| --- | --- | --- |
|
||||
| 🎯 `goal` | что приложение будет уметь | утверждение о возможности: «Соперником может быть компьютер» |
|
||||
| ✨ `feature`, 🐞 `fix`, 🧹 `chore` | что нужно сделать | глагол в неопределённой форме, допускается «не» перед ним: «Печатать поле одним куском кода» |
|
||||
| 🔬 `research` | о чём разведка | назывное, без обещания: «Подсказка следующего хода» |
|
||||
|
||||
Описательный заголовок задачи («Лишние символы молча отбрасываются») называет
|
||||
**состояние** и одинаково читается как жалоба и как задание. Заголовок цели в
|
||||
форме действия («Сделать соперника-компьютер») превращает роадмап в список
|
||||
работ — а он список возможностей.
|
||||
**состояние** и одинаково читается как жалоба и как задание.
|
||||
|
||||
**Область работ — не цель.** «Работа со слиянием», «Рефакторинг вывода» не
|
||||
отвечают ни на один из трёх вопросов; предложи возможность, которую эта работа
|
||||
создаёт, и скажи, если из текста её не видно. **Свойство поведения —
|
||||
законная возможность**: «исход слияния не зависит от порядка доставки» — цель,
|
||||
а не абстракция.
|
||||
**Область работ — не задача.** «Работа со слиянием», «Рефакторинг вывода» не
|
||||
отвечают ни на один из двух вопросов; предложи формулировку, называющую, что
|
||||
нужно сделать, и скажи, если из текста этого не видно.
|
||||
|
||||
2. **Тип сходится с тем, что в записи написано.** Тип — первое поле меты, и он
|
||||
решает, каких разделов запись требует; разошедшийся тип врёт ровно там, где
|
||||
@@ -68,7 +61,7 @@ color: green
|
||||
- **`feature`, после которой снаружи ничего не меняется**, — это `chore`, и
|
||||
сказать это честно дешевле, чем выдумывать пользовательскую пользу;
|
||||
- **`chore`, меняющий наблюдаемое поведение**, — это `feature` или `fix`, и у
|
||||
них другие требования (цель, воспроизведение);
|
||||
последнего другие требования (воспроизведение);
|
||||
- **`research`, у которого «Вопрос» — это тема, а не вопрос.** «Разобраться с
|
||||
выводом в терминалах» вопросом не является: на него нельзя ответить. Пока
|
||||
вопроса нет, запись остаётся сырьём — и это законное состояние, но назови
|
||||
@@ -105,20 +98,6 @@ color: green
|
||||
постановке. Он же путь понизить требования решением, принятым до
|
||||
проектирования.
|
||||
|
||||
7. **Задача называет, какую строку «Завершения» своей цели она двигает.**
|
||||
Открой файл цели из тега `goal:<слаг>` и сверь. Три исхода, и все три —
|
||||
разные находки:
|
||||
|
||||
- **строка не названа** — допиши предложение, какая это строка, если из текста
|
||||
задачи видно; не видно — так и скажи;
|
||||
- **строки с таким смыслом в «Завершении» нет** — либо задача не про эту цель,
|
||||
либо у цели неполное «Завершение». Назови оба варианта, выбирать не тебе;
|
||||
- **строка «Завершения», к которой не относится ни одна поданная задача**, —
|
||||
это незакрытая часть возможности. Скажи о ней отдельно, вне списка находок
|
||||
по файлам: это про набор, а не про запись.
|
||||
|
||||
У задачи **без цели** (`fix`, `chore`, `research`) правило не применяется
|
||||
вовсе — они служат работоспособности, а не направлению.
|
||||
|
||||
## Чего ты не проверяешь
|
||||
|
||||
@@ -126,13 +105,13 @@ color: green
|
||||
|
||||
**Чужому подрядчику — строкой в границах покрытия.** Язык у `task-wording`;
|
||||
согласованность документов канона между собой у `doc-consistency`, их
|
||||
соответствие коду у `doc-code-drift` — до задач эти двое не доходят вовсе, но
|
||||
если ты открыл цель и увидел расхождение в самом документе, оно их. Увидел —
|
||||
назови в конце одной строкой, чтобы находка не пропала, но находкой не оформляй.
|
||||
соответствие коду у `doc-code-drift` — до задач эти двое не доходят вовсе.
|
||||
Увидел не своё — назови в конце одной строкой, чтобы находка не пропала, но
|
||||
находкой не оформляй.
|
||||
|
||||
**Машинной проверке — вообще ничего.** Всё, что ловит `tasks.py check` (состав и
|
||||
написание секций, теги, тег `question` при непустом разделе «Вопросы»,
|
||||
согласованность индексов, битые ссылки, форма заголовка как строки), **не пиши
|
||||
согласованность индекса, битые ссылки, форма заголовка как строки), **не пиши
|
||||
даже строкой**: это не потерянная находка, а уже проверенное. Повторять машинную
|
||||
проверку словами — заводить второй дом для одного правила.
|
||||
|
||||
@@ -142,9 +121,9 @@ color: green
|
||||
твоя — раздел, который **есть и лжёт**: границы вместо замысла, критерий с
|
||||
оракулом только на словах.
|
||||
|
||||
**Содержание работы**: нужна ли задача, верно ли выбрана цель, не крупна ли она,
|
||||
достаточна ли декомпозиция. Седьмое правило подходит к этому близко и
|
||||
останавливается там, где кончается сверка с текстом цели. Об этом молчи.
|
||||
**Содержание работы**: нужна ли задача, не крупна ли она, достаточна ли
|
||||
декомпозиция. **И место в списке**: порядок строк значит зависимость на стройке и
|
||||
важность на доработке, а ты записи видишь поштучно, вне списка. Об этом молчи.
|
||||
|
||||
## Порог вмешательства
|
||||
|
||||
@@ -169,9 +148,9 @@ color: green
|
||||
|
||||
## Доклад
|
||||
|
||||
Находки по одной, в порядке важности: заголовок → «зачем» → границы → критерии →
|
||||
связь с целью. Порядок такой, потому что заголовок и «зачем» — это всё, что
|
||||
видно в индексе, а по индексу и выбирают.
|
||||
Находки по одной, в порядке важности: заголовок → «зачем» → границы → критерии.
|
||||
Порядок такой, потому что заголовок и «зачем» — это всё, что видно в индексе, а
|
||||
по индексу и выбирают.
|
||||
|
||||
```
|
||||
<файл>
|
||||
@@ -181,11 +160,8 @@ color: green
|
||||
почему: <одна фраза>
|
||||
```
|
||||
|
||||
Отдельным блоком после находок — **строки «Завершения» без задач**, если такие
|
||||
нашлись: цель, строка, и что это значит.
|
||||
|
||||
В конце — **границы покрытия**: сколько записей просмотрено из скольких, какие
|
||||
цели открыты, какие не смотрел и почему. Отчёт без этой строки читается как
|
||||
не смотрел и почему. Отчёт без этой строки читается как
|
||||
«беклог проверен», не сообщая, какая его часть осталась нетронутой. Туда же —
|
||||
строка «замечено не по моей части», если бросился в глаза язык; машинно
|
||||
проверяемое в неё **не идёт**.
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
---
|
||||
name: task-wording
|
||||
description: "Вычитка языка записей каталога задач по информационному стилю — задачи, цели, строки индексов и причины отказа. Смотрит отглагольные существительные и страдательный залог, оценку без факта, стоп-слова и канцелярит, «одна мысль — одно предложение», англицизм при живом русском слове, жаргон и метафоры вместо прямого называния, термин, которого нет в документах проекта, транслит в слаге. Отдаёт готовые формулировки на замену и ничего не правит сам. Форму записи (заголовок по типу, «зачем», границы, оракулы) смотрит отдельный агент task-form, документы проекта вычитывает doc-wording. Использовать после заведения или разбора пачки записей, до взятия в работу и на переоценке беклога. Только чтение."
|
||||
description: "Вычитка языка записей каталога задач по информационному стилю — задачи, строки индекса и причины отказа. Смотрит отглагольные существительные и страдательный залог, оценку без факта, стоп-слова и канцелярит, «одна мысль — одно предложение», англицизм при живом русском слове, жаргон и метафоры вместо прямого называния, термин, которого нет в документах проекта, транслит в слаге. Отдаёт готовые формулировки на замену и ничего не правит сам. Форму записи (заголовок по типу, «зачем», границы, оракулы) смотрит отдельный агент task-form, документы проекта вычитывает doc-wording. Использовать после заведения или разбора пачки записей, до взятия в работу и на переоценке беклога. Только чтение."
|
||||
tools: Read, Grep, Glob
|
||||
model: sonnet
|
||||
color: green
|
||||
---
|
||||
|
||||
Ты — **вычитка языка записей каталога задач**: задач, целей, строк индексов и
|
||||
причин отказа. Оптика — слова и фразы, а не то, что запись описывает: ты не
|
||||
судишь, нужна ли задача, верно ли выбрана цель и правильно ли запись оформлена.
|
||||
Ты — **вычитка языка записей каталога задач**: задач, строк индекса и причин
|
||||
отказа. Оптика — слова и фразы, а не то, что запись описывает: ты не судишь,
|
||||
нужна ли задача и правильно ли она оформлена.
|
||||
|
||||
Границу держи твёрдо, и она у тебя одна. **Форму записи** — тип, заголовок по
|
||||
типу, «зачем» вместо пересказа, раздел «Затрагивает», годность оракулов, связь
|
||||
со строкой «Завершения» цели — смотрит `task-form`, и тебе она не поручена даже
|
||||
типу, «зачем» вместо пересказа, раздел «Затрагивает», годность оракулов —
|
||||
смотрит `task-form`, и тебе она не поручена даже
|
||||
там, где бросается в глаза. Отсюда же исключение, и оно **против** тебя:
|
||||
неудачное слово **в заголовке** судит `task-form`, потому что заголовок целиком
|
||||
его. Увидел не по своей части — скажи одной строкой в конце доклада, не
|
||||
@@ -27,9 +27,8 @@ color: green
|
||||
|
||||
## Что тебе дают
|
||||
|
||||
Список записей или каталог задач: файлы `items/<slug>.md`, а с ними — индексы
|
||||
(`BACKLOG.md`, `ROADMAP.md`, `REJECTED.md`), где та же запись представлена
|
||||
строкой. **Строка индекса вычитывается наравне с файлом**: по ней запись
|
||||
Список записей или каталог задач: файлы `items/<slug>.md`, а с ними —
|
||||
`BACKLOG.md` и `REJECTED.md`, где та же запись представлена строкой. **Строка индекса вычитывается наравне с файлом**: по ней запись
|
||||
выбирают, не открывая тела, и «зачем» в ней повторяется дословно.
|
||||
|
||||
Плюс, если зовущий их назвал, документы проекта — паспорт, архитектура,
|
||||
@@ -200,8 +199,8 @@ color: green
|
||||
критериев `check` только считает — поимённо их судит `tasks.py ready`, и это
|
||||
тоже не твоя находка: твоя — язык того, что уже написано.
|
||||
|
||||
**Содержание работы**: нужна ли задача, верно ли выбрана цель, не крупна ли она,
|
||||
достаточна ли декомпозиция. Это разбор, и его ведёт человек со скиллом `task-track`.
|
||||
**Содержание работы**: нужна ли задача, не крупна ли она, достаточна ли
|
||||
декомпозиция. Это разбор, и его ведёт человек со скиллом `task-track`.
|
||||
|
||||
**Полезное действие, параллельность и работающий заголовок** — тоже не твои.
|
||||
Они в доктрине языка, судит их человек: находка по ним требует увидеть текст
|
||||
|
||||
+11
-2
@@ -16,7 +16,8 @@
|
||||
|
||||
| Ось | Значения | Дом |
|
||||
| --- | --- | --- |
|
||||
| тип записи | `goal` `feature` `fix` `chore` `research` | `task-track/SKILL.md`, «Тип записи» |
|
||||
| стадия проекта | `build` `support` | `task-track/SKILL.md`, «Две стадии» |
|
||||
| тип записи | `feature` `fix` `chore` `research` | `task-track/SKILL.md`, «Тип записи» |
|
||||
| сценарий | решение · обслуживание · разведка | `code-resolve/SKILL.md`, «Развилка» |
|
||||
| метка | `small` `medium` `large` | `code-review/SKILL.md`, «Метки» |
|
||||
| режим прогона | с меткой · без метки | здесь, ниже |
|
||||
@@ -35,6 +36,9 @@
|
||||
|
||||
| Влияет | На что | Где описано |
|
||||
| --- | --- | --- |
|
||||
| стадия проекта | что значит порядок строк беклога: зависимость или важность | `task-track/SKILL.md`, «Две стадии» |
|
||||
| стадия проекта | сколько у беклога секций, как его пополняют, применим ли груминг | там же и `task-groom/SKILL.md`, «Груминг — операция доработки» |
|
||||
| стадия проекта | метку, глубину и тип — **не влияет, и это записано явно** | `task-track/SKILL.md`, «Тип записи» |
|
||||
| тип записи | сценарий — **предлагает**, подтверждает предмет работы | `task-track/SKILL.md`, «Тип записи» |
|
||||
| тип записи | метку и глубину — **не влияет, и это записано явно** | там же |
|
||||
| сценарий | режим прогона: обслуживание идёт без метки | `code-resolve/references/maintain.md` |
|
||||
@@ -44,7 +48,7 @@
|
||||
| категория документа | заводит ли документ направление проверки | `canon.md`, «Три категории» |
|
||||
| severity | что с находкой делают дальше | `code-review/SKILL.md`, «Что происходит с находками» |
|
||||
|
||||
**Две клетки пусты, и это сказано намеренно, а не забыто.**
|
||||
**Три клетки пусты, и это сказано намеренно, а не забыто.**
|
||||
|
||||
**Категория документа × режим прогона.** На прогоне **с меткой** своя тема
|
||||
проекта закрыта при любом значении: `review-basics` — приёмник проектных тем и
|
||||
@@ -53,6 +57,11 @@
|
||||
проекта в нём нет. Значит, документ, заведённый проектом как тема, на
|
||||
обслуживании не смотрит никто, и строкой это нигде не называется.
|
||||
|
||||
**Стадия проекта × метка.** Изменение на стройке ничем не проще того же
|
||||
изменения на доработке: метку назначает разметка по факту изменения, и стадия в
|
||||
неё не входит. Заманчивая мысль «на стройке всё `small`, потому что приложения
|
||||
ещё нет» разбивается о первый же шаг, кладущий схему хранилища.
|
||||
|
||||
**Режим прогона × severity.** Триаж обязателен всегда, в том числе без метки. Но
|
||||
часть оснований `critical` — построенный путь к отказу, замер — добывается
|
||||
проходами, которые без метки не запускаются. Значит ли это, что `critical` на
|
||||
|
||||
+35
-3
@@ -26,9 +26,9 @@
|
||||
|
||||
[tasks]
|
||||
dir = "tasks" # каталог задач от корня репозитория
|
||||
stage = "build" # стадия проекта: build | support
|
||||
items = "items" # имена частей каталога — необязательны
|
||||
backlog = "BACKLOG.md"
|
||||
roadmap = "ROADMAP.md"
|
||||
|
||||
Коды выхода зовущих скриптов — общий словарь av-dev; отсюда возвращается
|
||||
исключение `ConfigError`, а решает по нему вызывающий.
|
||||
@@ -56,7 +56,7 @@ LEGACY_TASKS = ".tasks.json"
|
||||
|
||||
# Версия раскладки — одна на плагин. Журнал версий — references/changelog.md
|
||||
# скилла `canon`, повышает его операция `upgrade`.
|
||||
VERSION = 2
|
||||
VERSION = 3
|
||||
|
||||
VERSION_KEY = "version"
|
||||
|
||||
@@ -280,6 +280,33 @@ def merge_section(root: Path, name: str, values: dict) -> list[str]:
|
||||
return added
|
||||
|
||||
|
||||
def set_section_key(root: Path, name: str, key: str, value: str) -> None:
|
||||
"""Заменить значение ключа секции, не тронув остального.
|
||||
|
||||
Отличается от `merge_section` ровно тем, ради чего и заведена: та **не
|
||||
трогает** ключ, который уже есть, потому что дописывает умолчания в чужой
|
||||
файл. Здесь же значение меняет команда, которую позвал человек, и не
|
||||
переписать его значило бы промолчать о выполненном действии. Ключа нет —
|
||||
он дописывается, секции нет — заводится: и то и другое законное состояние
|
||||
файла, который правят руками.
|
||||
"""
|
||||
path = root / CONFIG_NAME
|
||||
lines = path.read_text(encoding="utf-8").splitlines() if path.is_file() else []
|
||||
start = next((i for i, ln in enumerate(lines) if _is_header(ln, name)), None)
|
||||
if start is None:
|
||||
merge_section(root, name, {key: value})
|
||||
return
|
||||
end = next((i for i in range(start + 1, len(lines)) if _is_header(lines[i])),
|
||||
len(lines))
|
||||
pattern = re.compile(rf"^(\s*{re.escape(key)}\s*=\s*)([^#]*?)(\s*(?:#.*)?)$")
|
||||
for i in range(start + 1, end):
|
||||
if (match := pattern.match(lines[i])):
|
||||
lines[i] = f"{match.group(1)}{quote(value)}{match.group(3)}"
|
||||
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
return
|
||||
merge_section(root, name, {key: value})
|
||||
|
||||
|
||||
def missing_keys(root: Path, name: str, values: dict) -> dict:
|
||||
"""Ключи секции, которые уже есть и разошлись с тем, что мы собирались дать.
|
||||
|
||||
@@ -317,7 +344,12 @@ def skeleton(number: int, docs: dict | None = None, tasks: dict | None = None) -
|
||||
out += ["", "[tasks]",
|
||||
"# каталог задач от корня репозитория; имена частей — умолчания скрипта",
|
||||
f"dir = {quote(tasks.get('dir', 'tasks'))}"]
|
||||
for key in ("items", "backlog", "roadmap"):
|
||||
if tasks.get("stage"):
|
||||
out += ["# стадия проекта: build — беклог это план стройки, порядок строк"
|
||||
" значит зависимость;",
|
||||
"# support — беклог это очередь правок, порядок значит важность",
|
||||
f"stage = {quote(tasks['stage'])}"]
|
||||
for key in ("items", "backlog", "rejected"):
|
||||
if tasks.get(key):
|
||||
out.append(f"{key} = {quote(tasks[key])}")
|
||||
return "\n".join(out) + "\n"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Сопровождение и эксплуатация
|
||||
|
||||
**Это дом.** Словарь «чем держат проект» назван в трёх местах трёх разных
|
||||
скиллов: секция `Сопровождение` в роадмапе (`task-track`), раздел «Эксплуатация»
|
||||
скиллов: задачи типа `chore` (`task-track`), раздел «Эксплуатация»
|
||||
в `architecture.md` (`canon`) и тема ревью `operations` (`code-review`). Ни
|
||||
один из трёх им не владеет, поэтому дом стоит в `shared/`.
|
||||
|
||||
@@ -18,16 +18,18 @@
|
||||
|
||||
| Место | Уровень | Что там |
|
||||
| --- | --- | --- |
|
||||
| `ROADMAP.md`, секция `Сопровождение` | план | **работы**, которые собираемся делать: цели и их задачи |
|
||||
| `BACKLOG.md`, задачи `chore` | план | **работы**, которые собираемся делать |
|
||||
| `architecture.md`, раздел «Эксплуатация» | состояние | **как устроено сейчас**: где работает, что рядом, кто перезапускает |
|
||||
| тема ревью `operations` | оптика | **чем проверяем**: «это упало через неделю на проде» |
|
||||
|
||||
Слово **«поддержка» не употребляется вовсе** — в нём слышится помощь
|
||||
пользователю, а это другая работа.
|
||||
пользователю, а это другая работа. По той же причине им не названа и **стадия
|
||||
проекта**: у неё имя «доработка» (`support`), словарь — `task-track`, «Две
|
||||
стадии».
|
||||
|
||||
**Граница с возможностями проходит по тому, кто наблюдает.** «Приложение
|
||||
сообщает о своём состоянии» — возможность приложения, её место среди прочих
|
||||
целей: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
|
||||
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
|
||||
секции роадмапа, и это верно — секции отвечают на разные вопросы.
|
||||
задач: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
|
||||
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в задачи
|
||||
разных типов, и это верно — типы отвечают на разные вопросы.
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
## Сопровождение и эксплуатация — целое и часть
|
||||
|
||||
Словарь этой темы — [shared/operations.md](../../../shared/operations.md):
|
||||
целое и часть, три места одной темы (секция роадмапа, раздел архитектуры, тема
|
||||
целое и часть, три места одной темы (задачи `chore`, раздел архитектуры, тема
|
||||
ревью `operations`) и граница с возможностями проекта. Здесь он не
|
||||
пересказывается: копия жила рядом с домом в одном дереве и была ровно тем
|
||||
вторым домом, против которого правило и написано.
|
||||
@@ -357,36 +357,35 @@ kebab-case.** Причина не эстетическая: имя файла с
|
||||
вовсе, и отказом это быть не может.
|
||||
|
||||
Раскладку, форму записи и команды держит скилл `av-dev:task-track`. Ниже — то,
|
||||
от чего зависит, читается ли проект как продукт: канон высказывается об этом
|
||||
потому, что роадмап отвечает на вопрос о **системе**, а не о работах.
|
||||
от чего зависит, читается ли проект как продукт.
|
||||
|
||||
**`ROADMAP.md` отвечает на «что приложение уже умеет и чего ещё не умеет».** Это
|
||||
не очередь работ: цель — **возможность приложения**, задача — шаг к ней.
|
||||
Достигнутая цель из роадмапа **не исчезает** — строка с датой переезжает в
|
||||
секцию достигнутого, потому что «что умеет» и есть половина вопроса, ради
|
||||
которого документ открывают. Вторым домом поведения роадмап при этом не
|
||||
становится: нормативное поведение живёт в `openspec/specs/`, роадмап отвечает,
|
||||
**когда и в каком порядке** оно появилось.
|
||||
**Индекс работ один — `BACKLOG.md`, и «что приложение уже умеет» он не
|
||||
отвечает.** На этот вопрос отвечают `openspec/specs/` (нормативное поведение) и
|
||||
`git log` индекса (когда и в каком порядке оно появилось). Роадмапа в каноне
|
||||
нет: половину своего вопроса он дублировал беклогом, а вторую — спеками.
|
||||
|
||||
**У каждой записи есть тип, и тип решает, что с ней можно делать.** Дом типа —
|
||||
**У проекта есть стадия, и она решает, что значит порядок строк беклога:**
|
||||
`build` — зависимость, `support` — важность. Канон её называет, потому что от
|
||||
неё зависит, читается ли список работ как план стройки или как очередь правок;
|
||||
механика — `task-track`, «Две стадии».
|
||||
|
||||
**У каждой задачи есть тип, и тип решает, что с ней можно делать.** Дом типа —
|
||||
поле меты `Тип` первой строкой; эмодзи в заголовке от него производна. Словарь
|
||||
закрыт:
|
||||
|
||||
| Тип | Что это |
|
||||
| --- | --- |
|
||||
| 🎯 `goal` | возможность приложения |
|
||||
| ✨ `feature` | снаружи появляется то, чего не было |
|
||||
| 🐞 `fix` | поведение расходится с заявленным |
|
||||
| 🧹 `chore` | обслуживание, поведение не меняется |
|
||||
| 🔬 `research` | исход — знание, а не изменение |
|
||||
|
||||
**Схемы записи здесь нет намеренно.** Какие разделы тип требует, нужна ли ему
|
||||
цель и берётся ли он в работу — скилл `av-dev:task-track`, раздел «Тип
|
||||
записи», подробно — по файлу на тип в его `references/task-<тип>.md`. Канон
|
||||
фиксирует **словарь**, потому что
|
||||
от него зависит, читается ли проект как продукт; схема — механика ведения задач,
|
||||
и второй её экземпляр разошёлся бы с первым (он и разошёлся: канон успел
|
||||
объявить цель у `fix` запрещённой, хотя она там необязательна).
|
||||
**Схемы записи здесь нет намеренно.** Какие разделы тип требует — скилл
|
||||
`av-dev:task-track`, раздел «Тип записи», подробно — по файлу на тип в его
|
||||
`references/task-<тип>.md`. Канон фиксирует **словарь**, потому что от него
|
||||
зависит, читается ли проект как продукт; схема — механика ведения задач, и второй
|
||||
её экземпляр разошёлся бы с первым (он и разошёлся: канон успел объявить цель у
|
||||
`fix` запрещённой, хотя она была необязательна, — и целей теперь нет вовсе).
|
||||
|
||||
Схема требуется **к взятию в работу**, а не к заведению: беклог пополняется чаще,
|
||||
чем разбирается, и требование на входе выгоняло бы в заметки то, что должно
|
||||
@@ -454,7 +453,7 @@ kebab-case.** Причина не эстетическая: имя файла с
|
||||
| почему решено так | `adr/`, источник — архивный `design.md` либо записка разведки |
|
||||
| граница домена, «чем не является» | `passport.md` |
|
||||
| инвариант и его severity | `CLAUDE.md` |
|
||||
| что приложение умеет и чего не умеет; порядок работ | `tasks/ROADMAP.md` |
|
||||
| что осталось сделать и в каком порядке | `tasks/BACKLOG.md` |
|
||||
| измеренное число | `research/` |
|
||||
| настройка с числовым значением | `database.md` |
|
||||
| периметр и модель угроз | `security.md` |
|
||||
@@ -488,8 +487,8 @@ kebab-case.** Причина не эстетическая: имя файла с
|
||||
| --- | --- |
|
||||
| `docs/review-brief.md` | документы канона и есть бриф; остаток — в `review.md` |
|
||||
| `docs/specs/` | `openspec/specs/` (поведение) и `architecture.md` (обзор) |
|
||||
| `docs/drafts/` | идея → запись `research`; отказ → ADR; порядок → `ROADMAP.md`; размышление → `opsx:explore` |
|
||||
| `docs/plan.md` | `tasks/ROADMAP.md` |
|
||||
| `docs/drafts/` | идея → запись `research`; отказ → ADR; порядок → `BACKLOG.md`; размышление → `opsx:explore` |
|
||||
| `docs/plan.md` | `tasks/BACKLOG.md` |
|
||||
| `BRIEF.md` | `passport.md` |
|
||||
| `docs/backlog/` | `tasks/` в корне репозитория |
|
||||
| `docs/review-journal.md`, `docs/review/journal.md` | `docs/review.md` |
|
||||
|
||||
@@ -22,6 +22,48 @@
|
||||
|
||||
---
|
||||
|
||||
## Версия 3 — 2026-08-13
|
||||
|
||||
Тип записи `goal` и индекс `ROADMAP.md` упразднены; у проекта появилась
|
||||
**стадия** — `build` (беклог это план стройки, порядок строк значит зависимость)
|
||||
или `support` (очередь правок, порядок значит важность).
|
||||
|
||||
Цель была зонтиком над параллельными направлениями — она нужна там, где список
|
||||
работ нельзя выстроить в один порядок. У проекта, который ведёт один человек,
|
||||
такого не бывает, и роадмап при этом наполовину дублировал беклог («чего ещё не
|
||||
умеет» = «что осталось в списке»), а вторую половину («что уже умеет») отвечают
|
||||
`openspec/specs/` и `git log` индекса.
|
||||
|
||||
**Что переехало.** Индекс остался один — `BACKLOG.md`. Поле меты `Секция` стало
|
||||
`Категория`; теги `goal:<слаг>`, `decomposed` и раздел `Завершение` упразднены;
|
||||
команды `list --goal`, `edit --goal`, `edit --section` и ключи `[tasks] roadmap`,
|
||||
`[tasks] completion_heading` — тоже. Появились ключ `[tasks] stage`, команда
|
||||
`tasks.py stage` и флаги `init --stage`, `adopt scan --stage`.
|
||||
|
||||
**Что сделать проекту.**
|
||||
|
||||
1. **Разобрать цели.** У каждой записи типа `goal` в `tasks/items/` два исхода, и
|
||||
выбирает человек: она становится обычной задачей (`edit <слаг> --type
|
||||
feature|fix|chore|research`) либо уходит (`close <слаг> --reason …`). Задачи,
|
||||
носившие её тег, живут дальше сами по себе. Скрипт этого не решает и говорит
|
||||
`НЕОДНОЗНАЧНО`.
|
||||
2. **Перенести содержимое `ROADMAP.md`.** Секция `Готово` **удаляется**: «что
|
||||
приложение умеет» отвечают спеки, «когда это появилось» — `git log`. Строки
|
||||
`Запланировано`, `Направления` и `Сопровождение` — это цели, и они разбираются
|
||||
шагом 1. Затем удалить сам файл и ключ `roadmap` из `.av-dev.toml`, если он там
|
||||
был.
|
||||
3. **Объявить стадию** — `tasks.py stage build` или `tasks.py stage support`.
|
||||
Приложение ещё строится и список работ линеен по зависимости — `build`;
|
||||
работает и правится точечно — `support`. Без ключа `check` отказывает: порядок
|
||||
строк нечем прочитать. На `build` секция беклога обязана остаться **одна** —
|
||||
слить полки надо руками, порядок строк в слитом списке знает только человек.
|
||||
4. **Поднять версию** — `docs.py bump`. Последним шагом.
|
||||
5. `docs.py check` и `tasks.py check --dir <каталог задач>` — до отсутствия
|
||||
дрейфа. Теги `goal:` и `decomposed`, поле `Секция` и старую форму меты снимет
|
||||
`tasks.py check --fix`.
|
||||
|
||||
---
|
||||
|
||||
## Версия 2 — 2026-08-13
|
||||
|
||||
Скилл `doc-canon` стал `canon`: префикс называл материал (`doc-`), а скилл
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
# Паспорт проекта
|
||||
|
||||
Зачем это и для кого. [architecture.md](architecture.md) отвечает «как
|
||||
устроено», [tasks/ROADMAP.md](../tasks/ROADMAP.md) — «в каком порядке», паспорт —
|
||||
устроено», [tasks/BACKLOG.md](../tasks/BACKLOG.md) — «что осталось», паспорт —
|
||||
«зачем и для кого».
|
||||
|
||||
## Цель
|
||||
@@ -261,7 +261,7 @@
|
||||
## Последствия
|
||||
|
||||
- `+` что стало лучше.
|
||||
- `−` чем платим: ограничения, риски, нагрузка на поддержку.
|
||||
- `−` чем платим: ограничения, риски, нагрузка на сопровождение.
|
||||
```
|
||||
|
||||
## `docs/review.md`
|
||||
|
||||
@@ -127,10 +127,10 @@ NOT_DOCS = {".docs.json", ".pm.json", "tasks"}
|
||||
RETIRED = {
|
||||
"review-brief.md": "документы канона и есть бриф; остаток — в review",
|
||||
"review-journal.md": "→ документ review",
|
||||
"plan.md": "→ tasks/ROADMAP.md (ведёт скилл task-track)",
|
||||
"plan.md": "→ tasks/BACKLOG.md (ведёт скилл task-track)",
|
||||
"local-research.md": "→ документ research",
|
||||
"specs": "поведение → openspec/specs/, обзор → тема architecture",
|
||||
"drafts": "идея → запись research, отказ → ADR, порядок → ROADMAP.md",
|
||||
"drafts": "идея → запись research, отказ → ADR, порядок → BACKLOG.md",
|
||||
"backlog": "→ tasks/ в корне репозитория (ведёт скилл task-track)",
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: doc-init
|
||||
description: "Завести новый проект — сессия вопросов и ответов по свободному описанию замысла, из которой рождается первичная документация по канону av-dev: паспорт, CLAUDE.md с инвариантами и командами, модель угроз с периметром и скелет остальных документов; первые цели собирает интервью, а записывает их вызовом скилла av-dev:task-track — роадмап принадлежит учёту работ. OpenSpec заводит не сам, а вызовом скилла av-dev:code-openspec — каталог принадлежит конвейеру. Использовать, когда начинают новый проект с нуля, когда есть только текст «что мне нужно и почему» и надо превратить его в рабочую документацию, когда просят провести стартовое интервью по брифу. Проект, где документация уже как-то ведётся, переводит скилл canon."
|
||||
description: "Завести новый проект — сессия вопросов и ответов по свободному описанию замысла, из которой рождается первичная документация по канону av-dev: паспорт, CLAUDE.md с инвариантами и командами, модель угроз с периметром и скелет остальных документов; первый план работ собирает интервью, а записывает его вызовом скилла av-dev:task-track — беклог принадлежит учёту работ. OpenSpec заводит не сам, а вызовом скилла av-dev:code-openspec — каталог принадлежит конвейеру. Использовать, когда начинают новый проект с нуля, когда есть только текст «что мне нужно и почему» и надо превратить его в рабочую документацию, когда просят провести стартовое интервью по брифу. Проект, где документация уже как-то ведётся, переводит скилл canon."
|
||||
---
|
||||
|
||||
# Заведение нового проекта
|
||||
@@ -32,10 +32,10 @@ description: "Завести новый проект — сессия вопро
|
||||
Честная строка информативна, а не «TBD»: «архитектуры пока нет: кода нет,
|
||||
заводится первой задачей». Проход читает её как факт.
|
||||
|
||||
**`tasks/ROADMAP.md` в таблице нет намеренно.** Первые цели `init` собирает
|
||||
интервью (блок 6), но записывает их не он: каталогом задач и формой целей владеет
|
||||
`av-dev:task-track`, и это шаг 7. Человек от каталога задач отказался — цели
|
||||
остаются списком в докладе, роадмапа в проекте не появляется, и это говорится
|
||||
**`tasks/BACKLOG.md` в таблице нет намеренно.** Первый план работ `init`
|
||||
собирает интервью (блок 6), но записывает его не он: каталогом задач владеет
|
||||
`av-dev:task-track`, и это шаг 7. Человек от каталога задач отказался — план
|
||||
остаётся списком в докладе, беклога в проекте не появляется, и это говорится
|
||||
строкой.
|
||||
|
||||
## Порядок интервью — зависимость, а не удобство
|
||||
@@ -54,9 +54,11 @@ description: "Завести новый проект — сессия вопро
|
||||
проекте нельзя откатить — деплой, выкладка наружу, перезапись данных.
|
||||
5. **Чем краснеет гейт.** Какие проверки обязательны; что красит безусловно;
|
||||
чего в гейте намеренно не будет и кто тогда это гоняет.
|
||||
6. **Первые цели.** Возможности приложения, а не задачи: три-пять целей в
|
||||
`Запланировано`, каждая — ответ на «что приложение будет уметь», с
|
||||
обоснованием очереди прозой.
|
||||
6. **Первые шаги стройки.** Новый проект по определению начинается со стадии
|
||||
`build`: приложения ещё нет. Собери **список от базы к деталям** — что нужно
|
||||
сделать, чтобы приложение заработало, — и обоснуй **порядок**: он значит
|
||||
зависимость, а не важность. Пять-десять шагов достаточно: план дописывается
|
||||
по ходу стройки, и это законно.
|
||||
|
||||
### Как вести
|
||||
|
||||
@@ -135,9 +137,9 @@ description: "Завести новый проект — сессия вопро
|
||||
первом же уточнении.
|
||||
6. Заведи скелет остальных по [скелетам](../canon/references/skeletons.md) —
|
||||
каждый с честной строкой.
|
||||
7. Каталог задач и первые цели — **вызови скилл `av-dev:task-track`**: он владеет
|
||||
форматом целей и задач. Не разрешился — учёт задач остаётся владельцу, и это
|
||||
тоже строка доклада.
|
||||
7. Каталог задач и первые шаги — **вызови скилл `av-dev:task-track`**: он владеет
|
||||
форматом задач и стадией (`init --stage build`). Не разрешился — учёт задач
|
||||
остаётся владельцу, и это тоже строка доклада.
|
||||
8. `docs.py check` из скилла `canon` — до отсутствия дрейфа. Замечания о
|
||||
незаполненных плейсхолдерах остаются: их закрывает не `init`, а работа.
|
||||
9. **Вычитай написанное — агент `doc-wording`**, по пачке заполненных документов
|
||||
|
||||
@@ -27,7 +27,7 @@ description: "Груминг беклога — интерактивный ра
|
||||
## Три правила, из которых всё следует
|
||||
|
||||
1. **Порядок назначает человек, машина его не выводит.** Ни давность, ни тип, ни
|
||||
число задач под целью приоритетом не являются. Единственное место в очереди,
|
||||
размер секции приоритетом не являются. Единственное место в очереди,
|
||||
назначенное не человеком, — конец секции у сырья, и оно из очереди изъято
|
||||
(`task-track`, правило 4).
|
||||
2. **Порция важнее охвата.** Тридцать задач за заход — это усталость и
|
||||
@@ -37,6 +37,28 @@ description: "Груминг беклога — интерактивный ра
|
||||
`--reason` у закрытия и переноса, ответ в теле задачи, строка в докладе.
|
||||
Решение, оставшееся в переписке, будет принято заново через месяц.
|
||||
|
||||
## Груминг — операция доработки
|
||||
|
||||
**Стадия проекта решает, применим ли груминг вообще** (дом стадии —
|
||||
[`task-track`, «Две стадии»](../task-track/SKILL.md#две-стадии); посмотреть —
|
||||
`tasks.py stage`).
|
||||
|
||||
На **доработке** он и есть основная гигиена: беклог пополняется извне и
|
||||
вразнобой, порядок значит важность, и назначить её может только человек.
|
||||
|
||||
На **стройке** оба вопроса скилла отвечены заранее. «Что сейчас самое важное» —
|
||||
первая строка плана, и назначил её не приоритет, а зависимость: переставить её
|
||||
значит сломать стройку. «Что перестало быть важным» возникает не порциями, а
|
||||
разом — когда меняется замысел, — и тогда пересматривается **план целиком**, а
|
||||
не 5–8 задач из середины. Порционный разбор здесь вреден: он вынимает шаги из
|
||||
списка, порядок которого и есть его содержание.
|
||||
|
||||
Поэтому на стройке скилл говорит это строкой и **предлагает другую работу**:
|
||||
пересмотр плана целиком, гигиену полей (`task-track`) или переход в доработку,
|
||||
если беклог исчерпан. Три вещи он делает и там, потому что от стадии они не
|
||||
зависят: `tasks.py check --fix`, разбор накопившихся вопросов и закрытие того,
|
||||
что сделано попутно.
|
||||
|
||||
## Когда груминг созрел
|
||||
|
||||
**Зовёт человек.** Скилл сам себя не назначает, но обязан **напоминать**, и
|
||||
@@ -122,7 +144,7 @@ flowchart TD
|
||||
**3. Что перестало быть важным.** Порциями по 5–8. Сперва то, что решается
|
||||
фактом и не требует ничьего суждения (сделано попутно, отменено решением,
|
||||
дублируется, симптомы одного дефекта), затем то, что решает человек (жива ли,
|
||||
та ли цель, задача ли это ещё).
|
||||
задача ли это ещё).
|
||||
|
||||
**4. Что важно сейчас.** Расстановка порядка — `move --after <слаг>` и
|
||||
`move --first`. Разбирается **не весь беклог, а верх очереди**: первые три-пять
|
||||
@@ -146,15 +168,15 @@ flowchart TD
|
||||
кодом стоит меньше, чем та же работа через квартал;
|
||||
- **что дорожает от ожидания** — данные копятся, миграция усложняется, внешний
|
||||
срок приближается;
|
||||
- **цель, которую человек назвал следующей.**
|
||||
- **то, что человек назвал следующим.**
|
||||
|
||||
Довод **записывается причиной** (`move --after <слаг> --reason …`). Порядок без
|
||||
причины — это порядок, который на следующем груминге назначат заново с нуля.
|
||||
|
||||
**Цель и приоритет — независимые оси.** Очередь может идти поперёк целей, и это
|
||||
законно: задачи одной цели не обязаны стоять подряд. Но если под целью годами
|
||||
ничего не поднимается наверх — это разговор про цель, а не про очередь, и он
|
||||
идёт на шаге 3.
|
||||
**Тема и приоритет — независимые оси.** Очередь может идти поперёк полок, и это
|
||||
законно: задачи одной темы не обязаны стоять подряд. Но если из одной полки
|
||||
годами ничего не поднимается наверх — это разговор про саму работу, а не про
|
||||
очередь, и он идёт на шаге 3.
|
||||
|
||||
## Документы устаревают тем же ходом работы
|
||||
|
||||
@@ -231,11 +253,11 @@ flowchart TD
|
||||
- Что просмотрено: N из M, сколько порций, по какому признаку отобраны.
|
||||
- Вопросы: разобрано N, из них отвечено без человека N, снято тегов N.
|
||||
- **Что перестало быть важным**: удалено как реализованное (со ссылками), ушло
|
||||
без реализации (с причинами), понижено до сырья, слито, сменило тип или цель.
|
||||
без реализации (с причинами), понижено до сырья, слито, сменило тип.
|
||||
- **Что важно сейчас**: верх очереди по каждой секции — слаги в порядке, и по
|
||||
каждому движению довод одной строкой.
|
||||
- **Границы покрытия**: сколько задач не трогали и какие именно секции, теги или
|
||||
цели остались — иначе доклад читается как «беклог разобран».
|
||||
- **Границы покрытия**: сколько задач не трогали и какие именно секции или теги
|
||||
остались — иначе доклад читается как «беклог разобран».
|
||||
- `tasks.py check` после правок — результат строкой.
|
||||
|
||||
## Чего этот скилл не делает
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
проверки на нужность. Свежесть меряется git'ом, как и залежалость, — датой
|
||||
появления файла в истории;
|
||||
2. дальше **по залежалости** — `list --stale`;
|
||||
3. по потребности — одна секция целиком, один тег (партия ревью), одна цель
|
||||
(`--goal`), список от человека.
|
||||
3. по потребности — одна секция целиком, один тег (партия ревью), список от
|
||||
человека.
|
||||
- **Останавливайся на границе порции**, даже если «ещё чуть-чуть осталось».
|
||||
Между порциями — промежуточный доклад.
|
||||
|
||||
@@ -84,20 +84,14 @@
|
||||
|
||||
6. **Жива ли она вообще.** Контекст мог измениться: ушла зависимость, отпал
|
||||
сценарий, обошли иначе. Здесь и звучит вопрос, выкидывать ли.
|
||||
7. **Та ли цель — и нужна ли она вообще.** `feature`, которой не находится цель,
|
||||
— кандидат на выход: новая возможность вне цели это возможность, которой никто
|
||||
не заказывал. Операционной задаче (`fix`, `chore`, `research`) цель не нужна,
|
||||
и выдумывать её здесь не надо.
|
||||
|
||||
**Отменяется и сама цель** — когда замысел оказался неверен, а не когда
|
||||
задача выбрала не ту. Тогда порция расширяется до всех задач этой цели: каждую
|
||||
либо закрыть своей причиной, либо перевесить на другую цель, и только потом
|
||||
закрыть цель. Порядок и почему он такой —
|
||||
[task-goal.md](../../task-track/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель).
|
||||
7. **Тот ли тип.** Заводилась починкой, а после разбора оказалось, что
|
||||
поведение никогда и не было заявлено, — это `feature`. Тип, оставшийся от
|
||||
прошлой формулировки, врёт ровно там, где по нему отбирают, и требует не тех
|
||||
разделов.
|
||||
8. **Задача ли это по-прежнему.** Не проходит `ready` по существу, а не по
|
||||
недописанным разделам → `edit <slug> --type research` и опустошённый раздел
|
||||
«Вопрос», то есть сырьё; дальше штурм. Разрослась → это несколько задач под
|
||||
той же целью, дальше декомпозиция.
|
||||
«Вопрос», то есть сырьё; дальше штурм. Разрослась → это несколько задач,
|
||||
дальше декомпозиция.
|
||||
9. **Не подешевела ли она.** Сделанная с прошлого раза работа меняет цену
|
||||
**других** задач: рядом с только что тронутым кодом та же работа стоит меньше.
|
||||
Это довод и на шаге 4 — задача, внезапно подешевевшая, поднимается в очереди
|
||||
@@ -111,7 +105,7 @@
|
||||
нигде не хранится.
|
||||
|
||||
Задача из верхних строк `--stale`, которую и этот заход оставляет без изменений,
|
||||
**либо двигается (меняет цель, поднимается в очереди, уходит с причиной), либо
|
||||
**либо двигается (меняет полку, поднимается в очереди, уходит с причиной), либо
|
||||
остаётся с явно записанной причиной**, почему её держим (`move <slug> --reason
|
||||
…` — без `--section` секция берётся текущая). Молчаливое «оставить как есть» на
|
||||
давно неподвижной задаче — это решение не принимать решение; запись причины
|
||||
@@ -123,9 +117,8 @@
|
||||
Разбирается **верх очереди**, а не весь беклог: первые три-пять строк каждой
|
||||
секции. Ниже пятой строки порядок всё равно перестаёт что-либо значить.
|
||||
|
||||
1. **Покажи текущий верх** — `list --index backlog`, по секциям, в том порядке,
|
||||
в каком строки лежат. Плюс состояние проекта из роадмапа: секция `Готово`
|
||||
отвечает на «где мы», `Запланировано` — на «куда шли».
|
||||
1. **Покажи текущий верх** — `list`, по секциям, в том порядке, в каком строки
|
||||
лежат.
|
||||
2. **Спрашивай сравнением, а не оценкой.** «Что из этих двух делают раньше»
|
||||
имеет проверяемый ответ, «насколько важна эта задача» — нет. Веди попарно и
|
||||
сверху: что первое, что после него.
|
||||
@@ -133,7 +126,7 @@
|
||||
или `move <slug> --first --reason …`. Довод берётся из перечня в
|
||||
[SKILL.md](../SKILL.md#приоритет-как-его-расставляют): сломано сейчас,
|
||||
разблокирует остальное, дешевеет от сделанного, дорожает от ожидания,
|
||||
названная цель.
|
||||
названо человеком.
|
||||
4. **Проверь верх на готовность** — `tasks.py ready <слаг> …` по первым строкам.
|
||||
Задача, стоящая первой и не проходящая `ready`, — это очередь, которая врёт:
|
||||
взять её нельзя. Либо дописывается здесь же, либо уступает место.
|
||||
|
||||
+195
-244
@@ -1,13 +1,13 @@
|
||||
---
|
||||
name: task-track
|
||||
description: Ведение задач и целей как каталога markdown-файлов (одна запись = один файл в items/ + строка в одном из индексов). У каждой записи есть тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение записи из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, штурм сырья, гигиена полей и проверка согласованности индексов. Использовать, когда просят добавить задачу/идею/цель, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат или проверить беклог. Каталог отстал от версии раскладки — это скажет tasks.py check, а повышает проект скилл av-dev:canon по общему журналу версий. Расстановка приоритетов и разбор накопившегося — скилл av-dev:task-groom. Не реализует задачи — этим занимается скилл решения задачи.
|
||||
description: Ведение задач как каталога markdown-файлов (одна задача = один файл в items/ + строка в BACKLOG.md). У каждой задачи есть тип (feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. У проекта есть стадия (build — беклог это план стройки, порядок строк значит зависимость; support — очередь правок, порядок значит важность). Заведение записи из диалога, разбор находок аудита/ревью, декомпозиция на независимо полезные части, штурм сырья, гигиена полей, смена стадии и проверка согласованности индекса. Использовать, когда просят добавить задачу или идею, превратить находки ревью в задачи, разбить задачу, проработать идею, поправить формат, объявить стадию или проверить беклог. Каталог отстал от версии раскладки — это скажет tasks.py check, а повышает проект скилл av-dev:canon по общему журналу версий. Расстановка приоритетов и разбор накопившегося — скилл av-dev:task-groom. Не реализует задачи — этим занимается скилл решения задачи.
|
||||
---
|
||||
|
||||
# Задачи
|
||||
|
||||
Задачи — каталог markdown-файлов. Одна запись = один файл `items/<slug>.md` плюс
|
||||
строка **ровно в одном** индексе. Скилл владеет **форматом и содержимым**:
|
||||
заводит, редактирует, закрывает, разбирает находки ревью, дробит, штурмует сырьё.
|
||||
Задачи — каталог markdown-файлов. Одна задача = один файл `items/<slug>.md` плюс
|
||||
строка в `BACKLOG.md`. Скилл владеет **форматом и содержимым**: заводит,
|
||||
редактирует, закрывает, разбирает находки ревью, дробит, штурмует сырьё.
|
||||
|
||||
Чем он **не** владеет: **очередью** — что делать следующим и что перестало быть
|
||||
важным, решает скилл `task-groom`, а этот скилл лишь даёт ему операции; и выполнением
|
||||
@@ -17,57 +17,53 @@ description: Ведение задач и целей как каталога mar
|
||||
|
||||
Ситуация не покрыта инструкцией — решай по ним.
|
||||
|
||||
0. **Цель — возможность приложения, задача — шаг к ней.** Цель отвечает на «что
|
||||
приложение будет уметь», её «Завершение» — наблюдаемый признак того, что уже
|
||||
умеет; задача отвечает на «что для этого нужно сделать». Оценивается проект
|
||||
по **поведению**, а не по внутреннему устройству, поэтому и роадмап отвечает
|
||||
не «сколько работ осталось», а «что уже умеет и чего ещё не умеет».
|
||||
Свойство поведения — тоже возможность: «сообщает о своём состоянии»,
|
||||
«исход слияния не зависит от порядка доставки» — законные цели.
|
||||
1. **Беклог гниёт с той стороны, где его пополняют.** Заведение — самая частая
|
||||
операция и с худшим отказом: из одного разговора рождается пять файлов, а
|
||||
переоценка потом разгребает то, чего не надо было заводить. Дедупликация и
|
||||
фильтр на входе дешевле любой чистки. Заводим только то, что **не делаем
|
||||
сейчас** и о потере чего пожалеем.
|
||||
2. **Файл — источник истины, индексы производны.** Разошлись — неправы индексы.
|
||||
0. **Стадия решает, что значит порядок строк.** Проект живёт в одной из двух
|
||||
стадий, и обе ведут один и тот же беклог, но читают его по-разному.
|
||||
На **стройке** (`build`) беклог это план от базы к деталям: порядок —
|
||||
зависимость, «раньше нельзя». На **доработке** (`support`) беклог это очередь
|
||||
правок: порядок — важность, «раньше лучше». Из этого следует остальное —
|
||||
сколько у беклога секций, как его пополняют, что значит его опустошение и
|
||||
нужен ли груминг. Стадия объявлена ключом `[tasks] stage`; молчание ответом
|
||||
не считается, и `check` без неё отказывает.
|
||||
1. **Беклог гниёт с той стороны, где его пополняют — на доработке.** Заведение
|
||||
там самая частая операция и с худшим отказом: из одного разговора рождается
|
||||
пять файлов, а переоценка потом разгребает то, чего не надо было заводить.
|
||||
Дедупликация и фильтр на входе дешевле любой чистки: заводим только то, что
|
||||
**не делаем сейчас** и о потере чего пожалеем.
|
||||
|
||||
**На стройке правило не применяется**, и это не послабление. Список стройки
|
||||
пишется вперёд целиком — он и есть замысел, — а фильтр «не заводи то, чего не
|
||||
делаешь сейчас» запретил бы написать план дальше первого шага. Дедуп остаётся
|
||||
в обеих стадиях: две записи об одном плохи всегда.
|
||||
2. **Файл — источник истины, индекс производен.** Разошлись — неправ индекс.
|
||||
Согласованность механизируема и проверяется командой, а не вниманием: всё,
|
||||
что ловит `tasks.py check`, не должно попадать ни в чек-лист, ни в промпт.
|
||||
Поэтому **«зачем» живёт в мете файла**, а строка индекса его лишь
|
||||
повторяет: пока поле лежало только в индексе, восстановление пропавшей
|
||||
строки теряло его молча и навсегда. Единственное исключение намеренное: **в каком
|
||||
индексе лежит запись, знают индексы** — поля-состояния в файле нет. И
|
||||
**порядок строк в беклоге**: приоритет это свойство очереди, а не задачи, и в
|
||||
файле ему места нет (правило 4).
|
||||
строки теряло его молча и навсегда. Единственное исключение намеренное:
|
||||
**порядок строк в беклоге** — он свойство списка, а не задачи, и в файле ему
|
||||
места нет (правило 4).
|
||||
3. **Причина переживает запись.** Выкинутая без причины задача вернётся через
|
||||
квартал тем же текстом. Реализованная оставляет след в коммите — выкинутая не
|
||||
оставляет ничего, поэтому у неё есть `REJECTED.md`.
|
||||
4. **Приоритет — это порядок строк, а цель есть не у всякой задачи.** Очередь
|
||||
внутри секции беклога значима: **первая строка — то, что делают следующим**.
|
||||
Приоритет назначает человек на груминге, машина его не выводит и не угадывает.
|
||||
4. **Порядок строк — единственное, чего в файле нет.** Он значим в обеих
|
||||
стадиях, и назначает его человек: на стройке — раскладывая шаги по
|
||||
зависимости, на доработке — на груминге. Машина порядок не выводит и не
|
||||
угадывает; всё, что она делает сама, — ставит машинную позицию в **конец**
|
||||
секции и говорит об этом вслух.
|
||||
|
||||
Прежде здесь стояло «порядка нет, есть цель», и обосновано это было тем, что
|
||||
на «что делать дальше» отвечает **набор спринта**. Набора больше нет, а
|
||||
вопрос остался — и без порядка отвечать на него стало нечем.
|
||||
|
||||
**Дом приоритета — индекс, а не файл.** Это то же исключение из правила 2,
|
||||
что и «в каком индексе лежит запись»: приоритет — свойство очереди. Положи он
|
||||
в файл числом, и два соседних файла смогли бы утверждать одно и то же место,
|
||||
а строка индекса — противоречить обоим.
|
||||
|
||||
Цель обязательна там, где она и есть содержание работы, — у **новой
|
||||
возможности** (`feature`). Починка, техдолг и разведка служат
|
||||
работоспособности, а не направлению, и живут без цели законно. Придуманная им
|
||||
цель — то же враньё, от которого спасает тип. **Цель и приоритет —
|
||||
независимые оси:** очередь может идти поперёк целей, и это законно.
|
||||
**Дом порядка — индекс, а не файл.** Положи его в файл числом, и два соседних
|
||||
файла смогли бы утверждать одно и то же место, а строка индекса —
|
||||
противоречить обоим.
|
||||
|
||||
Одно место в очереди назначено **не человеком, а типом**: **сырьё**
|
||||
(`research` без раздела «Вопрос») стоит в конце своей категории. Его не берут,
|
||||
(`research` без раздела «Вопрос») стоит в конце своей секции. Его не берут,
|
||||
и между берущимся оно каждый раз требует открыть файл, чтобы это понять. Раз
|
||||
это выводится, проверяет и чинит это машина.
|
||||
5. **Тип решает, что с записью можно делать.** Тип — единственная ось и первое
|
||||
поле меты: от него зависит, какие разделы обязательны в теле, нужна ли цель,
|
||||
берётся ли запись в работу и в каком индексе живёт её строка. Словарь закрыт;
|
||||
ни один тип не подошёл — значит, в записи их два, и её надо разделить.
|
||||
5. **Тип решает, что с задачей можно делать.** Тип — вторая ось и первое
|
||||
поле меты: от него зависит, какие разделы обязательны в теле и берётся ли
|
||||
запись в работу. Словарь закрыт; ни один тип не подошёл — значит, в записи их
|
||||
два, и её надо разделить.
|
||||
|
||||
## Раскладка
|
||||
|
||||
@@ -79,55 +75,23 @@ description: Ведение задач и целей как каталога mar
|
||||
|
||||
```
|
||||
tasks/
|
||||
items/ задачи и цели файлами, <slug>.md, слаги английские
|
||||
ROADMAP.md состояние проекта: что уже умеет и чего ещё не умеет
|
||||
BACKLOG.md что можно взять — только задачи, целей здесь нет.
|
||||
Порядок строк в секции значим: это очередь
|
||||
items/ задачи файлами, <slug>.md, слаги английские
|
||||
BACKLOG.md что можно взять. Порядок строк в секции значим,
|
||||
и значит он разное на разных стадиях
|
||||
REJECTED.md ушедшее БЕЗ реализации, с причиной и датой
|
||||
```
|
||||
|
||||
Правило, снимающее путаницу: **`BACKLOG.md` — то, что берут; `ROADMAP.md` — то,
|
||||
подо что берут.** Цель в работу взять нельзя — берут её задачи, — поэтому в
|
||||
списке берущихся ей не место.
|
||||
**Индекс один.** `REJECTED.md` индексом не считается: он не говорит, где запись
|
||||
числится, — это кладбище ушедшего.
|
||||
|
||||
**Четыре секции роадмапа, и последняя отвечает на половину вопроса:**
|
||||
**Секции беклога называет проект**, и `check` проверяет у них ровно две вещи:
|
||||
что секция есть хоть одна и что на стройке она **одна**. Смысла секции не несут
|
||||
— это полки домена (`Ядро`, `Инфра`), — и подгонять их имена под свой вкус
|
||||
скрипт права не имеет. Поле меты, называющее полку, зовётся **Категория**.
|
||||
|
||||
| Секция | Англ. | Что в ней |
|
||||
| --- | --- | --- |
|
||||
| `Запланировано` | `Planned` | очередь значима и обосновывается прозой рядом |
|
||||
| `Направления` | `Directions` | очереди нет, тянутся долго |
|
||||
| `Сопровождение` | `Operations` | чем держат проект: инструмент, процесс, эксплуатация — не возможности приложения, и потому отдельно |
|
||||
| `Готово` | `Done` | достигнутые цели — строкой с датой, **без ссылки на файл**: файл удалён, поведение живёт в спеках |
|
||||
|
||||
**Порядок тоже канонический, и `Готово` стоит последним не из скромности.**
|
||||
Достигнутое **копится**: через год этой секции больше, чем всех остальных
|
||||
вместе. Стоя первой, она отодвигает за экран ровно то, ради чего роадмап
|
||||
открывают чаще всего, — что делается сейчас и что дальше. Порядок проверяет
|
||||
`check`, переставляет `check --fix`.
|
||||
|
||||
**Секции роадмапа канонические, категории беклога — нет**, и разница не в любви к
|
||||
единообразию. У каждой секции роадмапа свой смысл, в достигнутое пишет сам `close`, и
|
||||
роадмап, названный по-своему, читался бы только своим автором. Категории беклога
|
||||
(`Ядро`, `Инфра`) смысла не несут — это полки домена, и остаются делом проекта.
|
||||
Отсюда и разные имена поля меты: у цели **Секция** (часть роадмапа — состояние
|
||||
очереди), у задачи **Категория** (полка домена, на которой она лежит).
|
||||
|
||||
Отсюда четыре правила, которые проверяет `tasks.py check`: **состав закреплён**
|
||||
(чужая секция — ошибка, а не вольность), **все четыре обязаны быть** (нет
|
||||
секции — нет ответа на её часть вопроса), **язык один на весь индекс**, **порядок
|
||||
канонический**. `--roadmap-sections` у `init` нет: выбирать нечего.
|
||||
|
||||
**Заголовок секции отбит пустой строкой с обеих сторон и написан с прописной.**
|
||||
Во всех индексах одинаково, включая категории беклога, которые проект называет сам.
|
||||
Написание канонических секций правит `check --fix` (заодно и ссылку на секцию в
|
||||
мете файлов: имя секции принадлежит заголовку индекса, файл на неё только
|
||||
ссылается); отбивку и порядок он правит везде.
|
||||
|
||||
Оговорка про `Сопровождение`: слово `окружение` сюда не годится — в
|
||||
`architecture.md` оно уже значит боевое окружение приложения, и одно слово в двух
|
||||
смыслах развело бы документы канона. А `Разработка`, стоявшая тут раньше,
|
||||
называла слишком много: роадмап **весь** про разработку, и секция с таким именем
|
||||
не отличалась от остальных ничем.
|
||||
**Заголовок секции отбит пустой строкой с обеих сторон и написан с прописной**;
|
||||
отбивку правит `check --fix`. Написание секции в мете файлов он тоже правит: имя
|
||||
секции принадлежит заголовку индекса, файл на неё только ссылается.
|
||||
|
||||
**Секции «блокеры» в беклоге нет.** Блокер — это *состояние* (работа не может
|
||||
продолжаться ни одной задачей), а не полка: он живёт ровно до ответа человека, и
|
||||
@@ -138,53 +102,31 @@ tasks/
|
||||
который переезжает с такой секцией, её надо удалить** — это единственное место,
|
||||
где это сказано.
|
||||
|
||||
**Запись живёт в одном индексе за раз.** Индексов два, и выбирает между ними
|
||||
тип: цель в роадмапе, задача в беклоге. Сменился тип — строка переезжает
|
||||
(`edit --type`). Файл в `items/` при этом **не двигается**: он и есть запись,
|
||||
индексы лишь показывают, где она числится и в каком порядке стоит.
|
||||
|
||||
**Порядок строк в беклоге — приоритет**, и он единственное, чего в файле нет
|
||||
(правило 4). Отсюда следствие для всякой машинной правки индекса:
|
||||
восстановленная или перенесённая строка встаёт **в конец своей секции**, и
|
||||
скрипт об этом говорит. Молчаливая вставка выдала бы машинную позицию за
|
||||
решение человека — а решение это его.
|
||||
**Порядок строк — единственное, чего в файле нет** (правило 4). Отсюда следствие
|
||||
для всякой машинной правки индекса: восстановленная или перенесённая строка
|
||||
встаёт **в конец своей секции**, и скрипт об этом говорит. Молчаливая вставка
|
||||
выдала бы машинную позицию за решение человека — а решение это его.
|
||||
|
||||
**У сделанной задачи записи не остаётся** — файл и строка удаляются (`close
|
||||
--implemented`). Ей хватает коммита и документации проекта; вторая запись была
|
||||
бы вторым домом для того же факта. Вопрос «что было сделано и когда» отвечается
|
||||
даром: индексы лежат под git, а закрытие коммитится отдельным коммитом учёта —
|
||||
даром: индекс лежит под git, а закрытие коммитится отдельным коммитом учёта —
|
||||
`git log -p tasks/BACKLOG.md` отдаёт историю без отдельного журнала.
|
||||
|
||||
**У достигнутой цели запись остаётся, и это единственное исключение.** Файл
|
||||
удаляется так же, а строка переезжает в секцию `Готово` с датой. Причина в том,
|
||||
что цель — не работа, а **возможность**: «что приложение умеет» это половина
|
||||
вопроса, ради которого роадмап и открывают, и стирать её вместе с файлом значит
|
||||
оставить инструмент, отвечающий только «что осталось». Вторым домом это не
|
||||
становится: поведение живёт в `openspec/specs/`, а роадмап отвечает **когда и в
|
||||
каком порядке оно появилось** — другой вопрос. Ссылки на файл в строке нет
|
||||
намеренно: файл удалён, а битая ссылка — законная ошибка `check`.
|
||||
|
||||
Куда запись может переехать и какой командой — весь набор переходов:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
state "BACKLOG.md — что берут" as B
|
||||
state "ROADMAP.md — подо что берут" as P
|
||||
state "REJECTED.md — ушла без реализации" as R
|
||||
state "записи нет — реализована" as D
|
||||
state "ROADMAP.md, «умеет» — цель достигнута" as A
|
||||
|
||||
[*] --> B: add --type feature|fix|chore|research
|
||||
[*] --> P: add --type goal
|
||||
B --> P: edit --type goal --section
|
||||
P --> B: edit --type feature|fix|chore|research --section
|
||||
B --> B: move --after | --first | --section
|
||||
B --> D: close --implemented
|
||||
P --> A: close --implemented
|
||||
B --> R: close --reason
|
||||
P --> R: close --reason
|
||||
D --> B: reopen --reason
|
||||
R --> B: reopen --reason
|
||||
A --> P: reopen --reason
|
||||
```
|
||||
|
||||
Состояния здесь — **где числится строка**, а не где лежит файл: файл
|
||||
@@ -195,87 +137,90 @@ stateDiagram-v2
|
||||
Схема — **сводка**: условия и оговорки живут в тексте разделов, и при
|
||||
расхождении прав текст.
|
||||
|
||||
## Цели
|
||||
## Две стадии
|
||||
|
||||
**Цель — возможность приложения.** Такой же файл в `items/`, тип `goal` (🎯),
|
||||
перечисленный в `ROADMAP.md`. Формулируется ответом на вопрос **«что приложение
|
||||
будет уметь»**, а не названием области работ: не «Работа с чтением», а «Чтение
|
||||
данных клиентами»; не «Рефакторинг слияния», а «Исход слияния не зависит от
|
||||
порядка доставки».
|
||||
**Стадия проекта — ось, и решает она, что значит порядок строк беклога.**
|
||||
Значения два, дом — ключ `[tasks] stage` в `.av-dev.toml`.
|
||||
|
||||
**Свойство поведения — тоже возможность.** «Наблюдаемость» это «приложение
|
||||
сообщает о своём состоянии»; «прочность слияния» это «исход не зависит от
|
||||
порядка». Такие цели законны и переформулировки в функцию не требуют — требуют
|
||||
только, чтобы формулировка отвечала на «что приложение делает», а не на «какую
|
||||
часть кода мы трогаем».
|
||||
| | `build` — стройка | `support` — доработка |
|
||||
| --- | --- | --- |
|
||||
| Порядок строк | зависимость: раньше **нельзя** | важность: раньше **лучше** |
|
||||
| Секции | ровно одна: список от базы к деталям | полки домена, сколько нужно |
|
||||
| Заведение | список пишется вперёд целиком | по одной, по мере появления |
|
||||
| Пустой беклог | план исчерпан, стройка окончена | нормальное состояние |
|
||||
| Груминг | не применяется; замысел сменился — план пересматривается целиком | основная гигиена, порциями по 5–8 |
|
||||
| Залежалость | не считается: шаг ждёт своей очереди законно | считается, `list --stale` |
|
||||
|
||||
**Целью не становится работа, которой держат проект.** Состав перечислен
|
||||
[в словаре сопровождения](../../shared/operations.md);
|
||||
на вопрос «что приложение будет уметь» ничто из него не отвечает. Им отведена отдельная секция роадмапа,
|
||||
чтобы они были видны в том же экране и при этом не читались как возможности
|
||||
продукта.
|
||||
**Стадия называется явно, и молчание ответом не считается.** Без неё порядок
|
||||
строк нечем прочитать: переставить строку значит на стройке сломать план, а на
|
||||
доработке — принять решение о важности, и это разные действия. `init --stage`
|
||||
обязателен, `check` без ключа отказывает, `check --fix` его не подставляет:
|
||||
какая стадия у проекта, знает человек, а подставленное умолчание соврало бы ровно
|
||||
там, где по нему принимают решение.
|
||||
|
||||
**Граница проходит по тому, кто наблюдает, а не по теме.** «Приложение сообщает
|
||||
о своём состоянии» — возможность: наблюдает пользователь сервиса, и цели место
|
||||
среди прочих. «Дежурный видит состояние на одном экране» — сопровождение:
|
||||
наблюдаем мы. Одна и та же наблюдаемость попадает в разные секции, и это верно —
|
||||
секции отвечают на разные вопросы.
|
||||
**Секций на стройке одна, и это не педантизм.** Порядок там — зависимость, и
|
||||
разложенный по полкам список перестаёт быть планом: два шага из разных секций
|
||||
уже не сравнить. На доработке полки законны — правки независимы, и очередь
|
||||
внутри полки самостоятельна.
|
||||
|
||||
**Сопровождение и эксплуатация — целое и часть**, а не синонимы, и та же тема
|
||||
живёт ещё в двух местах: разделе «Эксплуатация» в `architecture.md` и теме ревью
|
||||
`operations`. Словарь у всех трёх общий, и дом у него один:
|
||||
[shared/operations.md](../../shared/operations.md) — читается по ссылке.
|
||||
Пересказывать его своими словами нельзя: три перечня «чем держат проект» уже
|
||||
разъезжались на «метриках и логах» против «мониторинга».
|
||||
**Переход — событие, а не настройка.** `tasks.py stage support` переносит остаток
|
||||
беклога в первую новую секцию, правит «Категорию» в файлах и говорит, что порядок
|
||||
с этого момента значит другое. Датой ему служит коммит: отдельного журнала ради
|
||||
одной строки не заводится. Признак созревания наблюдаемый — беклог стройки
|
||||
исчерпан, и `check` об этом напоминает; **запретить переход раньше скрипт не
|
||||
берётся**: «приложение построено» решает человек, а не счётчик строк.
|
||||
|
||||
Секция выбирается так: очередь значима и обоснована прозой — `Запланировано`;
|
||||
тянется долго и очереди не имеет — `Направления`; не про приложение, а про то,
|
||||
чем его держат, — `Сопровождение`; в `Готово` кладёт сам `close`.
|
||||
Обратный переход (`stage build`) разрешён и устроен так же. Он редок — проект
|
||||
уходит на стройку заново разве что при переделке замысла целиком, — но
|
||||
запрещать его было бы запретом на то, что иногда и правда случается.
|
||||
|
||||
- **Список задач цели выводится, а не хранится.** В теле цели — зачем она и что
|
||||
считается её завершением; перечня задач там нет. Он был бы третьим индексом и
|
||||
поехал бы на первой же закрытой задаче, а `check` про него не знает. Связь
|
||||
однонаправленна: задача несёт тег `goal:<слаг>`, перечень даёт
|
||||
`tasks.py list --goal <слаг>`.
|
||||
- **Статус цели выводится.** Цель достигнута, когда у неё не осталось открытых
|
||||
задач; `[x]`/`[~]` руками не ведутся, а `close` цели с живыми задачами
|
||||
скрипт запретит. Достижение — `close <цель> --implemented`: файл удаляется,
|
||||
строка с датой переезжает в `Готово`. Ошиблись — `reopen` вернёт файл и
|
||||
**снимет строку достигнутого**, чтобы роадмап не утверждал того, чего нет. Единственная оговорка: цель без задач неотличима — «ещё не
|
||||
разобрана» или «всё закрыто». Различает **тег `decomposed`** в мете
|
||||
цели: он ставится, когда цель разложена на задачи. Тег, а не строка в теле —
|
||||
потому что проверяется механически: `check` **напоминает** о нём у пустой цели
|
||||
(замечанием, не ошибкой — неразобранная цель это законное состояние), а `check
|
||||
--fix` сам проставляет его цели, у которой задачи есть.
|
||||
- **Тип `[epic]` упразднён.** Он был зонтиком между целью и задачами — «задача,
|
||||
которая не мерджится целиком». Зонтик теперь цель, а слишком крупный шаг просто
|
||||
дробится на шаги помельче под той же целью, и промежуточному типу места не
|
||||
осталось. Замер подтвердил: ноль употреблений на 97 записей двух живых
|
||||
проектов. Встретился в чужом беклоге — это цель либо набор задач, и `check`
|
||||
назовёт его неизвестным типом.
|
||||
## Чего у задач больше нет
|
||||
|
||||
**Тип `goal` и `ROADMAP.md` упразднены.** Цель была зонтиком над параллельными
|
||||
направлениями: она нужна там, где список работ нельзя выстроить в один порядок,
|
||||
и очередь идёт поперёк направлений. У проекта, который ведёт один человек, такого
|
||||
не бывает — на стройке список линеен по зависимости, на доработке правки
|
||||
независимы, — и зонтик не стоял ни над чем.
|
||||
|
||||
Роадмап при этом отвечал на свой вопрос наполовину: «чего ещё не умеет» — это
|
||||
«что осталось в беклоге», то есть пересказ второго индекса. Вторая половина, «что
|
||||
уже умеет», живёт в двух домах и без него: нормативное поведение — в
|
||||
`openspec/specs/`, а когда и в каком порядке оно появилось — в `git log` индекса
|
||||
и коммитах задач.
|
||||
|
||||
Вместе с целью ушли: секция `Готово` (её ответ дают спеки и история), теги
|
||||
`goal:<слаг>` и `decomposed`, поле меты `Секция` (осталась `Категория`), раздел
|
||||
`Завершение` и команды `list --goal`, `edit --goal`. Встретились в проекте —
|
||||
`check` назовёт их поимённо, `check --fix` снимет теги, а запись типа `goal`
|
||||
оставит человеку: во что она превращается — в задачу или в ничто, — машина не
|
||||
решает.
|
||||
|
||||
**Тип `[epic]` упразднён раньше и не вернулся.** Слишком крупный шаг дробится на
|
||||
шаги помельче, стоящие в списке подряд.
|
||||
|
||||
## Тип записи
|
||||
|
||||
**Тип — единственная ось этого скилла, и он решает, что с записью можно делать.**
|
||||
**Тип решает, что с задачей можно делать.** Вторая ось скилла — первая стадия.
|
||||
Перечень осей всего процесса и того, чего каждая **не** решает, —
|
||||
[shared/axes.md](../../shared/axes.md). Дом типа —
|
||||
**поле меты `Тип` первой строкой**; эмодзи в заголовке H1 от него производна, её
|
||||
ставит `add` и чинит `check --fix`.
|
||||
|
||||
| Тип | Обязательные разделы | Цель | В работу | Устав |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 🎯 `goal` | `Завершение` | — | нет | [task-goal.md](references/task-goal.md) |
|
||||
| ✨ `feature` | `Затрагивает`, `Критерии приёмки` | **обязательна** | да | [task-feature.md](references/task-feature.md) |
|
||||
| 🐞 `fix` | `Воспроизведение`, `Затрагивает`, `Критерии приёмки` | необязательна | да | [task-fix.md](references/task-fix.md) |
|
||||
| 🧹 `chore` | `Затрагивает`, `Критерии приёмки` | нет | да | [task-chore.md](references/task-chore.md) |
|
||||
| 🔬 `research` | `Вопрос`, `Куда ляжет ответ` | нет | да | [task-research.md](references/task-research.md) |
|
||||
| Тип | Обязательные разделы | Устав |
|
||||
| --- | --- | --- |
|
||||
| ✨ `feature` | `Затрагивает`, `Критерии приёмки` | [task-feature.md](references/task-feature.md) |
|
||||
| 🐞 `fix` | `Воспроизведение`, `Затрагивает`, `Критерии приёмки` | [task-fix.md](references/task-fix.md) |
|
||||
| 🧹 `chore` | `Затрагивает`, `Критерии приёмки` | [task-chore.md](references/task-chore.md) |
|
||||
| 🔬 `research` | `Вопрос`, `Куда ляжет ответ` | [task-research.md](references/task-research.md) |
|
||||
|
||||
Берутся в работу все четыре: записи, которую нельзя взять, больше не существует.
|
||||
|
||||
Сверх обязательных у любой задачи допустимы `Рамки` и `Вопросы`. Раздел не из
|
||||
схемы своего типа — **замечание, а не ошибка**: свой раздел законная вольность
|
||||
проекта, но `Воспроизведение` у `chore` почти всегда значит, что тип проставлен
|
||||
не тот, и сказать об этом стоит, не запрещая.
|
||||
|
||||
**Осей было две, и ортогональность у них была фальшивой.** Тип записи
|
||||
**Прежних осей было две, и ортогональность у них была фальшивой.** Тип записи
|
||||
(`goal`/`idea`/`task`) и род работы (`kind:<род>` тегом) давали двенадцать клеток
|
||||
произведения, из которых законны были шесть: у цели род запрещён, у задачи
|
||||
обязателен, у идеи пуст. Плюс алгоритм работы крепится не к `task`, а к `fix` и
|
||||
@@ -301,7 +246,8 @@ stateDiagram-v2
|
||||
изменения, а не по типу задачи: `chore` бывает миграцией схемы, `fix` — правкой
|
||||
публичного контракта. Правило «предписание процесса в теле задачи снимается»
|
||||
типом не отменяется, а подтверждается: он описывает работу, а не то, как её
|
||||
проверять.
|
||||
проверять. **Стадия проекта их тоже не выбирает**: изменение на стройке ничем не
|
||||
проще того же изменения на доработке, и метку ему по-прежнему назначает разметка.
|
||||
|
||||
**Одно исполнителю тип всё же говорит — каким сценарием работу вести, и то не
|
||||
один.** Скилл `av-dev:code-resolve` выбирает сценарий связкой из двух
|
||||
@@ -316,11 +262,10 @@ stateDiagram-v2
|
||||
Три требования к тексту. Первое — про заголовок, два остальных про то, чтобы
|
||||
задачу можно было **оценить, не открывая код**.
|
||||
|
||||
**Заголовок отвечает на вопрос своего типа.** Вопросов три, поэтому и форм три:
|
||||
**Заголовок отвечает на вопрос своего типа.** Вопросов два, поэтому и форм две:
|
||||
|
||||
| Тип | Отвечает на | Пример |
|
||||
| --- | --- | --- |
|
||||
| 🎯 `goal` | что приложение будет уметь | Соперником может быть компьютер |
|
||||
| ✨ `feature`, 🐞 `fix`, 🧹 `chore` | что нужно сделать | Печатать поле одним куском кода |
|
||||
| 🔬 `research` | о чём разведка | Подсказка следующего хода |
|
||||
|
||||
@@ -333,10 +278,6 @@ stateDiagram-v2
|
||||
исход знание, а что делать — ещё неизвестно, и заголовок-действие обещал бы
|
||||
решённость, которой нет.
|
||||
|
||||
Из этого же правила растёт разница индексов: роадмап — список возможностей,
|
||||
беклог — список работ, и если заголовки перепутать формами, каждый из них
|
||||
начинает читаться как другой.
|
||||
|
||||
`check` считает заголовки не в форме действия и печатает **число** в блоке
|
||||
здоровья, не замечанием на файл: проверка эвристическая (первое слово на
|
||||
`-ть`/`-ти`/`-чь`), а беклог, заведённый до правила, не переоформляют «заодно».
|
||||
@@ -386,18 +327,20 @@ stateDiagram-v2
|
||||
подкаталога — обычное дело.
|
||||
|
||||
```
|
||||
python3 $tk check --dir D # согласованность индексов + здоровье
|
||||
python3 $tk check --dir D # согласованность индекса + здоровье
|
||||
python3 $tk check --dir D --fix # + починить дрейф (тип, эмодзи, место, заголовок, дубли, «зачем», форма меты)
|
||||
python3 $tk list --dir D [--stale] [--section S] [--type T] [--tag a,b] [--goal S] [--raw] [--index …] [--questions]
|
||||
python3 $tk add --dir D --slug S --title T --type goal|feature|fix|chore|research [--section S] [--goal G] [--why «зачем»] [--tag a,b]
|
||||
python3 $tk edit S --dir D [--title T] [--why «зачем»] [--type T] [--goal G] [--add-tag a,b] [--rm-tag c]
|
||||
python3 $tk list --dir D [--stale] [--section S] [--type T] [--tag a,b] [--raw] [--questions]
|
||||
python3 $tk add --dir D --slug S --title T --type feature|fix|chore|research [--section S] [--why «зачем»] [--tag a,b]
|
||||
python3 $tk edit S --dir D [--title T] [--why «зачем»] [--type T] [--add-tag a,b] [--rm-tag c]
|
||||
python3 $tk move S --dir D [--section S] [--reason R] [--after S | --first] # без --section — текущая секция
|
||||
python3 $tk close S --dir D --reason R # в REJECTED.md + удалить (ушла без реализации)
|
||||
python3 $tk close S --dir D --implemented # просто удалить (реализована и закоммичена)
|
||||
python3 $tk reopen S --dir D --reason R # вернуть закрытую: приёмка не сошлась
|
||||
python3 $tk ready S… --dir D # схема типа выполнена — можно брать в работу
|
||||
python3 $tk init --dir D [--sections …] [--items …] [--backlog …] …
|
||||
python3 $tk adopt scan --from … | apply --plan … # разовая адаптация, references/adopt.md
|
||||
python3 $tk stage --dir D # показать стадию
|
||||
python3 $tk stage support --dir D [--sections …] # сменить стадию: секции и смысл порядка
|
||||
python3 $tk init --dir D --stage build|support [--sections …] [--items …] …
|
||||
python3 $tk adopt scan --from … --stage S | apply --plan … # разовая адаптация, references/adopt.md
|
||||
```
|
||||
|
||||
**Копия.** Дом словаря — `shared/axes.md` в репозитории плагина: словарь общий
|
||||
@@ -422,35 +365,32 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
|
||||
<!-- /копия: коды-выхода -->
|
||||
|
||||
Здесь это значит: код 1 приходит **только от `check`** — найден дрейф индексов и
|
||||
Здесь это значит: код 1 приходит **только от `check`** — найден дрейф индекса и
|
||||
файлов, чинится `check --fix`, остаток разбирается руками. Код 3 — каталог не
|
||||
найден, конфиг битый или мимо диска: чинится путём или `.av-dev.toml` в корне.
|
||||
|
||||
Тип — английское ключевое слово `goal` / `feature` / `fix` / `chore` /
|
||||
`research` (как и прочие токены команд), у `add` **обязательное**: без него
|
||||
неизвестно, какой шаблон тела класть. Текст задачи при этом русский, а эмодзи в
|
||||
заголовке ставит скрипт.
|
||||
Тип — английское ключевое слово `feature` / `fix` / `chore` / `research` (как и
|
||||
прочие токены команд), у `add` **обязательное**: без него неизвестно, какой
|
||||
шаблон тела класть. Стадия — такое же слово, `build` / `support`, и у `init` она
|
||||
обязательна по той же причине: без неё неизвестно, что писать в шапке беклога и
|
||||
сколько заводить секций. Текст задачи при этом русский, а эмодзи в заголовке
|
||||
ставит скрипт.
|
||||
|
||||
**Мутации правят файл и индексы заодно** — руками строку индекса или мету
|
||||
не пиши, зови `add`/`edit`/`move`/`close`/`reopen`. Смена заголовка, «зачем», типа,
|
||||
цели и **тегов** — это `edit`: он держит H1 (вместе с эмодзи), мету и индекс
|
||||
**Мутации правят файл и индекс заодно** — руками строку индекса или мету
|
||||
не пиши, зови `add`/`edit`/`move`/`close`/`reopen`. Смена заголовка, «зачем», типа
|
||||
и **тегов** — это `edit`: он держит H1 (вместе с эмодзи), мету и индекс
|
||||
согласованными. Снятие тега — `--rm-tag` (после ответа на вопрос снимается
|
||||
`question`), смена цели — `--goal`, типа — `--type`; оба заменяют прежнее
|
||||
значение, а не добавляют второе.
|
||||
`question`), смена типа — `--type`; оба заменяют прежнее значение, а не
|
||||
добавляют второе.
|
||||
|
||||
**Переезд между индексами — следствие смены типа, а не отдельная команда.**
|
||||
`edit <slug> --type goal --section <часть роадмапа>` переносит строку из
|
||||
`BACKLOG.md` в `ROADMAP.md` (и обратно — задачным типом плюс
|
||||
`--section <категория беклога>`);
|
||||
`move` двигает только внутри одного индекса и пишет причину. `--section` у
|
||||
`edit` работает **только** при таком переезде — иначе он отсылает к `move`,
|
||||
потому что смена секции без причины и есть тот дрейф, который потом никто не
|
||||
объяснит.
|
||||
**Секцию меняет только `move`, и он пишет причину**: смена полки без причины и
|
||||
есть тот дрейф, который потом никто не объяснит.
|
||||
|
||||
**`move --after <слаг>` и `move --first` — это и есть расстановка приоритета.**
|
||||
**`move --after <слаг>` и `move --first` — это и есть расстановка порядка.**
|
||||
Порядок строк в секции значим (правило 4), и двигают его только этой командой:
|
||||
руками поправленная строка не оставляет причины, а причина здесь и есть половина
|
||||
решения.
|
||||
решения. Что именно этот порядок значит, говорит стадия: на стройке `--after`
|
||||
называет зависимость, на доработке — приоритет.
|
||||
|
||||
Тело задачи скрипт не трогает:
|
||||
`add` кладёт заголовок, мета-блок и шаблон с подсказками, тело дописываешь
|
||||
@@ -461,18 +401,23 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
правки**, даже если правил мутациями: дрейф мог накопиться раньше. Накопившееся
|
||||
чини `check --fix` — он детерминированно правит то, где истина однозначна (тип в
|
||||
своё поле, эмодзи заголовка, имя поля места, секция, заголовок, дубли, «зачем» из
|
||||
индекса в файл, старая форма меты, пометка `decomposed` у цели с задачами, сырьё
|
||||
в конец категории), а неоднозначное (задача сразу в двух индексах, нечего
|
||||
восстанавливать, **тип, которого неоткуда взять**) печатает отдельной пометкой
|
||||
индекса в файл, старая форма меты, снятые теги упразднённых целей, сырьё
|
||||
в конец секции), а неоднозначное (нечего восстанавливать, **тип, которого
|
||||
неоткуда взять**, запись типа `goal`) печатает отдельной пометкой
|
||||
`НЕОДНОЗНАЧНО` — это тебе, и это идёт строкой доклада. **Ссылка на исчезнувший
|
||||
файл в пометку не попадает:** `--fix` её просто не трогает, и она остаётся
|
||||
`ОШИБКА` обычного `check` — то есть видна, но в докладе её надо назвать отдельно.
|
||||
|
||||
`--fix` правит **и файлы** — там, где источник ровно один и выбирать не из чего:
|
||||
тип переезжает из прежнего дома (тег `kind:`, префикс `[goal]`/`[idea]`) в поле
|
||||
меты, заголовок получает эмодзи, поле места — имя по типу, «зачем», оставшееся
|
||||
только в индексе, переезжает в мету, цель с задачами получает `decomposed`.
|
||||
Каждый случай печатается поимённо.
|
||||
меты, заголовок получает эмодзи, поле места зовётся «Категория», «зачем»,
|
||||
оставшееся только в индексе, переезжает в мету, теги `goal:` и `decomposed`
|
||||
снимаются. Каждый случай печатается поимённо.
|
||||
|
||||
**Ни стадию, ни состав секций `--fix` не трогает.** Стадию он подставить не
|
||||
может — это решение человека; секции стройки не сливает — в каком порядке пойдут
|
||||
строки слитых полок, знает тоже только человек, а порядок здесь и есть
|
||||
содержание.
|
||||
|
||||
**Тип, который не выводится ниоткуда, `--fix` не угадывает.** `feature` от
|
||||
`chore` машина не отличает, и подставленное наугад значение врало бы ровно там,
|
||||
@@ -483,7 +428,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
работу — там, где по ней принимают решение; `check` поимённо о ней не говорит, а
|
||||
считает: строка здоровья **«схема типа не выполнена: N из M»** называет число и
|
||||
первые слаги, строка **«готово к взятию»** — сколько задач беклога пройдут
|
||||
`ready` целиком (схема плюс цель плюс отсутствие открытого вопроса). Это две
|
||||
`ready` целиком (схема плюс отсутствие открытого вопроса). Это две
|
||||
разные строки, и совпадение их чисел — совпадение. У каждой части своя глубина:
|
||||
|
||||
- **тип** — жёстко: назван и из закрытого словаря;
|
||||
@@ -491,7 +436,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
(меньше двух отказ, больше пяти замечание), наличие оракула **эвристикой** по
|
||||
слову «оракул» в пункте;
|
||||
- **прочие разделы схемы** (`Затрагивает`, `Воспроизведение`, `Вопрос`,
|
||||
`Куда ляжет ответ`, `Завершение`) — только **наличие непустого**. Содержимое
|
||||
`Куда ляжет ответ`) — только **наличие непустого**. Содержимое
|
||||
машине не видно: границу, которую забыли назвать, она от отсутствующей не
|
||||
отличает, а шаги, по которым ничего не воспроизводится, — от годных.
|
||||
|
||||
@@ -500,10 +445,10 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
разделов своего типа и число критериев, годность оракулов и полнота границ —
|
||||
глазами».
|
||||
|
||||
Формат записи, меты, слага, индексов и `REJECTED.md` —
|
||||
Формат записи, меты, слага, индекса и `REJECTED.md` —
|
||||
[references/task-format.md](references/task-format.md); там же тест «готова к
|
||||
взятию». Схема и алгоритм каждого типа — по файлу на тип:
|
||||
[goal](references/task-goal.md) · [feature](references/task-feature.md) ·
|
||||
[feature](references/task-feature.md) ·
|
||||
[fix](references/task-fix.md) · [chore](references/task-chore.md) ·
|
||||
[research](references/task-research.md).
|
||||
|
||||
@@ -530,9 +475,13 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
|
||||
### Завести запись из диалога
|
||||
|
||||
1. **Фильтр.** Делаем прямо сейчас — не заводим. Не пожалеем о потере — не
|
||||
заводим. Родилось три кандидата — покажи их и спроси, какие заводить: молча
|
||||
заведённая пачка и есть тот самый отказ из правила 1.
|
||||
0. **Посмотри стадию** — `stage`. От неё зависят шаг 1 и место новой строки: на
|
||||
доработке беклог пополняют по одной и с фильтром, на стройке пишут планом.
|
||||
1. **Фильтр — на доработке.** Делаем прямо сейчас — не заводим. Не пожалеем о
|
||||
потере — не заводим. Родилось три кандидата — покажи их и спроси, какие
|
||||
заводить: молча заведённая пачка и есть тот самый отказ из правила 1.
|
||||
**На стройке фильтра нет**: план пишется вперёд целиком, и «этого мы сейчас
|
||||
не делаем» — не довод против шага, а описание всякого шага, кроме первого.
|
||||
2. **Дедуп.** `list` плюс поиск по слагам, полю «зачем» и телам (`grep -ril`),
|
||||
**включая `REJECTED.md`**. Нашлось среди живых — **дописываем в существующий
|
||||
файл**, а не заводим соседний. Нашлось в `REJECTED.md` — покажи пользователю
|
||||
@@ -541,7 +490,6 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
переоценки.
|
||||
3. **Тип** — `--type` обязателен, и он же первое содержательное решение:
|
||||
|
||||
- возможность приложения, а не шаг к ней → `goal`;
|
||||
- снаружи появляется то, чего не было → `feature`;
|
||||
- поведение расходится с заявленным и **воспроизводится** → `fix`
|
||||
(не воспроизводится → `research`);
|
||||
@@ -550,12 +498,12 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
|
||||
Не подходит ни один — в записи их два, разбирай. Не проходит тест готовности
|
||||
(см. task-format) — это **сырьё**: `--type research`, раздел «Вопрос» пока
|
||||
пуст, место в конце категории. Не делается одним заходом — это не эпик, а
|
||||
несколько задач под одной целью: дроби сразу.
|
||||
4. **Цель — если тип её требует.** У `feature` должен быть `--goal <слаг>`:
|
||||
новая возможность и есть содержание цели. Подходящей нет — либо она
|
||||
заводится (`--type goal`), либо перед тобой не `feature`. У `fix`, `chore` и
|
||||
`research` цели может не быть вовсе, и придумывать её не надо.
|
||||
пуст, место в конце секции. Не делается одним заходом — дроби на шаги
|
||||
помельче и ставь их в списке подряд.
|
||||
4. **Место в списке.** `add` кладёт строку в конец секции всегда. На стройке это
|
||||
почти наверняка не то место: порядок там зависимость, и новый шаг чаще всего
|
||||
встаёт в середину — `move <слаг> --after <слаг>`. На доработке конец списка
|
||||
законен: место в очереди назначает груминг, а не заведение.
|
||||
5. `add …`, затем допиши тело редактором **по схеме своего типа** — шаблон её
|
||||
уже разложил, устав типа объясняет каждый раздел. «Зачем» отвечает «зачем
|
||||
нужна эта задача» — состояние, остаток, боль, — а не пересказывает первый
|
||||
@@ -569,13 +517,13 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
пять файлов из одной мысли, а сорок файлов из сорока сырых находок. Защита та
|
||||
же, что в самом ревью: кластеризация по причине, дедуп против живых и
|
||||
`REJECTED.md`, находка без свидетельства → сырьё (`research`), а не задача, и карта кластеров
|
||||
пользователю до создания файлов. Порядок, отображение серьёзности и привязка к
|
||||
целям — [references/from-review.md](references/from-review.md).
|
||||
пользователю до создания файлов. Порядок и отображение серьёзности —
|
||||
[references/from-review.md](references/from-review.md).
|
||||
|
||||
### Прийти в репозиторий, где задачи уже как-то ведутся
|
||||
|
||||
Разовая операция: вывести каталог задач из старой раскладки беклога, `TODO.md`,
|
||||
заметок или списка шагов роадмапа — [references/adopt.md](references/adopt.md).
|
||||
заметок или списка шагов плана — [references/adopt.md](references/adopt.md).
|
||||
Сюда же относится переименование транслитных слагов в английские: оно делается
|
||||
**одним проходом вместе с починкой перекрёстных ссылок**, а не по одному слагу.
|
||||
|
||||
@@ -601,13 +549,12 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
|
||||
| Проход | Что смотрит | Над чем работает |
|
||||
| --- | --- | --- |
|
||||
| `task-form` | заголовок по типу, «зачем» вместо пересказа, границы вместо замысла, годность оракулов, предписание процесса, связь со строкой «Завершения» цели | только `items/`, **открывает файл цели** |
|
||||
| `task-wording` | залог и отглагольные, оценка без факта, стоп-слова, англицизмы, жаргон, неизвестный термин, транслит в слаге | `items/` и строки индексов; документы проекта — только как словарь |
|
||||
| `task-form` | заголовок по типу, «зачем» вместо пересказа, границы вместо замысла, годность оракулов, предписание процесса | только `items/` |
|
||||
| `task-wording` | залог и отглагольные, оценка без факта, стоп-слова, англицизмы, жаргон, неизвестный термин, транслит в слаге | `items/` и строки индекса; документы проекта — только как словарь |
|
||||
|
||||
Разделены они не по охвату, а **по глубине**. Язык проверяется по словам и
|
||||
фразам, поштучно; форма записи требует понять, что задача делает, и открыть
|
||||
цель, на которую она ссылается. Слитый проход одну половину делает дорогой, а
|
||||
вторую — поверхностной.
|
||||
фразам, поштучно; форма записи требует понять, что задача делает. Слитый проход
|
||||
одну половину делает дорогой, а вторую — поверхностной.
|
||||
|
||||
Модель у обоих одна, `sonnet`, и это не отменяет разреза. Оба судят по
|
||||
**записанному правилу** — семь пунктов формы против правил языка, — а их находка
|
||||
@@ -690,18 +637,20 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
полагаться на него скилл не должен: молча найденный чужой каталог это дрейф.
|
||||
- **Версия и настройки живут в `.av-dev.toml` в корне репозитория** — версия
|
||||
ключом `version`, настройки каталога секцией `[tasks]`: `dir` — где каталог
|
||||
лежит, плюс **имена** файлов и заголовков, и последние только если отличаются
|
||||
от умолчания. Неизвестный ключ в секции — код 3 на любой команде, так что
|
||||
лишнее слово останавливает работу с задачами целиком.
|
||||
лежит, `stage` — стадия проекта, плюс **имена** файлов и заголовков, и
|
||||
последние только если отличаются от умолчания. Неизвестный ключ в секции — код
|
||||
3 на любой команде, так что лишнее слово останавливает работу с задачами
|
||||
целиком.
|
||||
|
||||
Дом в корне, а не внутри каталога задач, по двум причинам: настройка, лежащая
|
||||
внутри настраиваемого каталога, не смогла бы сказать, **где он**; и версия
|
||||
одна на весь плагин, а корень есть и у проекта без `docs/`. Прежние
|
||||
`<каталог задач>/.tasks.json` и `docs/.docs.json` не читаются — увидев их,
|
||||
скрипт говорит «прежняя раскладка» и зовёт `upgrade`.
|
||||
- **Секции беклога** берутся из заголовков `##` индекса как есть; их количество
|
||||
и названия — дело проекта (умолчание `Ядро` / `Инфра`). **В конфиге их нет** —
|
||||
второй список разошёлся бы с заголовками молча.
|
||||
- **Секции беклога** берутся из заголовков `##` индекса как есть; их названия —
|
||||
дело проекта (умолчание `План` на стройке, `Ядро` / `Инфра` на доработке), а
|
||||
количество ограничено стадией: на стройке секция одна. **В конфиге секций
|
||||
нет** — второй список разошёлся бы с заголовками молча.
|
||||
|
||||
### Вызов из другого плагина
|
||||
|
||||
@@ -738,8 +687,10 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
|
||||
|
||||
- **Развилки — пользователю.** Через `AskUserQuestion`, с уже сформулированным
|
||||
предварительным суждением (**рекомендация — первым вариантом**). Что выкинуть,
|
||||
под какую цель отнести, какая рамка разведки верна — решение пользователя. Слаг,
|
||||
формулировка, порядок строк в индексе — механика, делаем сами.
|
||||
какая рамка разведки верна, пора ли менять стадию — решение пользователя. Слаг
|
||||
и формулировка — механика, делаем сами. **Порядок строк механикой не
|
||||
считается** ни на одной стадии: на стройке он зависимость, на доработке
|
||||
приоритет, и оба называет человек.
|
||||
- **Не больше трёх вопросов за раз.** Пачка длиннее трёх тяжела для ответа;
|
||||
решений больше — веди **несколько итераций** диалога по ≤3, а не один
|
||||
перегруженный запрос. Между итерациями применяй уже решённое.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Адаптация каталога задач
|
||||
|
||||
Проект, где задачи уже как-то ведутся, и из имеющегося материала **выводится**
|
||||
заполненный каталог задач: цели, задачи, кладбище, индексы. Операция разовая —
|
||||
заполненный каталог задач: задачи, кладбище, индекс. Операция разовая —
|
||||
после неё проект живёт скиллами `task-track` и `task-groom`.
|
||||
|
||||
**Это часть приведения проекта к канону.** Раскладку `docs/` целиком ведёт скилл
|
||||
@@ -12,12 +12,12 @@
|
||||
Вход какой угодно: старая раскладка `av-dev-backlog` (индекс `README.md`,
|
||||
кладбище `CLOSED.md`, приоритеты секциями, транслитные слаги, файлы рядом с
|
||||
индексом), `TODO.md`, россыпь заметок, раздел «планы» в `README.md`, список
|
||||
шагов роадмапа проекта.
|
||||
шагов плана проекта.
|
||||
|
||||
## Три правила, из которых всё следует
|
||||
|
||||
1. **Сперва карта, потом файлы.** Человеку показывается, что найдено, как
|
||||
разложилось по целям и **что не разложилось**, — и только после подтверждения
|
||||
1. **Сперва карта, потом файлы.** Человеку показывается, что найдено, в каком
|
||||
порядке разложилось и **что не разложилось**, — и только после подтверждения
|
||||
пишется хоть один файл. Это то же правило, что у интейка находок ревью:
|
||||
массовое заведение записей без подтверждения — самый дорогой отказ, потому
|
||||
что разгребает его потом переоценка.
|
||||
@@ -38,7 +38,7 @@
|
||||
tk="$CLAUDE_PLUGIN_ROOT/skills/task-track/scripts/tasks.py"
|
||||
|
||||
python3 $tk adopt scan --from docs/backlog docs/plan.md TODO.md \
|
||||
--target tasks --out tasks-adopt-plan.json # только чтение
|
||||
--stage build --target tasks --out tasks-adopt-plan.json # только чтение
|
||||
python3 $tk adopt apply --plan tasks-adopt-plan.json \
|
||||
--refs docs openspec CLAUDE.md README.md # запись
|
||||
```
|
||||
@@ -53,56 +53,60 @@ python3 $tk adopt apply --plan tasks-adopt-plan.json \
|
||||
- **английские слаги.** Перевести `taj-brejk-pri-ravnoj-polnote` в
|
||||
`tie-break-equal-completeness` может только тот, кто понимает смысл. `scan`
|
||||
честно говорит: проверить надо **все** слаги, признаки транслита — эвристика;
|
||||
- **цели.** Шаги роадмапа — готовые цели в **`Запланировано`** (очередь и
|
||||
обоснование у них уже есть); тематические скопления задач — цели в
|
||||
**`Направления`** («прочность слияния»,
|
||||
«журнал и пересборка»). Предлагаешь ты, назначает человек;
|
||||
- **стадия.** `--stage` называет, чем этот беклог будет: планом стройки или
|
||||
очередью правок. Машине это не выводится — она видит список пунктов, а не то,
|
||||
построено приложение или нет;
|
||||
- **порядок.** Нумерованные шаги источника `scan` сохраняет по номерам, прочие
|
||||
ставит следом. Дальше порядок — твоё суждение и подтверждение человека: на
|
||||
стройке это зависимость, на доработке важность;
|
||||
- **что вообще не задача.** Обоснование порядка шагов, абзац прозой, заголовок
|
||||
раздела — это не пункты беклога, и они уходят в «не разложилось» с причиной.
|
||||
|
||||
## Порядок
|
||||
|
||||
1. **Осмотрись.** Где лежат задачи, роадмап, заметки. Каталог задач по канону —
|
||||
всегда `tasks`. Секции беклога (`--sections`) — по умолчанию
|
||||
`Ядро,Инфра`; если у проекта деление другое по существу, оно называется
|
||||
здесь, а не подгоняется под умолчание, и становится **заголовками `##`
|
||||
индекса** — их единственным домом. В `.av-dev.toml` секции не пишутся: там
|
||||
версия формата и имена частей, а второй список секций разошёлся бы с
|
||||
заголовками молча.
|
||||
1. **Осмотрись и назови стадию.** Где лежат задачи, план, заметки; построено
|
||||
приложение или строится. Каталог задач по канону — всегда `tasks`. Секции
|
||||
беклога (`--sections`) — на стройке ровно одна (умолчание `План`), на
|
||||
доработке сколько нужно (умолчание `Ядро,Инфра`); если у проекта деление
|
||||
другое по существу, оно называется здесь, а не подгоняется под умолчание, и
|
||||
становится **заголовками `##` индекса** — их единственным домом. В
|
||||
`.av-dev.toml` секции не пишутся: там версия, стадия и имена частей, а второй
|
||||
список секций разошёлся бы с заголовками молча.
|
||||
2. **`adopt scan`** по всем источникам разом. Один прогон, одна карта: два
|
||||
прохода дадут два несогласованных состояния.
|
||||
3. **Заполни карту**: `slug` (английский), `section`, `goal` у каждой записи;
|
||||
список `goals` — из шагов роадмапа и из тем. Закрытый шаг целью не
|
||||
заводится. Пустой `goal` законен у `fix`, `chore` и `research` — они служат
|
||||
работоспособности, а не направлению; у `feature` цель обязательна.
|
||||
3. **Заполни карту**: `slug` (английский), `type` и `section` у каждой записи, и
|
||||
**порядок `items`** — он уедет в индекс как есть. Пункт, помеченный
|
||||
закрытым, не переносится вовсе.
|
||||
4. **Покажи человеку карту** через `AskUserQuestion`, ≤3 вопроса за итерацию,
|
||||
рекомендация первым вариантом. Показывается: сколько записей, предлагаемые
|
||||
цели (порядок и темы) с обоснованием, спорные отнесения, список «не
|
||||
разложилось». Массовые механические решения (слаги, порядок строк) не
|
||||
выносятся — это механика.
|
||||
рекомендация первым вариантом. Показывается: сколько записей, предлагаемый
|
||||
порядок с обоснованием, спорные отнесения, список «не разложилось». Слаги не
|
||||
выносятся — это механика; **порядок выносится всегда**, потому что механикой
|
||||
он не является ни на одной стадии.
|
||||
5. **`adopt apply`.** `--refs` перечисляет **всё**, где могут стоять ссылки на
|
||||
слаги: документация, архив изменений, `CLAUDE.md`, `README.md`. Скрипт
|
||||
посчитает и покажет, сколько ссылок поправлено и по каким слагам.
|
||||
6. **`tasks.py check`** и доклад.
|
||||
|
||||
`apply` отказывается писать поверх живого каталога и проверяет карту целиком
|
||||
**до** первой записи: неверная секция, дубль слага, цель, которой нет в карте —
|
||||
всё это отказ до того, как на диске появился хотя бы один файл.
|
||||
**до** первой записи: неверная секция, дубль слага, неназванный тип, две секции
|
||||
при стадии `build` — всё это отказ до того, как на диске появился хотя бы один
|
||||
файл.
|
||||
|
||||
## Переходное состояние — объявляется, а не заминается
|
||||
|
||||
Сразу после адаптации задачи в большинстве своём **не готовы к взятию**: у них
|
||||
нет критериев приёмки, а у части может не быть цели. Это нормально, но обязано
|
||||
быть названо, иначе следующий агент примет пустой беклог за поломку.
|
||||
нет критериев приёмки. Это нормально, но обязано быть названо, иначе следующий
|
||||
агент примет пустой беклог за поломку.
|
||||
|
||||
`apply` печатает состояние по факту: сколько задач без цели (это **ошибки**
|
||||
`check`) и сколько не собрало разделы своего типа (для `check` это не ошибка, а
|
||||
строка здоровья, но `ready` такую задачу не пропустит). Закрывается это
|
||||
**порциями груминга** — скилл
|
||||
`groom`, 5–8 задач за порцию: проставить цели, превратить «готово, когда» в
|
||||
критерии с оракулами, вынуть вопросы из прозы в раздел «Вопросы». Там же
|
||||
беклогу впервые назначается **порядок**: после адаптации его нет вовсе, а
|
||||
очередь и есть то, ради чего каталог заводят.
|
||||
`apply` печатает состояние по факту: сколько задач не собрало разделы своего типа
|
||||
(для `check` это не ошибка, а строка здоровья, но `ready` такую задачу не
|
||||
пропустит). Закрывается это **порциями груминга** — скилл `groom`, 5–8 задач за
|
||||
порцию: превратить «готово, когда» в критерии с оракулами, вынуть вопросы из
|
||||
прозы в раздел «Вопросы».
|
||||
|
||||
**Порядок строк проверяется глазами отдельно.** На стройке он выведен из
|
||||
нумерации источника, и там, где её не было, он случаен. На доработке машина
|
||||
важности не знает вовсе — очередь расставляется первым же грумингом.
|
||||
|
||||
Готовность к первой задаче — не «`check` зелёный», а «`ready` пропускает хотя бы
|
||||
верхние строки очереди».
|
||||
@@ -113,18 +117,20 @@ python3 $tk adopt apply --plan tasks-adopt-plan.json \
|
||||
дело человека, удалять чужое молча нельзя. В доклад идёт готовая команда.
|
||||
- **Не переписывает подписи ссылок.** `[docs/backlog](tasks/BACKLOG.md)` —
|
||||
цель поправлена, текст остался; это правится глазами, и таких мест немного.
|
||||
- **Не сочиняет критерии приёмки и не придумывает цели**, которых в материале
|
||||
нет. Придуманная цель хуже отсутствующей: под неё заведут задачи.
|
||||
- **Не сочиняет критерии приёмки** и не додумывает пользы, которой в материале
|
||||
нет.
|
||||
- **Не выводит стадию.** Список пунктов одинаково выглядит и планом стройки, и
|
||||
очередью правок; отвечает `--stage`, а называет его человек.
|
||||
- **Не трогает историю.** В коммитах старые слаги остаются, и это нормально.
|
||||
|
||||
## Доклад
|
||||
|
||||
- Источники и что в каждом распознано (раскладка, индекс, кладбище, секции).
|
||||
- Сколько записей перенесено, сколько целей заведено (порядок / темы) и откуда
|
||||
каждая выведена.
|
||||
- Стадия и сколько записей перенесено; откуда взялся порядок (нумерация
|
||||
источника или суждение).
|
||||
- **Переименования**: сколько слагов, сколько ссылок поправлено и в скольких
|
||||
файлах — числом, а не «поправлены ссылки».
|
||||
- **Не разложилось**: поимённо, с причиной.
|
||||
- Переходное состояние: сколько задач без цели, сколько без критериев, чем и за
|
||||
сколько порций закрывается.
|
||||
- Переходное состояние: сколько задач без критериев, чем и за сколько порций
|
||||
закрывается.
|
||||
- `tasks.py check` — результат строкой.
|
||||
|
||||
@@ -50,17 +50,12 @@
|
||||
заведённое и уже выкинутое. Нашлось среди живых — дописываем находку в
|
||||
существующий файл. Нашлось в `REJECTED.md` — это сигнал: причина отказа могла
|
||||
устареть, выноси пользователю, а не заводи молча заново.
|
||||
4. **Разложи по целям — там, где цель нужна.** Большинство находок ревью это
|
||||
`fix` и `chore`, и **цель им не требуется**: они служат работоспособности, а
|
||||
не направлению. Придуманная им цель —
|
||||
ровно то враньё, от которого спасает тип.
|
||||
|
||||
Цель обязательна у находки, которая оказалась **новой возможностью**
|
||||
(`feature`): нашлось поведение, которого никто не заказывал, и его надо
|
||||
либо заказать целью, либо убрать. Подходящей цели нет — заведи её
|
||||
(`add --type goal --section Направления`) в том же проходе.
|
||||
4. **Проставь типы.** Большинство находок ревью это `fix` и `chore`. Находка,
|
||||
оказавшаяся **новой возможностью** (`feature`), — отдельный случай: нашлось
|
||||
поведение, которого никто не заказывал, и решение тут не «завести задачу», а
|
||||
«заказать или убрать». Выноси такую пользователю отдельно от прочих.
|
||||
5. **Покажи карту до создания файлов.** Кластер → задача / сырьё / строка в
|
||||
пакетный файл / уже заведено / отброшено, и под какую цель — пачкой через
|
||||
пакетный файл / уже заведено / отброшено — пачкой через
|
||||
`AskUserQuestion`. Это тот же барьер, что и «три кандидата» в интейке из
|
||||
диалога: массовое заведение файлов без подтверждения — ровно тот отказ, ради
|
||||
которого интейк из ревью и выделен. Дешёвая мелочь по явному согласию может
|
||||
@@ -88,8 +83,8 @@
|
||||
[скилле груминга](../../task-groom/SKILL.md#приоритет-как-его-расставляют), и
|
||||
серьёзность попадает ровно в один из них.
|
||||
|
||||
- **тяжёлая находка со свидетельством о сломанном сейчас** → задача под ту цель,
|
||||
которой она угрожает, и **первой строкой секции**: `move <слаг> --first
|
||||
- **тяжёлая находка со свидетельством о сломанном сейчас** → задача
|
||||
**первой строкой секции**: `move <слаг> --first
|
||||
--reason «сломано сейчас: …»`. Это довод «что сломано сейчас» из перечня
|
||||
груминга — единственный, который не требует сравнения с соседями по очереди,
|
||||
потому что сломанное дорожает само. Позицию всё равно назначает человек, и
|
||||
@@ -124,7 +119,7 @@
|
||||
## Доклад
|
||||
|
||||
- Источник (какое ревью/аудит, сколько находок на входе).
|
||||
- Свёрнуто в задачи: N кластеров из M находок, со слагами, целями и тегом партии.
|
||||
- Свёрнуто в задачи: N кластеров из M находок, со слагами и тегом партии.
|
||||
- Что не заведено и почему: починено инлайн, уже заведено, стало сырьём, ушло в
|
||||
`REJECTED.md`.
|
||||
- Поимённая сверка: находок на входе N, исход есть у N.
|
||||
|
||||
@@ -8,14 +8,19 @@
|
||||
|
||||
Задачу можно дробить, только если части удовлетворяют **обоим** условиям:
|
||||
|
||||
1. **Мерджатся независимо.** Часть Б не требует, чтобы часть А была уже влита.
|
||||
Есть порядок «сперва А, потом Б, иначе не собрать» → это не декомпозиция, а
|
||||
план реализации: шаги остаются **внутри одного файла**.
|
||||
1. **Каждая мерджится сама по себе.** Часть, после которой дерево не собирается
|
||||
или поведение сломано до прихода соседней, — не часть, а половина.
|
||||
2. **Каждая — самостоятельный шаг.** Часть, осмысленная только в комплекте с
|
||||
другой, — не задача. Проверяй тестом «готова к взятию» (task-format): какую
|
||||
строку «Завершения» цели двигает **именно эта часть** и какие у неё
|
||||
собственные критерии приёмки. У операционных частей (`fix`, `chore`,
|
||||
`research`) цели может не быть — тогда достаточно собственных критериев.
|
||||
другой, — не задача. Проверяй тестом «готова к взятию» (task-format): свои
|
||||
критерии приёмки у неё есть или нет.
|
||||
|
||||
**Порядок между частями законен на стройке и подозрителен на доработке**, и это
|
||||
единственное, что стадия здесь меняет. Беклог стройки **весь** состоит из
|
||||
упорядоченных зависимостью шагов: «сперва А, потом Б» — не повод не дробить, а
|
||||
описание того, как этот список устроен, и части просто встают подряд. На
|
||||
доработке правки независимы, и обнаруженный порядок «иначе не собрать» чаще
|
||||
всего значит, что перед тобой не декомпозиция, а план реализации: шаги остаются
|
||||
**внутри одного файла**.
|
||||
|
||||
Не проходит хотя бы одно — **не дроби**. Ложная декомпозиция плодит файлы,
|
||||
которые нельзя взять поодиночке, и переоценка потом склеивает их обратно.
|
||||
@@ -45,37 +50,29 @@
|
||||
гигиена полей снимает. Шов пользуется меткой как **признаком**, что в задаче
|
||||
две разнородные работы; решение о метке остаётся за конвейером.
|
||||
|
||||
**Цель наследуется.** Все части несут `goal:` родителя: декомпозиция не меняет
|
||||
того, чему работа служит. Если у части цель другая — это признак, что дробили не
|
||||
по той границе, либо что часть вообще из другой работы.
|
||||
|
||||
## Что делать с родителем
|
||||
|
||||
После разделения родитель **не остаётся** третьей висящей строкой:
|
||||
|
||||
- части полностью замещают его → `close <slug> --reason "разложена на a, b"`.
|
||||
части полностью замещают его → `close <slug> --reason "разложена на a, b"`.
|
||||
`REJECTED.md` здесь — не «выкинули», а именно тот след, что переживает запись:
|
||||
через квартал вопрос «куда делась задача X» отвечается строкой со ссылками на
|
||||
наследников, а не археологией git;
|
||||
- родитель осмыслен как **возможность**, а не как шаг → это цель, и **строка
|
||||
переезжает**: `edit <slug> --type goal --section <часть роадмапа>` снимает её с
|
||||
`BACKLOG.md` и вставляет в `ROADMAP.md`. Файл в `items/` при этом не двигается —
|
||||
он и есть запись. Части получают `--goal <слаг родителя>`, а закрывать родителя
|
||||
нечем и незачем: он не выкинут, он стал целью.
|
||||
наследников, а не археологией git.
|
||||
|
||||
**Промежуточного зонтика между целью и задачей нет.** Тип `epic` упразднён:
|
||||
роль зонтика играет цель, а слишком крупный шаг дробится на шаги помельче под
|
||||
той же целью. Если частям нужен общий заголовок — значит у них общая
|
||||
возможность, и её надо назвать целью, а не заводить временный тип.
|
||||
**Зонтика над частями нет никакого.** Тип `epic` упразднён, цель, игравшая его
|
||||
роль после него, — тоже. Если частям нужен общий заголовок, у них общее место в
|
||||
списке: они встают подряд, и соседство и есть тот ответ, ради которого заводили
|
||||
зонтик.
|
||||
|
||||
## Когда декомпозиция случается посреди работы
|
||||
|
||||
Задача, которая **оказалась крупнее задачи**, распознаётся до того, как под неё
|
||||
заведено предложение об изменении: иначе его придётся выбрасывать. Она выходит
|
||||
из работы на декомпозицию, а её строка возвращается в беклог с причиной
|
||||
(`move … --reason "крупнее задачи"`). Части заводятся сразу под той же целью, и
|
||||
**место в очереди им назначает человек**: машина поставит их в конец секции, а
|
||||
крупная задача редко распадается на что-то менее срочное, чем была сама.
|
||||
(`move … --reason "крупнее задачи"`). **Место в списке частям назначает
|
||||
человек**: машина поставит их в конец секции, а на стройке место наследуется от
|
||||
родителя (`move --after`), да и на доработке крупная задача редко распадается на
|
||||
что-то менее срочное, чем была сама.
|
||||
|
||||
## Мозговой штурм сырья
|
||||
|
||||
@@ -96,9 +93,9 @@ Applicative-штурм («перечисли задачи, следующие и
|
||||
applicative.
|
||||
2. **Вынеси формы пользователю** через `AskUserQuestion` с компромиссами. Рамку
|
||||
выбирает он: это продуктовое решение, не механика.
|
||||
3. **Назови цель.** Выбранная форма служит цели — существующей или новой. Идея,
|
||||
для которой цель не находится, скорее всего уезжает в `REJECTED.md`, а не
|
||||
заводится задачей.
|
||||
3. **Назови пользу.** Выбранная форма отвечает на «что станет наблюдаемо иначе».
|
||||
Идея, для которой такого ответа не находится, скорее всего уезжает в
|
||||
`REJECTED.md`, а не заводится задачей.
|
||||
4. **Только выбранную форму** дроби по тесту декомпозиции выше и проставь
|
||||
критерии приёмки: без них наследники останутся идеями под другим именем.
|
||||
|
||||
@@ -109,8 +106,8 @@ Applicative-штурм («перечисли задачи, следующие и
|
||||
## Доклад
|
||||
|
||||
- Идея/задача на входе, выбранная рамка (для штурма), задачи-наследники со
|
||||
слагами, целями и секциями.
|
||||
- Судьба родителя: удалён / стал целью / выкинут с причиной.
|
||||
слагами, секциями и местом в списке.
|
||||
- Судьба родителя: удалён / выкинут с причиной.
|
||||
- `tasks.py check` после правок.
|
||||
- Границы покрытия: какие постановки рассмотрены и какие сознательно отброшены —
|
||||
чтобы штурм не пришлось повторять с нуля.
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
| Обязательные разделы | `Затрагивает`, `Критерии приёмки` |
|
||||
| Допустимые сверх того | `Рамки`, `Вопросы` |
|
||||
| Поле места | **Категория** — полка домена беклога |
|
||||
| Цель (`goal:<слаг>`) | нет: цель — это возможность, а здесь её не появляется |
|
||||
| Индекс | `BACKLOG.md` |
|
||||
| Берётся в работу | да |
|
||||
|
||||
@@ -43,7 +42,7 @@
|
||||
## Алгоритм
|
||||
|
||||
1. **Проверить, что поведение не меняется.** Меняется — это `feature` или `fix`,
|
||||
и у неё другие требования (цель, воспроизведение).
|
||||
и у последнего другие требования (воспроизведение).
|
||||
2. **Назвать, что перестанет мешать** — одной фразой, адресуясь разработчику.
|
||||
«Прибраться в модуле X» — не ответ: непонятно, что изменится.
|
||||
3. **Назвать границы** в `Затрагивает`. У обслуживания они часто не в коде:
|
||||
@@ -55,9 +54,6 @@
|
||||
5. **Проверить, что это не «заодно».** Обслуживание любит склеиваться в пачку
|
||||
(«обновить зависимости и переписать сборку и убрать мёртвый код»). Не
|
||||
мерджится порознь — это несколько задач ([split.md](split.md)).
|
||||
6. **Цель не проставлять.** `chore` служит работоспособности, а не направлению.
|
||||
Работа по сопровождению проекта при этом видна в роадмапе — секцией
|
||||
`Сопровождение`, но целью не становится.
|
||||
|
||||
## Кто такую задачу решает
|
||||
|
||||
|
||||
@@ -15,18 +15,13 @@
|
||||
| Обязательные разделы | `Затрагивает`, `Критерии приёмки` |
|
||||
| Допустимые сверх того | `Рамки`, `Вопросы` |
|
||||
| Поле места | **Категория** — полка домена беклога |
|
||||
| Цель (`goal:<слаг>`) | **обязательна** |
|
||||
| Индекс | `BACKLOG.md` |
|
||||
| Берётся в работу | да |
|
||||
|
||||
**Цель обязательна, и это единственный тип, у которого так.** Новая возможность
|
||||
и есть содержание цели: подходящей нет — либо она заводится, либо перед тобой не
|
||||
`feature`. `ready` без цели откажет.
|
||||
|
||||
## Алгоритм
|
||||
|
||||
1. **Найти цель или завести её.** Задача без цели, названная функцией, — самый
|
||||
частый способ пронести в беклог работу, которой никто не заказывал.
|
||||
1. **Проверить, что возможность и правда новая.** Поведение расходится с уже
|
||||
заявленным — это `fix`, а не `feature`, и требования у него другие.
|
||||
2. **Назвать границы** в разделе `Затрагивает`: эндпоинт или команда, таблица и
|
||||
миграция, формат на диске, публичный тип пакета, внешний сервис. Названы
|
||||
**границы, а не замысел**: «переписать хранилище на новый драйвер» — замысел,
|
||||
@@ -35,13 +30,12 @@
|
||||
3. **Написать критерии приёмки** — 2–5 проверяемых утверждений списком, у
|
||||
каждого назван оракул. Не «работает корректно», а «повторный прогон даёт тот
|
||||
же отпечаток — оракул: команда сверки».
|
||||
4. **Сказать, какую строку «Завершения» цели задача двигает.** Одной строкой в
|
||||
теле. Это защита от задачи «отрефакторить X»: она проваливается не потому,
|
||||
что невидима снаружи, а потому, что не находит строки, к которой относится.
|
||||
4. **Поставить её на место в списке.** На стройке место называет зависимость:
|
||||
`move <слаг> --after <шаг, без которого нельзя>`. На доработке место в
|
||||
очереди назначает груминг, и конец списка законен.
|
||||
5. **Проверить, что задача одна.** Отвечается всё, но задача не делается одним
|
||||
заходом и не мерджится целиком — это несколько задач под одной целью, дроби
|
||||
сразу ([split.md](split.md)). Промежуточного зонтика между целью и задачей
|
||||
нет.
|
||||
заходом и не мерджится целиком — это несколько задач, дроби сразу
|
||||
([split.md](split.md)) и ставь их в списке подряд.
|
||||
6. **Реализация** — дело конвейера проекта, не этого скилла. Закрывается
|
||||
`close <слаг> --implemented`: файл и строка удаляются, суть переезжает в
|
||||
`openspec/specs/` и документацию.
|
||||
@@ -49,8 +43,8 @@
|
||||
## Что видит машина, а что человек
|
||||
|
||||
Схему типа судит `ready` на входе в работу: **наличие непустого** раздела
|
||||
`Затрагивает`, **число** критериев (меньше двух — отказ, больше пяти —
|
||||
замечание) и цель. Наличие оракула проверяется **эвристикой** — словом «оракул»
|
||||
`Затрагивает` и **число** критериев (меньше двух — отказ, больше пяти —
|
||||
замечание). Наличие оракула проверяется **эвристикой** — словом «оракул»
|
||||
в пункте. `check` этого поимённо не говорит, а считает строкой здоровья
|
||||
(`SKILL.md`, «Что механизировано, а что нет»).
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
| Обязательные разделы | **`Воспроизведение`**, `Затрагивает`, `Критерии приёмки` |
|
||||
| Допустимые сверх того | `Рамки`, `Вопросы` |
|
||||
| Поле места | **Категория** — полка домена беклога |
|
||||
| Цель (`goal:<слаг>`) | необязательна |
|
||||
| Индекс | `BACKLOG.md` |
|
||||
| Берётся в работу | да |
|
||||
|
||||
@@ -54,9 +53,7 @@
|
||||
почти всегда есть парный критерий: **прежнее поведение не сломалось**
|
||||
(«ввод `а1` принимается по-прежнему»). Без него починка чинит одно и ломает
|
||||
соседнее.
|
||||
6. **Цель не выдумывать.** `fix` служит работоспособности, а не направлению.
|
||||
Придуманная цель — то же враньё, от которого спасает тип.
|
||||
7. **Записать дефект в журнал** `docs/review.md` с пометкой «проскочил / пойман
|
||||
6. **Записать дефект в журнал** `docs/review.md` с пометкой «проскочил / пойман
|
||||
ревью». Проскочившие — проверочный набор для калибровки конвейера; пойманные с
|
||||
оракулом — лучшая опора для прохода ревью: проектные, воспроизводимые,
|
||||
однажды оказавшиеся правдой.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Формат записей и индексов
|
||||
# Формат записей и индекса
|
||||
|
||||
Заголовок, мета-блок и строку индекса ставит `tasks.py add` — руками их не
|
||||
пишут. Этот файл описывает **общую форму** любой записи и то, что проверяет
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
| Тип | Файл | Одной строкой |
|
||||
| --- | --- | --- |
|
||||
| 🎯 `goal` | [task-goal.md](task-goal.md) | возможность приложения |
|
||||
| ✨ `feature` | [task-feature.md](task-feature.md) | снаружи появляется то, чего не было |
|
||||
| 🐞 `fix` | [task-fix.md](task-fix.md) | поведение расходится с заявленным |
|
||||
| 🧹 `chore` | [task-chore.md](task-chore.md) | обслуживание, поведение не меняется |
|
||||
@@ -25,7 +24,6 @@
|
||||
- **Тип:** fix
|
||||
- **Категория:** Ядро — вернулась из работы: остаток писал нерешённое в журнал
|
||||
- **Зачем:** ввод «а1б2» ходит в a1 — игрок не видит, что ошибся, и винит игру
|
||||
- **Теги:** goal:merge-robustness
|
||||
|
||||
Разбор хода читает первые два символа и молча выбрасывает остаток строки.
|
||||
|
||||
@@ -55,8 +53,8 @@
|
||||
**эмодзи типа**, и она **производна**: её ставит `add` и чинит `check --fix`
|
||||
по полю меты. Второго дома у типа нет — эмодзи это его отображение, как
|
||||
строка индекса это отображение файла.
|
||||
- **Форма заголовка — по типу.** Цель отвечает на «что приложение будет уметь»;
|
||||
`feature`, `fix` и `chore` — на «что нужно сделать», глаголом в неопределённой
|
||||
- **Форма заголовка — по типу.** `feature`, `fix` и `chore` отвечают на «что
|
||||
нужно сделать», глаголом в неопределённой
|
||||
форме, перед ним допускается «не»; `research` называет предмет разведки и
|
||||
формы действия **не несёт намеренно**. Почему так — SKILL.md, «Как написана
|
||||
задача». `check` считает заголовки не в форме действия и печатает число в
|
||||
@@ -67,9 +65,8 @@
|
||||
теги необязательны. Нераспознанные поля сохраняются: скрипт правит свои и не
|
||||
трогает чужие.
|
||||
- **Тип — первым полем.** Он решает, что у записи вообще может быть: какие
|
||||
разделы обязательны, нужна ли цель, берётся ли она в работу, — и читается
|
||||
раньше всего остального. Словарь **закрыт**: `goal` | `feature` | `fix` |
|
||||
`chore` | `research`. Не подходит ни один — это сигнал, что в записи их два и
|
||||
разделы обязательны и берётся ли она в работу, — и читается раньше всего
|
||||
остального. Словарь **закрыт**: `feature` | `fix` | `chore` | `research`. Не подходит ни один — это сигнал, что в записи их два и
|
||||
её надо разделить.
|
||||
- **«Зачем» отвечает на «зачем нужна эта задача»** — состояние, остаток, боль.
|
||||
Не пересказ задачи: пересказ уже есть по ссылке. Живёт здесь, а не только в
|
||||
@@ -86,19 +83,16 @@
|
||||
Тело — не план реализации и не спецификация: принятое и реализованное переезжает
|
||||
в документацию проекта, а файл задачи удаляется.
|
||||
|
||||
### Поле места: «Категория» и «Секция»
|
||||
### Поле места: «Категория»
|
||||
|
||||
Поле называет, **где числится строка**, и имя у него **зависит от типа**:
|
||||
Поле называет **секцию беклога, в которой числится строка** — полку домена
|
||||
(`Ядро`, `Инфра`, …), куда задачу положили и куда вернут, если она уйдёт в работу
|
||||
и вернётся. **На стройке секция одна**, и поле называет её же: различать ей
|
||||
нечего, но производность от заголовка индекса сохраняется и там.
|
||||
|
||||
| Тип | Поле | Значения | Что это |
|
||||
| --- | --- | --- | --- |
|
||||
| `goal` | **Секция** | `Запланировано`, `Направления`, `Сопровождение` | часть роадмапа: состояние очереди |
|
||||
| прочие | **Категория** | секции беклога проекта (`Ядро`, `Инфра`, …) | полка домена, на которой задача лежит |
|
||||
|
||||
Разные имена потому, что это **разные вещи**. У задачи это полка: куда её
|
||||
положили и куда вернут, если она уйдёт в работу и вернётся. У цели оно называет
|
||||
не полку, а место в очереди работ. Одно имя на два смысла их и смешивало; `check` называет
|
||||
несовпадение дрейфом, `check --fix` переименовывает.
|
||||
Прежнее имя поля — **«Секция»**: так оно называлось у целей, указывая на часть
|
||||
роадмапа. Разбор его по-прежнему принимает, `check` называет дрейфом, `check
|
||||
--fix` переименовывает.
|
||||
|
||||
Имя самого места принадлежит **заголовку индекса** — файл на него лишь
|
||||
ссылается, и принадлежность сверяется по нижнему регистру.
|
||||
@@ -111,7 +105,8 @@
|
||||
| --- | --- |
|
||||
| префикс `[goal]` / `[idea]` в H1 | поле **Тип** + эмодзи в H1; `[idea]` → `research` |
|
||||
| тег `kind:<род>` | поле **Тип** (род работы стал типом) |
|
||||
| поле **Секция** у задачи | поле **Категория** |
|
||||
| поле **Секция** | поле **Категория** |
|
||||
| теги `goal:<слаг>` и `decomposed` | сняты: целей больше нет |
|
||||
| поле **Хук** | поле **Зачем** |
|
||||
| мета одной строкой через `·` | мета списком, поле на строку |
|
||||
|
||||
@@ -147,8 +142,8 @@
|
||||
забыли назвать, она от отсутствующей не отличает. Раздела нет — отказ во взятии:
|
||||
оценивать нечем.
|
||||
|
||||
**У `goal` и `research` раздела нет** — у первой границы называют её задачи, у
|
||||
второй они становятся известны, когда из разведки родятся задачи.
|
||||
**У `research` раздела нет** — её границы становятся известны, когда из разведки
|
||||
родятся задачи.
|
||||
|
||||
### Критерии приёмки
|
||||
|
||||
@@ -166,8 +161,7 @@
|
||||
что проверено больше проверенного, хуже, чем не проверять вовсе.
|
||||
|
||||
**У `research` критериев нет** — её приёмка это записанный ответ, и описывается
|
||||
она разделами «Вопрос» и «Куда ляжет ответ». **У `goal` их заменяет
|
||||
«Завершение».**
|
||||
она разделами «Вопрос» и «Куда ляжет ответ».
|
||||
|
||||
**Критерии — пол, но расхождение с ними есть дефект критериев.** Если приёмщик
|
||||
видит, что критерии закрыты, а суть задачи не достигнута, он **правит критерии и
|
||||
@@ -210,44 +204,6 @@
|
||||
на снятый тег при непустом разделе посоветует тег вернуть. Снять тег, не
|
||||
опустошив раздел, — значит закольцевать себя между двумя советами.
|
||||
|
||||
## Файл цели
|
||||
|
||||
Форма та же, разделы и алгоритм — [task-goal.md](task-goal.md).
|
||||
|
||||
```markdown
|
||||
# 🎯 Исход слияния не зависит от порядка доставки
|
||||
|
||||
- **Тип:** goal
|
||||
- **Секция:** Направления
|
||||
- **Теги:** decomposed
|
||||
|
||||
Ради чего: точки из разных доставок сходятся в один часовой объект, и сегодня
|
||||
исход столкновения зависит от порядка доставки, а не от содержания.
|
||||
|
||||
## Завершение
|
||||
|
||||
- повторная доставка тех же точек в другом порядке даёт то же состояние;
|
||||
- накопительная метрика за сутки не уменьшается после повторной доставки;
|
||||
- в логе видно, какая из двух точек выиграла и почему.
|
||||
```
|
||||
|
||||
- **Задачи цели здесь не перечисляются.** Перечень даёт
|
||||
`tasks.py list --goal <слаг>`; хранимый список стал бы третьим индексом и
|
||||
поехал бы на первой же закрытой задаче.
|
||||
- **Тег `decomposed`** отличает «цель ещё не разобрана» от «все её задачи
|
||||
закрыты» — два состояния, у которых снаружи один и тот же признак: задач нет.
|
||||
Пометка именно **тегом**, а не строкой в теле: только так она проверяется.
|
||||
`check` напоминает о нём у цели без задач замечанием — неразобранная цель
|
||||
законна и зелёного прогона не ломает; `check --fix` сам ставит его цели, у
|
||||
которой задачи есть, а цель с тегом и без задач — прямое приглашение закрыть.
|
||||
- Цель живёт в `ROADMAP.md` и **никогда** — в `BACKLOG.md`.
|
||||
- **Достигнутая цель не исчезает.** `close <слаг> --implemented` удаляет файл и
|
||||
переносит строку в секцию `Готово` с датой:
|
||||
`- 2026-08-04 \`merge-order\` — Исход слияния не зависит от порядка доставки. …`
|
||||
Ссылки на файл в ней нет — файл удалён, а битая ссылка это ошибка `check`.
|
||||
Поведение живёт в спеках проекта; роадмап отвечает, **когда и в каком порядке**
|
||||
оно появилось.
|
||||
|
||||
## Слаг
|
||||
|
||||
Латиница и цифры, kebab-case, без ведущих, хвостовых и двойных дефисов
|
||||
@@ -261,9 +217,9 @@
|
||||
проходом по всем местам, где слаг упомянут, иначе останутся битые ссылки,
|
||||
которых никто не проверяет.
|
||||
|
||||
## Индексы
|
||||
## Индекс
|
||||
|
||||
Строка везде одной формы:
|
||||
Строка одной формы:
|
||||
|
||||
```markdown
|
||||
- [🐞 Заголовок дословно](items/slug.md) — зачем
|
||||
@@ -276,52 +232,47 @@
|
||||
|
||||
| Файл | Что отвечает | Секции |
|
||||
| --- | --- | --- |
|
||||
| `ROADMAP.md` | что приложение уже умеет и чего ещё не умеет | канонические и в этом порядке: `Запланировано`, `Направления`, `Сопровождение`, `Готово` (англ. `Planned`, `Directions`, `Operations`, `Done`) |
|
||||
| `BACKLOG.md` | что **можно взять** — только задачи, **в порядке очереди** | категории проекта (по умолчанию Ядро/Инфра) |
|
||||
| `BACKLOG.md` | что **можно взять**, в значимом порядке | называет проект; на стройке ровно одна (умолчание `План`), на доработке сколько нужно (умолчание `Ядро`/`Инфра`) |
|
||||
| `REJECTED.md` | что ушло без реализации и почему | — |
|
||||
|
||||
Секции — **единственные заголовки `##` в индексе**: любой другой `##` в
|
||||
преамбуле проверка сочтёт секцией.
|
||||
|
||||
**Порядок строк внутри секции беклога значим: это очередь.** Первая строка — то,
|
||||
что делают следующим; назначает порядок человек на груминге, и двигают его
|
||||
`move --after` и `move --first`. Одно место из очереди изъято и **производно от
|
||||
типа и заполненности**: **сырьё** (`research` без раздела «Вопрос») стоит в конце
|
||||
своей секции, потому что его не берут, и между берущимся оно каждый раз требует
|
||||
**Порядок строк внутри секции значим, и стадия решает, что он значит:** на
|
||||
стройке зависимость, на доработке важность (SKILL.md, «Две стадии»). Назначает
|
||||
его человек — раскладывая шаги или на груминге, — и двигают его `move --after`
|
||||
и `move --first`. Одно место из очереди изъято и **производно от типа и
|
||||
заполненности**: **сырьё** (`research` без раздела «Вопрос») стоит в конце своей
|
||||
секции, потому что его не берут, и между берущимся оно каждый раз требует
|
||||
открыть файл, чтобы это понять. Проверяет `check`, переставляет `check --fix`,
|
||||
и человек этот порядок не назначает — иначе он был бы приоритетом, которого
|
||||
здесь нет.
|
||||
и человек этот порядок не назначает — иначе он был бы решением, которого здесь
|
||||
нет.
|
||||
|
||||
**Секции «блокеры» среди них нет.** Блокер — состояние, а не полка: он живёт до
|
||||
ответа человека, а следы остаются вопросами в файлах задач.
|
||||
Постоянно пустая секция со старой семантикой «разбираются пачками» противоречила
|
||||
бы правилу «эскалируем немедленно», поэтому `init` её не заводит, а `check`
|
||||
говорит о ней в чужом беклоге. Переезжаешь с такой секцией — удали её. В секции
|
||||
**`Запланировано`** очередь значима и обосновывается прозой; двигают строку
|
||||
`move <slug> --section Запланировано --after <другой>`. В секции **`Готово`**
|
||||
строки не той формы, что у прочих индексов: дата, слаг, заголовок — как в
|
||||
`REJECTED.md`, и по той же причине (файла уже нет, ссылаться некуда).
|
||||
говорит о ней в чужом беклоге. Переезжаешь с такой секцией — удали её.
|
||||
|
||||
**Секции роадмапа закреплены** — состав, полнота, единство языка и **порядок**
|
||||
проверяются `check`; категории беклога проект называет сам. Почему так —
|
||||
SKILL.md. Порядок закреплён потому, что `Готово` копится: стоя первым,
|
||||
достигнутое отодвигает за экран то, ради чего роадмап открывают чаще всего.
|
||||
**Имена секций проект выбирает сам, а количество ограничено стадией:** на
|
||||
стройке секция одна, потому что порядок там зависимость, и разложенный по полкам
|
||||
список перестаёт быть планом. Проверяет `check`; слить секции сам он не берётся —
|
||||
в каком порядке пойдут строки слитых полок, знает только человек.
|
||||
|
||||
**Заголовок секции пишется с прописной и отбивается пустой строкой с обеих
|
||||
сторон** — во всех индексах, включая категории беклога, имена которых выбирает
|
||||
проект. Написание канонических секций и отбивку правит `check --fix`; он же
|
||||
сводит написание места в мете файла с заголовком индекса.
|
||||
сторон.** Отбивку правит `check --fix`; он же сводит написание места в мете файла
|
||||
с заголовком индекса.
|
||||
|
||||
Индексы **производны**: расходятся с файлом — правим индексы (`check --fix`).
|
||||
Индекс **производен**: расходится с файлом — правим индекс (`check --fix`).
|
||||
Строку руками не пишут.
|
||||
|
||||
Отсюда же ответ на «а если оборвётся посередине». Мутация сперва проверяет всё
|
||||
и складывает правки, и только потом пишет: сначала все временные файлы, потом
|
||||
переименования подряд. Полной транзакции на несколько файлов файловая система не
|
||||
даёт, но окно сжато до цепочки переименований, а **всё, что в нём может
|
||||
разъехаться, — производное**: файлы целы, индексы восстанавливает `check --fix`.
|
||||
разъехаться, — производное**: файлы целы, индекс восстанавливает `check --fix`.
|
||||
Поэтому отказ на второй задаче из пяти не оставляет первую переписанной при
|
||||
нетронутых индексах.
|
||||
нетронутом индексе.
|
||||
|
||||
## `REJECTED.md`
|
||||
|
||||
@@ -346,27 +297,24 @@ SKILL.md. Порядок закреплён потому, что `Готово`
|
||||
Разметка сверх типа. Тип полем, потому что он один и обязателен; теги — потому
|
||||
что их много и `list --tag` уже умеет отбирать по ним порцию разбора.
|
||||
|
||||
- `goal:<слаг>` — цель, которой служит задача. Обязателен **у `feature`**:
|
||||
новая возможность и есть содержание цели. У `fix`, `chore` и `research` его
|
||||
может не быть — они служат работоспособности, а не направлению.
|
||||
- `question` — в файле есть неразобранный раздел «Вопросы».
|
||||
- `decomposed` — на цели: разложена на задачи (см. «Файл цели»).
|
||||
|
||||
Тега `kind:<род>` больше нет: род работы стал типом. Оставшийся в файле `check`
|
||||
называет дрейфом, а `check --fix` снимает, перенеся значение в поле «Тип».
|
||||
Тегов `kind:<род>`, `goal:<слаг>` и `decomposed` больше нет: род работы стал
|
||||
типом, а цели упразднены. Оставшиеся в файле `check` называет дрейфом, а `check
|
||||
--fix` снимает (значение `kind:` при этом переезжает в поле «Тип»).
|
||||
|
||||
Отбор — `list --tag a,b`: перечисленные через запятую теги требуются **все
|
||||
сразу** (это И, не ИЛИ). Тег, которого нет ни у одной задачи, `list` называет
|
||||
вслух: молчаливый ноль читается как «таких задач нет», а чаще это опечатка.
|
||||
|
||||
Свои теги проект заводит свободно (партия ревью `review-ГГГГ-ММ-ДД`, тема,
|
||||
источник) — словарь не фиксирован. В индексы теги не выносим: индексы
|
||||
производны, отбор делает `list --tag`, а не глаза.
|
||||
источник) — словарь не фиксирован. В индекс теги не выносим: он
|
||||
производен, отбор делает `list --tag`, а не глаза.
|
||||
|
||||
## Тест «готова к взятию»
|
||||
|
||||
Задача готова, если из файла отвечаются четыре вопроса. Первый и четвёртый —
|
||||
общие, второй и третий у каждого типа свои и перечислены в его файле.
|
||||
Задача готова, если из файла отвечаются три вопроса. Первый общий, второй и
|
||||
третий у каждого типа свои и перечислены в его файле.
|
||||
|
||||
1. **Что станет наблюдаемо иначе**, когда она сделана — снаружи: пользователю,
|
||||
владельцу сервиса или разработчику. «Отрефакторить X» — не ответ; «перестанет
|
||||
@@ -379,26 +327,13 @@ SKILL.md. Порядок закреплён потому, что `Готово`
|
||||
`chore` — `Затрагивает`.
|
||||
3. **По чему видно, что закончено** — критерии приёмки с оракулами;
|
||||
у `research` вместо них `Куда ляжет ответ`.
|
||||
4. **Какую часть «Завершения» своей цели она двигает** — у задачи с целью.
|
||||
Строкой: «двигает пункт 2 «Завершения» — накопительная метрика перестаёт
|
||||
уменьшаться». Это и есть защита от задачи «отрефакторить X»: она проваливает
|
||||
тест не потому, что невидима снаружи, а потому, что не находит строки, к
|
||||
которой относится. Заодно видно обратное — достаточен ли набор задач для
|
||||
цели: строка «Завершения», к которой не относится ни одна задача, это
|
||||
незакрытая часть возможности.
|
||||
|
||||
**У задачи без цели** (`fix`, `chore`, `research`) вопрос не задаётся: они
|
||||
служат работоспособности, а не направлению.
|
||||
|
||||
Не отвечается первый, второй или третий вопрос → это ещё не задача, а **сырьё**:
|
||||
тип `research` без раздела «Вопрос», место — конец секции, работа над ним —
|
||||
штурм. Не отвечается четвёртый у `feature` → либо цель есть и не проставлена,
|
||||
либо это не новая возможность.
|
||||
Не отвечается любой из трёх → это ещё не задача, а **сырьё**: тип `research` без
|
||||
раздела «Вопрос», место — конец секции, работа над ним — штурм.
|
||||
|
||||
Отвечается всё, но задача не делается одним заходом и не мерджится целиком →
|
||||
это **несколько задач под одной целью**, дроби сразу. Промежуточного зонтика
|
||||
между целью и задачей нет: тип `[epic]` упразднён, потому что зонтиком стала
|
||||
сама цель.
|
||||
это **несколько задач**, дроби сразу и ставь их в списке подряд. Промежуточного
|
||||
зонтика между планом и задачей нет: тип `[epic]` упразднён, и цель, ставшая
|
||||
зонтиком после него, упразднена тоже.
|
||||
|
||||
Тест применяется при заведении и при переоценке. К старым задачам, которых
|
||||
операция не касается, задним числом не применяется — беклог не переоформляют
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
# 🎯 `goal` — возможность приложения
|
||||
|
||||
Цель отвечает на **«что приложение будет уметь»**. Не область работ и не имя
|
||||
подсистемы: не «Работа со слиянием», а «Исход слияния не зависит от порядка
|
||||
доставки». Свойство поведения — тоже возможность.
|
||||
|
||||
Общая форма записи (мета, слаг, строка индекса) — [task-format.md](task-format.md).
|
||||
Здесь только то, что у этого типа своё.
|
||||
|
||||
## Схема
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| Заголовок отвечает на | что приложение будет уметь |
|
||||
| Обязательные разделы | `Завершение` |
|
||||
| Допустимые сверх того | — |
|
||||
| Поле места | **Секция** — часть роадмапа |
|
||||
| Цель (`goal:<слаг>`) | запрещена: цель и есть цель |
|
||||
| Индекс | `ROADMAP.md`, и никогда `BACKLOG.md` |
|
||||
| Берётся в работу | нет — берутся её задачи |
|
||||
|
||||
Поле места у цели называется **«Секция»**, а не «Категория», и это не разнобой:
|
||||
у задачи оно называет полку домена, на которой она лежит, а у цели
|
||||
— часть роадмапа, то есть состояние очереди. Одно имя на два смысла их и
|
||||
смешивало.
|
||||
|
||||
## «Завершение» — списком, а не абзацем
|
||||
|
||||
Это признаки того, что приложение **уже умеет**, и на строки этого раздела
|
||||
ссылаются задачи цели: «двигает пункт 2 «Завершения» — накопительная метрика
|
||||
перестаёт уменьшаться». Абзацем такая ссылка не берётся, поэтому список.
|
||||
|
||||
Отсюда же читается обратное и более полезное: **строка «Завершения», к которой
|
||||
не относится ни одна задача, — незакрытая часть возможности**. Достаточность
|
||||
набора задач видна из самой цели, а не из чьей-то памяти.
|
||||
|
||||
## Алгоритм
|
||||
|
||||
1. **Проверить, что это возможность, а не работа.** Работа, которой держат
|
||||
проект, на вопрос «что приложение будет уметь» не отвечает; состав перечислен
|
||||
[в словаре сопровождения](../../../shared/operations.md). Ей отведена секция
|
||||
`Сопровождение` — там она видна в том же
|
||||
экране и не читается как обещание продукта. Граница проходит по тому,
|
||||
**кто наблюдает**:
|
||||
«приложение сообщает о своём состоянии» — возможность, «дежурный видит
|
||||
состояние на одном экране» — сопровождение.
|
||||
2. **Выбрать секцию.** Очередь значима и обоснована прозой — `Запланировано`;
|
||||
тянется долго и очереди не имеет — `Направления`; про то, чем держат проект,
|
||||
— `Сопровождение`. В `Готово` кладёт сам `close`.
|
||||
3. **Написать «Завершение»** — 2–5 наблюдаемых признаков списком. Пишутся до
|
||||
декомпозиции: иначе задачи придумают себе цель задним числом.
|
||||
4. **Разложить на задачи** и проставить им `goal:<слаг>`. Перечень задач в теле
|
||||
цели **не хранится** — он был бы третьим индексом и поехал бы на первой же
|
||||
закрытой задаче; выводит `tasks.py list --goal <слаг>`.
|
||||
5. **Пометить `decomposed`.** Тег отличает «ещё не разобрана» от «все задачи
|
||||
закрыты» — два состояния с одним внешним признаком. `check --fix` ставит его
|
||||
сам цели, у которой задачи есть.
|
||||
6. **Закрыть достигнутой** — `close <слаг> --implemented`, когда не осталось
|
||||
открытых задач. Файл удаляется, строка с датой переезжает в `Готово`. Скрипт
|
||||
откажет, если задачи ещё живы.
|
||||
|
||||
## Отменённая цель — сперва задачи, потом цель
|
||||
|
||||
Замысел бывает неверен, и цель отменяют, не достигнув. Порядок обратный
|
||||
завершению и держится тем же запретом: цель, закрытая поверх живых задач,
|
||||
оставила бы их сиротами, и `close` этого не даст.
|
||||
|
||||
1. **Разобрать её задачи поштучно.** Задача, теряющая смысл вместе с целью, —
|
||||
`close <slug> --reason "<почему>"`; задача, переживающая цель, — `edit <slug>
|
||||
--goal <другая>`. **Причина обязательна и пишется своя каждой:** «цель
|
||||
отменена» это не причина, а пересказ команды, и в `REJECTED.md` от него нет
|
||||
пользы через квартал.
|
||||
2. **Закрыть саму цель** — `close <слаг> --reason "<почему замысел отменён>"`.
|
||||
Файл удаляется, строка с причиной и датой уходит в `REJECTED.md`. В `Готово`
|
||||
не попадает: `Готово` отвечает «что приложение умеет», а отменённая цель не
|
||||
умеет ничего.
|
||||
|
||||
**Место этому — груминг, а не отдельный заход.** Отмена цели значит
|
||||
разбор всех её задач, а разбор задач и есть шаг 3 груминга
|
||||
(скилл `task-groom`, «что перестало быть важным»). Отменять на ходу,
|
||||
между делом, — верный способ закрыть скопом то, что стоило перевесить.
|
||||
|
||||
## Что видит машина, а что человек
|
||||
|
||||
`check` считает цели, различает разобранные и пустые, ставит `decomposed`,
|
||||
запрещает закрыть цель с живыми задачами и держит `Секцию` в согласии с
|
||||
заголовком роадмапа. **Годность формулировки — не машине**: «возможность это или
|
||||
область работ» решает [агент вычитки](../SKILL.md#вычитка-два-прохода-а-не-один).
|
||||
|
||||
Достигнутая цель **не исчезает**: «что приложение умеет» — половина вопроса, ради
|
||||
которого роадмап открывают. Вторым домом поведения роадмап при этом не
|
||||
становится: нормативное поведение живёт в `openspec/specs/`, роадмап отвечает,
|
||||
**когда и в каком порядке** оно появилось.
|
||||
@@ -14,7 +14,6 @@
|
||||
| Обязательные разделы | `Вопрос`, `Куда ляжет ответ` |
|
||||
| Допустимые сверх того | `Рамки`, `Вопросы` |
|
||||
| Поле места | **Категория** — полка домена беклога |
|
||||
| Цель (`goal:<слаг>`) | нет |
|
||||
| Индекс | `BACKLOG.md` |
|
||||
| Берётся в работу | да — **но только с заполненным «Вопросом»** |
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@
|
||||
куда большей вероятностью, чем новая тема.
|
||||
|
||||
Адрес документа принадлежит одному скиллу, а называют его все: `docs/*` стоит
|
||||
примерно в сорока местах конвейера, `tasks/ROADMAP.md` — в четырёх местах
|
||||
примерно в сорока местах конвейера, `tasks/BACKLOG.md` — в нескольких местах
|
||||
канона. Переименование в каноне до этих мест не доходит.
|
||||
|
||||
**Почему тут нужна машина, а не аккуратность.** Прогон ревью умеет честно
|
||||
|
||||
Reference in New Issue
Block a user