# Шум ERROR фоновых циклов при недоступной зависимости

**Приоритет:** низкий · **Теги:** review-fable, logging, reliability

Остаток от задачи «классификация доменных ошибок + конвенции логирования»
(основное реализовано, см. ниже). Здесь — два смежных пункта про уровень
повторяющихся сбоев фоновых циклов, каждый требует небольшого решения, а не
только правки.

## Что уже сделано (не переоткрывать)

Коммит `f8fb4fa` (Tier A) + коммит этой задачи закрыли:

- **Классификация доменных ошибок:** sentinel `worker.ErrInvalidInput`→400;
  обёртки `ErrConflict` в Cancel/Retry/Defer/Undo; `layout.ErrCollision`→409 в
  `classifyErr` и ветка в tgbot; `logCmd` относит новые классы в DEBUG.
- **Конвенции:** `logging.md` — команды воркера = доменная граница, таблица
  уровней доменных отказов (граница команды vs асинхронная стадия), правило про
  `*url.Error`/секреты в URL, канон категории `state transition` (унифицированы
  cancel/retry/relink/recovery). `errors.md` — таблица маппинга ошибка→статус,
  развилка «транзиентный ответ vs персистентная диагностика» решена как (а):
  `error_msg`/`reasons` — операторская поверхность владельца (сырой текст ок,
  секреты запрещены; аудит показал, что секреты туда не текут).
- **Мелочи:** reason-коды const-блок; лог-поля `id`→`download_id`; preview
  WARN; комментарий у `parseIgnored`.

## Остаток

### ERROR-шторм при недоступном qBittorrent

Клиент `qbt` логирует `ext.*` `Failure` → **ERROR** на каждом тике поллинга
(`torrents/info`, `internal/qbt/qbt.go`), пока qBittorrent недоступен (рестарт
демона, сеть). Домен уже пишет `poll failed` = WARN (по новой конвенции), но
транспортная `ext.*`-запись остаётся ERROR по правилу ext-конвенции («сервис
недоступен → ERROR»). При частом поллинге это шумит.

Развилка (решить до правки):

- (а) Ввести у `logging.ExtCall` вариант с пониженным уровнем для рутинно-частых
  вызовов (симметрично `SuccessDebug`) — поллинг-вызовы (`torrents/info`) на
  транзиентном сбое пишут WARN, не ERROR;
- (б) Дедуп/circuit-breaker: первый ERROR, дальше тишина до восстановления;
- (в) Оставить как есть, признав `ext.*` ERROR легитимным сигналом «зависимость
  лежит» (тогда шум гасить уровнем сбора, а не кодом).

### Эскалация устойчивого сбоя тика

Сейчас транзиентный сбой тика = WARN всегда. Договорённость на будущее
(`logging.md`): устойчивый сбой N тиков подряд эскалировать в ERROR (реальная
деградация, а не разовый промах). Не реализовано — нужен счётчик подряд-сбоев по
циклу и порог в конфиге.

Вердикт: мелкая надёжностная полировка, не блокер. Делать вместе (обе про
уровень сбоев фоновых циклов) или отдельной строкой.
