## Why Ревью приёма 2026-07-08 оставило четыре нити, каждая из которых по отдельности дёшева, а вместе они портят три разных наблюдаемых поверхности: контекст распознавания (грязная строка), комментарии в коде (описывают контракт, которого уже нет), журнал (запись о неуспешном добавлении без корреляции) и знание о границе чужой библиотеки (не записано нигде). Пока нити открыты, каждый следующий проход ревью тратит внимание на то, что уже разобрано. ## What Changes - **N1 — вырожденное имя не покидает разборщик.** Раздача может объявить полем `name` значение `-` — конвенция «имени нет» (в библиотеке разбора это константа `metainfo.NoName`). Сейчас `.torrent`-приём отбрасывает `-` только для `source_ref`, а `torrent.Info.Context()` и подсказка имени для `namer` берут его как содержательное название. Нормализация переезжает на границу разбора: `DisplayName` пустеет прямо в `torrent.Parse`, и три места ниже по потоку перестают знать про вырожденное значение. Тем же местом схлопываются разделители строк в имени — иначе имя добавляет в построчный контекст строку, выглядящую как синтезированный нами факт. **Основание нити уточнено ревью предложения:** библиотека `-` не синтезирует (`BestName()` на раздаче без имени возвращает пустую строку), поэтому речь о разборе объявленного значения, а не о фильтре чужого сентинела; случай «раздача без поля `name`» уже отрабатывается верно и получает свой сценарий, чтобы впредь не путаться с первым. - **N3 — комментарии описывают фактический контракт `Ingest`.** После fast-catch-рефактора `Ingest` возвращает нулевой `Result` на **каждом** пути ошибки, а комментарии в `httpapi` и `tgbot` до сих пор обещают непустой `DownloadID` «при сбое после создания задачи». Контракт закрепляется в доке `Ingest`, удерживается структурно (обнуление результата одним `defer`, а не аккуратностью каждой ветки), подтверждается тестом и перестаёт пересказываться неверно на транспортах. Вызовов приёма три, а не два: REST, веб-форма и Telegram. - **N4 — запись о неуспешном добавлении в qBittorrent коррелируется.** Клиент `qbt` берёт логгер из `ctx` и своего инфохэша не знает (и знать не должен — разбор источника живёт в `magnet`/`torrent`). Путь `worker.Retry` не кладёт в `ctx` scoped-логгер загрузки, поэтому запись `Fails.` с этого пути уходит без `download_id`/`infohash`. Retry приводится к тому же виду, что и `Delete`. **Ревью изменения показало, что таких команд не одна, а семь** — те же `Relink`, `Rerecognize`, `Refine`, `ChooseCandidate`, `AddManualSource`, `SetProviderID` зовут qBittorrent или метабазу до постановки логгера. Починены все семь: иначе требование `identity` архивировалось бы ложным. - **N5 — граница чужой библиотеки записывается наблюдением.** `anacrolix/torrent` аллоцирует объявленную bencode-строку до её чтения, с потолком ~128 MiB. Правке не подлежит (чужой код), поэтому исход — запись в `docs/research/` с провенансом и замером, а не изменение кода. ## Capabilities ### New Capabilities Нет — изменение не вводит нового поведения и новых понятий. ### Modified Capabilities - `ingest`: приём `.torrent` перестаёт считать вырожденное имя `-` содержательным — ни в синтезированном контексте, ни в подсказке имени, ни в `source_ref`; плюс фиксируется контракт «на ошибке приёма результат пуст» и поимённо называется корреляционный ключ отказа на каждом транспорте. - `identity`: корреляция в журнале распространяется на записи о вызовах внешних сервисов, сделанных в контексте загрузки, — включая путь retry. ## Impact - `internal/torrent` — нормализация `DisplayName` на границе разбора; тест на безымянной раздаче. - `internal/ingest` — упрощение фильтра `source_ref`, дока и структурная гарантия контракта `Result`, тест «на ошибке результат нулевой». - `internal/httpapi` (REST `handleAPIAdd` **и** веб-форма `handleUIAdd`), `internal/tgbot` — комментарии и передача пустого id в диагностику вместо заведомо пустого `res.DownloadID`. - `internal/worker` — `Retry` кладёт scoped-логгер загрузки в `ctx`. - `internal/qbt` — тест с подставным сервером на поля записи о неуспешном `add`. - `docs/research/` — новая записка про границы разбора `.torrent` (предел `MaxStrLen` bencode + наблюдение о `BestName`/`NoName`); строка в индексе `docs/research/README.md` и полстроки в его вводной. - Схема БД, конфиг, API и тексты Telegram не затрагиваются; нумерованных артефактов (миграций, ADR) изменение не добавляет.