задачи: цель упразднена, у проекта появилась стадия

Тип goal и индекс ROADMAP.md убраны: цель — зонтик над параллельными
направлениями, а у проекта на одного человека список работ линеен. Роадмап
при этом наполовину дублировал беклог, а «что уже умеет» отвечают спеки и
git log индекса. Секция «Готово» удалена, а не перенесена.

Вместо цели — ось «стадия проекта»: build (беклог это план стройки, порядок
строк значит зависимость, секция одна) и support (очередь правок, порядок
значит важность, секции — полки домена). Стадия объявляется ключом
[tasks] stage, меняется командой stage, без неё check отказывает: порядок
строк нечем прочитать.

Ушли теги goal:/decomposed, поле «Секция», раздел «Завершение», флаги
--goal и edit --section. Версия раскладки 2 → 3, перевод проекта расписан
записью журнала.
This commit is contained in:
av
2026-08-13 14:26:21 +03:00
parent 0627199a1a
commit 3849f084be
26 changed files with 1128 additions and 1485 deletions
+11 -2
View File
@@ -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
View File
@@ -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"
+8 -6
View File
@@ -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`, «Две
стадии».
**Граница с возможностями проходит по тому, кто наблюдает.** «Приложение
сообщает о своём состоянии» — возможность приложения, её место среди прочих
целей: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
секции роадмапа, и это верно — секции отвечают на разные вопросы.
задач: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в задачи
разных типов, и это верно — типы отвечают на разные вопросы.