конвенции: перенести механизируемое в 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
+1 -2
View File
@@ -6,7 +6,6 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
"os"
"path/filepath"
@@ -753,7 +752,7 @@ func (f *fakeRecognizer) Director(_ context.Context, _ recognize.MediaType, _, _
func testWorkerWith(st Store, qb QBittorrent, rec Recognizer, lay Layouter) *Worker {
w := New(st, qb, rec, lay, Config{Category: "jellybit"},
slog.New(slog.NewTextHandler(io.Discard, nil)))
slog.New(slog.DiscardHandler))
n := 0
w.newID = func() string { n++; return "batch-" + itoa(n) }
return w
+1 -1
View File
@@ -281,7 +281,7 @@ func New(st Store, qb QBittorrent, rec Recognizer, lay Layouter, cfg Config, log
layouter: lay,
cfg: cfg,
log: log,
now: time.Now,
now: store.Now,
newID: defaultBatchID,
failNotified: map[string]time.Time{},
live: map[string]Live{},
+1 -2
View File
@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"io"
"log/slog"
"testing"
"time"
@@ -360,7 +359,7 @@ func newTestWorker(st *fakeStore, qb *fakeQbt) *Worker {
SavePath: "/srv/media/downloads",
MagnetTimeout: 30 * time.Minute,
StuckAfter: time.Hour,
}, slog.New(slog.NewTextHandler(io.Discard, nil)))
}, slog.New(slog.DiscardHandler))
w.now = func() time.Time { return time.Date(2026, 6, 14, 10, 0, 0, 0, time.UTC) }
return w
}