## Why

Сейчас приём (`Ingest`) синхронно делает всё: парсит источник, выводит
отображаемое имя (потенциально **медленный вызов LLM** в `namer.DeriveName`) и
добавляет источник в qBittorrent — и только потом отвечает клиенту. Долгий LLM
и внешний запрос к qBit задерживают ответ HTTP API / веб-UI / Telegram и
расширяют окно «строка в БД есть, в qBittorrent ещё нет».

Идея: сделать приём **быстрым** — синхронно только валидировать и сохранить
загрузку (новое состояние `catched`), сразу вернув ответ; вывод имени и
добавление в qBittorrent вынести в отдельный **асинхронный шаг машины
состояний**, который двигает worker.

## What Changes

- Новое состояние **`catched`** — загрузка поймана и персистентно сохранена
  (быстрый путь). Нетерминальное, активное (участвует в инварианте «≤1 активная
  загрузка на infohash»).
- **Приём (`ingest`) — быстрый**: парс magnet, извлечение инфохэшей, синтез
  контекста из полей ссылки (дёшево, без сети), атомарный дедуп и запись
  загрузки в `catched`. Ответ клиенту сразу. Синхронного вывода имени и
  добавления в qBittorrent в приёме больше нет.
- **Асинхронный шаг (`download-tracking`, worker)**: на каждом тике worker
  подхватывает `catched`-загрузки, выводит отображаемое имя из контекста (LLM +
  фолбек), добавляет источник в qBittorrent (категория/savepath/rename) и
  переводит `catched → downloading` (отдельного `added-to-qbittorrent` нет —
  `downloading` и так значит «в qBit, возможно metaDL»).
- **Обработка сбоев вне запроса клиента**: неуспешный `add` оставляет загрузку
  в `catched` (worker перетыкивает на следующем тике); предохранитель
  `catch_timeout` уводит долго-зависший `catched` в `failed`
  (`error_code` `qbit_add`) с уведомлением автора.
- `catched` **исключён** из проверок «раздача не найдена» (у него раздачи нет
  по дизайну) — ни поллинг, ни сверка не считают его рассинхроном/orphaned.
- **Веб-UI** показывает промежуточное состояние `catched` (бейдж/фаза
  жизненного цикла), заголовок деградирует, пока имя не выведено (фолбек уже
  есть). `catched` попадает в активную группу списка.

## Capabilities

### New Capabilities

_Нет._ Изменение переиспользует существующие capabilities.

### Modified Capabilities

- `ingest`: приём становится быстрым — сохранение в `catched` и мгновенный
  ответ; синхронный вывод имени и добавление в qBittorrent из приёма убраны
  (переезжают в асинхронный шаг). Требования по выводу имени переформулированы:
  выполняются на шаге добавления, а не в пути ответа клиента.
- `download-tracking`: добавляется шаг «добавление пойманной загрузки в
  qBittorrent» (вывод имени + `add` + переход `catched → downloading`),
  предохранитель `catch_timeout`, исключение `catched` из проверок пропажи
  раздачи.
- `web-ui`: человекочитаемый бейдж для `catched`; активная группа включает
  `catched`; заголовок при пустом имени — по фолбеку; карточка `catched`
  самообновляется htmx-поллингом до перехода в `downloading`.

_Без спек-правок:_ `state-reconciliation` и `live-status` не меняются.
Исключение `catched` из проверок рассинхрона нормативно закреплено требованием
`download-tracking` «catched не считается пропажей раздачи» (само поведение уже
верно — `catched` не входит в `desyncStates` и дебаунс пропажи источника его не
трогает). Иллюстративное перечисление активных состояний в тексте
`state-reconciliation` остаётся на кросс-ссылке и будет выверено при следующем
касании этой спеки. `live-status`: у `catched` нет qBit-телеметрии по дизайну —
живой прогресс для него корректно отсутствует.

## Impact

- Код: `internal/store` (состояние `StateCatched`, группа active), `internal/
  ingest` (быстрый путь: убрать namer/qbt-add, писать `catched`), `internal/
  worker` (новый шаг обработки `catched`: namer + qbt-add + переход, таймаут),
  `internal/httpapi`+`internal/tgbot` (без правок API — ответ и так по Result),
  веб-UI шаблоны (бейдж/фаза `catched`).
- Конфиг: новый `catch_timeout` (предохранитель), дефолт консервативный.
- Данные: у активной загрузки теперь есть фаза без infohash-раздачи; схема БД
  не меняется (используем существующие `state`/`error_code`/`error_msg`).
- Совместимость: существующие загрузки не затронуты; переход одноразовый на
  уровне логики приёма.
