av-dev-pm: плагин переименован, заведены канон документов и скиллы init/canon/docs
- av-dev-tasks → av-dev-pm; канон определён единственным reference-файлом, который читают все три новых скилла - canon: check/adopt/upgrade плюс docs.py — раскладка, битые ссылки, версия, маркеры долга, сверки миграций и capability с документацией - tasks и session: путь docs/tasks жёсткий, конфиг переехал в docs/.pm.json, слот «Команда учёта задач» убран в пользу вызова скилла, раздел «Стимулы» переписан под совпавших приёмщика и исполнителя
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
# Канон документов проекта
|
||||
|
||||
**Версия 1.**
|
||||
|
||||
Это **единственный дом определения канона**. Скиллы `init`, `canon` и `docs`
|
||||
читают его, а не пересказывают: три описания одной раскладки разъедутся, и
|
||||
работать будет то, которое прочитали последним. Меняется канон — меняется этот
|
||||
файл и появляется запись в [changelog.md](changelog.md).
|
||||
|
||||
## Зачем канон жёсткий
|
||||
|
||||
Пути фиксированы, и проект под них подгоняется, а не наоборот. Причина не
|
||||
техническая: проектов много, все малого и среднего размера, и ориентироваться в
|
||||
слегка похожих, но разных раскладках дороже, чем один раз привести их к общей.
|
||||
Рядом лежит OpenSpec, у которого структура тоже строгая.
|
||||
|
||||
Цена принята сознательно: плагин не переносится на чужой репозиторий как есть —
|
||||
чужой репозиторий **приводится** к канону скиллом `canon`.
|
||||
|
||||
## Раскладка
|
||||
|
||||
```
|
||||
CLAUDE.md памятка агенту: что это, стек, инварианты с
|
||||
severity, команды, семантика гейта, запреты
|
||||
docs/
|
||||
.pm.json версия канона и пути, нужные проверкам
|
||||
passport.md зачем и для кого; чем НЕ является; сценарии
|
||||
architecture.md как сложено — обзор; окружение и эксплуатация
|
||||
database.md схема хранилища; представление данных и настройки
|
||||
security.md периметр; недоверенный вход; что вне модели
|
||||
conventions/
|
||||
README.md индекс, правило промоута, что механизировано
|
||||
<тема>.md
|
||||
research/
|
||||
README.md как снималось, индекс
|
||||
<тема>.md наблюдения и числа с провенансом
|
||||
adr/
|
||||
README.md индекс записей, статусы, правило замены
|
||||
template.md
|
||||
ADR-ГГГГ-ММ-ДД-slug.md
|
||||
review.md настройка конвейера под проект + журнал дефектов
|
||||
tasks/ скилл tasks: items/, PLAN.md, BACKLOG.md,
|
||||
SPRINT.md, REJECTED.md
|
||||
openspec/
|
||||
config.yaml только нужды генерации артефактов + ссылки
|
||||
specs/<capability>/spec.md что система делает — нормативно
|
||||
changes/archive/ архив изменений с design.md — сырьё для ADR
|
||||
```
|
||||
|
||||
Текст документов — русский; слаги файлов, capability и задач — английские,
|
||||
kebab-case.
|
||||
|
||||
## Роли документов
|
||||
|
||||
Одна строка на каждый — на какой вопрос он отвечает и кто его читает.
|
||||
|
||||
| Документ | Вопрос | Кто читает, кроме человека |
|
||||
| --- | --- | --- |
|
||||
| `CLAUDE.md` | что нельзя нарушать, чем краснеет гейт | все агенты, всегда |
|
||||
| `passport.md` | зачем и для кого, чем это **не** является | `architecture`, `rubric`, `reimpl`, `specs` |
|
||||
| `architecture.md` | как сложено и где что работает | все проходы ревью |
|
||||
| `database.md` | что лежит в хранилище и какими настройками | `ops`, `adversary`, `reimpl` |
|
||||
| `security.md` | против кого защищаемся и что вне модели | `adversary` |
|
||||
| `conventions/` | как мы пишем код | `code` |
|
||||
| `research/` | что показала реальность, а не документация | `specs`, `reimpl`, `ops` |
|
||||
| `adr/` | почему решено именно так | `architecture` |
|
||||
| `review.md` | как настроен конвейер и что уже проскакивало | `triage`, каждый проход — свою часть |
|
||||
| `openspec/specs/` | что система делает — нормативно | `specs` |
|
||||
|
||||
### `passport.md`
|
||||
|
||||
Цель; закрытый список потребителей и что каждому нужно; **чем целью не
|
||||
является** — это граница домена, по которой архитектурный проход судит о
|
||||
переносе понятия; типовые сценарии; мера, по которой проект считается удавшимся;
|
||||
референсы, у кого подсматривать.
|
||||
|
||||
### `architecture.md` — **обзор, не поведение**
|
||||
|
||||
Принципы; компоненты **со ссылками на capability**, а не с пересказом их
|
||||
требований; внешние границы и форматы чужих систем; окружение — где работает,
|
||||
что рядом, кто перезапускает; **внешние зависимости поимённо** и чем каждая
|
||||
отказывает (не только «падает», но и «отвечает медленно», «молчит», «отдаёт
|
||||
мусор»); кто заметит отказ и когда; характер потока — непрерывный, по запросу,
|
||||
по расписанию; что обратимо, а что нет; деплой; открытые вопросы.
|
||||
|
||||
**Поведение системы сюда не пишется.** Его нормативный дом — `openspec/specs/`,
|
||||
куда `opsx:archive` вливает дельты; второй дом синхронизировать руками
|
||||
невозможно, и он разойдётся.
|
||||
|
||||
Раздел, ещё не разнесённый при переезде, помечается маркером долга:
|
||||
|
||||
```
|
||||
<!-- канон: поведение → openspec/specs/<capability> -->
|
||||
```
|
||||
|
||||
`docs.py` считает маркеры и печатает остаток числом. Гейт от них **не краснеет**:
|
||||
это долг, а не отказ, иначе постепенный переезд стал бы невозможен.
|
||||
|
||||
### `database.md`
|
||||
|
||||
Схема: таблицы, ключи, связи, правило времени и идентификаторов. Плюс то, чего
|
||||
нет в схеме, но без чего замер не превращается в находку: **чем физически лежит
|
||||
запись** (сжатый BLOB, JSON-строка, колонки), что происходит при чтении и записи
|
||||
(распаковка целиком, read-modify-write), и **настройки с числовым значением** —
|
||||
таймаут занятости, режим журналирования, лимит тела, размер пула, ретеншен.
|
||||
|
||||
Конвенции идентификаторов и именования — не схема, они в `conventions/`.
|
||||
|
||||
### `security.md`
|
||||
|
||||
**Периметр первой строкой.** «Сервис открыт наружу» и «контур доверенный,
|
||||
публичного интернета здесь нет, не выдумывай его» — противоположные постановки
|
||||
под одним заголовком, и враждебный проход между ними сам не выберет. Контур ещё
|
||||
не развёрнут — назови **оба** периметра, целевой и сегодняшний, и скажи прямо,
|
||||
против какого строятся находки.
|
||||
|
||||
Дальше: что недоверенное и каким каналом приходит; **из чего строятся пути и
|
||||
ключи** (раскладка файлов, состав координатного ключа, имя каталога) — отсюда
|
||||
строится выход за пределы песочницы; что разграничивает доступ; что
|
||||
чувствительнее чего; **что вне модели** — перечислить явно.
|
||||
|
||||
### `conventions/`
|
||||
|
||||
Прозой остаётся **только то, что не выражается правилом**. `README.md` держит
|
||||
индекс, правило промоута и **перечень уже механизированного** со ссылкой на
|
||||
место механизации — конфиг линтера, собственный анализатор, тест-сканер
|
||||
исходников. Непойманное место механизации означает, что проход добросовестно
|
||||
проверит уже проверенное.
|
||||
|
||||
### `research/`
|
||||
|
||||
Наблюдения за внешним миром: что реально шлёт источник, чем документация формата
|
||||
расходится с практикой, какие числа сняты с живого потока. **Числа — с
|
||||
провенансом**, то есть с командой или условиями, которыми получены.
|
||||
`README.md` — как снималось и индекс тем.
|
||||
|
||||
Число без источника проход обязан читать как условие, а не как замер. Число, чей
|
||||
источник по ссылке не подтвердился, не выбрасывается и не переписывается по
|
||||
догадке — остаётся с пометкой «расходится с источником: там <что нашли>».
|
||||
|
||||
### `adr/`
|
||||
|
||||
**ADR — промоут поверх архивных `design.md`, а не второе сочинение.** Запись
|
||||
цитирует решение и ссылается на `openspec/changes/archive/<id>/design.md`.
|
||||
|
||||
Заводится, когда верно одно из трёх:
|
||||
|
||||
- **дорогой откат** — переделка стоит дороже переписывания одного файла;
|
||||
- **намеренный отказ** от очевидного подхода;
|
||||
- **пересмотр прежнего решения** — тогда у старой записи обязателен статус
|
||||
«заменено на».
|
||||
|
||||
Не заводится для рутины и для того, что видно из кода и `git log`.
|
||||
|
||||
Записи неизменяемы: передумали — заводится новая, старая получает статус.
|
||||
Активная запись статуса не имеет.
|
||||
|
||||
### `review.md`
|
||||
|
||||
Два раздела с разными сроками жизни.
|
||||
|
||||
**Настройка конвейера под проект:** типовые узлы (рода узлов и 3–5 проверяемых
|
||||
свойств к каждому); типовые ложноположительные — находки, которые здесь выглядят
|
||||
убедительно и всегда неверны; вопросы к проходам поимённо с провенансом;
|
||||
недоступно проверке — два подраздела, «не проверит ни один проход»
|
||||
(принципиальная граница, по факту промаха не пересматривается) и «перестали
|
||||
проверять сознательно» (пересматривается первым).
|
||||
|
||||
**Журнал дефектов:** запись на каждый воспроизведённый дефект с пометкой
|
||||
**проскочил / пойман ревью**. Проскочившие — эвал-сет для калибровки конвейера,
|
||||
выборка по пометке. Пойманные с оракулом — лучшая опора для прохода: проектные,
|
||||
воспроизводимые, однажды оказавшиеся правдой.
|
||||
|
||||
### `CLAUDE.md`
|
||||
|
||||
Что это и стек; **инварианты с severity рядом с формулировкой** — по ним
|
||||
проходы присваивают `critical`, поэтому severity стоит здесь, а не выводится
|
||||
каждым проходом заново; команды; **семантика гейта** — чем краснеет безусловно и
|
||||
почему, где логи, что означает исход, чего в гейте намеренно нет, **кто и когда
|
||||
обязан гонять дорогое вне гейта**; что запускать запрещено, с путями; что
|
||||
считается необратимым; общий станок, врывающийся в замороженный спринт; ориентир
|
||||
по размеру спринта.
|
||||
|
||||
### `openspec/config.yaml`
|
||||
|
||||
**Только нужды генерации артефактов** — язык, правила именования capability,
|
||||
придирки валидатора RFC 2119 — плюс ссылки на документы канона. Правило ревью,
|
||||
пересказ конвенций и инварианты сюда не пишутся: у них есть свои дома, и второй
|
||||
дом разойдётся на первой же правке.
|
||||
|
||||
## Правило единственного дома
|
||||
|
||||
Факт живёт ровно в одном файле; остальные ссылаются. Карта на случай спора:
|
||||
|
||||
| Факт | Дом |
|
||||
| --- | --- |
|
||||
| поведение системы | `openspec/specs/<capability>/spec.md` |
|
||||
| почему решено так | `adr/`, источник — архивный `design.md` |
|
||||
| граница домена, «чем не является» | `passport.md` |
|
||||
| инвариант и его severity | `CLAUDE.md` |
|
||||
| порядок работ и его обоснование | `docs/tasks/PLAN.md` |
|
||||
| измеренное число | `research/` |
|
||||
| настройка с числовым значением | `database.md` |
|
||||
| периметр и модель угроз | `security.md` |
|
||||
| что уже механизировано правилом | `conventions/README.md` |
|
||||
|
||||
## Пустое называется пустым
|
||||
|
||||
Скелет канона заводится **целиком** с первого дня. Незаполненный документ держит
|
||||
**одну честную информативную строку**, а не заглушку:
|
||||
|
||||
- «внешних зависимостей нет — смотри на диск и на СУБД»;
|
||||
- «наблюдений на живых данных нет: внешний источник один, формат документирован»;
|
||||
- «прецедентов не накоплено»;
|
||||
- «сознательно ничего не отключали»;
|
||||
- «архитектуры пока нет: кода нет, заводится первой задачей».
|
||||
|
||||
Проход читает такую строку **как факт** и не тратит на неё обязательный вопрос.
|
||||
Отсутствие файла он не может прочитать никак, а «TBD» читает как пробел —
|
||||
поэтому `docs.py check` отличает честную строку от нетронутого плейсхолдера
|
||||
шаблона и напоминает о втором.
|
||||
|
||||
## Слотов нет
|
||||
|
||||
Файлы и каталоги, которых в каноне **нет**, и куда уезжает их содержимое:
|
||||
|
||||
| Было | Куда |
|
||||
| --- | --- |
|
||||
| `docs/review-brief.md` | документы канона и есть бриф; остаток — в `review.md` |
|
||||
| `docs/specs/` | `openspec/specs/` (поведение) и `architecture.md` (обзор) |
|
||||
| `docs/drafts/` | идея → задача `[idea]`; отказ → ADR; порядок → `PLAN.md`; размышление → `opsx:explore` |
|
||||
| `docs/plan.md` | `docs/tasks/PLAN.md` |
|
||||
| `BRIEF.md` | `passport.md` |
|
||||
| `docs/backlog/` | `docs/tasks/` |
|
||||
| `docs/review-journal.md`, `docs/review/journal.md` | `docs/review.md` |
|
||||
|
||||
## Что проверяет машина, а что человек
|
||||
|
||||
Граница объявляется вслух в каждом отчёте: `check`, отчитавшийся «канон
|
||||
соблюдён» на проекте, где из шести файлов три лишние, хуже отсутствующего.
|
||||
|
||||
| Проверяет `docs.py` | Судит агент |
|
||||
| --- | --- |
|
||||
| отсутствующие пути канона | смысловой дубль документа и capability |
|
||||
| файлы в `docs/` вне канона | поведение, оставшееся в `architecture.md` |
|
||||
| битые относительные ссылки | протухший факт, разошедшийся с кодом |
|
||||
| версия канона и её отставание | достаточность честной строки в пустом слоте |
|
||||
| нетронутый плейсхолдер шаблона | связность и читаемость |
|
||||
| маркеры долга — числом | |
|
||||
| миграция изменена, а `database.md` нет | |
|
||||
| capability без упоминания в `architecture.md` | |
|
||||
|
||||
## `docs/.pm.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"canon": 1,
|
||||
"migrations": "internal/store/migrations",
|
||||
"tasks": {
|
||||
"sections": ["ядро", "инфра"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`canon` — версия канона, под которую проект приведён, целым числом: обратной
|
||||
совместимости у канона нет, есть «приведён» и «не приведён». `migrations` — путь
|
||||
каталога миграций, если БД есть; по нему `docs.py` делает сверку с
|
||||
`database.md`. `tasks` — настройки каталога задач, переехавшие сюда из прежнего
|
||||
`<tasks>/.tasks.json`: **один конфиг на весь канон, а не по одному на каталог**.
|
||||
|
||||
Ключей будет больше по мере роста проверок; неизвестный ключ `docs.py`
|
||||
игнорирует, отсутствующий — считает «проверка неприменима» и говорит об этом
|
||||
строкой, а не молчит.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Журнал версий канона
|
||||
|
||||
Одна запись на версию. Проект знает свою версию из `docs/.pm.json`; `canon
|
||||
upgrade` идёт по записям снизу вверх от версии проекта до текущей и делает то,
|
||||
что в них названо.
|
||||
|
||||
Правило записи: **что добавилось, что переехало, что удалено, что сделать
|
||||
проекту**. Без последнего пункта запись бесполезна — по ней и работает
|
||||
`upgrade`.
|
||||
|
||||
Версия — целое число. Обратной совместимости у канона нет: есть «приведён» и «не
|
||||
приведён».
|
||||
|
||||
---
|
||||
|
||||
## Версия 1 — 2026-08-03
|
||||
|
||||
Первая версия. Проект любой прежней раскладки приводится к ней скиллом `canon`
|
||||
в режиме `adopt`, а не `upgrade`.
|
||||
|
||||
**Что вводится:** раскладка целиком — см. [canon.md](canon.md).
|
||||
|
||||
**Что сделать проекту, который приходит из свободной раскладки:**
|
||||
|
||||
1. `docs/.pm.json` с `{"canon": 1}` и путём миграций, если БД есть.
|
||||
2. Скелет канона целиком; незаполненное — одной честной строкой.
|
||||
3. `docs/specs/` разобрать: поведение — в `openspec/specs/`, обзор — в
|
||||
`docs/architecture.md`, знание о чужих системах — в `docs/research/`.
|
||||
Дубли capability удалить, сверив поимённо.
|
||||
4. `docs/plan.md` → `docs/tasks/PLAN.md` линией целей.
|
||||
5. `BRIEF.md` → `docs/passport.md`.
|
||||
6. `docs/backlog/` → `docs/tasks/`.
|
||||
7. `docs/review-journal.md` или `docs/review/journal.md` → `docs/review.md`,
|
||||
плюс раздел настройки конвейера.
|
||||
8. `docs/drafts/` растворить: идея → задача `[idea]`, намеренный отказ → ADR,
|
||||
порядок работ → `PLAN.md`.
|
||||
9. `docs/review-brief.md`, если заводился, удалить: его разделы разошлись по
|
||||
документам канона.
|
||||
10. `conventions.md` → `conventions/`, `local-research.md` → `research/`.
|
||||
11. Завести `docs/security.md` с периметром первой строкой и `docs/adr/`.
|
||||
12. В `CLAUDE.md`: severity рядом с каждым инвариантом, семантика гейта,
|
||||
запреты с путями; убрать раздел «Процесс», если он пересказывает пайплайн.
|
||||
13. В `openspec/config.yaml` оставить только нужды генерации и ссылки.
|
||||
14. Добавить шаг `docs.py check` в гейт проекта.
|
||||
@@ -0,0 +1,291 @@
|
||||
# Скелеты документов канона
|
||||
|
||||
Что кладут `init` и `canon adopt` в незаполненный слот. Правило одно:
|
||||
**честная информативная строка вместо заглушки**. Проход читает строку как факт;
|
||||
`<!-- заполнить: … -->` он читает как пробел, и `docs.py check` о таком
|
||||
плейсхолдере напоминает.
|
||||
|
||||
Плейсхолдер ставится только там, где ответ **обязан** быть и его не спросили.
|
||||
Всё, чего в проекте пока просто нет, описывается словами, а не плейсхолдером.
|
||||
|
||||
## `docs/passport.md`
|
||||
|
||||
```markdown
|
||||
# Паспорт проекта
|
||||
|
||||
Зачем это и для кого. [architecture.md](architecture.md) отвечает «как
|
||||
устроено», [tasks/PLAN.md](tasks/PLAN.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`.
|
||||
|
||||
## Когда заводить
|
||||
|
||||
Верно одно из трёх:
|
||||
|
||||
- **дорогой откат** — переделка стоит дороже переписывания одного файла;
|
||||
- **намеренный отказ** от очевидного подхода;
|
||||
- **пересмотр прежнего решения** — тогда у старой записи обязателен статус.
|
||||
|
||||
Не заводить для рутины и того, что видно из кода и `git log`.
|
||||
|
||||
## Соглашения
|
||||
|
||||
- Имя файла — `ADR-ГГГГ-ММ-ДД-slug.md`, слаг английский, дата — когда решение
|
||||
реально принято.
|
||||
- Записи неизменяемы: передумали — новая запись, старой ставится статус.
|
||||
- Активная запись статуса не имеет. Значений два: `заменено на ADR-…` и
|
||||
`устарело`.
|
||||
|
||||
## Записи
|
||||
|
||||
Новые сверху.
|
||||
|
||||
| Дата | Запись | Статус |
|
||||
| --- | --- | --- |
|
||||
```
|
||||
|
||||
## `docs/adr/template.md`
|
||||
|
||||
```markdown
|
||||
# Краткий заголовок решения
|
||||
|
||||
- Дата: ГГГГ-ММ-ДД
|
||||
- Источник: openspec/changes/archive/<id>/design.md
|
||||
|
||||
## Решение
|
||||
|
||||
Что именно решено — одной фразой.
|
||||
|
||||
## Почему
|
||||
|
||||
Намерение и причина. Цитата из источника, а не пересказ. Пиши так, чтобы через
|
||||
год было понятно без чтения переписки.
|
||||
|
||||
## Последствия
|
||||
|
||||
- `+` что стало лучше.
|
||||
- `−` чем платим: ограничения, риски, нагрузка на поддержку.
|
||||
```
|
||||
|
||||
## `docs/review.md`
|
||||
|
||||
```markdown
|
||||
# Ревью: настройка и журнал
|
||||
|
||||
## Как настроен конвейер
|
||||
|
||||
### Типовые узлы
|
||||
|
||||
Рода узлов проекта и 3–5 проверяемых свойств к каждому. Рода, а не инвентарь
|
||||
пакетов: род, который проект задумал, но ещё не написал, включать полезно.
|
||||
|
||||
### Типовые ложноположительные
|
||||
|
||||
Находки, которые здесь выглядят убедительно и всегда неверны. Каждая — с одной
|
||||
строкой «почему здесь это не дефект».
|
||||
|
||||
### Вопросы к проходам
|
||||
|
||||
Форма: `<имя прохода>: <вопрос> (<провенанс>)`. Главный источник — журнал ниже.
|
||||
|
||||
### Недоступно проверке
|
||||
|
||||
**Не проверит ни один проход** — принципиальная граница; по факту промаха не
|
||||
пересматривается.
|
||||
|
||||
**Перестали проверять сознательно** — что, когда и почему, со ссылкой на запись
|
||||
журнала. Пересматривается **первым**, как только что-то проскочило.
|
||||
|
||||
## Журнал дефектов
|
||||
|
||||
Запись на каждый воспроизведённый дефект, сразу, а не ретроспективно: со
|
||||
временем теряется не факт, а причина непоймания.
|
||||
|
||||
Форма:
|
||||
|
||||
## ГГГГ-ММ-ДД — краткое последствие [проскочил|пойман]
|
||||
|
||||
- **Где:** файл:строка
|
||||
- **Симптом:** как обнаружилось
|
||||
- **Чем воспроизведён:** тест, команда, замер
|
||||
- **Почему не поймали:** только для проскочивших
|
||||
- **Что меняем:** правило прохода, шаг гейта, конвенция — либо «ничего, цена
|
||||
поимки выше цены дефекта»
|
||||
```
|
||||
|
||||
Новый проект: «Дефектов пока не было. Настройка конвейера появится с первым
|
||||
ревью.»
|
||||
|
||||
## `docs/.pm.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"canon": 1
|
||||
}
|
||||
```
|
||||
|
||||
Плюс `"migrations": "<путь>"`, если есть БД, и `"tasks": {"sections": [...]}`,
|
||||
если секции беклога отличаются от умолчания.
|
||||
Reference in New Issue
Block a user