Эксперимент: по сабагенту на каждый скилл av-dev-pm, задача — переписать текст более простыми словами, но только там, где уверен и без потери смысла и точности. Нормой служил устав языка самого проекта, language.md, включая его раздел «Порог правки»: правка без нарушенного правила не делается. 36 правок в двенадцати файлах, +64/-63 — почти строго замена, а не переписывание. Правили залог (пассив с названным деятелем в творительном), отглагольные существительные, параллельность перечней, канцелярит «является», пару garden-path и одно двойное отрицание. Контракт не задет нигде: в диффе нет изменённых строк-заголовков, а код-спаны встречаются ровно парой минус-плюс, то есть ни имя, ни флаг, ни путь не переписаны. Отчёты «что рассматривал и не тронул» вышли длиннее отчётов о правках у всех пятерых, и это главный результат прогона. Самый частый повод остановиться — слово, живущее в четырёх файлах: конфляция, интейк, провенанс, непоймание. Правка в одном месте развела бы словарь, а править все — уже не упрощение текста скилла, а сквозной проход по репозиторию. Второй повод — формулировка, дословно повторённая в соседнем плагине: декорреляция, материализация нерешённого, «при расхождении прав текст». Шестой агент проверил все 36 правок и нашёл четыре. Перестановка слов в task-research.md развела формулу с её домом: «число без источника проход ревью обязан читать как условие» стоит в canon.md и в уставе doc-consistency, который прямо ссылается на канон как на источник. Откачено — это ровно тот класс расхождения, который сам doc-consistency и ловит. «Держит H1, мету и индекс в согласии» — управление требует дополнения, а language.md в разделе англицизмов прямо оговаривает: русский аналог звучит коряво — остаётся термин. Взят третий вариант, «согласованными». В skeletons.md «правка тянет запись, и она называет» — местоимение указывает на два женских существительных сразу. Стало «и запись называет». Четвёртая находка не откачена: правка в init/SKILL.md хорошая, но развела конструкцию с близнецом в canon/SKILL.md — выровнена вторая половина. Побочно найдена старая логическая инверсия в DECISIONS.md, решение U: «становится неотличимым, только если отрицание обязательно» — смысл вывернут, в docs/SKILL.md и во второй записи журнала он правильный. Починено. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
404 lines
19 KiB
Markdown
404 lines
19 KiB
Markdown
# Скелеты документов канона
|
||
|
||
Что кладут `init` и `canon adopt` в незаполненный слот. Правило одно:
|
||
**честная информативная строка вместо заглушки**. Проход читает строку как факт;
|
||
`<!-- заполнить: … -->` он читает как пробел, и `docs.py check` о таком
|
||
плейсхолдере напоминает.
|
||
|
||
Плейсхолдер ставится только там, где ответ **обязан** быть и его не спросили.
|
||
Всё, чего в проекте пока просто нет, описывается словами, а не плейсхолдером.
|
||
|
||
**Шаблоны — единственное место, где правило канона копируется намеренно.**
|
||
`adr/README.md` и `review.md` уезжают в репозиторий проекта и обязаны там что-то
|
||
говорить; определение при этом остаётся в [canon.md](canon.md). Отсюда
|
||
обязанность: **правка такого правила в каноне тянет запись в
|
||
[changelog.md](changelog.md)** — и запись называет, какой файл проекта поднимает
|
||
`upgrade`. Без этого копия в проекте останется на старой версии молча.
|
||
|
||
**Каждая такая копия помечена и сверяется машиной.** Дом обрамляется
|
||
`<!-- дом: <id> -->` … `<!-- /дом: <id> -->`, копия —
|
||
`<!-- копия: <id> из <путь> -->` … `<!-- /копия: <id> -->`;
|
||
`scripts/copies.py` маркетплейса требует дословного
|
||
совпадения. Комментарии невидимы в отрендеренном markdown и уезжают в проект
|
||
вместе со скелетом — там они говорят читателю, что у текста есть дом. Правишь
|
||
текст внутри маркеров — правь дом, а не копию.
|
||
|
||
## `docs/passport.md`
|
||
|
||
```markdown
|
||
# Паспорт проекта
|
||
|
||
Зачем это и для кого. [architecture.md](architecture.md) отвечает «как
|
||
устроено», [tasks/ROADMAP.md](tasks/ROADMAP.md) — «в каком порядке», паспорт —
|
||
«зачем и для кого».
|
||
|
||
## Цель
|
||
|
||
<!-- заполнить: одна фраза без технических деталей -->
|
||
|
||
**Потребители** — список закрытый: он определяет, что считать нужным, а что
|
||
интересным.
|
||
|
||
| Кто | Что ему нужно от нас |
|
||
| --- | --- |
|
||
|
||
Цель достигнута, когда:
|
||
|
||
## Что целью не является
|
||
|
||
Граница домена. По ней архитектурный проход судит, не перенесено ли понятие
|
||
через границу.
|
||
|
||
## Типовые сценарии
|
||
|
||
## Референсы
|
||
|
||
Где смотреть prior art, когда упёрлись.
|
||
```
|
||
|
||
## `docs/architecture.md`
|
||
|
||
```markdown
|
||
# Архитектура
|
||
|
||
Обзор: как сложено и где что работает. **Поведение системы здесь не
|
||
описывается** — его нормативный дом `openspec/specs/`.
|
||
|
||
## Принципы
|
||
|
||
## Компоненты
|
||
|
||
Каждый — строкой со ссылкой на capability, а не пересказом её требований.
|
||
|
||
## Внешние границы и форматы
|
||
|
||
## Эксплуатация
|
||
|
||
- Где работает, что рядом, кто перезапускает:
|
||
- Внешние зависимости поимённо и чем каждая отказывает (падает, отвечает
|
||
медленно, молчит, отдаёт мусор):
|
||
- Кто заметит отказ и когда:
|
||
- Характер потока (непрерывный, по запросу, по расписанию):
|
||
|
||
## Единые точки проекта
|
||
|
||
Где генерируются идентификаторы и время; где единственный парсер входного
|
||
формата; где маппинг доменной ошибки в код ответа; где общий путь приёма.
|
||
Материал для вопроса «не появился ли второй способ делать то, что уже делается».
|
||
|
||
## Деплой
|
||
|
||
## Открытые вопросы
|
||
```
|
||
|
||
Пустой проект: «Архитектуры пока нет: кода нет. Наполняется первой задачей.»
|
||
Нет внешних зависимостей: «Внешних зависимостей нет — смотри на диск и на СУБД.»
|
||
|
||
## `docs/database.md`
|
||
|
||
```markdown
|
||
# Схема хранилища
|
||
|
||
СУБД, миграции, правило времени и идентификаторов.
|
||
|
||
## Таблицы
|
||
|
||
## Представление данных
|
||
|
||
Чем физически лежит запись и что происходит при чтении и записи.
|
||
|
||
## Настройки с числовым значением
|
||
|
||
Таймаут занятости, режим журналирования, лимит тела, размер пула, ретеншен.
|
||
Без них замер не превращается в находку: пик памяти — аномалия только рядом
|
||
со строкой «запись лежит сжатой и распаковывается целиком».
|
||
```
|
||
|
||
Нет БД — файла нет, и в `docs/.pm.json` нет ключа `migrations`.
|
||
|
||
## `docs/security.md`
|
||
|
||
```markdown
|
||
# Модель угроз
|
||
|
||
## Периметр
|
||
|
||
<!-- заполнить: первой строкой, против кого защищаемся -->
|
||
|
||
Контур не развёрнут — назови оба периметра, целевой и сегодняшний, и скажи
|
||
прямо, против какого строятся находки.
|
||
|
||
## Недоверенный вход
|
||
|
||
Что приходит извне и каким каналом: тело запроса, файл, аргумент команды,
|
||
ответ внешней системы, содержимое архива.
|
||
|
||
## Из чего строятся пути и ключи
|
||
|
||
Раскладка файлов на диске, состав координатного ключа записи, имя каталога.
|
||
Отсюда строится выход за пределы песочницы.
|
||
|
||
## Что разграничивает доступ
|
||
|
||
## Что чувствительнее чего
|
||
|
||
## Что вне модели
|
||
|
||
Перечислить явно. Пустой пункт означает, что враждебный проход выдумает угрозу
|
||
сам, и находка никогда не будет исправлена.
|
||
```
|
||
|
||
## `docs/conventions/README.md`
|
||
|
||
```markdown
|
||
# Конвенции кода
|
||
|
||
Как мы пишем код — в отличие от `openspec/specs/`, который описывает, что
|
||
система делает.
|
||
|
||
**Прозой остаётся только то, что не выражается правилом.** Свойство, ставшее
|
||
правилом линтера, отсюда удаляется и переезжает в перечень ниже.
|
||
|
||
## Записи
|
||
|
||
## Механизировано
|
||
|
||
| Правило | Где механизировано |
|
||
| --- | --- |
|
||
|
||
Непойманное место механизации означает, что проход по конвенциям будет
|
||
добросовестно проверять уже проверенное.
|
||
```
|
||
|
||
Пустой проект: «Конвенций пока нет: код не написан. Наполняется по мере
|
||
реального трения, а не вперёд.»
|
||
|
||
## `docs/research/README.md`
|
||
|
||
```markdown
|
||
# Разведка
|
||
|
||
Наблюдения за внешним миром: что реально шлёт источник, чем документация
|
||
формата расходится с практикой. Источник истины — этот каталог, а не чужая
|
||
документация.
|
||
|
||
**Каждый вывод — с числами и командой, которой получен**, чтобы его можно было
|
||
перепроверить.
|
||
|
||
## Как снималось
|
||
|
||
## Записи
|
||
```
|
||
|
||
Нет внешних источников: «Внешних источников данных нет — разведка неприменима.»
|
||
|
||
## `docs/adr/README.md`
|
||
|
||
```markdown
|
||
# Журнал решений
|
||
|
||
Одна запись — одно решение. **ADR это промоут поверх архивного `design.md`**,
|
||
а не второе сочинение: запись цитирует решение и ссылается на
|
||
`openspec/changes/archive/<id>/design.md`.
|
||
|
||
## Когда заводить
|
||
|
||
Верно одно из трёх:
|
||
|
||
<!-- копия: adr-когда-заводить из av-dev-pm/skills/canon/references/canon.md -->
|
||
- **дорогой откат** — переделка стоит дороже переписывания одного файла;
|
||
- **намеренный отказ** от очевидного подхода;
|
||
- **пересмотр прежнего решения** — тогда у старой записи обязателен статус
|
||
«заменено на».
|
||
<!-- /копия: adr-когда-заводить -->
|
||
|
||
Не заводить для рутины и для того, что видно из кода и `git log`.
|
||
|
||
## Соглашения
|
||
|
||
- Имя файла — `ADR-ГГГГ-ММ-ДД-slug.md`, дата — когда решение реально принято.
|
||
Слаг **английский по сути, а не транслитом**: `queue-as-table`, не
|
||
`ochered-tablicej`. Форму имени и слаг проверяет `docs.py check`.
|
||
- Записи неизменяемы: передумали — новая запись, старой ставится статус.
|
||
- Активная запись статуса не имеет. Значений два: `заменено на ADR-…` и
|
||
`устарело`; ставятся полем меты записи — `- **Статус:** …` рядом с датой и
|
||
источником, а не абзацем в теле.
|
||
|
||
## Записи
|
||
|
||
Новые сверху.
|
||
|
||
| Дата | Запись | Статус |
|
||
| --- | --- | --- |
|
||
```
|
||
|
||
## `docs/adr/template.md`
|
||
|
||
```markdown
|
||
# Краткий заголовок решения
|
||
|
||
- **Дата:** ГГГГ-ММ-ДД
|
||
- **Источник:** openspec/changes/archive/<id>/design.md
|
||
|
||
Статус ставится тем же полем и только при пересмотре:
|
||
`- **Статус:** заменено на ADR-…` либо `- **Статус:** устарело`.
|
||
У активной записи поля нет.
|
||
|
||
## Решение
|
||
|
||
Что именно решено — одной фразой.
|
||
|
||
## Почему
|
||
|
||
Намерение и причина. Цитата из источника, а не пересказ. Пиши так, чтобы через
|
||
год было понятно без чтения переписки.
|
||
|
||
## Последствия
|
||
|
||
- `+` что стало лучше.
|
||
- `−` чем платим: ограничения, риски, нагрузка на поддержку.
|
||
```
|
||
|
||
## `docs/review.md`
|
||
|
||
```markdown
|
||
# Ревью: настройка и журнал
|
||
|
||
## Как настроен конвейер
|
||
|
||
### Типовые узлы
|
||
|
||
Рода узлов проекта и 3–5 проверяемых свойств к каждому. Рода, а не инвентарь
|
||
пакетов: род, который проект задумал, но ещё не написал, включать полезно.
|
||
|
||
### Типовые ложноположительные
|
||
|
||
Находки, которые здесь выглядят убедительно и всегда неверны. Каждая — с одной
|
||
строкой «почему здесь это не дефект».
|
||
|
||
### Вопросы к проходам
|
||
|
||
Форма: `<имя прохода>: <вопрос> (<провенанс>)`. Главный источник — журнал ниже.
|
||
Проход, увидев свой блок, задаёт эти вопросы дополнительно к обязательным.
|
||
|
||
### Триггеры профиля
|
||
|
||
Проектная конкретизация правила выбора профиля: что здесь считается **новым
|
||
понятием или структурной единицей** (поднимает прогон до `wide` и запускает
|
||
архитектурный проход) и **где живут правила идентичности, слияния и разбора**
|
||
(до `deep`, запускает независимую реализацию) — перечнем узлов или capability,
|
||
поимённо. Уточняет умолчания конвейера, не отменяет их; рабочее умолчание —
|
||
`standard`.
|
||
|
||
Перечень для `deep` **производен от теста конвейера**, а не заменяет его:
|
||
правило попадает в класс, когда вариантов несколько, спека между ними не
|
||
выбирает, а неверный выбор не падает, а молча меняет смысл данных. Перечисляй
|
||
места, где этот класс здесь живёт, а не переписывай определение. Таких мест нет
|
||
вовсе — так и напиши: `deep` тогда не запускается никогда, и это законное
|
||
состояние.
|
||
|
||
### Недоступно проверке
|
||
|
||
**Не проверит ни один проход** — принципиальная граница; по факту промаха не
|
||
пересматривается.
|
||
|
||
**Перестали проверять сознательно** — что, когда и почему, со ссылкой на запись
|
||
журнала. Пересматривается **первым**, как только что-то проскочило.
|
||
|
||
## Журнал дефектов
|
||
|
||
Запись на каждый воспроизведённый дефект, сразу, а не ретроспективно: со
|
||
временем теряется не факт, а причина непоймания.
|
||
|
||
Форма:
|
||
|
||
<!-- копия: журнал-дефектов-форма из av-dev-pipeline/skills/review-pipeline/references/review-journal.md -->
|
||
## ГГГГ-ММ-ДД — <краткое последствие> [проскочил|пойман]
|
||
|
||
- **Где:** путь:строка либо «конвейер, а не код»
|
||
- **Симптом:** как обнаружилось, кем и когда
|
||
- **Причина:** что на самом деле было не так
|
||
- **Чем воспроизведён:** тест, команда, замер — с числами
|
||
- **Почему не поймали:** только для проскочивших — какой проход обязан был найти
|
||
и что ему помешало
|
||
- **Что меняем:** правило прохода, шаг гейта, конвенция, факт в документе
|
||
проекта — либо «ничего, цена поимки выше цены дефекта»
|
||
<!-- /копия: журнал-дефектов-форма -->
|
||
```
|
||
|
||
Новый проект: «Дефектов пока не было. Настройка конвейера появится с первым
|
||
ревью.»
|
||
|
||
## `CLAUDE.md`
|
||
|
||
Лежит в корне, не в `docs/`. Единственный файл канона, который агент читает
|
||
**всегда**, поэтому в нём то, без чего нельзя сделать ни шага.
|
||
|
||
```markdown
|
||
# CLAUDE.md
|
||
|
||
Памятка для работы над <проект>. Перед задачей прочитай также
|
||
[docs/passport.md](docs/passport.md), [docs/architecture.md](docs/architecture.md)
|
||
и [docs/conventions/](docs/conventions/README.md).
|
||
|
||
## Что это
|
||
|
||
Абзац: что делает и чего **не** делает.
|
||
|
||
## Стек
|
||
|
||
## Инварианты
|
||
|
||
Что нарушать нельзя. Каждый пункт — три вещи: формулировка **как проверяемое
|
||
свойство**, а не лозунг; последствие нарушения и его обратимость; **severity**
|
||
рядом. По этим формулировкам проходы ревью присваивают `critical`, поэтому
|
||
severity стоит здесь, а не выводится каждым проходом заново.
|
||
|
||
## Команды
|
||
|
||
## Гейт
|
||
|
||
- Команда целиком и как определяется база диффа:
|
||
- Где логи шагов:
|
||
- Что означает каждый исход:
|
||
- **Что красит безусловно и почему:**
|
||
- Чего в гейте намеренно нет и **кто тогда обязан это гонять:**
|
||
|
||
## Запреты
|
||
|
||
Что запускать нельзя, **с путями**: рабочая БД, боевой каталог данных, внешние
|
||
сервисы. Плюс где `testdata` и куда писать временное.
|
||
|
||
## Работа
|
||
|
||
- **Основная ветка:** <имя>
|
||
- **Необратимое** (спрашивается у человека всегда):
|
||
- **Общий станок** — какая проверка, покраснев, врывается в замороженный спринт:
|
||
- **Ориентир по размеру спринта:** 5–8 задач, ориентир а не закон
|
||
- **Что такое «сделана»:** пайплайн проекта пройден + критерии приёмки проверены
|
||
поимённо
|
||
|
||
## Язык
|
||
|
||
- Документация, комментарии, сообщения коммитов — русский.
|
||
- Код и идентификаторы — английский.
|
||
```
|
||
|
||
Имя основной ветки, запреты с путями и «что необратимо» — не украшение: без
|
||
первого падают git-операции батча и расчёт базы диффа, без второго проход может
|
||
тронуть рабочие данные, без третьего вся шкала ранжирования триажа держится на
|
||
догадке.
|
||
|
||
## `docs/.pm.json`
|
||
|
||
```json
|
||
{
|
||
"canon": 4
|
||
}
|
||
```
|
||
|
||
Плюс `"migrations": "<путь>"`, если есть БД. Ключ `"tasks"` заводится **только**
|
||
когда имя файла или заголовка отличается от умолчания (`{"backlog":
|
||
"INDEX.md"}`); секций беклога в нём нет — их дом заголовки `##` индекса. Состав
|
||
ключей — [canon.md](canon.md).
|