секции PLAN.md: «линия» и «кусты» стали «порядком» и «темами»

Метафора требовала расшифровки при каждом употреблении, и в текстах она и
расшифровывалась: «звено упорядоченной линии продукта», «тематический куст —
цель, в последовательность не встающая». Если название приходится объяснять
рядом с каждым употреблением, объясняет не название.

Новые имена называют ровно то свойство, которым секции различаются: в первой
очередь значима и обоснована прозой, во второй порядка нет вовсе.

Заголовки строчные, как ядро/инфра в беклоге: имя секции одновременно значение
для --section, и проза приведена к тому же виду, чтобы «--section Порядок» не
выглядело правильным написанием.

Версия канона не меняется: canon.md называет файл PLAN.md и о его секциях не
говорит — их дом заголовки ## индекса, умолчание живёт в tasks.py.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-08-03 17:14:37 +03:00
co-authored by Claude Opus 5
parent eb10aa4177
commit 5b80ac8ff9
9 changed files with 66 additions and 35 deletions
+6 -6
View File
@@ -48,7 +48,7 @@ description: Ведение задач и целей как каталога mar
```
docs/tasks/
items/ задачи и цели файлами, <slug>.md, слаги английские
PLAN.md оглавление целей: линия (упорядоченная) и кусты
PLAN.md оглавление целей: порядок (значим) и темы (без порядка)
BACKLOG.md что можно взять — только задачи, целей здесь нет
SPRINT.md текущий спринт: цель, набор, дата
REJECTED.md ушедшее БЕЗ реализации, с причиной и датой
@@ -80,10 +80,10 @@ docs/tasks/
## Цели
**Цель — такой же файл в `items/`, тип `[goal]`**, перечисленный в `PLAN.md`:
либо звено упорядоченной **линии** продукта (с обоснованием порядка прозой),
либо тематический **куст** — цель, в последовательность не встающая («прочность
слияния», «журнал и пересборка»). Без второй части половина целей была бы нигде
не перечислена: находки ревью не служат ничему из линии.
либо цель из секции **порядок** — там очередь значима и обоснована прозой, — либо
**тематическая**, в порядок не встающая («прочность слияния», «журнал и
пересборка»). Без второй секции половина целей была бы нигде не перечислена:
находки ревью не служат ничему из порядка.
- **Список задач цели выводится, а не хранится.** В теле цели — зачем она и что
считается её завершением; перечня задач там нет. Он был бы третьим индексом и
@@ -205,7 +205,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
работа — цель (`--type goal`).
4. **Цель задачи.** У каждой задачи должен быть `--goal <слаг>`: задача вне цели
не попадёт ни в один спринт. Подходящей цели нет — либо она заводится
(`--type goal` кустом), либо это сигнал, что задача никому не служит и
(`--type goal` в «темы»), либо это сигнал, что задача никому не служит и
заводить её не надо. У идеи цели может не быть — она проставляется, когда
идея становится задачей.
5. `add …`, затем допиши тело редактором: одна фраза, критерии приёмки с
+6 -6
View File
@@ -53,9 +53,9 @@ python3 $tk adopt apply --plan tasks-adopt-plan.json \
- **английские слаги.** Перевести `taj-brejk-pri-ravnoj-polnote` в
`tie-break-equal-completeness` может только тот, кто понимает смысл. `scan`
честно говорит: проверить надо **все** слаги, признаки транслита — эвристика;
- **цели.** Шаги плана — готовые цели **линии** (порядок и обоснование у них уже
есть); тематические скопления задач — **кусты** («прочность слияния», «журнал
и пересборка»). Предлагаешь ты, назначает человек;
- **цели.** Шаги плана — готовые цели из **«порядка»** (очередь и обоснование у
них уже есть); тематические скопления задач — **«темы»** («прочность слияния»,
«журнал и пересборка»). Предлагаешь ты, назначает человек;
- **что вообще не задача.** Обоснование порядка шагов, абзац прозой, заголовок
раздела — это не пункты беклога, и они уходят в «не разложилось» с причиной.
@@ -69,11 +69,11 @@ python3 $tk adopt apply --plan tasks-adopt-plan.json \
2. **`adopt scan`** по всем источникам разом. Один прогон, одна карта: два
прохода дадут два несогласованных состояния.
3. **Заполни карту**: `slug` (английский), `section`, `goal` у каждой записи;
список `goals` — из шагов плана и из кустов. Закрытый шаг плана целью не
список `goals` — из шагов плана и из тем. Закрытый шаг плана целью не
заводится. Пустой `goal` — законный исход только у идеи.
4. **Покажи человеку карту** через `AskUserQuestion`, ≤3 вопроса за итерацию,
рекомендация первым вариантом. Показывается: сколько записей, предлагаемые
цели (линия и кусты) с обоснованием, спорные отнесения, список «не
цели (порядок и темы) с обоснованием, спорные отнесения, список «не
разложилось». Массовые механические решения (слаги, порядок строк) не
выносятся — это механика.
5. **`adopt apply`.** `--refs` перечисляет **всё**, где могут стоять ссылки на
@@ -113,7 +113,7 @@ take` такую задачу не возьмёт). Закрывается эт
## Доклад
- Источники и что в каждом распознано (раскладка, индекс, кладбище, секции).
- Сколько записей перенесено, сколько целей заведено (линия / кусты) и откуда
- Сколько записей перенесено, сколько целей заведено (порядок / темы) и откуда
каждая выведена.
- **Переименования**: сколько слагов, сколько ссылок поправлено и в скольких
файлах — числом, а не «поправлены ссылки».
@@ -42,9 +42,9 @@
существующий файл. Нашлось в `REJECTED.md` — это сигнал: причина отказа могла
устареть, выноси пользователю, а не заводи молча заново.
4. **Разложи по целям.** У каждой заводимой задачи должен быть `goal:<слаг>`.
Половина находок ревью не служит ничему из линии продукта — их цель это
**куст** («прочность слияния», «журнал и пересборка», «наблюдаемость»).
Подходящего куста нет — заведи его целью (`add --type goal --section кусты`)
Половина находок ревью не служит ничему из порядка — их цель **тематическая**
(«прочность слияния», «журнал и пересборка», «наблюдаемость»).
Подходящей темы нет — заведи её целью (`add --type goal --section темы`)
в том же проходе: без цели задача не попадёт ни в один спринт, а значит не
будет сделана никогда.
5. **Покажи карту до создания файлов.** Кластер → задача / идея / строка в
@@ -107,7 +107,7 @@
```markdown
# [goal] Прочность слияния
**Секция:** кусты · **Теги:** decomposed
**Секция:** темы · **Теги:** decomposed
Ради чего: точки из разных доставок сходятся в один часовой объект, и сегодня
исход столкновения зависит от порядка доставки, а не от содержания.
@@ -156,7 +156,7 @@
| Файл | Что отвечает | Секции |
| --- | --- | --- |
| `PLAN.md` | какие есть цели, в каком порядке идёт линия и почему | линия (упорядоченная) и кусты |
| `PLAN.md` | какие есть цели, в какой очереди идут и почему | порядок (очередь значима) и темы (порядка нет) |
| `BACKLOG.md` | что **можно взять** — только задачи | секции проекта (по умолчанию ядро/инфра) |
| `SPRINT.md` | какая цель и какой набор под неё | одна: «Набор» |
| `REJECTED.md` | что ушло без реализации и почему | — |
@@ -169,9 +169,9 @@
ответа человека, а следы остаются вопросами в файлах задач распущенного спринта.
Постоянно пустая секция со старой семантикой «разбираются пачками» противоречила
бы правилу «эскалируем немедленно», поэтому `init` её не заводит, а `check`
говорит о ней в чужом беклоге. Переезжаешь с такой секцией — удали её. В **линии** плана порядок значим и
обосновывается прозой; двигают строку `move <slug> --section линия --after
<другой>`.
говорит о ней в чужом беклоге. Переезжаешь с такой секцией — удали её. В секции
**«порядок»** очередь значима и обосновывается прозой; двигают строку
`move <slug> --section порядок --after <другой>`.
Индексы **производны**: расходятся с файлом — правим индексы (`check --fix`).
Строку руками не пишут.
+7 -7
View File
@@ -12,7 +12,7 @@ av-dev, и подгоняется под него проект. Имена вн
docs/tasks/
items/ задачи и цели файлами, <slug>.md
PLAN.md оглавление целей: линия (упорядоченная) и кусты
PLAN.md оглавление целей: порядок (значим) и темы (без порядка)
BACKLOG.md что можно взять — только задачи, целей здесь нет
SPRINT.md текущий спринт: цель, набор, дата, слаг
REJECTED.md ушедшее БЕЗ реализации, с причиной и датой
@@ -110,7 +110,7 @@ DEFAULTS = {
PATH_KEYS = ("items", "backlog", "plan", "sprint", "rejected")
DEFAULT_SECTIONS = "ядро,инфра"
DEFAULT_PLAN_SECTIONS = "линия,кусты"
DEFAULT_PLAN_SECTIONS = "порядок,темы"
META_FIELD = re.compile(r"^\*\*(.+?):\*\*\s*(.*)$")
INDEX_ENTRY = re.compile(r"^- \[(.+?)\]\((.+?\.md)\)\s*(?:—\s*(.*))?$")
@@ -1838,8 +1838,8 @@ def init_files(lay: Layout, sections: list[str], plan_sections: list[str],
"# План\n\n"
f"Оглавление целей. Цель — файл `[goal]` в `{lay.cfg['items']}/`; её задачи\n"
"здесь **не перечисляются** — перечень даёт `tasks.py list --goal <слаг>`.\n"
f"Первая секция{plan_sections[0]}») упорядочена, и порядок обосновывается\n"
"прозой; остальные — тематические кусты без порядка.\n\n"
f"В первой секции{plan_sections[0]}») очередь значима и обосновывается\n"
"прозой; в остальных порядка нет — это тематические цели.\n\n"
+ "".join(f"## {s}\n\n" for s in plan_sections))
out[lay.index("sprint")] = empty_sprint(lay)
out[lay.index("rejected")] = (
@@ -1976,8 +1976,8 @@ STEP = re.compile(r"^\**\s*(\d+)[.)]\s*\**\s*(.+?)\**\s*$")
def scan_list_file(path: Path) -> dict:
"""TODO.md, «планы» в README, список шагов в плане проекта.
**Нумерованный шаг плана → кандидат в цель линии** (готовая цель: у него уже
есть порядок и обоснование), прочий пункт списка → кандидат в задачу. Ничего
**Нумерованный шаг плана → кандидат в цель из «порядка»** (готовая цель: у
него уже есть очередь и обоснование), прочий пункт → кандидат в задачу. Ничего
не решает: и то и другое едет в карту предложением, назначает человек.
"""
found: dict = {"kind": "list-file", "source": str(path), "items": [],
@@ -2043,7 +2043,7 @@ def cmd_adopt_scan(a: argparse.Namespace) -> int:
rejected += sc.get("rejected", [])
unclassified += sc.get("unclassified", [])
goals += [{"slug": "", "title": g["title"],
"section": (a.plan_sections.split(",")[0].strip() or "линия"),
"section": (a.plan_sections.split(",")[0].strip() or "порядок"),
"from": g["from"], "step": g.get("step"), "done": g.get("done"),
"body": f"Выведена из шага «{g['title']}» ({g['from']})."
+ ("\n\nШаг помечен закрытым — цель, скорее всего,"