av-dev-pm расколот на av-dev-docs и av-dev-tasks

Плагин владел двумя разными вещами сразу — документацией проекта и учётом работ,
— и это мешало обеим. Канон нельзя было поставить без задач, задачи без канона, а
язык проектных текстов лежал внутри скилла canon и потому принадлежал половине.
Теперь плагина два, каждый ставится сам по себе.

av-dev-docs: скиллы canon, docs, init; агенты doc-consistency, doc-code-drift,
doc-wording; скрипт docs.py. av-dev-tasks: скиллы tasks, session; агенты
task-form, task-wording; скрипт tasks.py.

Между собой они зовутся через пространство имён, а не по пути в чужое дерево.
Все относительные ссылки, пересекшие границу плагина, сняты: tasks больше не
указывает в canon, canon не указывает в tasks. Вместо ссылки — имя скилла и
оговорка, что вызов может не разрешиться, и это исход, а не поломка.

То, что нужно обоим дословно, стало вторым общим домом. Словарь «Сопровождение и
эксплуатация» назван в трёх местах трёх плагинов — секция роадмапа, раздел
«Эксплуатация» в architecture.md, тема ревью operations — и ни один из трёх им не
владеет; он уехал в shared/operations.md, а canon.md и скилл задач везут копии.
Три перечня «чем держат проект» уже разъезжались на «метриках и логах» против
«мониторинга», так что ссылка тут не годится: плагин, поставленный в одиночку,
получил бы указатель в никуда. Тем же способом язык: у av-dev-tasks появилась
своя копия language.md.

Копий стало 18 при 8 домах.

Переименования разведены по смыслу, а не заменой строки: где речь о каноне —
av-dev-docs, где об учёте задач — av-dev-tasks. В пайплайне таких мест
одиннадцать, и оба адресата там встречаются вперемешку.

Журналы (DECISIONS, TODO, HISTORY) намеренно не тронуты: они описывают состояние
на момент записи. По той же причине оставлена наблюдённая строка в комментарии
docs.py — она цитирует конфиг живого проекта, а не называет плагин.

Не входит в этот заход и названо отдельно: слияние canon и docs в один скилл,
разделение docs/.pm.json на два конфига и переезд openspec в пайплайн.

