граница: правило стало про раскладку проекта, а не про соседний плагин

Дом shared/plugin-boundary.md переехал в shared/absence.md: отсутствовала всё
это время не установка плагина, а часть раскладки проекта, и узнавалась она
следом на диске. Перечень внешнего сократился до двух — opsx и av-dev-git.
Ветки «плагина нет» переписаны на «этой части в проекте нет»; там, где ветка
существовала только ради неразрешимого пути в чужое дерево, она снята вовсе.

Внутриплагинные копии языка и словаря сопровождения сняты: два справочника по
213 строк и один по 34 заменены ссылкой на общий дом. Копии остались там, где
текст обязан лежать внутри промпта, — в уставах вычитки. Заодно починены пути
$CLAUDE_PLUGIN_ROOT и относительные ссылки, разъехавшиеся с новыми именами
каталогов.
This commit is contained in:
av
2026-08-13 10:18:04 +03:00
parent de12a4d8a3
commit 6b162c421d
37 changed files with 368 additions and 832 deletions
+38 -31
View File
@@ -57,7 +57,7 @@ openspec init --tools claude
Разрез, по которому отличают одно от другого: **утверждение, которое можно
опровергнуть, открыв другой файл проекта, — пересказ; строка, которая говорит,
какой файл открыть, — ссылка.** Машина этот разрез не проверяет; его смотрит
агент `doc-consistency` из плагина канона, когда тот подключён.
агент `doc-consistency`, когда документы канона в проекте есть.
Два адреса обязательны — `docs/passport.md` и `CLAUDE.md`: предложение пишется до
того, как кто-либо откроет `docs/`, и без них его пишут, не зная ни границы
@@ -67,7 +67,7 @@ openspec init --tools claude
## Инструмент
```
os="$CLAUDE_PLUGIN_ROOT/skills/openspec/scripts/openspec.py"
os="$CLAUDE_PLUGIN_ROOT/skills/code-openspec/scripts/openspec.py"
python3 $os check --dir <корень> # форма config.yaml в проекте
python3 $os form # слепок формы против живого OpenSpec
@@ -87,9 +87,9 @@ python3 $os form # слепок формы против жив
имена артефактов схемы, а не свободные слова. Числа проверок здесь нет намеренно:
оно протухает от каждой добавленной.
**Адреса требуются только к тем документам, которые в проекте есть.** Канон
документов ставится отдельным плагином и может быть не подключён; требовать
ссылку на несуществующий файл значит требовать битую ссылку. Нет
**Адреса требуются только к тем документам, которые в проекте есть.** Документы
канона могут быть не заведены; требовать ссылку на несуществующий файл значит
требовать битую ссылку. Нет
`docs/passport.md` — проверка по нему идёт строкой «не проверялось», и там же
сказано, что без канона конвейер работает вслепую.
@@ -124,46 +124,53 @@ python3 $os form # слепок формы против жив
сюда вместо того, чтобы заводить его руками;
- человек — когда конвейер отказался работать без источника требований.
**Копия.** Дом правила — `shared/plugin-boundary.md` в репозитории плагинов.
**Копия.** Дом правила — `shared/absence.md` в репозитории плагина.
Правится дом, а не этот файл.
<!-- копия: граница-плагинов из av-dev/shared/plugin-boundary.md -->
<!-- копия: отсутствие из av-dev/shared/absence.md -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
живут порознь; каждая узнаётся своим следом:
**Чужой скилл зовётся полным именем**`av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
| Чего нет | Как видно | Чего теперь не делает никто |
| --- | --- | --- |
| раскладка av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Свой скилл зовётся полным именем** `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
поведении.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
сам.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.docs.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
Имя файла — имя плагина, который его завёл, и держит он в том числе версию своего
формата: у канона документов и у каталога задач они свои и двигаются порознь.
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
сделанного. Выдумывать обходной путь нельзя тоже.
<!-- /копия: граница-плагинов -->
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
Здесь это значит: вызов не разрешился — плагина конвейера в проекте нет, и тогда
OpenSpec заводит человек командой выше.
<!-- /копия: отсутствие -->
Здесь это значит: документов канона в проекте может не быть, и тогда `context`
называет только те адреса, которые есть, — строкой доклада говорится, что без
паспорта предложение пишут, не зная границы домена.
## Чего этот скилл не делает
- **Не пишет спеки и предложения.** Это `opsx:propose` и конвейер задачи.
- **Не ведёт документы канона** — их дом плагин `av-dev-docs`, и адреса в
- **Не ведёт документы канона** — их дом скилл `av-dev:doc-canon`, и адреса в
`context` только на них ссылаются.
- **Не чинит расхождение формы с версией OpenSpec в проекте.** Оно чинится в
плагине: константы скрипта, образец здесь, запись в журнал версий канона.
- **Не судит, ссылается `context` на документы или пересказывает их.** Машине
этот разрез не виден; его смотрит агент `doc-consistency` из плагина канона.
Плагина нет — эту проверку не делает никто, и так и скажи.
этот разрез не виден; его смотрит агент `doc-consistency`. Документов канона в
проекте нет — сверять пересказ не с чем, и так и скажи.
+34 -28
View File
@@ -48,38 +48,44 @@ description: "Взять одну задачу и довести её до за
`.claude/agents/<проект>-review-*.md`). Две копии одного скилла расходятся, и
побеждает та, что короче названа.
### Обращение к соседним плагинам
### Чего может не быть
**Копия.** Дом — `shared/plugin-boundary.md` в репозитории плагинов: правило
общее для всех, кто зовёт чужое, и ни один плагин им не владеет. Правится дом, а
не этот файл.
**Копия.** Дом правила`shared/absence.md` в репозитории плагина: правило
общее для всех, кто приходит в чужой проект, и ни один скилл им не владеет.
Правится дом, а не этот файл.
<!-- копия: граница-плагинов из av-dev/shared/plugin-boundary.md -->
<!-- копия: отсутствие из av-dev/shared/absence.md -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
живут порознь; каждая узнаётся своим следом:
**Чужой скилл зовётся полным именем**`av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
| Чего нет | Как видно | Чего теперь не делает никто |
| --- | --- | --- |
| раскладка av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Свой скилл зовётся полным именем** `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
поведении.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
сам.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.docs.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
Имя файла — имя плагина, который его завёл, и держит он в том числе версию своего
формата: у канона документов и у каталога задач они свои и двигаются порознь.
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
сделанного. Выдумывать обходной путь нельзя тоже.
<!-- /копия: граница-плагинов -->
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
<!-- /копия: отсутствие -->
Скилл зовёт `av-dev:code-review`, `av-dev:doc-sync` и
`av-dev:task-track`. Чем оборачивается отсутствие каждого — на самих шагах и в
@@ -87,7 +93,7 @@ description: "Взять одну задачу и довести её до за
Перед стартом прочитай `CLAUDE.md` проекта и то, на что он ссылается, если ещё
не в контексте. Проектные факты, нужные ревью — инварианты, семантика гейта,
объёмы, модель угроз, прецеденты, — живут в **документах канона** `av-dev-docs`;
объёмы, модель угроз, прецеденты, — живут в **документах канона**;
карта «что где» — `references/project-facts.md` конвейера ревью.
**Документов канона нет — проект к нему не приведён.** Скажи это строкой и
@@ -114,7 +120,7 @@ description: "Взять одну задачу и довести её до за
**Отказ `ready` сценарий не выбирает.** Запись `research` без раздела «Вопрос»
(сырьё) — отказ и здесь: у неё нет вопроса, и разведывать нечего.
Плагина `av-dev-tasks` в проекте нет или задача пришла текстом — прогонять
Каталога задач в проекте нет или задача пришла текстом — прогонять
нечего. Тогда прочитай постановку сам и скажи строкой, что готовность машиной не
проверялась; работу при этом не останавливай.
@@ -259,7 +265,7 @@ flowchart TD
что успели узнать, где остановились и почему.
**Что остатком не является — правило живёт не здесь.** Канонический текст с обеими
оговорками — в плагине `av-dev-tasks`, скилл `av-dev:task-groom`, раздел
оговорками — в скилле `av-dev:task-groom`, раздел
`## Вопрос, блокер, необратимое`, подраздел «Отличать вопрос от застревания».
Правило принадлежит управлению задачами, потому что решает **сделана задача или
вышла**, — это исход планирования, а не исполнения. **Ссылайся, не
@@ -272,7 +278,7 @@ flowchart TD
Оба порога — стоп: первый поднимает решение до начала записи, второй даёт исход
«не доведена».
Плагин `av-dev-tasks` не подключён — правило не отменяется, а становится
Каталога задач в проекте нет — правило не отменяется, а становится
осторожнее: прежде чем записать зависящее от нерешённого куда бы то ни было —
в хранилище, в журнал, в витрину или наружу, — спрашивай человека.
@@ -331,11 +331,9 @@ Change ты не передаёшь — его нет.
«ничего не решали, поменяли оснастку».
Список документов и их триггеров здесь не дублируется — он в чек-листе скилла
`av-dev:doc-sync`; копия уже однажды разошлась с оригиналом. Плагина в проекте
нет — иди за перечнем в свой reference,
[references/project-facts.md](../../review/references/project-facts.md) конвейера
ревью, добавь `adr/` руками и скажи строкой, что синк сделан по перечню
документов, без списка триггеров.
`av-dev:doc-sync`; копия уже однажды разошлась с оригиналом. Документов канона в
проекте нет — синка нет вовсе: скажи это исходом и предложи завести канон
скиллом `av-dev:doc-canon`.
### 6. Коммит
@@ -265,13 +265,9 @@ git и читается диффом, а второй стоп на каждой
незачем. Но **названо должно быть каждое место, куда ты писал**, — доклад без
перечня адресов неотличим от доклада о ненаписанном.
**Плагина `av-dev-docs` нет** — путь в его дерево не разрешится ниоткуда, поэтому
за перечнем документов иди в **свой** reference:
[references/project-facts.md](../../review/references/project-facts.md) конвейера
ревью. `docs/adr/` и `docs/research/` в нём отсутствуют намеренно (проход ревью их
не открывает), а разведке нужны как раз они — добавь их руками. Пиши сам, скажи
строкой: «ответ записан без скилла документации — форму и вычитку не сверял
никто».
**Документов канона в проекте нет** — писать ответ некуда: назови это исходом,
предложи завести канон скиллом `av-dev:doc-canon` и оставь ответ в докладе
целиком, чтобы работа не пропала. Заводить `docs/` мимо канона нельзя.
### 5. Задачи: завести и уточнить
+5 -16
View File
@@ -332,21 +332,10 @@ flowchart TD
`av-dev:doc-sync`, и копия уже однажды разошлась с оригиналом, потеряв два
триггера.
**Плагина `av-dev-docs` в проекте нет** — путь в его дерево не разрешится ниоткуда,
поэтому за списком иди в **свой** reference:
[references/project-facts.md](../../review/references/project-facts.md)
конвейера ревью перечисляет все документы канона с их предметом. Пройди по этому
перечню — каждый документ получает строку, отрицание остаётся обязательным.
**Двух домов в том перечне нет намеренно, а синку они нужны: `docs/adr/` и
`docs/research/`.** Проход ревью их не открывает — процессные, — но ADR как раз
**главный выход синка**: решение, принятое по ходу задачи, без этой строки
теряется систематически. Добавь их к перечню руками: `adr/` — решение с ценой,
принятое в этой задаче; `research/` — если по ходу узналось новое о внешнем мире
(записку разведки, предшествовавшей задаче, пишет не этот сценарий).
Триггеры при этом ты знаешь хуже, и это называется в докладе строкой: «синк
сделан по перечню документов, без списка триггеров — плагина `av-dev-docs` нет».
Канона в проекте тоже нет — назови это исходом и предложи `av-dev:doc-canon`.
**Документов канона в проекте нет** — синка нет вовсе: назови это исходом и
предложи завести канон скиллом `av-dev:doc-canon`. Придумывать раскладку под
задачу нельзя: документ, заведённый мимо канона, окажется вторым домом ровно
тому, что канон потом заведёт своим.
### 10. Коммит
@@ -368,7 +357,7 @@ flowchart TD
оставило бы задачу закрытой без единого следа работы, если шаг 10 упадёт.
**Закрытие тоже коммитится — вторым коммитом, тут же.** Удаление файла задачи и
правка индексов (их имена знает `av-dev-tasks`, не ты) — это правки в рабочем
правка индексов (их имена знает `av-dev:task-track`, не ты) — это правки в рабочем
дереве, и оставить их незакоммиченными нельзя: закрытие, не доехавшее до основной
ветки, оставит задачу открытой молча, а опора «индексы под git показывают, что и
когда закрыто» без коммита — пустые слова. Сообщение короткое, про учёт, а не про
+31 -25
View File
@@ -1,6 +1,6 @@
---
name: code-review
description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после propose: агент review-scope выводит размер и сложность, из их максимума — метка, и раздаёт темы проходам обеих стадий. Метка правит и ревью дизайна (small — только specs; medium — плюс rubric; large — плюс architecture), и ревью кода (small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс доказательство: враждебные постановки, эксплуатационный постмортем, архитектурный проход на широком входе). Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает проходы с мнением, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Проектная специфика приходит из документов канона av-dev-docs. Вызывается из скилла resolve — двумя стадиями: ревью дизайна до кода и ревью кода после apply. Третий вызов идёт от сценария обслуживания: без change и без метки, фиксированным планом (autotests, operations, плюс conventions, если тронут код), разметчик при этом не запускается."
description: "Конвейер ревью изменения, устроенный по темам: документ проекта либо заводит тему ревью, либо питает чужую тему источником, либо процессный и в ревью не читается вовсе. Ядро тем — requirements, autotests, conventions, architecture, security, operations; список тем открытый, свои темы проект заводит документом. Разметка задачи идёт один раз, после propose: агент review-scope выводит размер и сложность, из их максимума — метка, и раздаёт темы проходам обеих стадий. Метка правит и ревью дизайна (small — только specs; medium — плюс rubric; large — плюс architecture), и ревью кода (small — гейт, спеки, код, триаж; medium — плюс приёмник тем; large — плюс доказательство: враждебные постановки, эксплуатационный постмортем, архитектурный проход на широком входе). Триаж обязателен всегда. Порядок прогона — граф зависимостей: гейт открывает проходы с мнением, проходы с пометкой «держит машину» идут цепочкой, триаж — единственный сток. Проектная специфика приходит из документов канона проекта. Вызывается из скилла resolve — двумя стадиями: ревью дизайна до кода и ревью кода после apply. Третий вызов идёт от сценария обслуживания: без change и без метки, фиксированным планом (autotests, operations, плюс conventions, если тронут код), разметчик при этом не запускается."
---
# Конвейер ревью
@@ -66,37 +66,43 @@ description: "Конвейер ревью изменения, устроенны
`.claude/agents/<проект>-review-*.md` — снеси их. Иначе короткое имя разрешится
в устаревшую проектную копию, молча и без признаков подмены.
### Обращение к соседним плагинам
### Чего может не быть
**Копия.** Дом — `shared/plugin-boundary.md` в репозитории плагинов. Правится
дом, а не этот файл.
**Копия.** Дом правила`shared/absence.md` в репозитории плагина.
Правится дом, а не этот файл.
<!-- копия: граница-плагинов из av-dev/shared/plugin-boundary.md -->
<!-- копия: отсутствие из av-dev/shared/absence.md -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
живут порознь; каждая узнаётся своим следом:
**Чужой скилл зовётся полным именем**`av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
| Чего нет | Как видно | Чего теперь не делает никто |
| --- | --- | --- |
| раскладка av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Свой скилл зовётся полным именем** `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
поведении.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
сам.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.docs.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
Имя файла — имя плагина, который его завёл, и держит он в том числе версию своего
формата: у канона документов и у каталога задач они свои и двигаются порознь.
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
сделанного. Выдумывать обходной путь нельзя тоже.
<!-- /копия: граница-плагинов -->
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
<!-- /копия: отсутствие -->
Своих скиллов это касается ровно так же: `av-dev:code-review`,
`av-dev:code-resolve`, `av-dev:code-openspec` — подменяется короткое имя,
@@ -201,7 +207,7 @@ description: "Конвейер ревью изменения, устроенны
прохода между метками;
- **контракт находок** — путь к
[references/finding-contract.md](references/finding-contract.md) (в
установленном плагине — `${CLAUDE_PLUGIN_ROOT}/skills/review/references/`);
установленном плагине — `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/`);
- **изменение** — идентификатор change и путь к его дельта-спекам;
- **база диффа**;
- **метка, его глубина и режим** прогона — чтобы проход знал, что писать в
@@ -4,8 +4,8 @@
нельзя нарушать, чем краснеет гейт и сколько данных реально идёт через узел,
выдаёт правдоподобные общие места: их дорого опровергать и нечем подтверждать.
Отдельного файла-брифа **нет**. Проектная конкретика живёт в документах канона
`av-dev-docs`, и проход читает их напрямую: пути жёсткие, посредник не нужен, а
Отдельного файла-брифа **нет**. Проектная конкретика живёт в документах канона,
и проход читает их напрямую: пути жёсткие, посредник не нужен, а
второй дом для тех же фактов разошёлся бы и выглядел актуальным.
Определение канона держит скилл `av-dev:doc-canon`. Здесь только карта «тема →
@@ -1,7 +1,7 @@
# Журнал дефектов
Артефакт проекта, а не плагина: файл живёт в репозитории — **`docs/review.md`**,
слот канона `av-dev-docs`. Здесь описано, зачем он и какой формы, потому что без
слот канона документов. Здесь описано, зачем он и какой формы, потому что без
него конвейер не учится: находки закрываются, а почему их не поймали — забывается,
и один и тот же класс проскакивает второй раз.
+30 -24
View File
@@ -20,7 +20,7 @@ description: Привести проект к канону документов
- [references/skeletons.md](references/skeletons.md) — **что именно класть** в
каждый незаполненный слот. Не выдумывай заглушку своей формы: `docs.py`
узнаёт только плейсхолдер `<!-- заполнить: … -->` из шаблонов.
- [references/language.md](references/language.md) — **как это написано словами**:
- [shared/language.md](../../shared/language.md) — **как это написано словами**:
информационный стиль, применённый к проектным текстам, таблицы англицизмов и
жаргона. Раскладка отвечает, где текст лежит, — этот файл отвечает, каким он
должен быть. Правила общие для документов канона, задач, решений ADR и
@@ -45,7 +45,7 @@ description: Привести проект к канону документов
## Инструмент
```
ds="$CLAUDE_PLUGIN_ROOT/skills/canon/scripts/docs.py"
ds="$CLAUDE_PLUGIN_ROOT/skills/doc-canon/scripts/docs.py"
python3 $ds check --dir <корень> [--base <rev>] # раскладка, ссылки, версия, сверки
python3 $ds version --dir <корень> # версия канона скрипта и проекта
@@ -87,41 +87,47 @@ capability: незаполненный канон это переходное с
формулировка казалась удачной при написании. Ни один из них ничего не правит —
оба возвращают готовые формулировки, подставляешь ты.
## Обращение к соседним плагинам
## Чего может не быть
`adopt` зовёт двоих: `av-dev:code-openspec` (шаг 4, пункт 3) и
`av-dev:task-track` (шаг 4, пункт 5). Каталоги `openspec/` и `tasks/` каноном не
ведутся, и трогать их этому скиллу нечем, кроме вызова.
**Копия.** Дом правила — `shared/plugin-boundary.md` в репозитории плагинов.
**Копия.** Дом правила — `shared/absence.md` в репозитории плагина.
Правится дом, а не этот файл.
<!-- копия: граница-плагинов из av-dev/shared/plugin-boundary.md -->
<!-- копия: отсутствие из av-dev/shared/absence.md -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
живут порознь; каждая узнаётся своим следом:
**Чужой скилл зовётся полным именем**`av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
| Чего нет | Как видно | Чего теперь не делает никто |
| --- | --- | --- |
| раскладка av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Свой скилл зовётся полным именем** `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
поведении.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
сам.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.docs.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
Имя файла — имя плагина, который его завёл, и держит он в том числе версию своего
формата: у канона документов и у каталога задач они свои и двигаются порознь.
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
сделанного. Выдумывать обходной путь нельзя тоже.
<!-- /копия: граница-плагинов -->
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
<!-- /копия: отсутствие -->
Чем оборачивается отсутствие каждого — на самих пунктах шага 4. `adopt` из-за
этого не останавливается ни в одном из двух случаев.
+8 -31
View File
@@ -23,39 +23,16 @@
Раскладка отвечает, **где** текст лежит и на какой вопрос отвечает. Каким он
должен быть **словами** — общий для всех документов канона файл
[language.md](language.md): информационный стиль, англицизмы, жаргон. Он
[shared/language.md](../../../shared/language.md): информационный стиль, англицизмы, жаргон. Он
относится и к задачам, и к решениям ADR, и к запискам разведки.
## Сопровождение и эксплуатация — целое и часть
**Копия.** Дом — `shared/operations.md` в репозитории плагинов: словарь
делят роадмап, архитектура и тема ревью `operations`, то есть три плагина,
и ни один из трёх им не владеет. Правится дом, а не этот файл.
<!-- копия: сопровождение-словарь из av-dev/shared/operations.md -->
Одна тема живёт в трёх местах, и путать их слова нельзя.
**Сопровождение** — всё, чем держат проект: инструмент и сборка, процесс,
выкладка, метрики и логи, инфраструктура, дежурство. **Эксплуатация** — его
часть: работа системы на проде. Целое и часть, и никогда наоборот.
| Место | Уровень | Что там |
| --- | --- | --- |
| `ROADMAP.md`, секция `Сопровождение` | план | **работы**, которые собираемся делать: цели и их задачи |
| `architecture.md`, раздел «Эксплуатация» | состояние | **как устроено сейчас**: где работает, что рядом, кто перезапускает |
| тема ревью `operations` | оптика | **чем проверяем**: «это упало через неделю на проде» |
Слово **«поддержка» не употребляется вовсе** — в нём слышится помощь
пользователю, а это другая работа.
**Граница с возможностями проходит по тому, кто наблюдает.** «Приложение
сообщает о своём состоянии» — возможность приложения, её место среди прочих
целей: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
секции роадмапа, и это верно — секции отвечают на разные вопросы.
<!-- /копия: сопровождение-словарь -->
Словарь этой темы — [shared/operations.md](../../../shared/operations.md):
целое и часть, три места одной темы (секция роадмапа, раздел архитектуры, тема
ревью `operations`) и граница с возможностями проекта. Здесь он не
пересказывается: копия жила рядом с домом в одном дереве и была ровно тем
вторым домом, против которого правило и написано.
## Раскладка
@@ -79,7 +56,7 @@ docs/
adr.md | adr/ почему решено так; статусы, правило замены
review.md | review/ настройка конвейера под проект + журнал дефектов
<своя тема>.md | <своя тема>/ всё, что проект счёл нужным проверять
tasks/ каталог задач — плагин av-dev-tasks, не канон;
tasks/ каталог задач — скилл task-track, не канон;
лежит в корне, вне docs/, и канон его не требует
openspec/
config.yaml только нужды генерации артефактов + ссылки
@@ -119,7 +96,7 @@ openspec/
| `CLAUDE.md`, `AGENTS.md` | источник | `autotests` (семантика гейта); инварианты — сквозные |
| `openspec/specs/` | источник | `requirements` |
| `openspec/config.yaml` | процессный | — (настройка порождения артефактов, слой **до** тем; заводит конвейер) |
| `tasks/` | процессный | — (чужое владение: плагин `av-dev-tasks`) |
| `tasks/` | процессный | — (чужое владение: скилл `task-track`) |
| `review.*` | процессный | — (настройка самого конвейера, слой **над** темами) |
| `adr.*` | процессный | — |
| `research.*` | процессный | — |
@@ -1,213 +0,0 @@
# Язык проектных текстов
**Копия.** Дом — `shared/language.md` в репозитории плагинов; язык общий для
документов канона и для задач, и потому не принадлежит ни одному плагину.
Правится дом, а не этот файл: расхождение ловит `copies.py` на гейте коммита.
<!-- копия: язык-доктрина из av-dev/shared/language.md -->
Правила — для всего, что пишется словами: задачи и цели, документы канона,
решения ADR, записки разведки, сообщения коммитов. Не для кода и не для
сообщений программы пользователю — там свои конвенции проекта.
Основа — **информационный стиль** Максима Ильяхова ([учебник
бюро](https://bureau.ru/projects/book-text/), книга «Пиши, сокращай»). Он
написан для рекламы, статей и писем, поэтому взят не целиком.
## Зачем он здесь
Проектный текст читают в двух положениях, и оба неудобные: **выбирают, брать ли
задачу**, глядя в строку индекса и один экран тела; и **возвращаются через
квартал**, не помня контекста. Оба положения наказывают одно и то же — слова, не
несущие сведений. Информационный стиль ровно про это, и его польза здесь не
эстетическая: текст, из которого нельзя достать факт, заставляет открывать код,
а это и есть цена, которой мы избегаем.
## Что взято сверх правил вычитки
Эти три требования судит человек, а не проход вычитки: находка по ним требует
увидеть текст целиком, а не фразу.
**Полезное действие.** У каждого текста есть вопрос, на который он отвечает, и
читатель, который этот вопрос задаёт. Не отвечает — не пишется. У задачи это
«зачем она нужна» и «что станет наблюдаемо иначе»; у документа канона — его
собственный вопрос («что это за система», «как сложено», «почему так решили»).
Текст, который не отвечает ни на чей вопрос, сокращается до нуля — это законный
исход правки.
**Параллельность.** Однородное пишется одинаково: пункты списка — одной
грамматической формой, разделы одного вида — одним порядком, заголовки одного
уровня — одним типом фразы. Разнобой читатель принимает за разницу по существу и
ищет её.
**Заголовок работает.** Заголовок называет содержание раздела, а не тему
вообще: «Что проверяет `check`», а не «О проверках». Заголовков ставится
столько, чтобы длинный текст можно было просматривать, а не только читать
подряд.
## Что отброшено намеренно
Инфостиль написан для текстов, где читателя надо удержать. Проектный текст
читают потому, что надо, и держать его нечем. Отсюда три расхождения:
- **Парцелляция и рубленые фразы — нет.** Приём «Коротко. Ещё короче. Вот так»
ломает причинную связь, а в решении и в задаче ценность именно в ней:
«поэтому», «иначе», «раз так» несут смысл и остаются.
- **Не всякое вводное — мусор.** «Если», «иначе», «при таком-то условии»,
«в отличие от» — это условия и противопоставления, то есть сведения. Режутся
вводные, которые не меняют смысл предложения.
- **Скобки и точка с запятой остаются.** В технической записи скобки несут
уточнение — имя команды, единицы, слаг, — и запрет на них удлинил бы текст, а
не сократил. Запрет на многоточие принимаем: в проектном тексте оно значит
«дописать позже», и такой текст лучше не публиковать.
И общее: инфостиль призывает «снять корону с себя и надеть на читателя». Здесь
читатель — **ты сам через квартал** и тот, кто возьмёт задачу. Писать для них
значит называть состояние и остаток, а не пересказывать, как было интересно
разбираться.
<!-- /копия: язык-доктрина -->
## Правила
<!-- копия: язык-правила из av-dev/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`. Транслит
нечитаем тому, кто ищет по смыслу, и не сокращается, а имя стоит в ссылках,
коммитах и путях, которые набирают руками. Переименование — **перенос ссылок
одним проходом**, а не правка одного файла.
<!-- /копия: язык-правила -->
## Порог правки
<!-- копия: порог-правки из av-dev/shared/language.md -->
**Правка без нарушенного правила не делается.** Текст, переписанный «чтобы
звучало лучше», обесценивает список замечаний: когда половина из них вкусовая,
перестают читать весь список, и вместе с ним пропадают настоящие находки.
Сомневаешься — не правь. Формулировка, которая просто **не твоя**, — не находка.
**Систематичность нарушения — не довод в его пользу.** Одна и та же ошибка в
пяти файлах не становится «принятым стилем»: чаще это значит, что правило не
применялось вовсе, — и находка тем важнее. «Так сделано везде» годится как
основание для **одной находки на весь набор** («правило N нарушено в пяти
записях, перечень: …»), но не как основание промолчать. Принятым считается
только то, что назвал зовущий или что записано в конвенциях проекта.
<!-- /копия: порог-правки -->
И обратное: язык правится **по ходу той операции, которая записи касается**.
Беклог не переписывают ради языка.
+29 -23
View File
@@ -35,37 +35,43 @@ check` и его скрипт; здесь начинается там, где к
пришлось назвать заново** — иначе их не звал бы никто, кроме разовых `adopt` и
`upgrade`, то есть на живом проекте никогда.
## Обращение к соседним плагинам
## Чего может не быть
**Копия.** Дом — `shared/plugin-boundary.md` в репозитории плагинов. Правится
дом, а не этот файл.
**Копия.** Дом правила`shared/absence.md` в репозитории плагина.
Правится дом, а не этот файл.
<!-- копия: граница-плагинов из av-dev/shared/plugin-boundary.md -->
<!-- копия: отсутствие из av-dev/shared/absence.md -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
живут порознь; каждая узнаётся своим следом:
**Чужой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
| Чего нет | Как видно | Чего теперь не делает никто |
| --- | --- | --- |
| раскладка av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
поведении.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
сам.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.docs.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
Имя файла — имя плагина, который его завёл, и держит он в том числе версию своего
формата: у канона документов и у каталога задач они свои и двигаются порознь.
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
сделанного. Выдумывать обходной путь нельзя тоже.
<!-- /копия: граница-плагинов -->
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
<!-- /копия: отсутствие -->
Здесь сосед один: `av-dev:task-track`, когда находка тянет на задачу. Его нет —
находки остаются списком в докладе, и это говорится строкой.
+31 -25
View File
@@ -8,9 +8,9 @@ description: "Завести новый проект — сессия вопро
Вход — свободный текст «что мне нужно и почему». Выход — канон документов, с
которого дальше работают все остальные скиллы.
**Определение канона — [канон](../canon/references/canon.md).** Прочитай его до
**Определение канона — [канон](../doc-canon/references/canon.md).** Прочитай его до
первого вопроса: интервью идёт по слотам канона, а не по вкусу. Что класть в
каждый файл — [скелеты](../canon/references/skeletons.md); не выдумывай заглушки
каждый файл — [скелеты](../doc-canon/references/skeletons.md); не выдумывай заглушки
своей формы, `docs.py` узнаёт только плейсхолдер оттуда.
## Что `init` физически не может произвести
@@ -69,40 +69,46 @@ description: "Завести новый проект — сессия вопро
- **Развилка замысла — человеку, механика — сама.** Имена файлов, слаги, порядок
строк не выноси.
## Обращение к соседним плагинам
## Чего может не быть
Два шага порядка работы — вызовы чужого: OpenSpec заводит конвейер, каталог задач
ведёт плагин задач. Ни того, ни другого `init` не делает руками.
**Копия.** Дом правила — `shared/plugin-boundary.md` в репозитории плагинов.
**Копия.** Дом правила — `shared/absence.md` в репозитории плагина.
Правится дом, а не этот файл.
<!-- копия: граница-плагинов из av-dev/shared/plugin-boundary.md -->
<!-- копия: отсутствие из av-dev/shared/absence.md -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
живут порознь; каждая узнаётся своим следом:
**Чужой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
| Чего нет | Как видно | Чего теперь не делает никто |
| --- | --- | --- |
| раскладка av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
поведении.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
сам.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.docs.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
Имя файла — имя плагина, который его завёл, и держит он в том числе версию своего
формата: у канона документов и у каталога задач они свои и двигаются порознь.
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
сделанного. Выдумывать обходной путь нельзя тоже.
<!-- /копия: граница-плагинов -->
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
<!-- /копия: отсутствие -->
Чем оборачивается отсутствие каждого — на самих шагах 3 и 7. Заведение проекта
из-за этого не останавливается: проект без конвейера и без учёта задач законен.
@@ -124,7 +130,7 @@ description: "Завести новый проект — сессия вопро
5. Напиши заполняемые документы. **Бриф переезжает в `passport.md`** и
отдельным файлом не остаётся: два дома для одного замысла разойдутся на
первом же уточнении.
6. Заведи скелет остальных по [скелетам](../canon/references/skeletons.md) —
6. Заведи скелет остальных по [скелетам](../doc-canon/references/skeletons.md) —
каждый с честной строкой.
7. Каталог задач и первые цели — **вызови скилл `av-dev:task-track`**: он владеет
форматом целей и задач. Не разрешился — учёт задач остаётся владельцу, и это
+41 -37
View File
@@ -6,7 +6,7 @@ description: Вести содержимое документов канона
# Ведение содержимого канона
Скилл владеет **содержимым** документов канона; раскладкой владеет `canon`.
Определение канона и роли документов — [канон](../canon/references/canon.md),
Определение канона и роли документов — [канон](../doc-canon/references/canon.md),
здесь не пересказывается.
Главный вызывающий — **шаг синка документации в конвейере задачи**. Конвейер
@@ -106,11 +106,11 @@ description: Вести содержимое документов канона
`av-dev:code-resolve`, сценарий разведки: решение, принятое разведкой (намеренный отказ, выбор
подхода, «проверили и не делаем»), `design.md` не имеет по построению — change по
нему не будет никогда. Промоут при этом тот же: цитата и ссылка, но на записку.
Перечень источников закрыт и живёт в [каноне](../canon/references/canon.md),
Перечень источников закрыт и живёт в [каноне](../doc-canon/references/canon.md),
раздел `adr/`.
**Триггер заведения, форма имени и правило замены — в
[каноне](../canon/references/canon.md), раздел `adr/`.** Здесь они не
[каноне](../doc-canon/references/canon.md), раздел `adr/`.** Здесь они не
повторяются: копия правила расходится с оригиналом на первой же смене версии
канона, а расходится незаметно.
@@ -126,7 +126,7 @@ description: Вести содержимое документов канона
Обзор не держит поведение — его нормативный дом `openspec/specs/`. **Форма
маркера долга и правило «гейт от них не краснеет» — в
[каноне](../canon/references/canon.md), раздел `architecture.md`.**
[каноне](../doc-canon/references/canon.md), раздел `architecture.md`.**
Разбирается порциями: раздел вычищает та задача, которая его касается.
Содержимое не выбрасывается, а переезжает — требования в дельта-спеку change,
@@ -136,47 +136,53 @@ description: Вести содержимое документов канона
Наблюдение о внешнем мире: что реально шлёт источник, чем документация формата
расходится с практикой. **Требование провенанса и правило про расходящееся
число — в [каноне](../canon/references/canon.md), раздел `research/`.**
число — в [каноне](../doc-canon/references/canon.md), раздел `research/`.**
Твоя часть — заметить, что по ходу задачи узналось новое о внешних данных, и не
дать этому остаться в контексте. Признак: ты правил разбор, опираясь на то, чего
нет ни в одном документе.
## Обращение к соседним плагинам
## Чего может не быть
Два раздела ниже — запись в `review.md` и промоут в конвенции — берут форму у
конвейера ревью: она принадлежит ему, а не канону. Берут **вызовом скилла**, а не
чтением файла по пути.
**Копия.** Дом правила — `shared/plugin-boundary.md` в репозитории плагинов.
**Копия.** Дом правила — `shared/absence.md` в репозитории плагина.
Правится дом, а не этот файл.
<!-- копия: граница-плагинов из av-dev/shared/plugin-boundary.md -->
<!-- копия: отсутствие из av-dev/shared/absence.md -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
живут порознь; каждая узнаётся своим следом:
**Чужой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
| Чего нет | Как видно | Чего теперь не делает никто |
| --- | --- | --- |
| раскладка av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Свой скилл зовётся полным именем** — `av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
поведении.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
сам.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.docs.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
Имя файла — имя плагина, который его завёл, и держит он в том числе версию своего
формата: у канона документов и у каталога задач они свои и двигаются порознь.
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
сделанного. Выдумывать обходной путь нельзя тоже.
<!-- /копия: граница-плагинов -->
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
<!-- /копия: отсутствие -->
Чем оборачивается отсутствие конвейера — в каждом из двух разделов отдельно: без
него работа не отменяется, отменяется только его процедура.
@@ -185,12 +191,9 @@ description: Вести содержимое документов канона
Файл держит два раздела с разными сроками жизни — журнал дефектов и настройку
конвейера. **Что в каком и в какой форме — в
[каноне](../canon/references/canon.md), раздел `review.md`**; подробности формы
записи и выбор адреса, куда она ведёт, — у конвейера ревью проекта (при
`av-dev-code``Skill av-dev:code-review`, его
`references/review-journal.md`). **Конвейера в проекте нет** — пиши по форме из
скелета `review.md`, которую положил канон, и скажи в докладе, что подробностей
формы взять негде.
[каноне](../doc-canon/references/canon.md), раздел `review.md`**; подробности формы
записи и выбор адреса, куда она ведёт, — у конвейера ревью: `Skill
av-dev:code-review`, его `references/review-journal.md`.
Твоя часть на синке: **дефект пишется сразу**, а не «потом, когда починим».
Со временем теряется не факт, а то, почему дефект не поймали, — единственное,
@@ -200,10 +203,11 @@ description: Вести содержимое документов канона
## Промоут в конвенции
Находка → конвенция → правило линтера → **удаление из прозы**. Процедура целиком
принадлежит конвейеру ревью проекта (при `av-dev-code` — его
`references/promote.md`, читается через `Skill av-dev:code-review`);
роль каталога конвенций — в [каноне](../canon/references/canon.md). **Конвейера
нет** — три шага всё равно твои, просто без его процедуры: сформулируй правило,
принадлежит конвейеру ревью — его `references/promote.md`, читается через
`Skill av-dev:code-review`; роль каталога конвенций — в
[каноне](../doc-canon/references/canon.md). **Прогон идёт вне конвейера**
(находку принесли руками) — три шага всё равно твои, просто без его процедуры:
сформулируй правило,
поищи, чем оно механизируется, и вычеркни прозу, если механизировалось.
Твоя часть — **третий шаг, который пропускают чаще всего**: правило заработало,
+4 -4
View File
@@ -159,7 +159,7 @@ flowchart TD
## Документы устаревают тем же ходом работы
Груминг судит **задачи**, а не документы, и агентов канона не зовёт: они
принадлежат плагину `av-dev-docs`, и когда их звать — решает он.
принадлежат скиллам документации, и когда их звать — решают они.
Но повод назвать это здесь есть: беклог и документы протухают от одного и того
же — от сделанной работы. Пришёл на груминг и видишь, что с прошлого раза сделан
@@ -190,8 +190,8 @@ flowchart TD
тот же агент, который её и сделал. Груминг приёмкой не занимается — отдельного
ритуала у неё нет, — и настоящих опор остаётся две:
- **независимый отчёт ревью** — артефакт, написанный не исполнителем; при
конвейере `av-dev-code` это отчёт триажа в
- **независимый отчёт ревью** — артефакт, написанный не исполнителем: отчёт
триажа в
`openspec/changes/archive/<id>/review/` (до архивации — `changes/<id>/review/`);
- **`reopen <слаг> --reason`** — закрытие не окончательно. Заметил на груминге,
что закрытая задача сделана не тем, чем обещала, — возвращай, это штатная
@@ -244,4 +244,4 @@ flowchart TD
себе — формат и содержимое ведёт `tasks` (груминг зовёт его операции). Не решает
за человека, что важно: он готовит развилки и рекомендует. Не принимает
закрытые задачи отдельным ритуалом — `reopen` есть, момента у него нет. Не судит
документы проекта — это плагин `av-dev-docs`.
документы проекта — это скиллы `av-dev:doc-canon` и `av-dev:doc-healthcheck`.
@@ -20,7 +20,7 @@
(`edit <slug> --rm-tag question`), **перепиши «зачем»**: «Решено: …» на вопрос
«почему это лежит в беклоге» уже не отвечает. Опустошение раздела — не
уборка, а условие взятия: правило и причина в скилле `tasks`,
[references/task-format.md](../../tasks/references/task-format.md).
[references/task-format.md](../../task-track/references/task-format.md).
**Вопросы на верхних строках очереди разбираются вне очереди порции** — здесь
же, даже если сама задача в порцию переоценки не попала. Иначе правило «задача с
@@ -93,7 +93,7 @@
задача выбрала не ту. Тогда порция расширяется до всех задач этой цели: каждую
либо закрыть своей причиной, либо перевесить на другую цель, и только потом
закрыть цель. Порядок и почему он такой —
[task-goal.md](../../tasks/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель).
[task-goal.md](../../task-track/references/task-goal.md#отменённая-цель--сперва-задачи-потом-цель).
8. **Задача ли это по-прежнему.** Не проходит `ready` по существу, а не по
недописанным разделам → `edit <slug> --type research` и опустошённый раздел
«Вопрос», то есть сырьё; дальше штурм. Разрослась → это несколько задач под
+7 -7
View File
@@ -72,8 +72,8 @@ description: Ведение задач и целей как каталога mar
## Раскладка
Каталог задач — **`tasks/` в корне репозитория, жёстко.** Он принадлежит этому
плагину, а не канону документов: `docs/` ведёт другой плагин (`av-dev-docs`), и
проект, поставивший учёт работ без него, каталога `docs/` не имеет вовсе. Внутри
скиллу, а не канону документов: учёт работ ведут и в проекте, который к канону
не приведён, и каталога `docs/` там нет вовсе. Внутри
`docs/` задачи лежали до версии канона 11; непереехавший проект скрипт
по-прежнему находит, но новый заводит только в корне.
@@ -210,7 +210,7 @@ stateDiagram-v2
часть кода мы трогаем».
**Целью не становится работа, которой держат проект.** Состав перечислен
[в словаре сопровождения](references/operations.md);
[в словаре сопровождения](../../shared/operations.md);
на вопрос «что приложение будет уметь» ничто из него не отвечает. Им отведена отдельная секция роадмапа,
чтобы они были видны в том же экране и при этом не читались как возможности
продукта.
@@ -225,7 +225,7 @@ stateDiagram-v2
живёт ещё в двух местах: разделе «Эксплуатация» в `architecture.md` и теме ревью
`operations`. Словарь у всех трёх общий, дом у него один — `shared/operations.md`
в репозитории плагинов, — а здесь лежит дословная копия:
[references/operations.md](references/operations.md). Пересказывать его своими
[shared/operations.md](../../shared/operations.md). Пересказывать его своими
словами нельзя: три перечня «чем держат проект» уже разъезжались на «метриках и
логах» против «мониторинга».
@@ -303,7 +303,7 @@ stateDiagram-v2
проверять.
**Одно исполнителю тип всё же говорит — каким сценарием работу вести, и то не
один.** В плагине `av-dev-code` скилл `resolve` выбирает сценарий связкой из двух
один.** Скилл `av-dev:code-resolve` выбирает сценарий связкой из двух
признаков: тип **предлагает** (`chore` — обслуживание, `research` — разведка),
а подтверждает его предмет работы — есть ли что менять в спеках. Признаки
разошлись — работа останавливается, и тип меняется здесь, командой `edit --type`,
@@ -356,7 +356,7 @@ stateDiagram-v2
Язык — общий для всех проектных текстов, и дом у него один,
`shared/language.md` в репозитории плагинов; здесь лежит дословная копия:
[references/language.md](references/language.md) (информационный стиль,
[shared/language.md](../../shared/language.md) (информационный стиль,
применённый к задачам и документам канона; там же таблицы англицизмов и жаргона
и то, что из стиля отброшено намеренно). Задаче он даёт четыре требования,
которые нарушаются чаще прочих:
@@ -381,7 +381,7 @@ stateDiagram-v2
## Инструмент (`tasks.py`)
Пусть `tk="$CLAUDE_PLUGIN_ROOT/skills/tasks/scripts/tasks.py"`, а `D`
Пусть `tk="$CLAUDE_PLUGIN_ROOT/skills/task-track/scripts/tasks.py"`, а `D`
`tasks` от корня проекта. `--dir` стоит в примерах намеренно: вызов из
подкаталога — обычное дело.
+1 -1
View File
@@ -35,7 +35,7 @@
«машина умеет / не умеет»:
```
tk="$CLAUDE_PLUGIN_ROOT/skills/tasks/scripts/tasks.py"
tk="$CLAUDE_PLUGIN_ROOT/skills/task-track/scripts/tasks.py"
python3 $tk adopt scan --from docs/backlog docs/plan.md TODO.md \
--target tasks --out tasks-adopt-plan.json # только чтение
@@ -85,7 +85,7 @@
отображается **в позицию в очереди**, потому что приоритет и есть порядок строк
в беклоге (правило 4 [SKILL.md](../SKILL.md)). Отображается через довод, а не
напрямую: своей шкалы у интейка нет, доводы расстановки перечислены в
[скилле груминга](../../groom/SKILL.md#приоритет-как-его-расставляют), и
[скилле груминга](../../task-groom/SKILL.md#приоритет-как-его-расставляют), и
серьёзность попадает ровно в один из них.
- **тяжёлая находка со свидетельством о сломанном сейчас** → задача под ту цель,
@@ -1,213 +0,0 @@
# Язык проектных текстов
**Копия.** Дом — `shared/language.md` в репозитории плагинов; язык общий для
документов канона и для задач, и потому не принадлежит ни одному плагину.
Правится дом, а не этот файл: расхождение ловит `copies.py` на гейте коммита.
<!-- копия: язык-доктрина из av-dev/shared/language.md -->
Правила — для всего, что пишется словами: задачи и цели, документы канона,
решения ADR, записки разведки, сообщения коммитов. Не для кода и не для
сообщений программы пользователю — там свои конвенции проекта.
Основа — **информационный стиль** Максима Ильяхова ([учебник
бюро](https://bureau.ru/projects/book-text/), книга «Пиши, сокращай»). Он
написан для рекламы, статей и писем, поэтому взят не целиком.
## Зачем он здесь
Проектный текст читают в двух положениях, и оба неудобные: **выбирают, брать ли
задачу**, глядя в строку индекса и один экран тела; и **возвращаются через
квартал**, не помня контекста. Оба положения наказывают одно и то же — слова, не
несущие сведений. Информационный стиль ровно про это, и его польза здесь не
эстетическая: текст, из которого нельзя достать факт, заставляет открывать код,
а это и есть цена, которой мы избегаем.
## Что взято сверх правил вычитки
Эти три требования судит человек, а не проход вычитки: находка по ним требует
увидеть текст целиком, а не фразу.
**Полезное действие.** У каждого текста есть вопрос, на который он отвечает, и
читатель, который этот вопрос задаёт. Не отвечает — не пишется. У задачи это
«зачем она нужна» и «что станет наблюдаемо иначе»; у документа канона — его
собственный вопрос («что это за система», «как сложено», «почему так решили»).
Текст, который не отвечает ни на чей вопрос, сокращается до нуля — это законный
исход правки.
**Параллельность.** Однородное пишется одинаково: пункты списка — одной
грамматической формой, разделы одного вида — одним порядком, заголовки одного
уровня — одним типом фразы. Разнобой читатель принимает за разницу по существу и
ищет её.
**Заголовок работает.** Заголовок называет содержание раздела, а не тему
вообще: «Что проверяет `check`», а не «О проверках». Заголовков ставится
столько, чтобы длинный текст можно было просматривать, а не только читать
подряд.
## Что отброшено намеренно
Инфостиль написан для текстов, где читателя надо удержать. Проектный текст
читают потому, что надо, и держать его нечем. Отсюда три расхождения:
- **Парцелляция и рубленые фразы — нет.** Приём «Коротко. Ещё короче. Вот так»
ломает причинную связь, а в решении и в задаче ценность именно в ней:
«поэтому», «иначе», «раз так» несут смысл и остаются.
- **Не всякое вводное — мусор.** «Если», «иначе», «при таком-то условии»,
«в отличие от» — это условия и противопоставления, то есть сведения. Режутся
вводные, которые не меняют смысл предложения.
- **Скобки и точка с запятой остаются.** В технической записи скобки несут
уточнение — имя команды, единицы, слаг, — и запрет на них удлинил бы текст, а
не сократил. Запрет на многоточие принимаем: в проектном тексте оно значит
«дописать позже», и такой текст лучше не публиковать.
И общее: инфостиль призывает «снять корону с себя и надеть на читателя». Здесь
читатель — **ты сам через квартал** и тот, кто возьмёт задачу. Писать для них
значит называть состояние и остаток, а не пересказывать, как было интересно
разбираться.
<!-- /копия: язык-доктрина -->
## Правила
<!-- копия: язык-правила из av-dev/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`. Транслит
нечитаем тому, кто ищет по смыслу, и не сокращается, а имя стоит в ссылках,
коммитах и путях, которые набирают руками. Переименование — **перенос ссылок
одним проходом**, а не правка одного файла.
<!-- /копия: язык-правила -->
## Порог правки
<!-- копия: порог-правки из av-dev/shared/language.md -->
**Правка без нарушенного правила не делается.** Текст, переписанный «чтобы
звучало лучше», обесценивает список замечаний: когда половина из них вкусовая,
перестают читать весь список, и вместе с ним пропадают настоящие находки.
Сомневаешься — не правь. Формулировка, которая просто **не твоя**, — не находка.
**Систематичность нарушения — не довод в его пользу.** Одна и та же ошибка в
пяти файлах не становится «принятым стилем»: чаще это значит, что правило не
применялось вовсе, — и находка тем важнее. «Так сделано везде» годится как
основание для **одной находки на весь набор** («правило N нарушено в пяти
записях, перечень: …»), но не как основание промолчать. Принятым считается
только то, что назвал зовущий или что записано в конвенциях проекта.
<!-- /копия: порог-правки -->
И обратное: язык правится **по ходу той операции, которая записи касается**.
Беклог не переписывают ради языка.
@@ -1,34 +0,0 @@
# Сопровождение и эксплуатация
**Копия.** Дом — `shared/operations.md` в репозитории плагинов. Словарь общий для
роадмапа, архитектуры и темы ревью `operations`, и не принадлежит ни одному из
трёх — правится дом, а не этот файл.
Скиллу задач он нужен для секции `Сопровождение` в `ROADMAP.md`: она отвечает не
на «что приложение будет уметь», а на «чем его держат», и путать эти два вопроса
нельзя.
<!-- копия: сопровождение-словарь из av-dev/shared/operations.md -->
Одна тема живёт в трёх местах, и путать их слова нельзя.
**Сопровождение** — всё, чем держат проект: инструмент и сборка, процесс,
выкладка, метрики и логи, инфраструктура, дежурство. **Эксплуатация** — его
часть: работа системы на проде. Целое и часть, и никогда наоборот.
| Место | Уровень | Что там |
| --- | --- | --- |
| `ROADMAP.md`, секция `Сопровождение` | план | **работы**, которые собираемся делать: цели и их задачи |
| `architecture.md`, раздел «Эксплуатация» | состояние | **как устроено сейчас**: где работает, что рядом, кто перезапускает |
| тема ревью `operations` | оптика | **чем проверяем**: «это упало через неделю на проде» |
Слово **«поддержка» не употребляется вовсе** — в нём слышится помощь
пользователю, а это другая работа.
**Граница с возможностями проходит по тому, кто наблюдает.** «Приложение
сообщает о своём состоянии» — возможность приложения, её место среди прочих
целей: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
секции роадмапа, и это верно — секции отвечают на разные вопросы.
<!-- /копия: сопровождение-словарь -->
@@ -61,7 +61,7 @@
## Кто такую задачу решает
Решает её конвейер проекта — в плагине `av-dev-code` это скилл `resolve`,
Решает её конвейер проекта — скилл `av-dev:code-resolve`,
**сценарий обслуживания**: он не заводит change и не пишет требований, потому что
у работы, не меняющей поведения, дельта-спек нет по построению. Тип записи там
только **предлагает** сценарий, а подтверждает его отсутствие дельт: разошлись —
@@ -38,7 +38,7 @@
1. **Проверить, что это возможность, а не работа.** Работа, которой держат
проект, на вопрос «что приложение будет уметь» не отвечает; состав перечислен
[в словаре сопровождения](operations.md). Ей отведена секция
[в словаре сопровождения](../../../shared/operations.md). Ей отведена секция
`Сопровождение` — там она видна в том же
экране и не читается как обещание продукта. Граница проходит по тому,
**кто наблюдает**:
@@ -66,9 +66,8 @@
4. **Провести разведку** и **записать ответ по названному адресу**. Числа — с
провенансом: с командой или условиями, которыми получены. Число без источника
проход ревью обязан читать как условие, а не как замер. Проводит её конвейер
проекта — в плагине `av-dev-code` это скилл `resolve`, сценарий разведки;
плагина нет — разведка ведётся как проект привык, а этот скилл её только
заводит и закрывает.
проекта — скилл `av-dev:code-resolve`, сценарий разведки; этот скилл её
только заводит и закрывает.
5. **Разложить исход на задачи** — если он их родил. Разведка кончается одним из
трёх: заведены задачи, записано знание, отказ. **Отказ — полноправный исход**:
«проверили, не проблема» экономит работу.