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

Дом 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
+2 -2
View File
@@ -13,7 +13,7 @@ color: yellow
равно опасен. равно опасен.
Находки — по контракту Находки — по контракту
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). (точный путь конвейер передаёт в задании).
**Ты помечен «держит машину»** — за тем, чтобы построенный путь можно было **Ты помечен «держит машину»** — за тем, чтобы построенный путь можно было
@@ -73,7 +73,7 @@ color: yellow
находкой. находкой.
Карта «что нужно проходу → где лежит» — Карта «что нужно проходу → где лежит» —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/project-facts.md`. `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/project-facts.md`.
**Деградация поразрядная, и каждый пробел называется своей строкой.** **Деградация поразрядная, и каждый пробел называется своей строкой.**
`docs/security.md` нет — работай по общей рамке ниже, `critical` не присваивай и `docs/security.md` нет — работай по общей рамке ниже, `critical` не присваивай и
+2 -2
View File
@@ -25,7 +25,7 @@ color: yellow
и граф зависимостей есть только у тебя. и граф зависимостей есть только у тебя.
Находки — по контракту Находки — по контракту
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). (точный путь конвейер передаёт в задании).
## Вход (собери до чтения диффа) ## Вход (собери до чтения диффа)
@@ -52,7 +52,7 @@ grep по именам концепций) и скажи об этом в гра
- дельта-спеки change. - дельта-спеки change.
Карта «что нужно проходу → где лежит» — Карта «что нужно проходу → где лежит» —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/project-facts.md`. `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/project-facts.md`.
Дифф — **последним, не первым**: он должен ложиться на карту, а не задавать её. Дифф — **последним, не первым**: он должен ложиться на карту, а не задавать её.
+3 -3
View File
@@ -19,7 +19,7 @@ color: green
намеренно нет, из темы не выпадает — она уходит в границы покрытия. намеренно нет, из темы не выпадает — она уходит в границы покрытия.
Находки — по контракту Находки — по контракту
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). Русская проза, идентификаторы и (точный путь конвейер передаёт в задании). Русская проза, идентификаторы и
команды — в оригинале. команды — в оригинале.
@@ -31,7 +31,7 @@ color: green
запускать запрещено, с путями. запускать запрещено, с путями.
Карта «что нужно проходу → где лежит» — Карта «что нужно проходу → где лежит» —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/project-facts.md`. `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/project-facts.md`.
**Семантики гейта в `CLAUDE.md` нет** — найди команду сама (`Taskfile.yml`, **Семантики гейта в `CLAUDE.md` нет** — найди команду сама (`Taskfile.yml`,
`Makefile`, `justfile`, `scripts/`) и выполни её, но: `critical` по основанию `Makefile`, `justfile`, `scripts/`) и выполни её, но: `critical` по основанию
@@ -96,7 +96,7 @@ color: green
просило: она может стоить минут и трогать данные. просило: она может стоить минут и трогать данные.
- **Правило есть в конвенциях, но не в линтере.** Если по ходу видно, что отказ - **Правило есть в конвенциях, но не в линтере.** Если по ходу видно, что отказ
или замечание могло быть поймано правилом, — пиши `Promote candidate` по или замечание могло быть поймано правилом, — пиши `Promote candidate` по
процедуре `${CLAUDE_PLUGIN_ROOT}/skills/review/references/promote.md`. процедуре `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/promote.md`.
## Что читать не нужно ## Что читать не нужно
+1 -1
View File
@@ -42,7 +42,7 @@ color: yellow
самый дорогой проход, вместо которого его позвали. самый дорогой проход, вместо которого его позвали.
Находки — по контракту Находки — по контракту
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). (точный путь конвейер передаёт в задании).
## Что тебе даёт план прогона ## Что тебе даёт план прогона
+1 -1
View File
@@ -58,7 +58,7 @@ color: yellow
его неизбежным. его неизбежным.
Находки — по контракту Находки — по контракту
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). Русская проза, идентификаторы и пути — (точный путь конвейер передаёт в задании). Русская проза, идентификаторы и пути —
в оригинале. Читай реальный код, ничего не выдумывай. в оригинале. Читай реальный код, ничего не выдумывай.
+2 -2
View File
@@ -11,7 +11,7 @@ color: green
увидит владелец сервиса, и дойди до строки кода. увидит владелец сервиса, и дойди до строки кода.
Находки — по контракту Находки — по контракту
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). (точный путь конвейер передаёт в задании).
**Ты помечен «держит машину».** Конвейер за это ставит тебя в цепочку с другими **Ты помечен «держит машину».** Конвейер за это ставит тебя в цепочку с другими
@@ -46,7 +46,7 @@ color: green
`docs/research/` процессный документ, и прогон его не открывает; чужое число `docs/research/` процессный документ, и прогон его не открывает; чужое число
неизвестной свежести делало находку похожей на доказанную, ничего не доказывая. неизвестной свежести делало находку похожей на доказанную, ничего не доказывая.
Почему именно так и какие ещё есть стыки — Почему именно так и какие ещё есть стыки —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/project-facts.md`, раздел `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/project-facts.md`, раздел
«Сшивать обязаны проходы». Там же карта «что нужно проходу → где лежит». «Сшивать обязаны проходы». Там же карта «что нужно проходу → где лежит».
Два обстоятельства почти всегда меняют цену отказов, и если документы их Два обстоятельства почти всегда меняют цену отказов, и если документы их
+3 -3
View File
@@ -11,7 +11,7 @@ color: yellow
**порождаешь сам** — и делаешь это до того, как увидишь код. **порождаешь сам** — и делаешь это до того, как увидишь код.
Находки — по контракту Находки — по контракту
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). Русская проза, идентификаторы — в (точный путь конвейер передаёт в задании). Русская проза, идентификаторы — в
оригинале. оригинале.
@@ -26,7 +26,7 @@ color: yellow
сформулированное по прецеденту, сильнее любого общего. сформулированное по прецеденту, сильнее любого общего.
Карта «что нужно проходу → где лежит» — Карта «что нужно проходу → где лежит» —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/project-facts.md`. `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/project-facts.md`.
**Документа нет — строка на каждый, отдельно.** Нет `docs/review.md`: «рода **Документа нет — строка на каждый, отдельно.** Нет `docs/review.md`: «рода
узлов и прецеденты неизвестны; требование „минимум три пункта специфичны для узлов и прецеденты неизвестны; требование „минимум три пункта специфичны для
@@ -106,7 +106,7 @@ color: yellow
Пункты рубрики, которых **нет в конвенциях проекта**, — кандидаты на промоут: это Пункты рубрики, которых **нет в конвенциях проекта**, — кандидаты на промоут: это
и есть неявный слой, ради которого проход существует. Выведи их отдельной секцией и есть неявный слой, ради которого проход существует. Выведи их отдельной секцией
`Promote candidates` (процедура — `Promote candidates` (процедура —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/promote.md`). `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/promote.md`).
## Чего этот проход принципиально не может поймать ## Чего этот проход принципиально не может поймать
+2 -2
View File
@@ -10,7 +10,7 @@ color: yellow
Development на OpenSpec). Оптика — требования, а не стиль кода. Development на OpenSpec). Оптика — требования, а не стиль кода.
Находки — по контракту Находки — по контракту
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). Русская проза; идентификаторы, пути и (точный путь конвейер передаёт в задании). Русская проза; идентификаторы, пути и
ключевые слова спек (`SHALL`, `GIVEN/WHEN/THEN`) — в оригинале. Читай реальные ключевые слова спек (`SHALL`, `GIVEN/WHEN/THEN`) — в оригинале. Читай реальные
файлы перед выводом, ничего не выдумывай. файлы перед выводом, ничего не выдумывай.
@@ -49,7 +49,7 @@ Development на OpenSpec). Оптика — требования, а не ст
Пути спек жёсткие: актуальные — `openspec/specs/<capability>/spec.md`, дельты — Пути спек жёсткие: актуальные — `openspec/specs/<capability>/spec.md`, дельты —
`openspec/changes/<id>/specs/`. Карта «что нужно проходу → где лежит» — `openspec/changes/<id>/specs/`. Карта «что нужно проходу → где лежит» —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/project-facts.md`. `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/project-facts.md`.
**Нет инвариантов в `CLAUDE.md`** — сверяй только спеку с кодом, `critical` по **Нет инвариантов в `CLAUDE.md`** — сверяй только спеку с кодом, `critical` по
основанию «нарушен инвариант проекта» не присваивай и дай строку: «инвариантов в основанию «нарушен инвариант проекта» не присваивай и дай строку: «инвариантов в
+2 -2
View File
@@ -16,7 +16,7 @@ color: yellow
Потолок в 7 пунктов защищает код, а не читателя. Потолок в 7 пунктов защищает код, а не читателя.
Контракт находок и формат финального отчёта — Контракт находок и формат финального отчёта —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/finding-contract.md` `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/finding-contract.md`
(точный путь конвейер передаёт в задании). (точный путь конвейер передаёт в задании).
## Вход ## Вход
@@ -47,7 +47,7 @@ color: yellow
целиком уезжают в границы покрытия и **не сливаются в один список**. целиком уезжают в границы покрытия и **не сливаются в один список**.
Карта «что нужно проходу → где лежит» — Карта «что нужно проходу → где лежит» —
`${CLAUDE_PLUGIN_ROOT}/skills/review/references/project-facts.md`. `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/project-facts.md`.
**Деградация поразрядная, и ты — тот, кто собирает её строки в один список, **Деградация поразрядная, и ты — тот, кто собирает её строки в один список,
сохраняя каждую.** Свою часть сохраняя каждую.** Свою часть
+59
View File
@@ -0,0 +1,59 @@
# Чего может не быть
**Это дом.** Правило нужно почти каждому скиллу: любой приходит в проект, где
может не оказаться ни документов канона, ни каталога задач, ни `openspec/`, а
рядом может не стоять внешний плагин, которого он ждёт. Ни один скилл правилом
не владеет, поэтому дом стоит в `shared/`, а скиллы везут **копии**, помеченные
разметкой `copies.py`.
Правится **здесь**. Копия, поправленная у себя, — расхождение, а не правка.
До слияния правило называлось «граница плагинов» и говорило о соседе:
`av-dev-docs`, `av-dev-tasks` и `av-dev-code` ставились порознь, и каждый обязан
был пережить отсутствие двоих. Плагин теперь один, а правило осталось, и не по
инерции: **отсутствовала всё это время не установка, а раскладка проекта**, и
узнавалась она следом на диске, а не перечнем плагинов. Перечень того, чего
может не быть, стал короче на три имени — механика не изменилась вовсе.
Заведено правило по замеру: к первому расколу оно стояло в пяти местах в пяти
редакциях, и три из пяти молчали о том, ради чего написано, — что делать, когда
недостающее обнаружено.
<!-- дом: отсутствие -->
**Скилл не вправе считать раскладку проекта полной.** Части заводятся порознь и
живут порознь; каждая узнаётся своим следом:
| Чего нет | Как видно | Чего теперь не делает никто |
| --- | --- | --- |
| раскладка av-dev | нет `.av-dev.toml` в корне | проект под процесс не заводился; версии нет, настроек нет |
| документы канона | нет `docs/` | проектную конкретику брать неоткуда — темы, инварианты, прецеденты |
| учёт работ | нет каталога задач | запись остаётся владельцу: назови её текстом в докладе |
| источник требований | нет `openspec/config.yaml` | цикл SDD не запускается: спеки не с чем сверять |
**Свой скилл зовётся полным именем**`av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную
копию из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в
поведении.
**Внешний плагин может не стоять.** Их два: `opsx:*` — цикл SDD, и
`av-dev-git:commit` — сообщения коммитов. Путь в дерево чужого плагина не
пишется никогда: `$CLAUDE_PLUGIN_ROOT` ведёт только в своё дерево, а
вычисленный от него путь к соседу либо не откроется, либо откроет чужую
установку. Нужен чужой справочник — зови владеющий им скилл, он прочитает его
сам.
**Отсутствие — исход, а не поломка.** Назови строкой доклада, чего теперь не
делает никто, и продолжай работу. Молчать нельзя: пропуск неотличим от
сделанного. Выдумывать обходной путь нельзя тоже.
**Присутствие узнаётся следом в проекте, а не объявлением.** Перечня того, что
здесь заведено, проект не ведёт — он разошёлся бы с действительностью молча.
<!-- /дом: отсутствие -->
**Что в дом не идёт: чем именно оборачивается нехватка у тебя.** «Нет каталога
задач — учёт остаётся владельцу» знает конвейер; «нет `openspec/``docs.py`
о каталоге молчит» знает канон. Правило общее, последствие местное, и держать
последствия здесь значило бы завести дом, который знает про всех своих
потребителей.
+10 -12
View File
@@ -1,26 +1,26 @@
# Язык проектных текстов # Язык проектных текстов
**Это дом.** Файл не входит ни в один плагин: язык общий для документов канона и **Это дом.** Файл не принадлежит ни одному скиллу: язык общий для документов
для задач, и хранить его внутри одного из них значило бы отдать общее правило во канона, для задач и для решений ADR, и хранить его внутри одного из них значило
владение половине. Плагины везут **копии**, помеченные разметкой `copies.py`, и бы отдать общее правило во владение части. Скиллы читают **этот файл** по
расхождение ловит гейт коммита, а не внимание. ссылке; дословные **копии**, помеченные разметкой `copies.py`, уезжают только в
charter'ы вычитки — там текст обязан лежать внутри самого промпта, потому что
именно он и есть критерий суждения. Расхождение ловит гейт коммита, а не
внимание.
Правится **здесь**. Копия, поправленная у себя, — расхождение, а не правка. Правится **здесь**. Копия, поправленная у себя, — расхождение, а не правка.
Три блока, и делятся они по потребителю, а не по теме: Два блока копируются, и делятся они по потребителю, а не по теме:
| Блок | Что в нём | Кто копирует | | Блок | Что в нём | Кто копирует |
| --- | --- | --- | | --- | --- | --- |
| `язык-доктрина` | зачем стиль нужен, что взято сверх устава, что отброшено | справочник языка в плагине | | `язык-правила` | девять правил, по которым судят текст | уставы вычитки |
| `язык-правила` | девять правил, по которым судят текст | справочник и уставы вычитки | | `порог-правки` | когда находка не заводится | уставы вычитки, `task-form` |
| `порог-правки` | когда находка не заводится | справочник, уставы вычитки, `task-form` |
`порог-правки` вынесен из правил намеренно: он нужен и тому, кто правил языка не `порог-правки` вынесен из правил намеренно: он нужен и тому, кто правил языка не
проверяет вовсе, — а вложенных блоков разметка не знает, и внутри `язык-правила` проверяет вовсе, — а вложенных блоков разметка не знает, и внутри `язык-правила`
его было бы не забрать отдельно. его было бы не забрать отдельно.
<!-- дом: язык-доктрина -->
Правила — для всего, что пишется словами: задачи и цели, документы канона, Правила — для всего, что пишется словами: задачи и цели, документы канона,
решения ADR, записки разведки, сообщения коммитов. Не для кода и не для решения ADR, записки разведки, сообщения коммитов. Не для кода и не для
сообщений программы пользователю — там свои конвенции проекта. сообщений программы пользователю — там свои конвенции проекта.
@@ -81,8 +81,6 @@
значит называть состояние и остаток, а не пересказывать, как было интересно значит называть состояние и остаток, а не пересказывать, как было интересно
разбираться. разбираться.
<!-- /дом: язык-доктрина -->
## Правила ## Правила
<!-- дом: язык-правила --> <!-- дом: язык-правила -->
+6 -8
View File
@@ -1,15 +1,14 @@
# Сопровождение и эксплуатация # Сопровождение и эксплуатация
**Это дом.** Словарь «чем держат проект» назван в трёх местах трёх разных **Это дом.** Словарь «чем держат проект» назван в трёх местах трёх разных
плагинов: секция `Сопровождение` в роадмапе (`av-dev-tasks`), раздел скиллов: секция `Сопровождение` в роадмапе (`task-track`), раздел «Эксплуатация»
«Эксплуатация» в `architecture.md` (`av-dev-docs`) и тема ревью `operations` в `architecture.md` (`doc-canon`) и тема ревью `operations` (`code-review`). Ни
(`av-dev-code`). Ни один из трёх им не владеет, поэтому дом стоит снаружи, а один из трёх им не владеет, поэтому дом стоит в `shared/`.
плагины везут копии.
Три перечня «чем держат проект» уже разъезжались — на «метриках и логах» против Три перечня «чем держат проект» уже разъезжались — на «метриках и логах» против
«мониторинга», — и разъехались молча. Отсюда дословная копия вместо ссылки. «мониторинга», — и разъехались молча. Пока скиллы жили тремя плагинами, отсюда
уезжали дословные копии: путь в чужое дерево не разрешался. Теперь дерево одно —
<!-- дом: сопровождение-словарь --> кому словарь нужен, тот открывает **этот файл**, и сверять машиной больше нечего.
Одна тема живёт в трёх местах, и путать их слова нельзя. Одна тема живёт в трёх местах, и путать их слова нельзя.
@@ -32,4 +31,3 @@
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
секции роадмапа, и это верно — секции отвечают на разные вопросы. секции роадмапа, и это верно — секции отвечают на разные вопросы.
<!-- /дом: сопровождение-словарь -->
-59
View File
@@ -1,59 +0,0 @@
# Граница между плагинами
**Это дом.** Правило обращения к соседнему плагину нужно всем, кто зовёт чужой
скилл, — а таких скиллов больше половины всех, и ни один плагин правилом не
владеет. (Числа здесь нет намеренно: оно уже дважды протухало за один день.) Поэтому дом стоит снаружи, а плагины везут **копии**, помеченные
разметкой `copies.py`.
Правится **здесь**. Копия, поправленная у себя, — расхождение, а не правка.
Дом заведён по замеру, а не на всякий случай. К моменту раскола правило стояло в
пяти местах в пяти редакциях:
| Где стояло | Довод | Ветка «не разрешился» |
| --- | --- | --- |
| `task-pipeline` | устаревшая проектная копия | нет |
| `task-batch` | то же | нет |
| `review-pipeline` | вшито в пункт про удаление проектных копий | нет |
| `openspec` | путём в чужое дерево — никогда | есть |
| `canon` | — | есть |
Имена с тех пор изменились — `task-pipeline` стал `resolve`, `review-pipeline`
`review`, `task-batch` удалён, — но замер относится к местам, а не к названиям.
Два разных довода, и ни в одном месте не было обоих. Три места из пяти молчали о
том, что делать, когда вызов не разрешился, — то есть о единственном, ради чего
правило и написано.
**Что в дом не идёт: чем оборачивается отсутствие конкретного соседа.** «Нет
`av-dev-tasks` — учёт остаётся владельцу» знает только конвейер; «нет конвейера —
`docs.py` о каталоге `openspec/` молчит» знает только канон. Правило общее,
последствие местное, и держать последствия здесь значило бы завести дом, который
знает про всех своих потребителей.
<!-- дом: граница-плагинов -->
Плагины `av-dev` ставятся порознь, и ни один не вправе считать, что сосед на
месте.
**Чужой скилл зовётся полным именем**`av-dev:doc-canon`, `av-dev:task-track`,
`av-dev:code-review`. Короткое имя может разрешиться в устаревшую проектную копию
из `.claude/skills/`, и подмены не будет видно ни в докладе, ни в поведении.
**Путь в дерево чужого плагина не пишется никогда.** `$CLAUDE_PLUGIN_ROOT` ведёт
только в свой плагин; вычисленный от него путь к соседу либо не откроется, либо
откроет чужую установку. Нужен чужой справочник — зови владеющий им скилл, он
прочитает его сам.
**Вызов не разрешился — плагина в проекте нет.** Это исход, а не поломка: назови
строкой доклада, чего теперь не делает никто, и продолжай работу. Молчать нельзя,
пропуск неотличим от сделанного; выдумывать обходной путь нельзя тоже.
**Присутствие узнаётся вызовом или следом в проекте, но не объявлением.** Перечня
установленных плагинов проект не ведёт — он разошёлся бы с действительностью
молча. Что сосед здесь работал, видно по заведённому им файлу: `docs/.docs.json`
канон, `<каталог задач>/.tasks.json` — задачи, `openspec/config.yaml` — конвейер.
Имя файла — имя плагина, который его завёл, и держит он в том числе версию своего
формата: у канона документов и у каталога задач они свои и двигаются порознь.
<!-- /дом: граница-плагинов -->
+38 -31
View File
@@ -57,7 +57,7 @@ openspec init --tools claude
Разрез, по которому отличают одно от другого: **утверждение, которое можно Разрез, по которому отличают одно от другого: **утверждение, которое можно
опровергнуть, открыв другой файл проекта, — пересказ; строка, которая говорит, опровергнуть, открыв другой файл проекта, — пересказ; строка, которая говорит,
какой файл открыть, — ссылка.** Машина этот разрез не проверяет; его смотрит какой файл открыть, — ссылка.** Машина этот разрез не проверяет; его смотрит
агент `doc-consistency` из плагина канона, когда тот подключён. агент `doc-consistency`, когда документы канона в проекте есть.
Два адреса обязательны — `docs/passport.md` и `CLAUDE.md`: предложение пишется до Два адреса обязательны — `docs/passport.md` и `CLAUDE.md`: предложение пишется до
того, как кто-либо откроет `docs/`, и без них его пишут, не зная ни границы того, как кто-либо откроет `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 check --dir <корень> # форма config.yaml в проекте
python3 $os form # слепок формы против живого OpenSpec python3 $os form # слепок формы против живого OpenSpec
@@ -87,9 +87,9 @@ python3 $os form # слепок формы против жив
имена артефактов схемы, а не свободные слова. Числа проверок здесь нет намеренно: имена артефактов схемы, а не свободные слова. Числа проверок здесь нет намеренно:
оно протухает от каждой добавленной. оно протухает от каждой добавленной.
**Адреса требуются только к тем документам, которые в проекте есть.** Канон **Адреса требуются только к тем документам, которые в проекте есть.** Документы
документов ставится отдельным плагином и может быть не подключён; требовать канона могут быть не заведены; требовать ссылку на несуществующий файл значит
ссылку на несуществующий файл значит требовать битую ссылку. Нет требовать битую ссылку. Нет
`docs/passport.md` — проверка по нему идёт строкой «не проверялось», и там же `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` и конвейер задачи. - **Не пишет спеки и предложения.** Это `opsx:propose` и конвейер задачи.
- **Не ведёт документы канона** — их дом плагин `av-dev-docs`, и адреса в - **Не ведёт документы канона** — их дом скилл `av-dev:doc-canon`, и адреса в
`context` только на них ссылаются. `context` только на них ссылаются.
- **Не чинит расхождение формы с версией OpenSpec в проекте.** Оно чинится в - **Не чинит расхождение формы с версией OpenSpec в проекте.** Оно чинится в
плагине: константы скрипта, образец здесь, запись в журнал версий канона. плагине: константы скрипта, образец здесь, запись в журнал версий канона.
- **Не судит, ссылается `context` на документы или пересказывает их.** Машине - **Не судит, ссылается `context` на документы или пересказывает их.** Машине
этот разрез не виден; его смотрит агент `doc-consistency` из плагина канона. этот разрез не виден; его смотрит агент `doc-consistency`. Документов канона в
Плагина нет — эту проверку не делает никто, и так и скажи. проекте нет — сверять пересказ не с чем, и так и скажи.
+34 -28
View File
@@ -48,38 +48,44 @@ description: "Взять одну задачу и довести её до за
`.claude/agents/<проект>-review-*.md`). Две копии одного скилла расходятся, и `.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:code-review`, `av-dev:doc-sync` и
`av-dev:task-track`. Чем оборачивается отсутствие каждого — на самих шагах и в `av-dev:task-track`. Чем оборачивается отсутствие каждого — на самих шагах и в
@@ -87,7 +93,7 @@ description: "Взять одну задачу и довести её до за
Перед стартом прочитай `CLAUDE.md` проекта и то, на что он ссылается, если ещё Перед стартом прочитай `CLAUDE.md` проекта и то, на что он ссылается, если ещё
не в контексте. Проектные факты, нужные ревью — инварианты, семантика гейта, не в контексте. Проектные факты, нужные ревью — инварианты, семантика гейта,
объёмы, модель угроз, прецеденты, — живут в **документах канона** `av-dev-docs`; объёмы, модель угроз, прецеденты, — живут в **документах канона**;
карта «что где» — `references/project-facts.md` конвейера ревью. карта «что где» — `references/project-facts.md` конвейера ревью.
**Документов канона нет — проект к нему не приведён.** Скажи это строкой и **Документов канона нет — проект к нему не приведён.** Скажи это строкой и
@@ -114,7 +120,7 @@ description: "Взять одну задачу и довести её до за
**Отказ `ready` сценарий не выбирает.** Запись `research` без раздела «Вопрос» **Отказ `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`; копия уже однажды разошлась с оригиналом. Плагина в проекте `av-dev:doc-sync`; копия уже однажды разошлась с оригиналом. Документов канона в
нет — иди за перечнем в свой reference, проекте нет — синка нет вовсе: скажи это исходом и предложи завести канон
[references/project-facts.md](../../review/references/project-facts.md) конвейера скиллом `av-dev:doc-canon`.
ревью, добавь `adr/` руками и скажи строкой, что синк сделан по перечню
документов, без списка триггеров.
### 6. Коммит ### 6. Коммит
@@ -265,13 +265,9 @@ git и читается диффом, а второй стоп на каждой
незачем. Но **названо должно быть каждое место, куда ты писал**, — доклад без незачем. Но **названо должно быть каждое место, куда ты писал**, — доклад без
перечня адресов неотличим от доклада о ненаписанном. перечня адресов неотличим от доклада о ненаписанном.
**Плагина `av-dev-docs` нет** — путь в его дерево не разрешится ниоткуда, поэтому **Документов канона в проекте нет** — писать ответ некуда: назови это исходом,
за перечнем документов иди в **свой** reference: предложи завести канон скиллом `av-dev:doc-canon` и оставь ответ в докладе
[references/project-facts.md](../../review/references/project-facts.md) конвейера целиком, чтобы работа не пропала. Заводить `docs/` мимо канона нельзя.
ревью. `docs/adr/` и `docs/research/` в нём отсутствуют намеренно (проход ревью их
не открывает), а разведке нужны как раз они — добавь их руками. Пиши сам, скажи
строкой: «ответ записан без скилла документации — форму и вычитку не сверял
никто».
### 5. Задачи: завести и уточнить ### 5. Задачи: завести и уточнить
+5 -16
View File
@@ -332,21 +332,10 @@ flowchart TD
`av-dev:doc-sync`, и копия уже однажды разошлась с оригиналом, потеряв два `av-dev:doc-sync`, и копия уже однажды разошлась с оригиналом, потеряв два
триггера. триггера.
**Плагина `av-dev-docs` в проекте нет** — путь в его дерево не разрешится ниоткуда, **Документов канона в проекте нет** — синка нет вовсе: назови это исходом и
поэтому за списком иди в **свой** reference: предложи завести канон скиллом `av-dev:doc-canon`. Придумывать раскладку под
[references/project-facts.md](../../review/references/project-facts.md) задачу нельзя: документ, заведённый мимо канона, окажется вторым домом ровно
конвейера ревью перечисляет все документы канона с их предметом. Пройди по этому тому, что канон потом заведёт своим.
перечню — каждый документ получает строку, отрицание остаётся обязательным.
**Двух домов в том перечне нет намеренно, а синку они нужны: `docs/adr/` и
`docs/research/`.** Проход ревью их не открывает — процессные, — но ADR как раз
**главный выход синка**: решение, принятое по ходу задачи, без этой строки
теряется систематически. Добавь их к перечню руками: `adr/` — решение с ценой,
принятое в этой задаче; `research/` — если по ходу узналось новое о внешнем мире
(записку разведки, предшествовавшей задаче, пишет не этот сценарий).
Триггеры при этом ты знаешь хуже, и это называется в докладе строкой: «синк
сделан по перечню документов, без списка триггеров — плагина `av-dev-docs` нет».
Канона в проекте тоже нет — назови это исходом и предложи `av-dev:doc-canon`.
### 10. Коммит ### 10. Коммит
@@ -368,7 +357,7 @@ flowchart TD
оставило бы задачу закрытой без единого следа работы, если шаг 10 упадёт. оставило бы задачу закрытой без единого следа работы, если шаг 10 упадёт.
**Закрытие тоже коммитится — вторым коммитом, тут же.** Удаление файла задачи и **Закрытие тоже коммитится — вторым коммитом, тут же.** Удаление файла задачи и
правка индексов (их имена знает `av-dev-tasks`, не ты) — это правки в рабочем правка индексов (их имена знает `av-dev:task-track`, не ты) — это правки в рабочем
дереве, и оставить их незакоммиченными нельзя: закрытие, не доехавшее до основной дереве, и оставить их незакоммиченными нельзя: закрытие, не доехавшее до основной
ветки, оставит задачу открытой молча, а опора «индексы под git показывают, что и ветки, оставит задачу открытой молча, а опора «индексы под git показывают, что и
когда закрыто» без коммита — пустые слова. Сообщение короткое, про учёт, а не про когда закрыто» без коммита — пустые слова. Сообщение короткое, про учёт, а не про
+31 -25
View File
@@ -1,6 +1,6 @@
--- ---
name: code-review 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` — снеси их. Иначе короткое имя разрешится `.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-review`,
`av-dev:code-resolve`, `av-dev:code-openspec` — подменяется короткое имя, `av-dev:code-resolve`, `av-dev:code-openspec` — подменяется короткое имя,
@@ -201,7 +207,7 @@ description: "Конвейер ревью изменения, устроенны
прохода между метками; прохода между метками;
- **контракт находок** — путь к - **контракт находок** — путь к
[references/finding-contract.md](references/finding-contract.md) (в [references/finding-contract.md](references/finding-contract.md) (в
установленном плагине — `${CLAUDE_PLUGIN_ROOT}/skills/review/references/`); установленном плагине — `${CLAUDE_PLUGIN_ROOT}/skills/code-review/references/`);
- **изменение** — идентификатор change и путь к его дельта-спекам; - **изменение** — идентификатор change и путь к его дельта-спекам;
- **база диффа**; - **база диффа**;
- **метка, его глубина и режим** прогона — чтобы проход знал, что писать в - **метка, его глубина и режим** прогона — чтобы проход знал, что писать в
@@ -4,8 +4,8 @@
нельзя нарушать, чем краснеет гейт и сколько данных реально идёт через узел, нельзя нарушать, чем краснеет гейт и сколько данных реально идёт через узел,
выдаёт правдоподобные общие места: их дорого опровергать и нечем подтверждать. выдаёт правдоподобные общие места: их дорого опровергать и нечем подтверждать.
Отдельного файла-брифа **нет**. Проектная конкретика живёт в документах канона Отдельного файла-брифа **нет**. Проектная конкретика живёт в документах канона,
`av-dev-docs`, и проход читает их напрямую: пути жёсткие, посредник не нужен, а и проход читает их напрямую: пути жёсткие, посредник не нужен, а
второй дом для тех же фактов разошёлся бы и выглядел актуальным. второй дом для тех же фактов разошёлся бы и выглядел актуальным.
Определение канона держит скилл `av-dev:doc-canon`. Здесь только карта «тема → Определение канона держит скилл `av-dev:doc-canon`. Здесь только карта «тема →
@@ -1,7 +1,7 @@
# Журнал дефектов # Журнал дефектов
Артефакт проекта, а не плагина: файл живёт в репозитории — **`docs/review.md`**, Артефакт проекта, а не плагина: файл живёт в репозитории — **`docs/review.md`**,
слот канона `av-dev-docs`. Здесь описано, зачем он и какой формы, потому что без слот канона документов. Здесь описано, зачем он и какой формы, потому что без
него конвейер не учится: находки закрываются, а почему их не поймали — забывается, него конвейер не учится: находки закрываются, а почему их не поймали — забывается,
и один и тот же класс проскакивает второй раз. и один и тот же класс проскакивает второй раз.
+30 -24
View File
@@ -20,7 +20,7 @@ description: Привести проект к канону документов
- [references/skeletons.md](references/skeletons.md) — **что именно класть** в - [references/skeletons.md](references/skeletons.md) — **что именно класть** в
каждый незаполненный слот. Не выдумывай заглушку своей формы: `docs.py` каждый незаполненный слот. Не выдумывай заглушку своей формы: `docs.py`
узнаёт только плейсхолдер `<!-- заполнить: … -->` из шаблонов. узнаёт только плейсхолдер `<!-- заполнить: … -->` из шаблонов.
- [references/language.md](references/language.md) — **как это написано словами**: - [shared/language.md](../../shared/language.md) — **как это написано словами**:
информационный стиль, применённый к проектным текстам, таблицы англицизмов и информационный стиль, применённый к проектным текстам, таблицы англицизмов и
жаргона. Раскладка отвечает, где текст лежит, — этот файл отвечает, каким он жаргона. Раскладка отвечает, где текст лежит, — этот файл отвечает, каким он
должен быть. Правила общие для документов канона, задач, решений ADR и должен быть. Правила общие для документов канона, задач, решений 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 check --dir <корень> [--base <rev>] # раскладка, ссылки, версия, сверки
python3 $ds version --dir <корень> # версия канона скрипта и проекта python3 $ds version --dir <корень> # версия канона скрипта и проекта
@@ -87,41 +87,47 @@ capability: незаполненный канон это переходное с
формулировка казалась удачной при написании. Ни один из них ничего не правит — формулировка казалась удачной при написании. Ни один из них ничего не правит —
оба возвращают готовые формулировки, подставляешь ты. оба возвращают готовые формулировки, подставляешь ты.
## Обращение к соседним плагинам ## Чего может не быть
`adopt` зовёт двоих: `av-dev:code-openspec` (шаг 4, пункт 3) и `adopt` зовёт двоих: `av-dev:code-openspec` (шаг 4, пункт 3) и
`av-dev:task-track` (шаг 4, пункт 5). Каталоги `openspec/` и `tasks/` каноном не `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` из-за Чем оборачивается отсутствие каждого — на самих пунктах шага 4. `adopt` из-за
этого не останавливается ни в одном из двух случаев. этого не останавливается ни в одном из двух случаев.
+8 -31
View File
@@ -23,39 +23,16 @@
Раскладка отвечает, **где** текст лежит и на какой вопрос отвечает. Каким он Раскладка отвечает, **где** текст лежит и на какой вопрос отвечает. Каким он
должен быть **словами** — общий для всех документов канона файл должен быть **словами** — общий для всех документов канона файл
[language.md](language.md): информационный стиль, англицизмы, жаргон. Он [shared/language.md](../../../shared/language.md): информационный стиль, англицизмы, жаргон. Он
относится и к задачам, и к решениям ADR, и к запискам разведки. относится и к задачам, и к решениям ADR, и к запискам разведки.
## Сопровождение и эксплуатация — целое и часть ## Сопровождение и эксплуатация — целое и часть
**Копия.** Дом — `shared/operations.md` в репозитории плагинов: словарь Словарь этой темы — [shared/operations.md](../../../shared/operations.md):
делят роадмап, архитектура и тема ревью `operations`, то есть три плагина, целое и часть, три места одной темы (секция роадмапа, раздел архитектуры, тема
и ни один из трёх им не владеет. Правится дом, а не этот файл. ревью `operations`) и граница с возможностями проекта. Здесь он не
пересказывается: копия жила рядом с домом в одном дереве и была ровно тем
<!-- копия: сопровождение-словарь из av-dev/shared/operations.md --> вторым домом, против которого правило и написано.
Одна тема живёт в трёх местах, и путать их слова нельзя.
**Сопровождение** — всё, чем держат проект: инструмент и сборка, процесс,
выкладка, метрики и логи, инфраструктура, дежурство. **Эксплуатация** — его
часть: работа системы на проде. Целое и часть, и никогда наоборот.
| Место | Уровень | Что там |
| --- | --- | --- |
| `ROADMAP.md`, секция `Сопровождение` | план | **работы**, которые собираемся делать: цели и их задачи |
| `architecture.md`, раздел «Эксплуатация» | состояние | **как устроено сейчас**: где работает, что рядом, кто перезапускает |
| тема ревью `operations` | оптика | **чем проверяем**: «это упало через неделю на проде» |
Слово **«поддержка» не употребляется вовсе** — в нём слышится помощь
пользователю, а это другая работа.
**Граница с возможностями проходит по тому, кто наблюдает.** «Приложение
сообщает о своём состоянии» — возможность приложения, её место среди прочих
целей: наблюдает пользователь сервиса. «Дежурный видит состояние на одном
экране» — сопровождение: наблюдаем мы. Одни и те же метрики попадают в разные
секции роадмапа, и это верно — секции отвечают на разные вопросы.
<!-- /копия: сопровождение-словарь -->
## Раскладка ## Раскладка
@@ -79,7 +56,7 @@ docs/
adr.md | adr/ почему решено так; статусы, правило замены adr.md | adr/ почему решено так; статусы, правило замены
review.md | review/ настройка конвейера под проект + журнал дефектов review.md | review/ настройка конвейера под проект + журнал дефектов
<своя тема>.md | <своя тема>/ всё, что проект счёл нужным проверять <своя тема>.md | <своя тема>/ всё, что проект счёл нужным проверять
tasks/ каталог задач — плагин av-dev-tasks, не канон; tasks/ каталог задач — скилл task-track, не канон;
лежит в корне, вне docs/, и канон его не требует лежит в корне, вне docs/, и канон его не требует
openspec/ openspec/
config.yaml только нужды генерации артефактов + ссылки config.yaml только нужды генерации артефактов + ссылки
@@ -119,7 +96,7 @@ openspec/
| `CLAUDE.md`, `AGENTS.md` | источник | `autotests` (семантика гейта); инварианты — сквозные | | `CLAUDE.md`, `AGENTS.md` | источник | `autotests` (семантика гейта); инварианты — сквозные |
| `openspec/specs/` | источник | `requirements` | | `openspec/specs/` | источник | `requirements` |
| `openspec/config.yaml` | процессный | — (настройка порождения артефактов, слой **до** тем; заводит конвейер) | | `openspec/config.yaml` | процессный | — (настройка порождения артефактов, слой **до** тем; заводит конвейер) |
| `tasks/` | процессный | — (чужое владение: плагин `av-dev-tasks`) | | `tasks/` | процессный | — (чужое владение: скилл `task-track`) |
| `review.*` | процессный | — (настройка самого конвейера, слой **над** темами) | | `review.*` | процессный | — (настройка самого конвейера, слой **над** темами) |
| `adr.*` | процессный | — | | `adr.*` | процессный | — |
| `research.*` | процессный | — | | `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` и пришлось назвать заново** — иначе их не звал бы никто, кроме разовых `adopt` и
`upgrade`, то есть на живом проекте никогда. `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`, когда находка тянет на задачу. Его нет — Здесь сосед один: `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` узнаёт только плейсхолдер оттуда. своей формы, `docs.py` узнаёт только плейсхолдер оттуда.
## Что `init` физически не может произвести ## Что `init` физически не может произвести
@@ -69,40 +69,46 @@ description: "Завести новый проект — сессия вопро
- **Развилка замысла — человеку, механика — сама.** Имена файлов, слаги, порядок - **Развилка замысла — человеку, механика — сама.** Имена файлов, слаги, порядок
строк не выноси. строк не выноси.
## Обращение к соседним плагинам ## Чего может не быть
Два шага порядка работы — вызовы чужого: OpenSpec заводит конвейер, каталог задач Два шага порядка работы — вызовы чужого: OpenSpec заводит конвейер, каталог задач
ведёт плагин задач. Ни того, ни другого `init` не делает руками. ведёт плагин задач. Ни того, ни другого `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. Заведение проекта Чем оборачивается отсутствие каждого — на самих шагах 3 и 7. Заведение проекта
из-за этого не останавливается: проект без конвейера и без учёта задач законен. из-за этого не останавливается: проект без конвейера и без учёта задач законен.
@@ -124,7 +130,7 @@ description: "Завести новый проект — сессия вопро
5. Напиши заполняемые документы. **Бриф переезжает в `passport.md`** и 5. Напиши заполняемые документы. **Бриф переезжает в `passport.md`** и
отдельным файлом не остаётся: два дома для одного замысла разойдутся на отдельным файлом не остаётся: два дома для одного замысла разойдутся на
первом же уточнении. первом же уточнении.
6. Заведи скелет остальных по [скелетам](../canon/references/skeletons.md) — 6. Заведи скелет остальных по [скелетам](../doc-canon/references/skeletons.md) —
каждый с честной строкой. каждый с честной строкой.
7. Каталог задач и первые цели — **вызови скилл `av-dev:task-track`**: он владеет 7. Каталог задач и первые цели — **вызови скилл `av-dev:task-track`**: он владеет
форматом целей и задач. Не разрешился — учёт задач остаётся владельцу, и это форматом целей и задач. Не разрешился — учёт задач остаётся владельцу, и это
+41 -37
View File
@@ -6,7 +6,7 @@ description: Вести содержимое документов канона
# Ведение содержимого канона # Ведение содержимого канона
Скилл владеет **содержимым** документов канона; раскладкой владеет `canon`. Скилл владеет **содержимым** документов канона; раскладкой владеет `canon`.
Определение канона и роли документов — [канон](../canon/references/canon.md), Определение канона и роли документов — [канон](../doc-canon/references/canon.md),
здесь не пересказывается. здесь не пересказывается.
Главный вызывающий — **шаг синка документации в конвейере задачи**. Конвейер Главный вызывающий — **шаг синка документации в конвейере задачи**. Конвейер
@@ -106,11 +106,11 @@ description: Вести содержимое документов канона
`av-dev:code-resolve`, сценарий разведки: решение, принятое разведкой (намеренный отказ, выбор `av-dev:code-resolve`, сценарий разведки: решение, принятое разведкой (намеренный отказ, выбор
подхода, «проверили и не делаем»), `design.md` не имеет по построению — change по подхода, «проверили и не делаем»), `design.md` не имеет по построению — change по
нему не будет никогда. Промоут при этом тот же: цитата и ссылка, но на записку. нему не будет никогда. Промоут при этом тот же: цитата и ссылка, но на записку.
Перечень источников закрыт и живёт в [каноне](../canon/references/canon.md), Перечень источников закрыт и живёт в [каноне](../doc-canon/references/canon.md),
раздел `adr/`. раздел `adr/`.
**Триггер заведения, форма имени и правило замены — в **Триггер заведения, форма имени и правило замены — в
[каноне](../canon/references/canon.md), раздел `adr/`.** Здесь они не [каноне](../doc-canon/references/canon.md), раздел `adr/`.** Здесь они не
повторяются: копия правила расходится с оригиналом на первой же смене версии повторяются: копия правила расходится с оригиналом на первой же смене версии
канона, а расходится незаметно. канона, а расходится незаметно.
@@ -126,7 +126,7 @@ description: Вести содержимое документов канона
Обзор не держит поведение — его нормативный дом `openspec/specs/`. **Форма Обзор не держит поведение — его нормативный дом `openspec/specs/`. **Форма
маркера долга и правило «гейт от них не краснеет» — в маркера долга и правило «гейт от них не краснеет» — в
[каноне](../canon/references/canon.md), раздел `architecture.md`.** [каноне](../doc-canon/references/canon.md), раздел `architecture.md`.**
Разбирается порциями: раздел вычищает та задача, которая его касается. Разбирается порциями: раздел вычищает та задача, которая его касается.
Содержимое не выбрасывается, а переезжает — требования в дельта-спеку change, Содержимое не выбрасывается, а переезжает — требования в дельта-спеку change,
@@ -136,47 +136,53 @@ description: Вести содержимое документов канона
Наблюдение о внешнем мире: что реально шлёт источник, чем документация формата Наблюдение о внешнем мире: что реально шлёт источник, чем документация формата
расходится с практикой. **Требование провенанса и правило про расходящееся расходится с практикой. **Требование провенанса и правило про расходящееся
число — в [каноне](../canon/references/canon.md), раздел `research/`.** число — в [каноне](../doc-canon/references/canon.md), раздел `research/`.**
Твоя часть — заметить, что по ходу задачи узналось новое о внешних данных, и не Твоя часть — заметить, что по ходу задачи узналось новое о внешних данных, и не
дать этому остаться в контексте. Признак: ты правил разбор, опираясь на то, чего дать этому остаться в контексте. Признак: ты правил разбор, опираясь на то, чего
нет ни в одном документе. нет ни в одном документе.
## Обращение к соседним плагинам ## Чего может не быть
Два раздела ниже — запись в `review.md` и промоут в конвенции — берут форму у Два раздела ниже — запись в `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`**; подробности формы [каноне](../doc-canon/references/canon.md), раздел `review.md`**; подробности формы
записи и выбор адреса, куда она ведёт, — у конвейера ревью проекта (при записи и выбор адреса, куда она ведёт, — у конвейера ревью: `Skill
`av-dev-code``Skill av-dev:code-review`, его av-dev:code-review`, его `references/review-journal.md`.
`references/review-journal.md`). **Конвейера в проекте нет** — пиши по форме из
скелета `review.md`, которую положил канон, и скажи в докладе, что подробностей
формы взять негде.
Твоя часть на синке: **дефект пишется сразу**, а не «потом, когда починим». Твоя часть на синке: **дефект пишется сразу**, а не «потом, когда починим».
Со временем теряется не факт, а то, почему дефект не поймали, — единственное, Со временем теряется не факт, а то, почему дефект не поймали, — единственное,
@@ -200,10 +203,11 @@ description: Вести содержимое документов канона
## Промоут в конвенции ## Промоут в конвенции
Находка → конвенция → правило линтера → **удаление из прозы**. Процедура целиком Находка → конвенция → правило линтера → **удаление из прозы**. Процедура целиком
принадлежит конвейеру ревью проекта (при `av-dev-code` — его принадлежит конвейеру ревью — его `references/promote.md`, читается через
`references/promote.md`, читается через `Skill av-dev:code-review`); `Skill av-dev:code-review`; роль каталога конвенций — в
роль каталога конвенций — в [каноне](../canon/references/canon.md). **Конвейера [каноне](../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/`); `openspec/changes/archive/<id>/review/` (до архивации — `changes/<id>/review/`);
- **`reopen <слаг> --reason`** — закрытие не окончательно. Заметил на груминге, - **`reopen <слаг> --reason`** — закрытие не окончательно. Заметил на груминге,
что закрытая задача сделана не тем, чем обещала, — возвращай, это штатная что закрытая задача сделана не тем, чем обещала, — возвращай, это штатная
@@ -244,4 +244,4 @@ flowchart TD
себе — формат и содержимое ведёт `tasks` (груминг зовёт его операции). Не решает себе — формат и содержимое ведёт `tasks` (груминг зовёт его операции). Не решает
за человека, что важно: он готовит развилки и рекомендует. Не принимает за человека, что важно: он готовит развилки и рекомендует. Не принимает
закрытые задачи отдельным ритуалом — `reopen` есть, момента у него нет. Не судит закрытые задачи отдельным ритуалом — `reopen` есть, момента у него нет. Не судит
документы проекта — это плагин `av-dev-docs`. документы проекта — это скиллы `av-dev:doc-canon` и `av-dev:doc-healthcheck`.
@@ -20,7 +20,7 @@
(`edit <slug> --rm-tag question`), **перепиши «зачем»**: «Решено: …» на вопрос (`edit <slug> --rm-tag question`), **перепиши «зачем»**: «Решено: …» на вопрос
«почему это лежит в беклоге» уже не отвечает. Опустошение раздела — не «почему это лежит в беклоге» уже не отвечает. Опустошение раздела — не
уборка, а условие взятия: правило и причина в скилле `tasks`, уборка, а условие взятия: правило и причина в скилле `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` по существу, а не по 8. **Задача ли это по-прежнему.** Не проходит `ready` по существу, а не по
недописанным разделам → `edit <slug> --type research` и опустошённый раздел недописанным разделам → `edit <slug> --type research` и опустошённый раздел
«Вопрос», то есть сырьё; дальше штурм. Разрослась → это несколько задач под «Вопрос», то есть сырьё; дальше штурм. Разрослась → это несколько задач под
+7 -7
View File
@@ -72,8 +72,8 @@ description: Ведение задач и целей как каталога mar
## Раскладка ## Раскладка
Каталог задач — **`tasks/` в корне репозитория, жёстко.** Он принадлежит этому Каталог задач — **`tasks/` в корне репозитория, жёстко.** Он принадлежит этому
плагину, а не канону документов: `docs/` ведёт другой плагин (`av-dev-docs`), и скиллу, а не канону документов: учёт работ ведут и в проекте, который к канону
проект, поставивший учёт работ без него, каталога `docs/` не имеет вовсе. Внутри не приведён, и каталога `docs/` там нет вовсе. Внутри
`docs/` задачи лежали до версии канона 11; непереехавший проект скрипт `docs/` задачи лежали до версии канона 11; непереехавший проект скрипт
по-прежнему находит, но новый заводит только в корне. по-прежнему находит, но новый заводит только в корне.
@@ -210,7 +210,7 @@ stateDiagram-v2
часть кода мы трогаем». часть кода мы трогаем».
**Целью не становится работа, которой держат проект.** Состав перечислен **Целью не становится работа, которой держат проект.** Состав перечислен
[в словаре сопровождения](references/operations.md); [в словаре сопровождения](../../shared/operations.md);
на вопрос «что приложение будет уметь» ничто из него не отвечает. Им отведена отдельная секция роадмапа, на вопрос «что приложение будет уметь» ничто из него не отвечает. Им отведена отдельная секция роадмапа,
чтобы они были видны в том же экране и при этом не читались как возможности чтобы они были видны в том же экране и при этом не читались как возможности
продукта. продукта.
@@ -225,7 +225,7 @@ stateDiagram-v2
живёт ещё в двух местах: разделе «Эксплуатация» в `architecture.md` и теме ревью живёт ещё в двух местах: разделе «Эксплуатация» в `architecture.md` и теме ревью
`operations`. Словарь у всех трёх общий, дом у него один — `shared/operations.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` — разведка), признаков: тип **предлагает** (`chore` — обслуживание, `research` — разведка),
а подтверждает его предмет работы — есть ли что менять в спеках. Признаки а подтверждает его предмет работы — есть ли что менять в спеках. Признаки
разошлись — работа останавливается, и тип меняется здесь, командой `edit --type`, разошлись — работа останавливается, и тип меняется здесь, командой `edit --type`,
@@ -356,7 +356,7 @@ stateDiagram-v2
Язык — общий для всех проектных текстов, и дом у него один, Язык — общий для всех проектных текстов, и дом у него один,
`shared/language.md` в репозитории плагинов; здесь лежит дословная копия: `shared/language.md` в репозитории плагинов; здесь лежит дословная копия:
[references/language.md](references/language.md) (информационный стиль, [shared/language.md](../../shared/language.md) (информационный стиль,
применённый к задачам и документам канона; там же таблицы англицизмов и жаргона применённый к задачам и документам канона; там же таблицы англицизмов и жаргона
и то, что из стиля отброшено намеренно). Задаче он даёт четыре требования, и то, что из стиля отброшено намеренно). Задаче он даёт четыре требования,
которые нарушаются чаще прочих: которые нарушаются чаще прочих:
@@ -381,7 +381,7 @@ stateDiagram-v2
## Инструмент (`tasks.py`) ## Инструмент (`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` стоит в примерах намеренно: вызов из `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 \ python3 $tk adopt scan --from docs/backlog docs/plan.md TODO.md \
--target tasks --out tasks-adopt-plan.json # только чтение --target tasks --out tasks-adopt-plan.json # только чтение
@@ -85,7 +85,7 @@
отображается **в позицию в очереди**, потому что приоритет и есть порядок строк отображается **в позицию в очереди**, потому что приоритет и есть порядок строк
в беклоге (правило 4 [SKILL.md](../SKILL.md)). Отображается через довод, а не в беклоге (правило 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 и не пишет требований, потому что **сценарий обслуживания**: он не заводит change и не пишет требований, потому что
у работы, не меняющей поведения, дельта-спек нет по построению. Тип записи там у работы, не меняющей поведения, дельта-спек нет по построению. Тип записи там
только **предлагает** сценарий, а подтверждает его отсутствие дельт: разошлись — только **предлагает** сценарий, а подтверждает его отсутствие дельт: разошлись —
@@ -38,7 +38,7 @@
1. **Проверить, что это возможность, а не работа.** Работа, которой держат 1. **Проверить, что это возможность, а не работа.** Работа, которой держат
проект, на вопрос «что приложение будет уметь» не отвечает; состав перечислен проект, на вопрос «что приложение будет уметь» не отвечает; состав перечислен
[в словаре сопровождения](operations.md). Ей отведена секция [в словаре сопровождения](../../../shared/operations.md). Ей отведена секция
`Сопровождение` — там она видна в том же `Сопровождение` — там она видна в том же
экране и не читается как обещание продукта. Граница проходит по тому, экране и не читается как обещание продукта. Граница проходит по тому,
**кто наблюдает**: **кто наблюдает**:
@@ -66,9 +66,8 @@
4. **Провести разведку** и **записать ответ по названному адресу**. Числа — с 4. **Провести разведку** и **записать ответ по названному адресу**. Числа — с
провенансом: с командой или условиями, которыми получены. Число без источника провенансом: с командой или условиями, которыми получены. Число без источника
проход ревью обязан читать как условие, а не как замер. Проводит её конвейер проход ревью обязан читать как условие, а не как замер. Проводит её конвейер
проекта — в плагине `av-dev-code` это скилл `resolve`, сценарий разведки; проекта — скилл `av-dev:code-resolve`, сценарий разведки; этот скилл её
плагина нет — разведка ведётся как проект привык, а этот скилл её только только заводит и закрывает.
заводит и закрывает.
5. **Разложить исход на задачи** — если он их родил. Разведка кончается одним из 5. **Разложить исход на задачи** — если он их родил. Разведка кончается одним из
трёх: заведены задачи, записано знание, отказ. **Отказ — полноправный исход**: трёх: заведены задачи, записано знание, отказ. **Отказ — полноправный исход**:
«проверили, не проблема» экономит работу. «проверили, не проблема» экономит работу.