конвенции: перенести механизируемое в 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:
@@ -2,7 +2,6 @@ package httpapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -50,7 +49,7 @@ func (a actionReviewer) Refine(_ context.Context, _ string, hint string) error {
|
||||
func testRouterAction(t *testing.T, r stubReader, rv Reviewer, cmd Commander, lv stubLive) http.Handler {
|
||||
t.Helper()
|
||||
h, err := NewRouter(Deps{
|
||||
Logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
|
||||
Logger: slog.New(slog.DiscardHandler),
|
||||
Reader: r,
|
||||
Reviewer: rv,
|
||||
Commander: cmd,
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.vakhrushev.me/av/jellybit/internal/naming"
|
||||
"git.vakhrushev.me/av/jellybit/internal/recognize"
|
||||
@@ -134,7 +133,7 @@ func (s *server) buildDownloadView(id string, rd *worker.ReviewData) downloadDet
|
||||
// как в порядке и карточках списка); неразбираемое время просто опускаем.
|
||||
if t, ok := addedTime(d); ok {
|
||||
view.Added = fmtDate(t, s.deps.Loc)
|
||||
view.AddedAgo = humanizeAge(t, time.Now())
|
||||
view.AddedAgo = humanizeAge(t, store.Now())
|
||||
}
|
||||
|
||||
if rd.Recognition != nil {
|
||||
|
||||
@@ -303,7 +303,7 @@ func (s *server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
layoutSizes = nil // деградируем: размер уедет в фолбэк «—», страница не падает
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
now := store.Now()
|
||||
for _, d := range downloads {
|
||||
view.Downloads = append(view.Downloads, s.buildCardView(d, now, layoutSizes[d.ID]))
|
||||
}
|
||||
@@ -500,7 +500,7 @@ func (s *server) renderCardFragment(w http.ResponseWriter, r *http.Request, id s
|
||||
s.deps.Logger.Error("layout sizes", "download_id", id, "error", err)
|
||||
sizes = nil // деградируем: размер уедет в фолбэк «—», фрагмент не падает
|
||||
}
|
||||
v := s.buildCardView(*d, time.Now(), sizes[id])
|
||||
v := s.buildCardView(*d, store.Now(), sizes[id])
|
||||
if actionErr != nil {
|
||||
v.ActionError = userErr(r, actionErr, id)
|
||||
}
|
||||
@@ -841,7 +841,7 @@ func requestLogger(logger *slog.Logger) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
|
||||
start := time.Now()
|
||||
start := time.Now() //nolint:forbidigo // измеряем длительность запроса, а не метку времени в БД
|
||||
|
||||
next.ServeHTTP(ww, r)
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ func (f *fakeReader) LayoutSizeByDownload(_ context.Context, _ []string) (map[st
|
||||
func newServer(t *testing.T, d httpapi.Deps) *httptest.Server {
|
||||
t.Helper()
|
||||
if d.Logger == nil {
|
||||
d.Logger = slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||
d.Logger = slog.New(slog.DiscardHandler)
|
||||
}
|
||||
h, err := httpapi.NewRouter(d)
|
||||
if err != nil {
|
||||
|
||||
@@ -113,7 +113,7 @@ func (s *server) handleFragCard(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
// layoutSize 0: у catched раскладки нет; в downloading размер берётся из
|
||||
// живого снимка внутри buildCardView.
|
||||
s.render(w, "card", s.buildCardView(*d, time.Now(), 0))
|
||||
s.render(w, "card", s.buildCardView(*d, store.Now(), 0))
|
||||
}
|
||||
|
||||
// handleFragSeeding отдаёт партиал секции «Раздача» (htmx-поллинг).
|
||||
|
||||
@@ -2,7 +2,6 @@ package httpapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -77,7 +76,7 @@ func testRouter(t *testing.T, r stubReader, rv stubReviewer) http.Handler {
|
||||
func testRouterLive(t *testing.T, r stubReader, rv stubReviewer, lv stubLive) http.Handler {
|
||||
t.Helper()
|
||||
h, err := NewRouter(Deps{
|
||||
Logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
|
||||
Logger: slog.New(slog.DiscardHandler),
|
||||
Reader: r,
|
||||
Reviewer: rv,
|
||||
Live: lv,
|
||||
|
||||
Reference in New Issue
Block a user