Гейт зелёный: копии, фронтматтеры, диаграммы, json. Оба скрипта прогнаны после
переезда — docs.py version и tasks.py check на фикстуре.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-08-09 14:06:26 +03:00
co-authored by Claude Opus 5
parent 86e22d932c
commit 00ddfb0dde
42 changed files with 417 additions and 97 deletions
+9 -4
View File
@@ -6,14 +6,19 @@
}, },
"plugins": [ "plugins": [
{ {
"name": "av-dev-pm", "name": "av-dev-docs",
"source": "./av-dev-pm", "source": "./av-dev-docs",
"description": "Управление продуктом: канон документов проекта, задачи и цели вместо приоритетов, спринт под одну цель с заморозкой набора, старт проекта интервью по брифу и приведение существующего к канону. Ничего не выполняет сам и никакого пайплайна не требует: задача выполняется чем угодно, а канон описывает документы, из которых конвейер ревью берёт проектную конкретику." "description": "Документация проекта: канон раскладки docs/ и CLAUDE.md, роли документов, правило единственного дома. check / adopt / upgrade со скриптом docs.py, старт проекта интервью по брифу, ведение содержимого по ходу разработки. Ничего не выполняет сам и никакого пайплайна не требует."
},
{
"name": "av-dev-tasks",
"source": "./av-dev-tasks",
"description": "Задачи и цели каталогом markdown-файлов, у каждой записи тип, и тип задаёт её схему. Спринт под одну цель, ритуал между спринтами, проверка согласованности скриптом tasks.py. Задача выполняется чем угодно: пайплайна плагин не требует и сам его не зовёт."
}, },
{ {
"name": "av-dev-pipeline", "name": "av-dev-pipeline",
"source": "./av-dev-pipeline", "source": "./av-dev-pipeline",
"description": "Проведение задачи через цикл SDD и конвейер ревью с обязательным триажем, плюс прогон нескольких задач разом. Требует OpenSpec. Задача принимается и обычным текстом; плагин av-dev-pm опционален — он даёт документы канона для проходов ревью и учёт задач, без него прогон деградирует поразрядно и говорит об этом." "description": "Проведение задачи через цикл SDD и конвейер ревью с обязательным триажем, плюс прогон нескольких задач разом. Требует OpenSpec. Задача принимается и обычным текстом; плагины av-dev-docs и av-dev-tasks опциональны — первый даёт документы канона для проходов ревью, второй учёт задач, без них прогон деградирует поразрядно и говорит об этом."
}, },
{ {
"name": "av-dev-git", "name": "av-dev-git",
+28 -15
View File
@@ -9,7 +9,7 @@
## Плагины ## Плагины
- **av-dev-pm** — управление продуктом. Владеет всем `docs/`. - **av-dev-docs** — документация проекта. Владеет `docs/` и `CLAUDE.md`.
- `init` — новый проект: интервью по свободному описанию замысла → первичная - `init` — новый проект: интервью по свободному описанию замысла → первичная
документация; документация;
- `canon` — привести проект к канону документов: `check` / `adopt` / - `canon` — привести проект к канону документов: `check` / `adopt` /
@@ -20,7 +20,8 @@
`doc-code-drift` (документы против кода) и `doc-wording` (язык документов); `doc-code-drift` (документы против кода) и `doc-wording` (язык документов);
- `docs` — содержимое канона по ходу разработки: ADR из архивного - `docs` — содержимое канона по ходу разработки: ADR из архивного
`design.md`, промоут конвенций, запись в разведку и журнал ревью, чистка `design.md`, промоут конвенций, запись в разведку и журнал ревью, чистка
архитектуры; архитектуры.
- **av-dev-tasks** — учёт работ. Владеет каталогом задач.
- `tasks` — задачи и цели каталогом markdown-файлов, у каждой записи тип - `tasks` — задачи и цели каталогом markdown-файлов, у каждой записи тип
(`goal`, `feature`, `fix`, `chore`, `research`), и тип задаёт её схему; (`goal`, `feature`, `fix`, `chore`, `research`), и тип задаёт её схему;
вычитывают их два отдельных прохода: `task-form` (форма записи) и вычитывают их два отдельных прохода: `task-form` (форма записи) и
@@ -53,13 +54,18 @@ flowchart TB
tp --> rp["review-pipeline<br/>10 агентов-проходов"] tp --> rp["review-pipeline<br/>10 агентов-проходов"]
batch --> rp batch --> rp
end end
subgraph pm["av-dev-pm — управление продуктом, владеет docs/"] subgraph docsp["av-dev-docs — документация, владеет docs/"]
direction LR direction LR
init["init"] --> tasks["tasks"] init["init"]
canon["canon"] --> tasks canon["canon"]
session["session"] --> tasks
docs["docs"] docs["docs"]
end end
subgraph tasksp["av-dev-tasks — учёт работ"]
direction LR
session["session"] --> tasks["tasks"]
end
init --> tasks
canon --> tasks
opsx["opsx:* — внешний плагин:<br/>explore, propose, apply, archive"] opsx["opsx:* — внешний плагин:<br/>explore, propose, apply, archive"]
git["av-dev-git: commit"] git["av-dev-git: commit"]
@@ -69,9 +75,13 @@ flowchart TB
tp --> tasks tp --> tasks
``` ```
Зависимость **односторонняя: `av-dev-pipeline` знает про `av-dev-pm`, обратно — Зависимости **односторонние: `av-dev-pipeline` знает про `av-dev-docs` и
нет.** Управление продуктом работает в проекте без конвейера; конвейер без `av-dev-tasks`, обратно — нет.** Между собой эти двое тоже не связаны жёстко:
канона деградирует поразрядно и говорит об этом строкой. каждый работает без другого и зовёт соседа **через пространство имён**, а не по
пути в чужое дерево. Не разрешился вызов — плагина нет, и это исход, который
проговаривается строкой, а не поломка. То, что нужно обоим дословно — язык
проектных текстов и словарь сопровождения, — живёт домом в `shared/` и уезжает в
каждый плагин помеченной копией.
## Канон документов проекта ## Канон документов проекта
@@ -80,7 +90,7 @@ flowchart TB
`docs/` (паспорт, архитектура, база, безопасность, конвенции, разведка, ADR, `docs/` (паспорт, архитектура, база, безопасность, конвенции, разведка, ADR,
ревью, задачи) и `openspec/` — **раскладка целиком, роли документов и правило ревью, задачи) и `openspec/` — **раскладка целиком, роли документов и правило
единственного дома живут одним домом**: единственного дома живут одним домом**:
[canon.md](av-dev-pm/skills/canon/references/canon.md). Здесь она не [canon.md](av-dev-docs/skills/canon/references/canon.md). Здесь она не
пересказывается: копия перечня путей уже расходилась с домом, и как раз в пересказывается: копия перечня путей уже расходилась с домом, и как раз в
обязательных — в ней не хватало путей, чьё отсутствие `docs.py check` считает обязательных — в ней не хватало путей, чьё отсутствие `docs.py check` считает
нарушением. нарушением.
@@ -98,9 +108,9 @@ flowchart TB
«тема → её дом → что оттуда берётся» — «тема → её дом → что оттуда берётся» —
[project-facts.md](av-dev-pipeline/skills/review-pipeline/references/project-facts.md). [project-facts.md](av-dev-pipeline/skills/review-pipeline/references/project-facts.md).
Прийти в старый проект и перевести его на канон — `/av-dev-pm:canon`. Канон Прийти в старый проект и перевести его на канон — `/av-dev-docs:canon`. Канон
версионируется, и проекты повышаются по [журналу версионируется, и проекты повышаются по [журналу
версий](av-dev-pm/skills/canon/references/changelog.md). версий](av-dev-docs/skills/canon/references/changelog.md).
## Подключение ## Подключение
@@ -115,7 +125,8 @@ cd /path/to/project
claude plugin marketplace add https://git.vakhrushev.me/av/dev-skills.git --scope project claude plugin marketplace add https://git.vakhrushev.me/av/dev-skills.git --scope project
# плагины: scope обязателен, умолчание у команды — user, а нам нужен project # плагины: scope обязателен, умолчание у команды — user, а нам нужен project
claude plugin install av-dev-pm@av-dev-skills --scope project claude plugin install av-dev-docs@av-dev-skills --scope project
claude plugin install av-dev-tasks@av-dev-skills --scope project
claude plugin install av-dev-pipeline@av-dev-skills --scope project claude plugin install av-dev-pipeline@av-dev-skills --scope project
claude plugin install av-dev-git@av-dev-skills --scope project claude plugin install av-dev-git@av-dev-skills --scope project
``` ```
@@ -132,7 +143,8 @@ claude plugin install av-dev-git@av-dev-skills --scope project
} }
}, },
"enabledPlugins": { "enabledPlugins": {
"av-dev-pm@av-dev-skills": true, "av-dev-docs@av-dev-skills": true,
"av-dev-tasks@av-dev-skills": true,
"av-dev-pipeline@av-dev-skills": true, "av-dev-pipeline@av-dev-skills": true,
"av-dev-git@av-dev-skills": true "av-dev-git@av-dev-skills": true
} }
@@ -162,7 +174,8 @@ claude plugin marketplace update av-dev-skills
# 2. снимки плагинов — из каталога проекта, где они установлены # 2. снимки плагинов — из каталога проекта, где они установлены
cd /path/to/project cd /path/to/project
claude plugin update av-dev-pm@av-dev-skills --scope project claude plugin update av-dev-docs@av-dev-skills --scope project
claude plugin update av-dev-tasks@av-dev-skills --scope project
claude plugin update av-dev-pipeline@av-dev-skills --scope project claude plugin update av-dev-pipeline@av-dev-skills --scope project
claude plugin update av-dev-git@av-dev-skills --scope project claude plugin update av-dev-git@av-dev-skills --scope project
``` ```
+8
View File
@@ -0,0 +1,8 @@
{
"name": "av-dev-docs",
"description": "Документация проекта: канон раскладки (CLAUDE.md плюс docs/ — паспорт, архитектура, схема БД, безопасность, конвенции, разведка, ADR, журнал ревью), роли документов и правило единственного дома. Три операции одной машиной сравнения — check, adopt, upgrade — со скриптом docs.py; заведение нового проекта интервью по брифу; ведение содержимого по ходу разработки: синк после сделанной задачи, ADR промоутом из архивного design.md, записка разведки, запись дефекта в журнал ревью. Смысловое, чего скрипт не видит, судят три агента: doc-consistency, doc-code-drift, doc-wording. Задач не ведёт — это плагин av-dev-tasks, и он опционален.",
"author": {
"name": "Anton Vakhrushev",
"email": "anwinged@gmail.com"
}
}
@@ -15,11 +15,11 @@ color: yellow
машина, а что человек», и её правая колонка — твой устав дословно. машина, а что человек», и её правая колонка — твой устав дословно.
Карта домов, по которой ты судишь о правиле 1, — дословная копия канона; дом её Карта домов, по которой ты судишь о правиле 1, — дословная копия канона; дом её
`av-dev-pm/skills/canon/references/canon.md`, раздел «Правило единственного `av-dev-docs/skills/canon/references/canon.md`, раздел «Правило единственного
дома», и правится она там. Здесь она стоит потому, что ты работаешь в дома», и правится она там. Здесь она стоит потому, что ты работаешь в
репозитории проекта, где плагина может не быть вовсе. репозитории проекта, где плагина может не быть вовсе.
<!-- копия: карта-домов из av-dev-pm/skills/canon/references/canon.md --> <!-- копия: карта-домов из av-dev-docs/skills/canon/references/canon.md -->
| Факт | Дом | | Факт | Дом |
| --- | --- | | --- | --- |
| поведение системы | `openspec/specs/<capability>/spec.md` | | поведение системы | `openspec/specs/<capability>/spec.md` |
@@ -155,7 +155,7 @@ capability), `openspec/config.yaml`.
ею. Пересказ инвариантов, конвенций и правил ревью из `context` вычисти ею. Пересказ инвариантов, конвенций и правил ревью из `context` вычисти
ссылкой на дом — на переводимом проекте он там почти наверняка есть; ссылкой на дом — на переводимом проекте он там почти наверняка есть;
4. переносы содержимого; 4. переносы содержимого;
5. каталог задач — **вызови скилл `av-dev-pm:tasks`**, сценарий адаптации: он 5. каталог задач — **вызови скилл `av-dev-tasks:tasks`**, сценарий адаптации: он
владеет форматом задач. Он же переименует транслитные слаги в английские и владеет форматом задач. Он же переименует транслитные слаги в английские и
тем же проходом починит перекрёстные ссылки; тем же проходом починит перекрёстные ссылки;
6. починка ссылок на перенесённое во всём репозитории — `docs/`, `openspec/`, 6. починка ссылок на перенесённое во всём репозитории — `docs/`, `openspec/`,
@@ -172,7 +172,8 @@ capability), `openspec/config.yaml`.
незаполненный канон это объявленное переходное состояние из шага 5, а не незаполненный канон это объявленное переходное состояние из шага 5, а не
отказ. **Пункт «задачи без цели» из вложенной проверки `tasks.py` тоже отказ. **Пункт «задачи без цели» из вложенной проверки `tasks.py` тоже
остаётся** и зелёным на этом шаге не станет: цели не сочиняются адаптацией остаётся** и зелёным на этом шаге не станет: цели не сочиняются адаптацией
(запрет в [tasks/references/adopt.md](../tasks/references/adopt.md)), их (запрет записан у того, кто ведёт задачи, — сценарий адаптации скилла
`av-dev-tasks:tasks`), их
проставляет человек порциями переоценки на первой сессии. Пересчитай эти проставляет человек порциями переоценки на первой сессии. Пересчитай эти
пункты в докладе переходного состояния — не выдавай их за поломку и не пункты в докладе переходного состояния — не выдавай их за поломку и не
молчи о них. молчи о них.
@@ -24,7 +24,13 @@
## Сопровождение и эксплуатация — целое и часть ## Сопровождение и эксплуатация — целое и часть
Одна тема живёт в трёх местах канона, и путать их слова нельзя. **Копия.** Дом — `shared/operations.md` в репозитории плагинов: словарь
делят роадмап, архитектура и тема ревью `operations`, то есть три плагина,
и ни один из трёх им не владеет. Правится дом, а не этот файл.
<!-- копия: сопровождение-словарь из shared/operations.md -->
Одна тема живёт в трёх местах, и путать их слова нельзя.
**Сопровождение** — всё, чем держат проект: инструмент и сборка, процесс, **Сопровождение** — всё, чем держат проект: инструмент и сборка, процесс,
выкладка, метрики и логи, инфраструктура, дежурство. **Эксплуатация** — его выкладка, метрики и логи, инфраструктура, дежурство. **Эксплуатация** — его
@@ -45,6 +51,8 @@
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
секции роадмапа, и это верно — секции отвечают на разные вопросы. секции роадмапа, и это верно — секции отвечают на разные вопросы.
<!-- /копия: сопровождение-словарь -->
## Раскладка ## Раскладка
**Документ канона живёт файлом или каталогом.** `docs/security.md` и **Документ канона живёт файлом или каталогом.** `docs/security.md` и
@@ -370,9 +378,10 @@ kebab-case.** Причина не эстетическая: имя файла с
| 🔬 `research` | исход — знание, а не изменение | | 🔬 `research` | исход — знание, а не изменение |
**Схемы записи здесь нет намеренно.** Какие разделы тип требует, нужна ли ему **Схемы записи здесь нет намеренно.** Какие разделы тип требует, нужна ли ему
цель и берётся ли он в спринт — скилл `tasks`: сводка в его цель и берётся ли он в спринт — скилл `av-dev-tasks:tasks`, раздел «Тип
[SKILL.md](../../tasks/SKILL.md), раздел «Тип записи», подробно — по файлу на записи», подробно — по файлу на тип в его `references/task-<тип>.md`. Ссылки в
тип в `tasks/references/task-<тип>.md`. Канон фиксирует **словарь**, потому что дерево того плагина здесь нет намеренно: он ставится отдельно, и путь наружу
разрешился бы не всегда. Канон фиксирует **словарь**, потому что
от него зависит, читается ли проект как продукт; схема — механика ведения задач, от него зависит, читается ли проект как продукт; схема — механика ведения задач,
и второй её экземпляр разошёлся бы с первым (он и разошёлся: канон успел и второй её экземпляр разошёлся бы с первым (он и разошёлся: канон успел
объявить цель у `fix` запрещённой, хотя она там необязательна). объявить цель у `fix` запрещённой, хотя она там необязательна).
@@ -205,7 +205,7 @@
Верно одно из трёх: Верно одно из трёх:
<!-- копия: adr-когда-заводить из av-dev-pm/skills/canon/references/canon.md --> <!-- копия: adr-когда-заводить из av-dev-docs/skills/canon/references/canon.md -->
- **дорогой откат** — переделка стоит дороже переписывания одного файла; - **дорогой откат** — переделка стоит дороже переписывания одного файла;
- **намеренный отказ** от очевидного подхода; - **намеренный отказ** от очевидного подхода;
- **пересмотр прежнего решения** — тогда у старой записи обязателен статус - **пересмотр прежнего решения** — тогда у старой записи обязателен статус
@@ -87,7 +87,7 @@ description: "Завести новый проект — сессия вопро
capability, придирки валидатора и **адреса** `docs/passport.md` и `CLAUDE.md`. capability, придирки валидатора и **адреса** `docs/passport.md` и `CLAUDE.md`.
Инварианты, конвенции и правило ревью не пересказывай — у них есть дома, и Инварианты, конвенции и правило ревью не пересказывай — у них есть дома, и
второй дом разойдётся с первым молча. второй дом разойдётся с первым молча.
8. Каталог задач и первые цели — **вызови скилл `av-dev-pm:tasks`**: он владеет 8. Каталог задач и первые цели — **вызови скилл `av-dev-tasks:tasks`**: он владеет
форматом целей и задач. форматом целей и задач.
9. `docs.py check` из скилла `canon` — до отсутствия дрейфа. Замечания о 9. `docs.py check` из скилла `canon` — до отсутствия дрейфа. Замечания о
незаполненных плейсхолдерах остаются: их закрывает не `init`, а работа. незаполненных плейсхолдерах остаются: их закрывает не `init`, а работа.
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "av-dev-pipeline", "name": "av-dev-pipeline",
"description": "Проведение задачи через полный цикл Spec Driven Development и конвейер ревью с детерминированным гейтом, сверкой со спеками, враждебными постановками, эксплуатационным постмортемом, независимой реализацией и обязательным триажем; плюс прогон нескольких задач разом по одной в изолированном worktree. Требует OpenSpec. Задача принимается и обычным текстом. Плагин av-dev-pm опционален: он даёт документы канона, из которых проходы читают проектную конкретику, и учёт задач; без него прогон деградирует поразрядно и называет это строкой.", "description": "Проведение задачи через полный цикл Spec Driven Development и конвейер ревью с детерминированным гейтом, сверкой со спеками, враждебными постановками, эксплуатационным постмортемом, независимой реализацией и обязательным триажем; плюс прогон нескольких задач разом по одной в изолированном worktree. Требует OpenSpec. Задача принимается и обычным текстом. Плагины av-dev-docs и av-dev-tasks опциональны: первый даёт документы канона, из которых проходы читают проектную конкретику, второй — учёт задач; без них прогон деградирует поразрядно и называет это строкой.",
"author": { "author": {
"name": "Anton Vakhrushev", "name": "Anton Vakhrushev",
"email": "anwinged@gmail.com" "email": "anwinged@gmail.com"
@@ -1,6 +1,6 @@
--- ---
name: review-pipeline name: review-pipeline
description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после propose: агент review-scope выводит размер и сложность, из их максимума — метка, и раздаёт темы проходам обеих стадий. Метка правит и ревью дизайна (small — только specs; medium — плюс rubric; large — плюс architecture), и ревью кода (small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс доказательство: враждебные постановки, эксплуатационный постмортем, архитектурный проход на широком входе). Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает опиниативные проходы, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Проектная специфика приходит из документов канона av-dev-pm. Вызывается из task-pipeline (чекпоинты ревью) и из task-batch (финальная сверка)." description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после propose: агент review-scope выводит размер и сложность, из их максимума — метка, и раздаёт темы проходам обеих стадий. Метка правит и ревью дизайна (small — только specs; medium — плюс rubric; large — плюс architecture), и ревью кода (small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс доказательство: враждебные постановки, эксплуатационный постмортем, архитектурный проход на широком входе). Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает опиниативные проходы, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Проектная специфика приходит из документов канона av-dev-docs. Вызывается из task-pipeline (чекпоинты ревью) и из task-batch (финальная сверка)."
--- ---
# Конвейер ревью # Конвейер ревью
@@ -52,7 +52,7 @@ description: "Конвейер ревью изменения, устроенны
требований. **Проект без OpenSpec этим конвейером не проверяется** — подключай требований. **Проект без OpenSpec этим конвейером не проверяется** — подключай
OpenSpec, а не понижай прогон: ветка деградации здесь не пишется, потому что OpenSpec, а не понижай прогон: ветка деградации здесь не пишется, потому что
непроверенная ветка деградации хуже честного отказа. Заводить руками не надо: непроверенная ветка деградации хуже честного отказа. Заводить руками не надо:
`av-dev-pm:init` делает `openspec init` на новом проекте, `canon adopt` — на `av-dev-docs:init` делает `openspec init` на новом проекте, `canon adopt` — на
переводимом, и оба кладут `openspec/config.yaml` канонической формы. переводимом, и оба кладут `openspec/config.yaml` канонической формы.
- **Документы канона** — см. следующий раздел. - **Документы канона** — см. следующий раздел.
- **Проектные копии этих скиллов и агентов удаляются при установке.** Если в - **Проектные копии этих скиллов и агентов удаляются при установке.** Если в
@@ -88,7 +88,7 @@ description: "Конвейер ревью изменения, устроенны
критерий, по которому судит изменение. `adr.*`, `research.*` и `tasks/` не критерий, по которому судит изменение. `adr.*`, `research.*` и `tasks/` не
открывает никто. открывает никто.
Дом канона этой раскладки — `av-dev-pm`, `references/canon.md`, раздел «Три Дом канона этой раскладки — `av-dev-docs`, `references/canon.md`, раздел «Три
категории документов». Конвейер её **читатель**: категории и имена тем он берёт категории документов». Конвейер её **читатель**: категории и имена тем он берёт
оттуда и своих не заводит. оттуда и своих не заводит.
@@ -120,7 +120,7 @@ description: "Конвейер ревью изменения, устроенны
читал решения, а эксплуатационный и `specs` — числа. Цена решения записана в читал решения, а эксплуатационный и `specs` — числа. Цена решения записана в
каноне и повторяется здесь, потому что платит её конвейер: **расхождение каноне и повторяется здесь, потому что платит её конвейер: **расхождение
изменения с записанным решением прогоном не ловится**, это работа сверки изменения с записанным решением прогоном не ловится**, это работа сверки
документации (`av-dev-pm`, агент `doc-consistency`) на сессии между спринтами. документации (`av-dev-docs`, агент `doc-consistency`) на сессии между спринтами.
Строка об этом обязательна в границах покрытия каждого прогона. Строка об этом обязательна в границах покрытия каждого прогона.
**Своя тема проекта бывает двух происхождений, и обе законны:** документ, который **Своя тема проекта бывает двух происхождений, и обе законны:** документ, который
@@ -147,7 +147,7 @@ description: "Конвейер ревью изменения, устроенны
дом для тех же фактов разошёлся бы и выглядел актуальным. дом для тех же фактов разошёлся бы и выглядел актуальным.
**Документов канона нет вовсе** — проект не приведён к канону. Скажи это строкой **Документов канона нет вовсе** — проект не приведён к канону. Скажи это строкой
и предложи скилл `av-dev-pm:canon`: одна операция на проект против деградации на и предложи скилл `av-dev-docs:canon`: одна операция на проект против деградации на
каждой задаче. Прогон при этом не останавливается. каждой задаче. Прогон при этом не останавливается.
## Что получает каждый проход ## Что получает каждый проход
@@ -1021,7 +1021,7 @@ flowchart TD
и где это лежит в документах проекта; таблица поразрядной деградации. и где это лежит в документах проекта; таблица поразрядной деградации.
- [references/review-levels.md](references/review-levels.md) — дом правила выбора - [references/review-levels.md](references/review-levels.md) — дом правила выбора
метки: две оси, спорное вниз, чем `small` дешевле, доли как проверка правила. метки: две оси, спорное вниз, чем `small` дешевле, доли как проверка правила.
- Skill `av-dev-pm:canon` — приведение проекта к канону документов. - Skill `av-dev-docs:canon` — приведение проекта к канону документов.
- [references/finding-contract.md](references/finding-contract.md) — контракт находок. - [references/finding-contract.md](references/finding-contract.md) — контракт находок.
- [references/promote.md](references/promote.md) — промоут находка → конвенция → правило → удаление. - [references/promote.md](references/promote.md) — промоут находка → конвенция → правило → удаление.
- [references/calibration.md](references/calibration.md) — калибровка инъекцией, вердикты keep/retune/drop. - [references/calibration.md](references/calibration.md) — калибровка инъекцией, вердикты keep/retune/drop.
@@ -5,10 +5,10 @@
выдаёт правдоподобные общие места: их дорого опровергать и нечем подтверждать. выдаёт правдоподобные общие места: их дорого опровергать и нечем подтверждать.
Отдельного файла-брифа **нет**. Проектная конкретика живёт в документах канона Отдельного файла-брифа **нет**. Проектная конкретика живёт в документах канона
`av-dev-pm`, и проход читает их напрямую: пути жёсткие, посредник не нужен, а `av-dev-docs`, и проход читает их напрямую: пути жёсткие, посредник не нужен, а
второй дом для тех же фактов разошёлся бы и выглядел актуальным. второй дом для тех же фактов разошёлся бы и выглядел актуальным.
Определение канона — в плагине `av-dev-pm`, Определение канона — в плагине `av-dev-docs`,
`skills/canon/references/canon.md`. Здесь только карта «тема → её дом → что `skills/canon/references/canon.md`. Здесь только карта «тема → её дом → что
оттуда берётся». оттуда берётся».
@@ -119,7 +119,7 @@
строка неотличима от «мы просто не стали» и перестаёт читаться на третьей задаче. строка неотличима от «мы просто не стали» и перестаёт читаться на третьей задаче.
**Документов канона нет вовсе** — проект не приведён к канону. Это не повод **Документов канона нет вовсе** — проект не приведён к канону. Это не повод
работать вслепую: скажи об этом строкой и предложи `av-dev-pm:canon`. Одна работать вслепую: скажи об этом строкой и предложи `av-dev-docs:canon`. Одна
операция на проект против деградации на каждой задаче. операция на проект против деградации на каждой задаче.
## Правило чтения ## Правило чтения
@@ -1,7 +1,7 @@
# Журнал дефектов # Журнал дефектов
Артефакт проекта, а не плагина: файл живёт в репозитории — **`docs/review.md`**, Артефакт проекта, а не плагина: файл живёт в репозитории — **`docs/review.md`**,
слот канона `av-dev-pm`. Здесь описано, зачем он и какой формы, потому что без слот канона `av-dev-docs`. Здесь описано, зачем он и какой формы, потому что без
него конвейер не учится: находки закрываются, а почему их не поймали — забывается, него конвейер не учится: находки закрываются, а почему их не поймали — забывается,
и один и тот же класс проскакивает второй раз. и один и тот же класс проскакивает второй раз.
@@ -41,7 +41,7 @@
## Форма записи ## Форма записи
**Это дом формы, и у него есть копия.** Скелет `docs/review.md`, который кладёт **Это дом формы, и у него есть копия.** Скелет `docs/review.md`, который кладёт
в проект `av-dev-pm` (`skills/canon/references/skeletons.md`), повторяет её в проект `av-dev-docs` (`skills/canon/references/skeletons.md`), повторяет её
дословно — он уезжает в репозиторий и обязан там что-то говорить. Правка формы дословно — он уезжает в репозиторий и обязан там что-то говорить. Правка формы
здесь **обязана** тянуть правку скелета и запись в журнал версий канона; иначе здесь **обязана** тянуть правку скелета и запись в журнал версий канона; иначе
проекты продолжат писать по старой форме, а конвейер — ждать поля, которого нет. проекты продолжат писать по старой форме, а конвейер — ждать поля, которого нет.
@@ -94,7 +94,7 @@
костяк — гейт, спеки, код, триаж**. Разрезать задачу, обе половины которой костяк — гейт, спеки, код, триаж**. Разрезать задачу, обе половины которой
остаются в одной метке, значит заплатить костяк дважды за ту же проверку. остаются в одной метке, значит заплатить костяк дважды за ту же проверку.
Резать стоит там, где разрез **снимает доказательство с большей части диффа**. Резать стоит там, где разрез **снимает доказательство с большей части диффа**.
Шов и правило нарезки живут у того, кто ведёт задачи, — скилл `av-dev-pm:tasks`, Шов и правило нарезки живут у того, кто ведёт задачи, — скилл `av-dev-tasks:tasks`,
его `references/split.md`. Пути туда конвейер не выносит: за пределы своего его `references/split.md`. Пути туда конвейер не выносит: за пределы своего
плагина он ходит вызовом скилла, а не файлом. плагина он ходит вызовом скилла, а не файлом.
+4 -4
View File
@@ -28,7 +28,7 @@ description: Проводит несколько задач разом — пл
проход `review-specs` финальной сверки. Проекта без OpenSpec это касается так проход `review-specs` финальной сверки. Проекта без OpenSpec это касается так
же, как одиночного пайплайна (см. его раздел «Предпосылки»). же, как одиночного пайплайна (см. его раздел «Предпосылки»).
- **Скиллы зовутся с пространством имён**: `av-dev-pipeline:task-pipeline`, - **Скиллы зовутся с пространством имён**: `av-dev-pipeline:task-pipeline`,
`av-dev-pipeline:review-pipeline`, `av-dev-pm:tasks`. Короткое имя `av-dev-pipeline:review-pipeline`, `av-dev-tasks:tasks`. Короткое имя
может разрешиться в устаревшую проектную копию, и это произойдёт молча — в может разрешиться в устаревшую проектную копию, и это произойдёт молча — в
charter'е сабагента пиши полное имя, он твоего контекста не видит. charter'е сабагента пиши полное имя, он твоего контекста не видит.
- **Проектные копии этих скиллов и агентов при установке плагина удаляются.** - **Проектные копии этих скиллов и агентов при установке плагина удаляются.**
@@ -39,7 +39,7 @@ description: Проводит несколько задач разом — пл
`docs/database.md` и `docs/.pm.json` (ключ `migrations`). `docs/database.md` и `docs/.pm.json` (ключ `migrations`).
**Документов канона нет — проект к нему не приведён.** Скажи это строкой и **Документов канона нет — проект к нему не приведён.** Скажи это строкой и
предложи `av-dev-pm:canon` **до первой задачи**: иначе каждая задача батча предложи `av-dev-docs:canon` **до первой задачи**: иначе каждая задача батча
заплатит поразрядной деградацией ревью, а имя основной ветки придётся заплатит поразрядной деградацией ревью, а имя основной ветки придётся
угадывать. угадывать.
@@ -52,7 +52,7 @@ description: Проводит несколько задач разом — пл
же трёх словах, что и `task-pipeline`: сделана / не доведена / оказалась крупнее же трёх словах, что и `task-pipeline`: сделана / не доведена / оказалась крупнее
задачи. задачи.
- **Задачи закрывает пайплайн внутри каждого сабагента**, шагом 12 — после - **Задачи закрывает пайплайн внутри каждого сабагента**, шагом 12 — после
коммита работы и **отдельным коммитом учёта**, вызовом Skill `av-dev-pm:tasks`. коммита работы и **отдельным коммитом учёта**, вызовом Skill `av-dev-tasks:tasks`.
Батч сам записей учёта не трогает: он не знает, чем кончилась приёмка, и Батч сам записей учёта не трогает: он не знает, чем кончилась приёмка, и
дублировать закрытие ему незачем. Но грязное дерево после сабагента — **его** дублировать закрытие ему незачем. Но грязное дерево после сабагента — **его**
проблема: на нём откажут и `rebase`, и `worktree remove` (см. шаг 6). Урожай ревью батч проблема: на нём откажут и `rebase`, и `worktree remove` (см. шаг 6). Урожай ревью батч
@@ -88,7 +88,7 @@ description: Проводит несколько задач разом — пл
### 1. Прочитать набор ### 1. Прочитать набор
Набор задан списком (слаги, файлы, описания) — прочитай файл каждой задачи и Набор задан списком (слаги, файлы, описания) — прочитай файл каждой задачи и
связанные спеки и черновики. Сырьё (в терминах `av-dev-pm` — запись типа связанные спеки и черновики. Сырьё (в терминах `av-dev-tasks` — запись типа
`research` с пустым разделом «Вопрос») включается, но помни: сабагент проведёт `research` с пустым разделом «Вопрос») включается, но помни: сабагент проведёт
его сперва через `opsx:explore`, это тяжелее и чаще упирается в вопрос. его сперва через `opsx:explore`, это тяжелее и чаще упирается в вопрос.
+16 -16
View File
@@ -23,7 +23,7 @@ description: "Автономно проводит одну задачу чере
вырождай цикл: ветка деградации здесь не пишется, потому что непроверенная вырождай цикл: ветка деградации здесь не пишется, потому что непроверенная
ветка деградации хуже честного отказа. ветка деградации хуже честного отказа.
- **Скиллы зовутся с пространством имён** — `av-dev-pipeline:review-pipeline`, - **Скиллы зовутся с пространством имён** — `av-dev-pipeline:review-pipeline`,
`av-dev-pm:docs`, `av-dev-pm:tasks`. Короткое имя может разрешиться в `av-dev-docs:docs`, `av-dev-tasks:tasks`. Короткое имя может разрешиться в
устаревшую проектную копию, и это произойдёт молча. устаревшую проектную копию, и это произойдёт молча.
- **Проектные копии этих скиллов и агентов удаляются при установке плагина** - **Проектные копии этих скиллов и агентов удаляются при установке плагина**
(`.claude/skills/` — и голые имена `task-pipeline`, `review-pipeline`, (`.claude/skills/` — и голые имена `task-pipeline`, `review-pipeline`,
@@ -34,11 +34,11 @@ description: "Автономно проводит одну задачу чере
Перед стартом прочитай `CLAUDE.md` проекта и то, на что он ссылается, если ещё Перед стартом прочитай `CLAUDE.md` проекта и то, на что он ссылается, если ещё
не в контексте. Проектные факты, нужные ревью — инварианты, семантика гейта, не в контексте. Проектные факты, нужные ревью — инварианты, семантика гейта,
объёмы, модель угроз, прецеденты, — живут в **документах канона** `av-dev-pm`; объёмы, модель угроз, прецеденты, — живут в **документах канона** `av-dev-docs`;
карта «что где» — `references/project-facts.md` конвейера ревью. карта «что где» — `references/project-facts.md` конвейера ревью.
**Документов канона нет — проект к нему не приведён.** Скажи это строкой и **Документов канона нет — проект к нему не приведён.** Скажи это строкой и
предложи скилл `av-dev-pm:canon`: одна операция на проект против поразрядной предложи скилл `av-dev-docs:canon`: одна операция на проект против поразрядной
деградации на каждой задаче. Работу при этом не останавливай. деградации на каждой задаче. Работу при этом не останавливай.
## Границы: чем пайплайн не владеет ## Границы: чем пайплайн не владеет
@@ -47,12 +47,12 @@ description: "Автономно проводит одну задачу чере
её не выбирает, не приоритизирует, не заводит и не переоценивает; если в её не выбирает, не приоритизирует, не заводит и не переоценивает; если в
проекте есть свой процесс управления задачами — он и решает, что брать. проекте есть свой процесс управления задачами — он и решает, что брать.
- **Форматом задач.** Пайплайн **не правит индексы руками и не выдумывает путь - **Форматом задач.** Пайплайн **не правит индексы руками и не выдумывает путь
к скрипту учёта**: он зовёт Skill `av-dev-pm:tasks`, который этим владеет к скрипту учёта**: он зовёт Skill `av-dev-tasks:tasks`, который этим владеет
(шаг 12). Закрытие как таковое — его работа, и это осознанное решение с (шаг 12). Закрытие как таковое — его работа, и это осознанное решение с
названной ценой: **приёмщик и исполнитель совпали**. Закрытие поэтому **не названной ценой: **приёмщик и исполнитель совпали**. Закрытие поэтому **не
окончательно** — человек на сессии возвращает задачу `reopen` с причиной, а окончательно** — человек на сессии возвращает задачу `reopen` с причиной, а
доклад по критериям приёмки становится единственным, по чему приёмка вообще доклад по критериям приёмки становится единственным, по чему приёмка вообще
возможна. Плагина `av-dev-pm` в проекте нет — вызов не разрешится, и тогда возможна. Плагина `av-dev-tasks` в проекте нет — вызов не разрешится, и тогда
учёт остаётся владельцу, о чём говорится в докладе. учёт остаётся владельцу, о чём говорится в докладе.
- **Заведением задач из урожая ревью.** Отложенные находки отдаются **списком** - **Заведением задач из урожая ревью.** Отложенные находки отдаются **списком**
(см. шаг 8); превращать их в задачи — работа того, кто ведёт задачи проекта. (см. шаг 8); превращать их в задачи — работа того, кто ведёт задачи проекта.
@@ -113,7 +113,7 @@ description: "Автономно проводит одну задачу чере
в объявленных границах. в объявленных границах.
**Что остатком не является — правило живёт не здесь.** Канонический текст с обеими **Что остатком не является — правило живёт не здесь.** Канонический текст с обеими
оговорками — в плагине `av-dev-pm`, скилл `av-dev-pm:session`, раздел оговорками — в плагине `av-dev-tasks`, скилл `av-dev-tasks:session`, раздел
`## Вопрос, блокер, необратимое`, подраздел «Отличать вопрос от застревания». `## Вопрос, блокер, необратимое`, подраздел «Отличать вопрос от застревания».
Правило принадлежит управлению задачами, потому что решает **сделана задача или Правило принадлежит управлению задачами, потому что решает **сделана задача или
вышла**, — это исход планирования, а не исполнения. **Ссылайся, не вышла**, — это исход планирования, а не исполнения. **Ссылайся, не
@@ -126,7 +126,7 @@ description: "Автономно проводит одну задачу чере
Оба порога — стоп: первый поднимает решение до начала записи, второй даёт исход Оба порога — стоп: первый поднимает решение до начала записи, второй даёт исход
«не доведена». «не доведена».
Плагин `av-dev-pm` не подключён — правило не отменяется, а становится Плагин `av-dev-tasks` не подключён — правило не отменяется, а становится
осторожнее: прежде чем записать зависящее от нерешённого куда бы то ни было — осторожнее: прежде чем записать зависящее от нерешённого куда бы то ни было —
в хранилище, в журнал, в витрину или наружу, — спрашивай человека. в хранилище, в журнал, в витрину или наружу, — спрашивай человека.
@@ -164,9 +164,9 @@ flowchart TD
s7["7. opsx:apply — код, гейт, поведенческая верификация"] s7["7. opsx:apply — код, гейт, поведенческая верификация"]
s8["8. ревью кода, состав по той же метки"] s8["8. ревью кода, состав по той же метки"]
s9["9. opsx:archive"] s9["9. opsx:archive"]
s10["10. синк документации — av-dev-pm:docs"] s10["10. синк документации — av-dev-docs:docs"]
s11["11. коммит работы — av-dev-git:commit"] s11["11. коммит работы — av-dev-git:commit"]
s12["12. закрыть задачу — av-dev-pm:tasks,<br/>вторым коммитом учёта"] s12["12. закрыть задачу — av-dev-tasks:tasks,<br/>вторым коммитом учёта"]
s1 --> triv s1 --> triv
s1 -.-> big s1 -.-> big
@@ -383,7 +383,7 @@ change `<id>`, **план разметки с шага 4** и указание,
### 10. Синк документации ### 10. Синк документации
Ревью выполненного — до этого шага. Затем **вызови Skill `av-dev-pm:docs`**: он Ревью выполненного — до этого шага. Затем **вызови Skill `av-dev-docs:docs`**: он
владеет содержимым документов канона и ведёт чек-лист синка. Плагина нет — шаг владеет содержимым документов канона и ведёт чек-лист синка. Плагина нет — шаг
всё равно делается, см. ниже. всё равно делается, см. ниже.
@@ -394,17 +394,17 @@ change `<id>`, **план разметки с шага 4** и указание,
работает только обязательное отрицание. работает только обязательное отрицание.
**Список документов и их триггеров здесь не дублируется** — он в чек-листе **Список документов и их триггеров здесь не дублируется** — он в чек-листе
скилла `av-dev-pm:docs`, и копия уже однажды разошлась с оригиналом, потеряв два скилла `av-dev-docs:docs`, и копия уже однажды разошлась с оригиналом, потеряв два
триггера. триггера.
**Плагина `av-dev-pm` в проекте нет** — путь в его дерево не разрешится ниоткуда, **Плагина `av-dev-docs` в проекте нет** — путь в его дерево не разрешится ниоткуда,
поэтому за списком иди в **свой** reference: поэтому за списком иди в **свой** reference:
[references/project-facts.md](../review-pipeline/references/project-facts.md) [references/project-facts.md](../review-pipeline/references/project-facts.md)
конвейера ревью перечисляет все документы канона с их предметом. Пройди по этому конвейера ревью перечисляет все документы канона с их предметом. Пройди по этому
перечню — каждый документ получает строку, отрицание остаётся обязательным. перечню — каждый документ получает строку, отрицание остаётся обязательным.
Триггеры при этом ты знаешь хуже, и это называется в докладе строкой: «синк Триггеры при этом ты знаешь хуже, и это называется в докладе строкой: «синк
сделан по перечню документов, без списка триггеров — плагина `av-dev-pm` нет». сделан по перечню документов, без списка триггеров — плагина `av-dev-docs` нет».
Канона в проекте тоже нет — назови это исходом и предложи `av-dev-pm:canon`. Канона в проекте тоже нет — назови это исходом и предложи `av-dev-docs:canon`.
### 11. Коммит ### 11. Коммит
@@ -419,7 +419,7 @@ change `<id>`, **план разметки с шага 4** и указание,
### 12. Закрыть задачу — **после коммита, не раньше** ### 12. Закрыть задачу — **после коммита, не раньше**
**Вызови Skill `av-dev-pm:tasks`** и попроси закрыть задачу как реализованную — **Вызови Skill `av-dev-tasks:tasks`** и попроси закрыть задачу как реализованную —
он владеет форматом и двигает строку из набора спринта сам. Путь к его скрипту не он владеет форматом и двигает строку из набора спринта сам. Путь к его скрипту не
выясняй и индексы руками не правь: мост между плагинами — вызов скилла, а не выясняй и индексы руками не правь: мост между плагинами — вызов скилла, а не
путь. путь.
@@ -428,7 +428,7 @@ change `<id>`, **план разметки с шага 4** и указание,
оставило бы задачу закрытой без единого следа работы, если шаг 11 упадёт. оставило бы задачу закрытой без единого следа работы, если шаг 11 упадёт.
**Закрытие тоже коммитится — вторым коммитом, тут же.** Удаление файла задачи и **Закрытие тоже коммитится — вторым коммитом, тут же.** Удаление файла задачи и
правка индексов (их имена знает `av-dev-pm`, не ты) — это правки в рабочем правка индексов (их имена знает `av-dev-tasks`, не ты) — это правки в рабочем
дереве, и оставить их незакоммиченными нельзя по трём причинам: `task-batch` следом делает `rebase` дереве, и оставить их незакоммиченными нельзя по трём причинам: `task-batch` следом делает `rebase`
и `worktree remove`, а те откажут на грязном дереве; закрытие, не доехавшее до и `worktree remove`, а те откажут на грязном дереве; закрытие, не доехавшее до
основной ветки, оставит задачу открытой молча; и опора «набор спринта под git основной ветки, оставит задачу открытой молча; и опора «набор спринта под git
-8
View File
@@ -1,8 +0,0 @@
{
"name": "av-dev-pm",
"description": "Управление продуктом: канон документов проекта (паспорт, архитектура, схема БД, безопасность, конвенции, разведка, ADR, журнал ревью), задачи и цели вместо приоритетов, спринт под одну цель с заморозкой набора, старт нового проекта интервью по брифу и приведение существующего к канону. Не выполняет задачи — этим занимается пайплайн проекта.",
"author": {
"name": "Anton Vakhrushev",
"email": "anwinged@gmail.com"
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"name": "av-dev-tasks",
"description": "Задачи и цели каталогом markdown-файлов: одна запись — файл в items/ плюс строка ровно в одном индексе, у записи тип (goal, feature, fix, chore, research), и тип решает, каких разделов она требует и что с ней можно делать. Заведение из диалога с фильтром и дедупом, разбор находок ревью в задачи, декомпозиция на независимо полезные части, гигиена полей, согласованность индексов скриптом tasks.py. Спринт под одну цель с заморозкой набора и ритуал между спринтами. Записи вычитывают два прохода: task-form (форма записи) и task-wording (язык). Канон документов ведёт плагин av-dev-docs, он опционален. Задач не выполняет — этим занимается пайплайн проекта.",
"author": {
"name": "Anton Vakhrushev",
"email": "anwinged@gmail.com"
}
}
@@ -275,9 +275,10 @@ python3 $tk reopen <слаг> --dir D --reason … # приёмка не со
## Слоты проекта ## Слоты проекта
Сессия не знает ни языка, ни сборки, ни CI. На часть проектного отвечает своей Сессия не знает ни языка, ни сборки, ни CI. На часть проектного отвечает своей
структурой [канон](../canon/references/canon.md): разбор процесса (шаг 2) живёт структурой канон документов (его ведёт плагин `av-dev-docs`): разбор процесса
в `docs/review.md`, оракулы и «чем краснеет безусловно» — в семантике гейта в (шаг 2) живёт в `docs/review.md`, оракулы и «чем краснеет безусловно» — в
`CLAUDE.md`. Остальное проект **дописывает в `CLAUDE.md`**: семантике гейта в `CLAUDE.md`. Пути известны, ссылки в чужое дерево нет: канон
ставится отдельно, а без него оба файла всё равно читаются по имени. Остальное проект **дописывает в `CLAUDE.md`**:
1. **Пайплайн задачи** — чем задача выполняется и что входит в его определение 1. **Пайплайн задачи** — чем задача выполняется и что входит в его определение
готовности. Сессия требует только форму: пайплайн пройден + критерии приёмки готовности. Сессия требует только форму: пайплайн пройден + критерии приёмки
@@ -117,7 +117,7 @@ flowchart TD
пайплайна, после коммита. Порядок: пайплайна, после коммита. Порядок:
1. пайплайн доводит задачу до коммита; 1. пайплайн доводит задачу до коммита;
2. **после коммита** зовёт `Skill av-dev-pm:tasks` и закрывает задачу 2. **после коммита** зовёт `Skill av-dev-tasks:tasks` и закрывает задачу
(`close <slug> --implemented`); строка уходит из `SPRINT.md`; (`close <slug> --implemented`); строка уходит из `SPRINT.md`;
3. **докладывает исход и по каждому критерию — оракул и наблюдаемый исход.** 3. **докладывает исход и по каждому критерию — оракул и наблюдаемый исход.**
Это доклад приёмщику, а не отметка «принято». Это доклад приёмщику, а не отметка «принято».
@@ -60,9 +60,10 @@ description: Ведение задач и целей как каталога mar
## Раскладка ## Раскладка
Каталог задач — **`docs/tasks`, жёстко**: это часть Каталог задач — **`docs/tasks`, жёстко**: это часть канона документов, и
[канона документов](../canon/references/canon.md), и подгоняется под него подгоняется под него проект, а не наоборот. Канон ведёт другой плагин
проект, а не наоборот. (`av-dev-docs`), и **путь известен скиллу сам** — ссылки в чужое дерево здесь
нет намеренно: скилл работает и там, где того плагина не поставили.
``` ```
docs/tasks/ docs/tasks/
@@ -194,7 +195,7 @@ stateDiagram-v2
часть кода мы трогаем». часть кода мы трогаем».
**Целью не становится работа, которой держат проект.** Состав перечислен **Целью не становится работа, которой держат проект.** Состав перечислен
[в каноне](../canon/references/canon.md), раздел «Сопровождение и эксплуатация»; [в словаре сопровождения](references/operations.md);
на вопрос «что приложение будет уметь» ничто из него не отвечает. Им отведена отдельная секция роадмапа, на вопрос «что приложение будет уметь» ничто из него не отвечает. Им отведена отдельная секция роадмапа,
чтобы они были видны в том же экране и при этом не читались как возможности чтобы они были видны в том же экране и при этом не читались как возможности
продукта. продукта.
@@ -206,11 +207,12 @@ stateDiagram-v2
секции отвечают на разные вопросы. секции отвечают на разные вопросы.
**Сопровождение и эксплуатация — целое и часть**, а не синонимы, и та же тема **Сопровождение и эксплуатация — целое и часть**, а не синонимы, и та же тема
живёт ещё в двух местах канона: разделе «Эксплуатация» в `architecture.md` и живёт ещё в двух местах: разделе «Эксплуатация» в `architecture.md` и теме ревью
теме ревью `operations`. Словарь у всех трёх общий и живёт одним домом — `operations`. Словарь у всех трёх общий, дом у него один — `shared/operations.md`
[canon.md](../canon/references/canon.md), раздел «Сопровождение и эксплуатация». в репозитории плагинов, — а здесь лежит дословная копия:
Пересказывать его здесь нельзя: три перечня «чем держат проект» уже разъезжались [references/operations.md](references/operations.md). Пересказывать его своими
на «метриках и логах» против «мониторинга». словами нельзя: три перечня «чем держат проект» уже разъезжались на «метриках и
логах» против «мониторинга».
Секция выбирается так: очередь значима и обоснована прозой — `Запланировано`; Секция выбирается так: очередь значима и обоснована прозой — `Запланировано`;
тянется долго и очереди не имеет — `Направления`; не про приложение, а про то, тянется долго и очереди не имеет — `Направления`; не про приложение, а про то,
@@ -329,11 +331,12 @@ stateDiagram-v2
**Предметно, но без усложнения.** Текст задачи читает человек, который решает, **Предметно, но без усложнения.** Текст задачи читает человек, который решает,
брать её или нет, и делает это по строке индекса и одному экрану тела. брать её или нет, и делает это по строке индекса и одному экрану тела.
Язык — общий для всех проектных текстов, и живёт он одним файлом: Язык — общий для всех проектных текстов, и дом у него один,
[../canon/references/language.md](../canon/references/language.md) `shared/language.md` в репозитории плагинов; здесь лежит дословная копия:
(информационный стиль, применённый к задачам и документам канона; там же таблицы [references/language.md](references/language.md) (информационный стиль,
англицизмов и жаргона и то, что из стиля отброшено намеренно). Задаче он даёт применённый к задачам и документам канона; там же таблицы англицизмов и жаргона
четыре требования, которые нарушаются чаще прочих: и то, что из стиля отброшено намеренно). Задаче он даёт четыре требования,
которые нарушаются чаще прочих:
- **глагол вместо отглагольного существительного**: «обработчик не проверяет - **глагол вместо отглагольного существительного**: «обработчик не проверяет
владельца», а не «проверка владельца не осуществляется»; владельца», а не «проверка владельца не осуществляется»;
@@ -514,7 +517,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
**одним проходом вместе с починкой перекрёстных ссылок**, а не по одному слагу. **одним проходом вместе с починкой перекрёстных ссылок**, а не по одному слагу.
Если переводить надо не только задачи, а весь `docs/` — это скилл Если переводить надо не только задачи, а весь `docs/` — это скилл
`av-dev-pm:canon`, и он зовёт этот сценарий сам на своём шаге. `av-dev-docs:canon`, и он зовёт этот сценарий сам на своём шаге.
### Декомпозиция и штурм сырья ### Декомпозиция и штурм сырья
@@ -618,7 +621,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
- **Каталог задач — `docs/tasks`, жёстко**, и `--dir` передаётся явно всегда: - **Каталог задач — `docs/tasks`, жёстко**, и `--dir` передаётся явно всегда:
раскладка канона одинакова во всех проектах, и искать больше нечего. Каталога раскладка канона одинакова во всех проектах, и искать больше нечего. Каталога
нет — код 3 и вопрос человеку; `init` заводит его **только** когда проект нет — код 3 и вопрос человеку; `init` заводит его **только** когда проект
действительно новый, а перевод чужой раскладки делает `av-dev-pm:canon`. действительно новый, а перевод чужой раскладки делает `av-dev-docs:canon`.
У скрипта поиск вверх по дереву ещё жив — он для непереведённых проектов, и У скрипта поиск вверх по дереву ещё жив — он для непереведённых проектов, и
полагаться на него скилл не должен: молча найденный чужой каталог это дрейф. полагаться на него скилл не должен: молча найденный чужой каталог это дрейф.
- **Настройки живут в `docs/.pm.json`**, ключ `tasks`: **имена** файлов и - **Настройки живут в `docs/.pm.json`**, ключ `tasks`: **имена** файлов и
@@ -636,7 +639,7 @@ python3 $tk adopt scan --from … | apply --plan … # разовая адап
переменной не дотянутся. Мост — **вызов скилла через пространство имён**, а не переменной не дотянутся. Мост — **вызов скилла через пространство имён**, а не
путь: путь:
> Чужой контекст зовёт `Skill av-dev-pm:tasks` и называет, что нужно сделать > Чужой контекст зовёт `Skill av-dev-tasks:tasks` и называет, что нужно сделать
> («закрой задачу `<слаг>`, реализована»). Скилл разрешает свой > («закрой задачу `<слаг>`, реализована»). Скилл разрешает свой
> `$CLAUDE_PLUGIN_ROOT` сам. Путь наружу не выносится вовсе. > `$CLAUDE_PLUGIN_ROOT` сам. Путь наружу не выносится вовсе.
@@ -5,7 +5,7 @@
после неё проект живёт скиллами `tasks` и `session`. после неё проект живёт скиллами `tasks` и `session`.
**Это часть приведения проекта к канону.** Раскладку `docs/` целиком ведёт скилл **Это часть приведения проекта к канону.** Раскладку `docs/` целиком ведёт скилл
`av-dev-pm:canon`; он же зовёт этот сценарий на шаге «каталог задач», потому что `av-dev-docs:canon`; он же зовёт этот сценарий на шаге «каталог задач», потому что
форматом задач владеет `tasks`, а не `canon`. Отдельно сценарий вызывается, форматом задач владеет `tasks`, а не `canon`. Отдельно сценарий вызывается,
когда переводить надо **только** задачи. когда переводить надо **только** задачи.
@@ -0,0 +1,211 @@
# Язык проектных текстов
**Копия.** Дом — `shared/language.md` в репозитории плагинов; язык общий для
документов канона и для задач, и потому не принадлежит ни одному плагину.
Правится дом, а не этот файл: расхождение ловит `copies.py` на гейте коммита.
<!-- копия: язык-доктрина из shared/language.md -->
Правила — для всего, что пишется словами: задачи и цели, документы канона,
решения ADR, записки разведки, сообщения коммитов. Не для кода и не для
сообщений программы пользователю — там свои конвенции проекта.
Основа — **информационный стиль** Максима Ильяхова ([учебник
бюро](https://bureau.ru/projects/book-text/), книга «Пиши, сокращай»). Он
написан для рекламы, статей и писем, поэтому взят не целиком.
## Зачем он здесь
Проектный текст читают в двух положениях, и оба неудобные: **выбирают, брать ли
задачу**, глядя в строку индекса и один экран тела; и **возвращаются через
квартал**, не помня контекста. Оба положения наказывают одно и то же — слова, не
несущие сведений. Информационный стиль ровно про это, и его польза здесь не
эстетическая: текст, из которого нельзя достать факт, заставляет открывать код,
а это и есть цена, которой мы избегаем.
## Что взято сверх правил вычитки
Эти три требования судит человек, а не проход вычитки: находка по ним требует
увидеть текст целиком, а не фразу.
**Полезное действие.** У каждого текста есть вопрос, на который он отвечает, и
читатель, который этот вопрос задаёт. Не отвечает — не пишется. У задачи это
«зачем она нужна» и «что станет наблюдаемо иначе»; у документа канона — его
собственный вопрос («что это за система», «как сложено», «почему так решили»).
Текст, который не отвечает ни на чей вопрос, сокращается до нуля — это законный
исход правки.
**Параллельность.** Однородное пишется одинаково: пункты списка — одной
грамматической формой, разделы одного вида — одним порядком, заголовки одного
уровня — одним типом фразы. Разнобой читатель принимает за разницу по существу и
ищет её.
**Заголовок работает.** Заголовок называет содержание раздела, а не тему
вообще: «Что проверяет `check`», а не «О проверках». Заголовков ставится
столько, чтобы длинный текст можно было просматривать, а не только читать
подряд.
## Что отброшено намеренно
Инфостиль написан для текстов, где читателя надо удержать. Проектный текст
читают потому, что надо, и держать его нечем. Отсюда три расхождения:
- **Парцелляция и рубленые фразы — нет.** Приём «Коротко. Ещё короче. Вот так»
ломает причинную связь, а в решении и в задаче ценность именно в ней:
«поэтому», «иначе», «раз так» несут смысл и остаются.
- **Не всякое вводное — мусор.** «Если», «иначе», «при таком-то условии»,
«в отличие от» — это условия и противопоставления, то есть сведения. Режутся
вводные, которые не меняют смысл предложения.
- **Скобки и точка с запятой остаются.** В технической записи скобки несут
уточнение — имя команды, единицы, слаг, — и запрет на них удлинил бы текст, а
не сократил. Запрет на многоточие принимаем: в проектном тексте оно значит
«дописать позже», и такой текст лучше не публиковать.
И общее: инфостиль призывает «снять корону с себя и надеть на читателя». Здесь
читатель — **ты сам через квартал** и тот, кто возьмёт задачу. Писать для них
значит называть состояние и остаток, а не пересказывать, как было интересно
разбираться.
<!-- /копия: язык-доктрина -->
## Правила
<!-- копия: язык-правила из shared/language.md -->
У каждого правила названа причина: она же говорит, где правило **не**
применяется.
1. **Глагол вместо отглагольного существительного, активный залог.** «Обработчик
не проверяет владельца», а не «проверка владельца не осуществляется»;
«скрипт переписывает индекс», а не «индекс переписывается скриптом».
Отглагольное существительное прячет того, кто действует, — а в техническом
тексте важен именно он. Страдательный залог **остаётся**, когда деятель
неизвестен или неважен: «файл удаляется» верно, если удаляет любая из трёх
команд.
2. **Факт вместо оценки.** «Время ответа доходит до 800 мс», а не «работает
медленно»; «тело 40 МиБ держит блокировку 5 секунд», а не «большие тела
тормозят». Оценка допустима, когда факт стоит рядом, в той же фразе. Без
факта это настроение, а не сведение, — и находка тем ценнее, что оценку
потом не проверить.
3. **Стоп-слова.** Канцелярит (является, осуществляется, в целях, в рамках,
данный, вышеуказанный), вводные-паразиты (в общем, как известно, стоит
отметить), усилители (очень, крайне, достаточно, абсолютно, максимально),
синонимы одного качества («понятный и простой»), неопределённое
(соответствующий, определённый, некоторый).
Проверка одна: **вычеркни слово — смысл изменился, оставляй.** И осторожно с
вводными: «если», «иначе», «при таком-то условии», «в отличие от» несут
условие и противопоставление, то есть сведения, — их не трогают.
4. **Одна мысль — одно предложение.** Предложение с двумя независимыми
утверждениями делится. **Причинную связь не режут**: «поэтому», «иначе», «раз
так» — смысл, а не длина; рубленые фразы ради краткости тут вредят.
**Поля меты не делятся.** «Зачем» в мете задачи по формату — одно
предложение: оно повторяется строкой индекса, и второму там не поместиться.
Тесно — сокращают, но не делят. То же с любым полем вида `- **Имя:** …`.
5. **Англицизм, у которого есть живое русское слово, заменяется.**
| Калька | Русский аналог |
| --- | --- |
| флоу | поток, процесс, сценарий |
| фикс, зафиксить | исправление, исправить, починить |
| чекать | проверять |
| апрув, заапрувить | согласование, согласовать |
| best-effort | по возможности |
| кейс | случай, сценарий |
| перформанс | производительность |
| матчинг, смэтчить | сопоставление, сопоставить |
| зарелизить | выпустить, выложить |
| отрефакторить | переписать, разделить, убрать второй путь |
Насильно не переводится то, что является **именем вещи**: термины технологий
и протоколов (`SQL`, `API`, `CSV`, `N+1`, `IDOR`), имена классов, методов,
полей, таблиц и команд, слаг, а также термин, у которого нет точного русского
эквивалента и который в команде уже прижился.
Цель — простой и точный текст, а не пуризм. Русский аналог звучит коряво или
искажает смысл — остаётся термин.
6. **Слово из своего словаря не трогается — список закрыт.** Оговорка «термин
прижился» без списка проверяема на глаз и потому не проверяема: прижившимся
выглядит любое слово, встреченное трижды.
| Термин | Что называет |
| --- | --- |
| интейк | заведение записи с фильтром и дедупом: «заведение» называет создание файла, слить их — смешать две операции |
| триаж | стадия конвейера, сводящая находки в решение |
| провенанс | обязательное свойство числа: чем и при каких условиях получено. «Источник» рядом называет саму запись, а не свойство |
| дедуп, дедупликация | сверка нового против уже лежащего |
| чек-лист | перечень, по которому идут сверху вниз, называя исход каждой строки |
| дифф, `--base` | разница между состояниями в git |
| промпт | текст, которым зовут модель |
| change, capability, spec | сущности OpenSpec, имена вещей чужого инструмента |
| generative, applicative | роды проходов ревью, вводятся определением по месту |
**Список закрыт.** Слово не отсюда и не из таблицы имён вещей выше — находка,
а не «принятый стиль»: у него либо есть живой русский аналог, либо оно
требует ввода одной строкой при первом употреблении.
Отсюда же читается снятое. Эти слова из текстов убраны, и возвращать их не
надо: **конфляция** (смешение), **декорреляция** (разведённость, разведён с
кем-то), **непоймание** (почему не поймали), **эвал-сет** (проверочный
набор), **гайд** (руководство). Каждое было латинизмом или калькой при живом
русском слове, и каждое к моменту снятия жило в трёх-шести файлах разом — то
есть выглядело словарём, не будучи им.
7. **Жаргон и метафоры заменяются прямым называнием.** Автору образ понятен,
читателю — нет.
| Метафора-жаргон | Прямо |
| --- | --- |
| рычаг (кэша, отбора) | условие отбора, параметр |
| навешен не на тот счётчик | завязан не на тот счётчик |
| переширокий матчинг по имени | слишком грубое сопоставление по имени, слишком много слабых совпадений |
| костыль | временное решение, обходной путь — и в чём именно |
| просело, отвалилось | стало медленнее на столько-то, перестало отвечать |
Проверка: **фраза требует, чтобы читатель додумал образ, — заменяется
буквальным описанием того, что происходит.**
8. **Термин, которого нет в документах проекта, вводится одной строкой или не
употребляется.** Термин, не встречающийся ни в паспорте, ни в архитектуре, ни
в конвенциях, — свой словарь у отдельной записи, а это самый дешёвый способ
сделать беклог нечитаемым для того, кто вернётся к нему через квартал.
Заменять незнакомый термин догадкой нельзя: догадка о предметной области
дороже непонятного слова, потому что выглядит понятной.
**Слово, занятое в другом смысле, — то же нарушение.** Термин, который в
одном документе проекта значит одно, а здесь другое, ломает оба.
9. **Имя файла — английское слово по сути, а не транслит.** `queue-as-table`, а
не `ochered-tablicej`; `move-parse-strict`, а не `razbor-hoda`. Транслит
нечитаем тому, кто ищет по смыслу, и не сокращается, а имя стоит в ссылках,
коммитах и путях, которые набирают руками. Переименование — **перенос ссылок
одним проходом**, а не правка одного файла.
<!-- /копия: язык-правила -->
## Порог правки
<!-- копия: порог-правки из shared/language.md -->
**Правка без нарушенного правила не делается.** Текст, переписанный «чтобы
звучало лучше», обесценивает список замечаний: когда половина из них вкусовая,
перестают читать весь список, и вместе с ним пропадают настоящие находки.
Сомневаешься — не правь. Формулировка, которая просто **не твоя**, — не находка.
**Систематичность нарушения — не довод в его пользу.** Одна и та же ошибка в
пяти файлах не становится «принятым стилем»: чаще это значит, что правило не
применялось вовсе, — и находка тем важнее. «Так сделано везде» годится как
основание для **одной находки на весь набор** («правило N нарушено в пяти
записях, перечень: …»), но не как основание промолчать. Принятым считается
только то, что назвал зовущий или что записано в конвенциях проекта.
<!-- /копия: порог-правки -->
И обратное: язык правится **по ходу той операции, которая записи касается**.
Беклог не переписывают ради языка.
@@ -0,0 +1,34 @@
# Сопровождение и эксплуатация
**Копия.** Дом — `shared/operations.md` в репозитории плагинов. Словарь общий для
роадмапа, архитектуры и темы ревью `operations`, и не принадлежит ни одному из
трёх — правится дом, а не этот файл.
Скиллу задач он нужен для секции `Сопровождение` в `ROADMAP.md`: она отвечает не
на «что приложение будет уметь», а на «чем его держат», и путать эти два вопроса
нельзя.
<!-- копия: сопровождение-словарь из shared/operations.md -->
Одна тема живёт в трёх местах, и путать их слова нельзя.
**Сопровождение** — всё, чем держат проект: инструмент и сборка, процесс,
выкладка, метрики и логи, инфраструктура, дежурство. **Эксплуатация** — его
часть: работа системы на проде. Целое и часть, и никогда наоборот.
| Место | Уровень | Что там |
| --- | --- | --- |
| `ROADMAP.md`, секция `Сопровождение` | план | **работы**, которые собираемся делать: цели и их задачи |
| `architecture.md`, раздел «Эксплуатация» | состояние | **как устроено сейчас**: где работает, что рядом, кто перезапускает |
| тема ревью `operations` | оптика | **чем проверяем**: «это упало через неделю на проде» |
Слово **«поддержка» не употребляется вовсе** — в нём слышится помощь
пользователю, а это другая работа.
**Граница с возможностями проходит по тому, кто наблюдает.** «Приложение
сообщает о своём состоянии» — возможность приложения, её место среди прочих
целей: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
секции роадмапа, и это верно — секции отвечают на разные вопросы.
<!-- /копия: сопровождение-словарь -->
@@ -38,8 +38,8 @@
1. **Проверить, что это возможность, а не работа.** Работа, которой держат 1. **Проверить, что это возможность, а не работа.** Работа, которой держат
проект, на вопрос «что приложение будет уметь» не отвечает; состав перечислен проект, на вопрос «что приложение будет уметь» не отвечает; состав перечислен
[в каноне](../../canon/references/canon.md), раздел «Сопровождение и [в словаре сопровождения](operations.md). Ей отведена секция
эксплуатация». Ей отведена секция `Сопровождение` — там она видна в том же `Сопровождение` — там она видна в том же
экране и не читается как обещание продукта. Граница проходит по тому, экране и не читается как обещание продукта. Граница проходит по тому,
**кто наблюдает**: **кто наблюдает**:
«приложение сообщает о своём состоянии» — возможность, «дежурный видит «приложение сообщает о своём состоянии» — возможность, «дежурный видит
@@ -77,7 +77,7 @@ goal | feature | fix | chore | research, по-английски, как и пр
Каталог задач: `--dir` (обязан быть внутри рабочего каталога) `docs/tasks` Каталог задач: `--dir` (обязан быть внутри рабочего каталога) `docs/tasks`
вверх от текущего каталога. Прежние раскладки (`tasks`, `doc/tasks`) читаются, вверх от текущего каталога. Прежние раскладки (`tasks`, `doc/tasks`) читаются,
пока живы непереехавшие проекты; переводит их скилл av-dev-pm:canon. пока живы непереехавшие проекты; переводит их скилл av-dev-docs:canon.
Коды выхода (единый словарь, на нём ветвятся скиллы): Коды выхода (единый словарь, на нём ветвятся скиллы):
@@ -484,7 +484,7 @@ def _validate_config(data: dict, path: Path) -> dict:
if "plan" in unknown: if "plan" in unknown:
raise Env(f"{path}: ключ «plan» переименован в «roadmap»," raise Env(f"{path}: ключ «plan» переименован в «roadmap»,"
f" а PLAN.md — в ROADMAP.md. Повысь проект скиллом" f" а PLAN.md — в ROADMAP.md. Повысь проект скиллом"
f" av-dev-pm:canon (upgrade), а не правь ключ в одиночку:" f" av-dev-docs:canon (upgrade), а не правь ключ в одиночку:"
f" файл и ссылки на него переезжают вместе с ним") f" файл и ссылки на него переезжают вместе с ним")
if unknown: if unknown:
raise Env(f"{path}: неизвестные ключи: {', '.join(sorted(unknown))}" raise Env(f"{path}: неизвестные ключи: {', '.join(sorted(unknown))}"
@@ -567,7 +567,7 @@ def resolve_layout(explicit: str | None) -> Layout:
break # выше корня репозитория не ищем break # выше корня репозитория не ищем
raise Env("каталог задач не найден: ни --dir, ни docs/tasks вверх от" raise Env("каталог задач не найден: ни --dir, ни docs/tasks вверх от"
f" {here}. По канону путь всегда docs/tasks; чужую раскладку" f" {here}. По канону путь всегда docs/tasks; чужую раскладку"
" переводит скилл av-dev-pm:canon, новый проект —" " переводит скилл av-dev-docs:canon, новый проект —"
" tasks.py init --dir docs/tasks") " tasks.py init --dir docs/tasks")
+35
View File
@@ -0,0 +1,35 @@
# Сопровождение и эксплуатация
**Это дом.** Словарь «чем держат проект» назван в трёх местах трёх разных
плагинов: секция `Сопровождение` в роадмапе (`av-dev-tasks`), раздел
«Эксплуатация» в `architecture.md` (`av-dev-docs`) и тема ревью `operations`
(`av-dev-pipeline`). Ни один из трёх им не владеет, поэтому дом стоит снаружи, а
плагины везут копии.
Три перечня «чем держат проект» уже разъезжались — на «метриках и логах» против
«мониторинга», — и разъехались молча. Отсюда дословная копия вместо ссылки.
<!-- дом: сопровождение-словарь -->
Одна тема живёт в трёх местах, и путать их слова нельзя.
**Сопровождение** — всё, чем держат проект: инструмент и сборка, процесс,
выкладка, метрики и логи, инфраструктура, дежурство. **Эксплуатация** — его
часть: работа системы на проде. Целое и часть, и никогда наоборот.
| Место | Уровень | Что там |
| --- | --- | --- |
| `ROADMAP.md`, секция `Сопровождение` | план | **работы**, которые собираемся делать: цели и их задачи |
| `architecture.md`, раздел «Эксплуатация» | состояние | **как устроено сейчас**: где работает, что рядом, кто перезапускает |
| тема ревью `operations` | оптика | **чем проверяем**: «это упало через неделю на проде» |
Слово **«поддержка» не употребляется вовсе** — в нём слышится помощь
пользователю, а это другая работа.
**Граница с возможностями проходит по тому, кто наблюдает.** «Приложение
сообщает о своём состоянии» — возможность приложения, её место среди прочих
целей: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
секции роадмапа, и это верно — секции отвечают на разные вопросы.
<!-- /дом: сопровождение-словарь -->