- Раскладка 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.
4.7 KiB
Конвенции кода
Как мы пишем код — в отличие от openspec/specs/, который описывает, что
система делает, и от ../architecture.md, который
описывает, как она сложена.
Прозой остаётся только то, что не выражается правилом. Свойство, ставшее
правилом линтера или тестом-сканером, отсюда удаляется и переезжает в
перечень «Механизировано» ниже. Причина: файл на несколько сотен строк
размазывает внимание по тривиальному — и модель, и человек добросовестно
проверят именование и не дойдут до формы решения. Процедура промоута —
references/promote.md скилла av-dev-pipeline:review-pipeline.
Обоснование «почему именно так» живёт в ../adr/; инварианты с severity — в CLAUDE.md.
Записи
- logging.md — логирование: уровень по адресату, единственный
логирующий чекпоинт, поля,
ext.*, что не логируем. - errors.md — ошибки: stdlib, обёртка
%w,errors.Is/As, трансляция доменной ошибки на внешней границе, sentinel против типизированной. - config.md — конфигурация: TOML, секреты рендерит деплой в файл
0600, самодокументируемыйconfig.example.toml, валидация на старте. - database.md — БД и идентификаторы: время в UTC RFC 3339, TEXT
ULID через
internal/ident,ident.Parseна входной границе, естественные ключи у деталей. - web-ui.md — веб-UI на htmx: единый партиал = страница = фрагмент,
ветвление по
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 |
Непойманное место механизации означает, что проход по конвенциям будет добросовестно проверять уже проверенное.