конвенции: перенести механизируемое в golangci-lint и internal/archrules

Правило, которое проверяет машина, не должно оставаться прозой: файл конвенций
на сотни строк размазывает внимание по тривиальному — модель добросовестно
проверит именование полей лога и не дойдёт до формы решения.

Включены sloglint (константный msg, стиль ключ-значение), forbidigo (fmt.Print*,
os.Getenv, time.Now мимо store.Now), errorlint (сравнение ошибок), depguard
(сторонние пакеты ошибок). internal/archrules — сканеры на то, что линтером не
выражается: направление зависимостей ядро↔транспорты, AUTOINCREMENT и серверное
время в новых миграциях, матчинг ошибки по тексту.

Код приведён к правилам: logging.StartCall как единая точка отсчёта длительности
внешних вызовов, store.Now вместо time.Now в httpapi и часах воркера,
slog.DiscardHandler в тестах.

Перенесённое вычеркнуто из docs/conventions/* и openspec/config.yaml — прозой
осталось только то, что правилом не выражается.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-07-23 18:17:40 +03:00
co-authored by Claude Opus 4.8
parent 6792f7082a
commit 612344bab3
28 changed files with 325 additions and 98 deletions
+65 -1
View File
@@ -1,11 +1,61 @@
# Конфиг golangci-lint (схема v2; устанавливается через `task setup`).
#
# Базовый набор v2 (`default: standard`) — errcheck, govet, ineffassign,
# staticcheck, unused; дополнительно включаем misspell.
# staticcheck, unused. Сверх него включены линтеры, которые механизируют
# конвенции из docs/conventions/*: то, что проверяет правило, не должно
# оставаться прозой в конвенциях и в промптах ревью (см.
# .claude/skills/review-pipeline/references/promote.md).
version: "2"
linters:
enable:
- misspell
# docs/conventions/logging.md: msg — константная категория, данные — в
# полях, единый стиль ключ-значение.
- sloglint
# docs/conventions/logging.md (без fmt.Println), config.md (конфиг только
# из TOML, env не используем), database.md (время — только store.Now()).
- forbidigo
# docs/conventions/errors.md: сравнение ошибок через errors.Is/As, а не
# `err == ErrX` и не приведением типа.
- errorlint
# docs/conventions/errors.md: ошибки — только stdlib.
- depguard
settings:
sloglint:
no-mixed-args: true # не мешать пары «ключ-значение» с slog.Attr
kv-only: true # принятый в проекте стиль вызова
static-msg: true # msg — константа, без fmt.Sprintf и интерполяции
# key-naming-case НЕ включаем: словарь полей намеренно смешанный —
# доменные поля snake_case, системные домены с точкой (`http.method`,
# `ext.service`, адаптация OpenTelemetry). См. logging.md, «Поля».
forbidigo:
forbid:
- pattern: ^fmt\.Print.*$
msg: логируем через slog, в stdout напрямую не пишем (docs/conventions/logging.md)
- pattern: ^os\.Getenv$
msg: конфигурация только из TOML, env для конфига не используем (docs/conventions/config.md)
- pattern: ^time\.Now$
msg: время генерирует store.Now() (UTC, единая точка) — docs/conventions/database.md
errorlint:
# Обёртка вида fmt.Errorf("%w: %v", ErrSentinel, err) осознанна: sentinel
# раскрываем для errors.Is, причину — намеренно нет (errors.md, «%w vs %v»).
errorf: false
asserts: true
comparison: true
depguard:
rules:
main:
deny:
- pkg: github.com/pkg/errors
desc: ошибки — только stdlib errors + fmt.Errorf (docs/conventions/errors.md)
- pkg: github.com/cockroachdb/errors
desc: стек-трейсы избыточны, контекст несёт slog (docs/conventions/errors.md)
exclusions:
generated: lax
presets:
@@ -17,6 +67,20 @@ linters:
- third_party$
- builtin$
- examples$
rules:
# CLI — другая поверхность: печатает результат в stdout и меряет
# длительность своей работы, это не логирование и не время в БД.
- path: ^cmd/
linters: [forbidigo]
# Интеграционные тесты берут креды внешних сервисов из окружения —
# это не конфигурация приложения.
- path: _test\.go$
text: os.Getenv
linters: [forbidigo]
# Единые точки генерации id и времени — им time.Now по определению можно.
- path: ^internal/(ident|store)/
text: time.Now
linters: [forbidigo]
formatters:
exclusions: