docs: перевод документации на канон av-dev
- Раскладка docs/ приведена к канону 2: заведены passport/architecture/ database/security/review и research; docs/specs, drafts, backlog, review/ и BRIEF.md разобраны и удалены, беклог переехал в docs/tasks (34 задачи, 6 целей, слаги на английский). - Нарративы specs удалены как дубли openspec-спек после поимённой сверки; остаток заведён задачами (редактор маппинга ревью, крайние случаи именования), отказ от сущности title промоутнут в ADR. - Проектные копии агентов и скиллов ревью/пайплайна удалены в пользу плагинов av-dev-pm и av-dev-pipeline; в task gate добавлен шаг canon вместо er-schema.
This commit is contained in:
+44
-24
@@ -1,33 +1,53 @@
|
||||
# Конвенции кода
|
||||
|
||||
Кросс-каттинг правила того, **как** мы пишем код (логирование, ошибки,
|
||||
именование) — в отличие от `docs/specs/` и `openspec/specs/`, которые
|
||||
описывают, **что** система делает.
|
||||
Как мы пишем код — в отличие от `openspec/specs/`, который описывает, что
|
||||
система делает, и от [../architecture.md](../architecture.md), который
|
||||
описывает, как она сложена.
|
||||
|
||||
**Прозой здесь остаётся только то, что не выражается правилом.** Как только
|
||||
свойство удаётся проверить машиной, оно уезжает в `.golangci.yml` или в
|
||||
`internal/archrules`, а формулировка отсюда **удаляется** (остаётся пометка
|
||||
«механизировано» со ссылкой на линтер). Процедура — [промоут находка →
|
||||
конвенция → правило → удаление](../../.claude/skills/review-pipeline/references/promote.md).
|
||||
Причина: файл на несколько сотен строк размазывает внимание по тривиальному —
|
||||
и модель, и человек добросовестно проверят именование и не дойдут до формы
|
||||
решения.
|
||||
**Прозой остаётся только то, что не выражается правилом.** Свойство, ставшее
|
||||
правилом линтера или тестом-сканером, отсюда **удаляется** и переезжает в
|
||||
перечень «Механизировано» ниже. Причина: файл на несколько сотен строк
|
||||
размазывает внимание по тривиальному — и модель, и человек добросовестно
|
||||
проверят именование и не дойдут до формы решения. Процедура промоута —
|
||||
`references/promote.md` скилла `av-dev-pipeline:review-pipeline`.
|
||||
|
||||
Конвенции **не** переносятся в OpenSpec: это не capability. Короткие
|
||||
инварианты дублируются в [CLAUDE.md](../../CLAUDE.md) (агент читает его
|
||||
всегда) и кратко в `openspec/config.yaml` → `context` (подмешивается в
|
||||
генерацию артефактов); детали — здесь. Обоснование «почему» — в `docs/adr/`.
|
||||
Обоснование «почему именно так» живёт в [../adr/](../adr/README.md); инварианты
|
||||
с severity — в [CLAUDE.md](../../CLAUDE.md).
|
||||
|
||||
## Записи
|
||||
|
||||
- [logging.md](logging.md) — логирование: уровни, поля, что не логируем.
|
||||
- [config.md](config.md) — конфигурация: TOML, секреты через деплой
|
||||
(Ansible+Vault), валидация на старте.
|
||||
- [logging.md](logging.md) — логирование: уровень по адресату, единственный
|
||||
логирующий чекпоинт, поля, `ext.*`, что не логируем.
|
||||
- [errors.md](errors.md) — ошибки: stdlib, обёртка `%w`, `errors.Is`/`As`,
|
||||
трансляция на внешней границе.
|
||||
- [database.md](database.md) — БД и идентификаторы: TEXT ULID PK через
|
||||
`internal/ident` (без AUTOINCREMENT), lowercase + нормализация на границах,
|
||||
естественные ключи у деталей.
|
||||
трансляция доменной ошибки на внешней границе, sentinel против типизированной.
|
||||
- [config.md](config.md) — конфигурация: TOML, секреты рендерит деплой в файл
|
||||
`0600`, самодокументируемый `config.example.toml`, валидация на старте.
|
||||
- [database.md](database.md) — БД и идентификаторы: время в UTC RFC 3339, TEXT
|
||||
ULID через `internal/ident`, `ident.Parse` на входной границе, естественные
|
||||
ключи у деталей.
|
||||
- [web-ui.md](web-ui.md) — веб-UI на htmx: единый партиал = страница = фрагмент,
|
||||
ветвление `isHTMX`, деградация без JS, ошибка = 200 + фрагмент, самозавершающийся
|
||||
поллинг, вендоринг/кэш статики.
|
||||
ветвление по `isHTMX`, деградация без JS, ошибка на htmx-пути = 200 +
|
||||
фрагмент, самозавершающийся поллинг, вендоринг и кэш статики.
|
||||
|
||||
## Механизировано
|
||||
|
||||
Проверяется `task gate`; прозой не дублируется и в промптах ревью не
|
||||
пересказывается.
|
||||
|
||||
| Правило | Где механизировано |
|
||||
| --- | --- |
|
||||
| `msg` лога — константная категория, данные в полях, единый стиль ключ-значение | `.golangci.yml` → `sloglint` (`static-msg`, `kv-only`, `no-mixed-args`) |
|
||||
| В stdout напрямую не пишем (`fmt.Print*`) | `.golangci.yml` → `forbidigo` |
|
||||
| Конфигурация только из TOML, `os.Getenv` для конфига не используем | `.golangci.yml` → `forbidigo` |
|
||||
| Время только через `store.Now()` — `time.Now` запрещён вне `internal/{ident,store}` | `.golangci.yml` → `forbidigo` |
|
||||
| Сравнение ошибок через `errors.Is`/`As`, не `==` и не приведением типа | `.golangci.yml` → `errorlint` |
|
||||
| Ошибки — только stdlib (`github.com/pkg/errors`, `cockroachdb/errors` запрещены) | `.golangci.yml` → `depguard` |
|
||||
| Опечатки в тексте | `.golangci.yml` → `misspell` |
|
||||
| Транспорты не зависят друг от друга | `internal/archrules` → `TestТранспортыНеЗависятДругОтДруга` |
|
||||
| Ядро не зависит от транспортов | `internal/archrules` → `TestЯдроНеЗависитОтТранспортов` |
|
||||
| Миграции без `AUTOINCREMENT` и без серверного времени | `internal/archrules` → `TestМиграцииБезAutoincrementИСерверногоВремени` |
|
||||
| Ошибки не матчатся по тексту сообщения | `internal/archrules` → `TestОшибкиНеМатчатсяПоТексту` |
|
||||
| Покрытие изменённых строк, секреты в диффе, миграция без правки `database.md` | `scripts/gate.py`, `scripts/diff-coverage.py`, `docs.py check` |
|
||||
|
||||
Непойманное место механизации означает, что проход по конвенциям будет
|
||||
добросовестно проверять уже проверенное.
|
||||
|
||||
Reference in New Issue
Block a user