Files
jellybit/docs/conventions/README.md
T
av 3bce73fc34 раскладка av-dev повышена с канона 12 до версии 5
- три плагина слились в один `av-dev`: служебные `docs/.docs.json` и
  `tasks/.tasks.json` заменены на `.av-dev.toml` в корне, в гейте переехали пути
  трёх скриптов, вызовы скиллов переименованы по всему репозиторию
- тип задачи `goal` и `ROADMAP.md` упразднены: семь целей закрыты с причинами,
  теги сняты, объявлена стадия `support`
- метка `small`/`medium`/`large` снята из процесса — вместо «Триггеров метки» в
  review.md подраздел «Когда звать глубокое ревью»; следом разобран урожай
  doc-consistency: девять фактов сведены к одному дому
2026-09-02 09:55:28 +03:00

54 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Конвенции кода
Как мы пишем код — в отличие от `openspec/specs/`, который описывает, что
система делает, и от [../architecture.md](../architecture.md), который
описывает, как она сложена.
**Прозой остаётся только то, что не выражается правилом.** Свойство, ставшее
правилом линтера или тестом-сканером, отсюда **удаляется** и переезжает в
перечень «Механизировано» ниже. Причина: файл на несколько сотен строк
размазывает внимание по тривиальному — и модель, и человек добросовестно
проверят именование и не дойдут до формы решения. Процедура промоута —
`references/promote.md` скилла `av-dev:code-review`.
Обоснование «почему именно так» живёт в [../adr/](../adr/README.md); инварианты
с severity — в [CLAUDE.md](../../CLAUDE.md).
## Записи
- [logging.md](logging.md) — логирование: уровень по адресату, единственный
логирующий чекпоинт, поля, `ext.*`, что не логируем.
- [errors.md](errors.md) — ошибки: stdlib, обёртка `%w`, `errors.Is`/`As`,
трансляция доменной ошибки на внешней границе, 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, ошибка на 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` |
Непойманное место механизации означает, что проход по конвенциям будет
добросовестно проверять уже проверенное.