av-dev-tasks: починены находки ревью, добавлена адаптация чужого репозитория
- атомарность: sprint drop и move собирают план правок целиком и пишут одним проходом; раньше отказ на втором слаге оставлял первый файл переписанным при нетронутом индексе - хук переехал в мета-строку файла: индекс стал производным, и check --fix больше не теряет текст, восстанавливая строку - механизировано то, что было записано, но не проверялось: слаг спринта и автотег, отказ по факту непустого раздела вопросов, число критериев, пометка decomposed, покрытие причин - reopen возвращает закрытую задачу: без него порядок «пайплайн доложил → приёмщик судит → владелец закрывает» был односторонним - скилл adopt: приходит в чужой репозиторий и выводит заполненный каталог задач. На копии беклога healthlog — 12 целей, 38 задач, 36 переименований, 86 ссылок в 36 файлах, check зелёный
This commit is contained in:
@@ -25,8 +25,11 @@ description: Ведение задач и целей как каталога mar
|
||||
2. **Файл — источник истины, индексы производны.** Разошлись — неправы индексы.
|
||||
Согласованность механизируема и проверяется командой, а не вниманием: всё,
|
||||
что ловит `tasks.py check`, не должно попадать ни в чек-лист, ни в промпт.
|
||||
Единственное исключение намеренное: **в каком индексе лежит задача, знают
|
||||
индексы** — «в спринте» это свойство спринта, а не файла, поля-состояния нет.
|
||||
Поэтому **хук живёт в мета-строке файла**, а строка индекса его лишь
|
||||
повторяет: пока хук лежал только в индексе, восстановление пропавшей строки
|
||||
теряло его молча и навсегда. Единственное исключение намеренное: **в каком
|
||||
индексе лежит задача, знают индексы** — «в спринте» это свойство спринта, а
|
||||
не файла, поля-состояния нет.
|
||||
3. **Причина переживает запись.** Выкинутая без причины задача вернётся через
|
||||
квартал тем же текстом. Реализованная оставляет след в коммите — выкинутая не
|
||||
оставляет ничего, поэтому у неё есть `REJECTED.md`.
|
||||
@@ -51,6 +54,15 @@ description: Ведение задач и целей как каталога mar
|
||||
подо что берут.** Цель в спринт взять нельзя, поэтому в списке берущихся ей не
|
||||
место.
|
||||
|
||||
**Секции «блокеры» в беклоге нет.** Блокер — это *состояние* (спринт не может
|
||||
продолжаться ни одной задачей), а не полка: он живёт ровно до ответа человека, и
|
||||
записи в такой секции не успевают жить. Следы блокера остаются вопросами в
|
||||
файлах задач распущенного спринта. Постоянно пустая секция со старой семантикой
|
||||
«разбираются пачками» противоречила бы правилу «блокер эскалируется немедленно»,
|
||||
поэтому `init` её заводить отказывается, а `check` о ней говорит. **Проекту,
|
||||
который переезжает с такой секцией, её надо удалить** — это единственное место,
|
||||
где это сказано.
|
||||
|
||||
**Задача живёт в одном индексе за раз.** Взята в спринт — строка переезжает из
|
||||
`BACKLOG.md` в `SPRINT.md`; вышла — обратно. Файл в `items/` при этом **не
|
||||
двигается**: он и есть запись, индексы лишь показывают, где она числится.
|
||||
@@ -77,8 +89,10 @@ description: Ведение задач и целей как каталога mar
|
||||
- **Статус цели выводится.** Цель закрыта, когда у неё не осталось открытых
|
||||
задач; `[x]`/`[~]` руками не ведутся, а `close` цели с живыми задачами
|
||||
скрипт запретит. Единственная оговорка: цель без задач неотличима — «ещё не
|
||||
декомпозирована» или «всё закрыто». Различает пометка «декомпозирована» в
|
||||
теле, проставляемая при переоценке.
|
||||
разобрана» или «всё закрыто». Различает **тег `decomposed`** в мета-строке
|
||||
цели: он ставится, когда цель разложена на задачи. Тег, а не строка в теле —
|
||||
потому что проверяется механически: `check` требует его у пустой цели, а
|
||||
`check --fix` сам проставляет его цели, у которой задачи есть.
|
||||
- **`[goal]` и `[epic]` — разные вещи.** Цель **постоянна**: живёт, пока живёт
|
||||
направление. Эпик **временен**: это задача, которая не мерджится целиком, её
|
||||
разбирают, и он исчезает. Два срока жизни под одним словом разъезжаются,
|
||||
@@ -86,21 +100,38 @@ description: Ведение задач и целей как каталога mar
|
||||
|
||||
## Инструмент (`tasks.py`)
|
||||
|
||||
Пусть `tk="$CLAUDE_PLUGIN_ROOT/skills/tasks/scripts/tasks.py"`.
|
||||
Пусть `tk="$CLAUDE_PLUGIN_ROOT/skills/tasks/scripts/tasks.py"`, а `D` — каталог
|
||||
задач проекта (см. «Переносимость»; `--dir` опускается только если каталог
|
||||
лежит в умолчаниях под текущим каталогом).
|
||||
|
||||
```
|
||||
python3 $tk check # согласованность всех индексов + здоровье, exit 1 при расхождениях
|
||||
python3 $tk check --fix # + починить безопасный дрейф (секция, заголовок, дубли)
|
||||
python3 $tk list [--stale] [--section S] [--type T] [--tag T] [--goal S] [--index …] [--questions]
|
||||
python3 $tk add --slug S --title T [--type goal|idea|epic] [--section S] [--goal G] [--hook H] [--tag a,b]
|
||||
python3 $tk edit S [--title T] [--hook H] [--type T] [--goal G] [--add-tag a,b] [--rm-tag c]
|
||||
python3 $tk move S --section S [--reason R] [--after S | --first]
|
||||
python3 $tk close S --reason R # в REJECTED.md + удалить (ушла без реализации)
|
||||
python3 $tk close S --implemented # просто удалить (реализована, есть коммит)
|
||||
python3 $tk sprint start --goal S | take S… | drop S… --reason R | close [--dissolve --reason R]
|
||||
python3 $tk init [--dir D] [--sections …] [--plan-sections …] [--items …] [--backlog …] …
|
||||
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] [--index …] [--questions]
|
||||
python3 $tk add --dir D --slug S --title T [--type goal|idea|epic] [--section S] [--goal G] [--hook H] [--tag a,b]
|
||||
python3 $tk edit S --dir D [--title T] [--hook H] [--type T] [--goal G] [--add-tag a,b] [--rm-tag c]
|
||||
python3 $tk move S --dir D --section S [--reason R] [--after S | --first]
|
||||
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 sprint start --goal S --dir D | take S… | drop S… --reason R | close [--dissolve --reason R]
|
||||
python3 $tk init --dir D [--sections …] [--plan-sections …] [--items …] [--backlog …] …
|
||||
python3 $tk adopt scan --from … | apply --plan … # разовая адаптация чужого репозитория, скилл adopt
|
||||
```
|
||||
|
||||
**Коды выхода — единый словарь; на нём ветвятся скиллы, а не на тексте вывода:**
|
||||
|
||||
| Код | Что случилось | Что делать |
|
||||
| --- | --- | --- |
|
||||
| 0 | сошлось / сделано | дальше по сценарию |
|
||||
| 1 | **только `check`:** найден дрейф индексов и файлов | `check --fix`, остаток разобрать |
|
||||
| 2 | ошибка употребления: аргументы или нарушенное правило | читать сообщение, это отказ по существу |
|
||||
| 3 | окружение: каталог не найден, конфиг битый или мимо диска | чинится путём или `.tasks.json`, повтор не поможет |
|
||||
| 4 | внутренний сбой | дефект скрипта, доложить |
|
||||
|
||||
Различать 1 и 3 обязательно: «дрейф в беклоге» — рабочая ситуация, «каталога
|
||||
нет» — нерабочая, и одинаковая реакция на них была бы неверна в обоих случаях.
|
||||
|
||||
Тип — английское ключевое слово `goal` / `idea` / `epic` / `task` (как и прочие
|
||||
токены команд); `task` префикса не несёт, остальные кодируются `[goal]`/
|
||||
`[idea]`/`[epic]` в заголовке. Текст задачи при этом русский.
|
||||
@@ -109,16 +140,40 @@ python3 $tk init [--dir D] [--sections …] [--plan-sections …] [--items …]
|
||||
не пиши, зови `add`/`edit`/`move`/`close`/`sprint`. Смена заголовка, хука, типа,
|
||||
цели и **тегов** — это `edit`: он держит H1, мета-строку и индекс в синхроне.
|
||||
Снятие тега — `--rm-tag` (после ответа на вопрос снимается `question`), смена
|
||||
цели — `--goal`, он заменяет прежний `goal:*`. Тело задачи скрипт не трогает:
|
||||
цели — `--goal`, он заменяет прежний `goal:*`.
|
||||
|
||||
**Переезд между индексами — следствие смены типа, а не отдельная команда.**
|
||||
`edit <slug> --type goal --section <часть плана>` переносит строку из
|
||||
`BACKLOG.md` в `PLAN.md` (и обратно `--type task --section <секция беклога>`);
|
||||
`move` двигает только внутри одного индекса и пишет причину. `--section` у
|
||||
`edit` работает **только** при таком переезде — иначе он отсылает к `move`,
|
||||
потому что смена секции без причины и есть тот дрейф, который потом никто не
|
||||
объяснит. Задача в наборе спринта тип не меняет вовсе: сперва `sprint drop`.
|
||||
|
||||
Тело задачи скрипт не трогает:
|
||||
`add` кладёт заголовок, мета-строку и шаблон с подсказками, тело дописываешь
|
||||
редактором (пока плейсхолдер на месте, `check` напоминает).
|
||||
|
||||
`check` — единственный судья согласованности; что именно он ловит, скажет его
|
||||
вывод, здесь не пересказываем. Гоняй его **в начале сессии** и **после каждой
|
||||
правки**, даже если правил мутациями: дрейф мог накопиться раньше. Накопившееся
|
||||
чини `check --fix` — он детерминированно правит безопасное, а неоднозначное
|
||||
(ссылка на исчезнувший файл, задача сразу в двух индексах) выносит тебе. Это
|
||||
идёт строкой доклада.
|
||||
чини `check --fix` — он детерминированно правит то, где истина однозначна
|
||||
(секция, заголовок, дубли, хук из индекса в файл, строка в чужом индексе,
|
||||
пометка `decomposed` у цели с задачами), а неоднозначное (ссылка на исчезнувший
|
||||
файл, задача сразу в двух индексах) печатает отдельной пометкой
|
||||
`НЕОДНОЗНАЧНО` — это тебе, и это идёт строкой доклада.
|
||||
|
||||
`--fix` правит **и файлы** — ровно в двух местах, где источник ровно один и
|
||||
выбирать не из чего: хук, оставшийся только в индексе, переезжает в мета-строку,
|
||||
и цель, у которой есть задачи, получает тег `decomposed`. Оба случая печатаются
|
||||
поимённо.
|
||||
|
||||
**Что механизировано, а что нет.** Критерии приёмки проверяются у задачи, взятой
|
||||
в набор (`sprint take` и `check` по задачам спринта): число пунктов — жёстко
|
||||
(меньше двух — отказ, больше пяти — замечание), наличие оракула — **эвристикой**
|
||||
по слову «оракул» в пункте. Настоящий оракул от слова «оракул» машина не
|
||||
отличает, поэтому эвристика даёт только замечание, и в докладе это называется
|
||||
как есть: «проверено число пунктов, годность оракулов — глазами».
|
||||
|
||||
Формат файла, мета-строки, слага, индексов и `REJECTED.md` —
|
||||
[references/task-format.md](references/task-format.md). Там же тест «готова к
|
||||
@@ -162,6 +217,13 @@ python3 $tk init [--dir D] [--sections …] [--plan-sections …] [--items …]
|
||||
пользователю до создания файлов. Порядок, отображение серьёзности и привязка к
|
||||
целям — [references/from-review.md](references/from-review.md).
|
||||
|
||||
### Прийти в репозиторий, где задачи уже как-то ведутся
|
||||
|
||||
Разовая операция: вывести каталог задач из старой раскладки беклога, `TODO.md`,
|
||||
заметок или списка шагов в плане — скилл `adopt`. Сюда же относится
|
||||
переименование транслитных слагов в английские: оно делается **одним проходом
|
||||
вместе с починкой перекрёстных ссылок**, а не по одному слагу.
|
||||
|
||||
### Декомпозиция и штурм идеи
|
||||
|
||||
[references/split.md](references/split.md). Обе операции превращают одну запись в
|
||||
@@ -175,7 +237,8 @@ python3 $tk init [--dir D] [--sections …] [--plan-sections …] [--items …]
|
||||
|
||||
- **протухший хук** — задача изменилась, а хук отвечает на старый вопрос;
|
||||
особенно после ответа на вопрос задачи: «Решено: …» на «почему это лежит в
|
||||
беклоге» уже не отвечает, хук переписывается;
|
||||
беклоге» уже не отвечает. Переписывается `edit <slug> --hook …` — он правит
|
||||
мета-строку файла и строку индекса заодно;
|
||||
- **вопрос, застрявший в прозе** — вынимается в раздел «Вопросы» плюс тег
|
||||
`question` (`edit --add-tag question`), иначе он не виден ни `list
|
||||
--questions`, ни правилу «задача с открытым вопросом в набор не берётся»;
|
||||
@@ -188,6 +251,40 @@ python3 $tk init [--dir D] [--sections …] [--plan-sections …] [--items …]
|
||||
такой-то агент»: это второй дом для правила выбора и путь понизить требования
|
||||
решением, принятым до проектирования. Снимается.
|
||||
|
||||
## Переносимость
|
||||
|
||||
Скилл независим от **языка программирования, сборки, CI и трекера**: он ничего
|
||||
не знает ни про Go, ни про npm, ни про конкретный багтрекер — задачи для него
|
||||
просто каталог markdown. Текст задач — русский (язык документации проекта);
|
||||
зашита только латиница слага.
|
||||
|
||||
- **Каталог задач** ищется цепочкой: `--dir` → **указатель в `CLAUDE.md`
|
||||
проекта** (его читаешь ты и передаёшь `--dir`; скрипт чужую документацию не
|
||||
разбирает) → `.tasks.json` вверх от текущего каталога → умолчания
|
||||
(`docs/tasks`, `tasks`, `doc/tasks`) вверх от текущего каталога, до корня
|
||||
репозитория. Не нашлось — код 3 и вопрос человеку, а не догадка: `init`
|
||||
заводит каталог **только** когда проект действительно новый.
|
||||
**В примерах `--dir` стоит намеренно:** каталог вне умолчаний иначе не
|
||||
находится, а вызов из подкаталога — обычное дело.
|
||||
- **Секции беклога** берутся из заголовков `##` индекса как есть; их количество
|
||||
и названия — дело проекта (умолчание `ядро` / `инфра`).
|
||||
- **Имена индексов и подкаталога** — параметры `init`, живут в
|
||||
`<tasks>/.tasks.json`. Ничего не зашито именем файла.
|
||||
|
||||
### Вызов из другого плагина
|
||||
|
||||
`$CLAUDE_PLUGIN_ROOT` раскрывается **только внутри своего плагина**: чужой
|
||||
контекст — пайплайн задачи, конвейер ревью, любой другой скилл — до `tasks.py`
|
||||
по этой переменной не дотянется. Поэтому контракт такой:
|
||||
|
||||
> **Проект называет команду учёта задач в своём `CLAUDE.md`** — целиком, готовой
|
||||
> к запуску строкой (слот 6 ниже). Вызывающий берёт её оттуда. Слота нет —
|
||||
> вызывающий **не выдумывает путь и не правит индекс руками**, а сообщает в
|
||||
> докладе, что закрытие/заведение остаётся за владельцем задач.
|
||||
|
||||
Так вызывающему не нужно знать ни про плагин, ни про его расположение: он знает
|
||||
проект, а проект знает команду.
|
||||
|
||||
## Слоты проекта
|
||||
|
||||
Скилл не знает ни языка программирования, ни сборки, ни CI, ни трекера — задачи
|
||||
@@ -207,6 +304,16 @@ python3 $tk init [--dir D] [--sections …] [--plan-sections …] [--items …]
|
||||
(деплой, выкладка наружу, удаление или перезапись данных).
|
||||
5. **Оракулы, которые в проекте вообще есть** — чем проверяется критерий
|
||||
приёмки: тест, команда, прогон на реальных данных, глазами по логу.
|
||||
6. **Команда учёта задач** — готовая строка, которой чужой контекст зовёт
|
||||
`tasks.py`, потому что путь к плагину ему неизвестен. Например:
|
||||
|
||||
```
|
||||
Команда учёта задач: python3 ~/.claude/plugins/marketplaces/av-dev-skills/\
|
||||
av-dev-tasks/skills/tasks/scripts/tasks.py --dir docs/tasks
|
||||
```
|
||||
|
||||
Слот заполняется один раз при подключении плагина. Он же отвечает на вопрос
|
||||
«кто закрывает задачу»: команду знает проект, зовёт её владелец спринта.
|
||||
|
||||
Ничего из этого скилл не угадывает: не нашёл — спрашивает пользователя, а не
|
||||
подставляет умолчание.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
```markdown
|
||||
# Тай-брейк при равной полноте
|
||||
|
||||
**Секция:** ядро — вышла из спринта: остаток писал нерешённое в журнал · **Теги:** goal:merge-robustness, sprint:2026-08
|
||||
**Секция:** ядро — вышла из спринта: остаток писал нерешённое в журнал · **Хук:** порядок канонических форм берёт меньшее в 96% случаев — для накопительных это систематический недосчёт · **Теги:** goal:merge-robustness, sprint:2026-08-03
|
||||
|
||||
При столкновении точек выигрывает более полная, но при равной полноте побеждает
|
||||
последняя доставка — а она систематически беднее первой.
|
||||
@@ -35,9 +35,14 @@
|
||||
префикс виден прямо в индексе, где и принимается решение «брать или не брать».
|
||||
- **Мета-строка** — первая непустая строка после заголовка. Обязательна секция,
|
||||
причина после тире желательна (именно она объясняет, почему задача здесь
|
||||
оказалась — в том числе «вышла из спринта: …»), теги опциональны. Поля
|
||||
оказалась — в том числе «вышла из спринта: …»), хук и теги опциональны. Поля
|
||||
разделяются ` · `, порядок свободный. `·` — служебный разделитель: в тексте
|
||||
причины его быть не должно.
|
||||
причины и хука его быть не должно.
|
||||
- **Хук живёт здесь, а не только в индексе.** Строка индекса его повторяет и
|
||||
производна от него: `check` сверяет, `check --fix` восстанавливает пропавшую
|
||||
строку **вместе с хуком**. Пока хук лежал только в индексе, штатная починка
|
||||
дрейфа теряла его молча и навсегда — а хук это единственное, по чему задачу
|
||||
выбирают, не открывая.
|
||||
- **Тело** — одна фраза «что станет наблюдаемо иначе», критерии приёмки, рамки,
|
||||
контекст, ссылки. Пишется на языке документации проекта.
|
||||
|
||||
@@ -46,11 +51,18 @@
|
||||
|
||||
### Критерии приёмки
|
||||
|
||||
2–5 проверяемых утверждений, **у каждого назван оракул**. Не «работает
|
||||
корректно», а «повторный прогон даёт тот же отпечаток — оракул: команда сверки».
|
||||
Это не второе определение готовности, а проектная конкретизация вопроса «по чему
|
||||
видно, что закончено» из теста готовности ниже: там сказано «признак
|
||||
завершённости», здесь — «признак плюс чем проверяется».
|
||||
2–5 проверяемых утверждений **списком** `- …`, **у каждого назван оракул**. Не
|
||||
«работает корректно», а «повторный прогон даёт тот же отпечаток — оракул:
|
||||
команда сверки». Это не второе определение готовности, а проектная
|
||||
конкретизация вопроса «по чему видно, что закончено» из теста готовности ниже:
|
||||
там сказано «признак завершённости», здесь — «признак плюс чем проверяется».
|
||||
|
||||
**Что из этого механизировано.** `check` и `sprint take` считают пункты: меньше
|
||||
двух — отказ («— работает» одной строкой больше не проходит), больше пяти —
|
||||
замечание, обычно это признак, что задача крупнее задачи. Наличие оракула
|
||||
проверяется **эвристикой** — словом «оракул» в пункте, — и потому даёт только
|
||||
замечание: настоящий оракул от слова «оракул» машина не отличает, и делать вид,
|
||||
что проверено больше проверенного, хуже, чем не проверять вовсе.
|
||||
|
||||
**У идей критериев нет — именно поэтому они идеи.**
|
||||
|
||||
@@ -71,9 +83,14 @@
|
||||
### Вопросы
|
||||
|
||||
Неразобранное решение человека живёт разделом `## Вопросы` **плюс тегом
|
||||
`question`**. Тег — то, по чему вопрос виден снаружи файла (`list --questions`) и
|
||||
чем работает правило «задача с открытым вопросом в набор не берётся». Раздел без
|
||||
тега или тег без раздела — дрейф, `check` о нём скажет.
|
||||
`question`**. Раздел без тега или тег без раздела — дрейф, `check` о нём скажет.
|
||||
|
||||
**Судит факт, а не метка.** Отказ во взятии даёт **непустой раздел «Вопросы»**,
|
||||
независимо от того, стоит ли тег: иначе забывший тег проходил бы, а поставивший
|
||||
спотыкался — стимул ровно обратный записанному правилу. Тег производен: он нужен
|
||||
отбору снаружи файла (`list --questions`, `list --tag question`), и его
|
||||
отсутствие при непустом разделе — замечание, а не лазейка. Тег без раздела тоже
|
||||
отказ, но с другим советом: либо вопрос записан не туда, либо тег пора снять.
|
||||
|
||||
Ответ записывается в тело, тег снимается `edit <slug> --rm-tag question`, а хук
|
||||
переписывается: «Решено: …» на вопрос «почему это лежит в беклоге» уже не
|
||||
@@ -98,10 +115,12 @@
|
||||
- **Задачи цели здесь не перечисляются.** Перечень даёт
|
||||
`tasks.py list --goal <слаг>`; хранимый список стал бы третьим индексом и
|
||||
поехал бы на первой же закрытой задаче.
|
||||
- **Раздел «Завершение»** — то, по чему видно, что цель достигнута. Он же
|
||||
отличает «цель ещё не декомпозирована» от «все её задачи закрыты»: пометка
|
||||
вроде тега `decomposed` или строки в теле ставится, когда цель разложена на
|
||||
задачи.
|
||||
- **Раздел «Завершение»** — то, по чему видно, что цель достигнута.
|
||||
- **Тег `decomposed`** отличает «цель ещё не разобрана» от «все её задачи
|
||||
закрыты» — два состояния, у которых снаружи один и тот же признак: задач нет.
|
||||
Пометка именно **тегом**, а не строкой в теле: только так она проверяется.
|
||||
`check` требует его у цели без задач, `check --fix` сам ставит его цели, у
|
||||
которой задачи есть, а цель с тегом и без задач — прямое приглашение закрыть.
|
||||
- Цель живёт в `PLAN.md` и **никогда** — в `BACKLOG.md` или `SPRINT.md`.
|
||||
|
||||
## Слаг
|
||||
@@ -137,13 +156,27 @@
|
||||
|
||||
Секции — **единственные заголовки `##` в индексе**: любой другой `##` в
|
||||
преамбуле проверка сочтёт секцией. Внутри секции беклога порядок значения не
|
||||
имеет — порядка в беклоге нет вовсе. В **линии** плана порядок значим и
|
||||
имеет — порядка в беклоге нет вовсе.
|
||||
|
||||
**Секции «блокеры» среди них нет.** Блокер — состояние, а не полка: он живёт до
|
||||
ответа человека, а следы остаются вопросами в файлах задач распущенного спринта.
|
||||
Постоянно пустая секция со старой семантикой «разбираются пачками» противоречила
|
||||
бы правилу «эскалируем немедленно», поэтому `init` её не заводит, а `check`
|
||||
говорит о ней в чужом беклоге. Переезжаешь с такой секцией — удали её. В **линии** плана порядок значим и
|
||||
обосновывается прозой; двигают строку `move <slug> --section линия --after
|
||||
<другой>`.
|
||||
|
||||
Индексы **производны**: расходятся с файлом — правим индексы (`check --fix`).
|
||||
Строку руками не пишут.
|
||||
|
||||
Отсюда же ответ на «а если оборвётся посередине». Мутация сперва проверяет всё
|
||||
и складывает правки, и только потом пишет: сначала все временные файлы, потом
|
||||
переименования подряд. Полной транзакции на несколько файлов файловая система не
|
||||
даёт, но окно сжато до цепочки переименований, а **всё, что в нём может
|
||||
разъехаться, — производное**: файлы целы, индексы восстанавливает `check --fix`.
|
||||
Поэтому отказ на второй задаче из пяти не оставляет первую переписанной при
|
||||
нетронутых индексах.
|
||||
|
||||
`SPRINT.md` и есть артефакт заморозки: без него набор существует только в
|
||||
контексте сессии, и нарушение заморозки ненаблюдаемо.
|
||||
|
||||
@@ -174,7 +207,16 @@
|
||||
попадёт ни в один спринт.
|
||||
- `question` — в файле есть неразобранный раздел «Вопросы».
|
||||
- `sprint:<слаг>` — задача заведена в этом спринте; по нему отбирается первая
|
||||
порция разбора («урожай спринта»).
|
||||
порция разбора («урожай спринта»). **Ставится сам**: слаг спринта заводит
|
||||
`sprint start` (по умолчанию — дата начала, он же пишется в `SPRINT.md`), и
|
||||
`add` при открытом спринте помечает заводимое. Тег, который надо помнить
|
||||
ставить руками, не ставится никогда — а на нём висит правило «первая порция
|
||||
разбора — урожай прошедшего спринта».
|
||||
- `decomposed` — на цели: разложена на задачи (см. «Файл цели»).
|
||||
|
||||
Отбор — `list --tag a,b`: перечисленные через запятую теги требуются **все
|
||||
сразу** (это И, не ИЛИ). Тег, которого нет ни у одной задачи, `list` называет
|
||||
вслух: молчаливый ноль читается как «таких задач нет», а чаще это опечатка.
|
||||
|
||||
Свои теги проект заводит свободно (партия ревью `review-ГГГГ-ММ-ДД`, тема,
|
||||
источник) — словарь не фиксирован. В индексы теги не выносим: индексы
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user