учёт: закрыт переезд хранилища, заведён урожай его ревью

- storage-without-pocketbase закрыта как реализованная: приёмка сошлась по всем
  пяти критериям записи и по двенадцати приёмочным свойствам рубрики ревью
  дизайна, работа лежит коммитом c9b7765
- урожай триажа ревью развёрнут в одиннадцать записей с тегом партии
  review-2026-08-23 и расставлен по зависимости, а не в конец списка
- находка про признак живости воркера слита в stalled-pipeline-metric: у неё та
  же причина — вставший конвейер неотличим от простоя
This commit is contained in:
av
2026-08-23 08:41:49 +03:00
parent c9b7765646
commit 75c6f0168a
14 changed files with 540 additions and 50 deletions
@@ -0,0 +1,44 @@
# 🧹 Писать об одном отказе шага одну строку журнала
- **Тип:** chore
- **Категория:** Очередь — Правит цикл воркера следом за мелочами того же цикла: уровень записи и число записей — один заход
- **Зачем:** Временный отказ шага доезжает до владельца двумя строками ERROR: шаг пишет ошибку и возвращает её, воркер пишет её снова — в журнале отказов вдвое больше, чем было.
- **Теги:** review-2026-08-23
Временный отказ шага конвейера доезжает до владельца сервиса дважды: шаг
пишет ошибку в журнал и возвращает её, а цикл воркера пишет её снова строкой
`Worker error``internal/controller/worker/worker.go`.
Вопрос стоит триггером ревью в [review.md](../../docs/review.md) с 2026-08-10 —
«не удвоилась ли запись об одном сбое» — и остаётся открытым: на прогоне ревью
change `2026-08-23-storage-without-pocketbase` удвоение воспроизведено дословным
выводом (проход `review-ops`, O2).
Цена — счёт: всплеск отказов в журнале вдвое больше настоящего, и владелец
судит по нему о поломке.
То же правило для транспорта записано критерием задачи
[http-transport-nits](http-transport-nits.md); порознь они потому, что живут в
разных пакетах и правятся разными заходами.
## Затрагивает
- цикл воркера `internal/controller/worker/worker.go` — строка `Worker error`;
- шаги конвейера `internal/service` — их собственные записи об отказе;
- конвенция [logging.md](../../docs/conventions/logging.md) — кто отвечает за
запись об ошибке, родивший её слой или получивший.
## Критерии приёмки
- Об одном временном отказе шага в журнале одна запись. **Оракул:** тест с
перехваченным журналом — шаг отказывает один раз, строк уровня `ERROR` про
этот отказ ровно одна.
- Запись несёт то, чего у второй стороны нет. **Оракул:** тот же тест — в
строке есть имя шага, идентификатор записи и причина.
- Молчание не заводится. **Оракул:** тот же тест — отказ шага без записи в
журнал не проходит: строк по нему не ноль.
## Рамки
`NoopJobError` не логируется и не считается — инвариант, и эта задача его не
трогает. Уровни `WARN` и `ERROR` не переопределяются: правит кто пишет, а не чем.