- имя раздачи нормализуется на границе разбора: вырожденное `-` (metainfo.NoName) даёт пустое имя, пробельное схлопывается — сентинел больше не доходит ни до контекста распознавания, ни до source_ref, ни до подсказки вывода имени - контракт «на любом пути ошибки приёма результат нулевой» объявлен в ingest и удерживается структурно; три транспорта перестали обещать идентификатор, которого нет, и коррелируют отказ по request_id - scoped-логгер загрузки ставится до вызова внешнего сервиса в семи командах воркера — записи об отказе qBittorrent и метабаз получили download_id и infohash; граница разбора bencode записана в docs/research
7.0 KiB
7.0 KiB
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не кладёт вctxscoped-логгер загрузки, поэтому запись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(RESThandleAPIAddи веб-формаhandleUIAdd),internal/tgbot— комментарии и передача пустого id в диагностику вместо заведомо пустогоres.DownloadID.internal/worker—Retryкладёт scoped-логгер загрузки вctx.internal/qbt— тест с подставным сервером на поля записи о неуспешномadd.docs/research/— новая записка про границы разбора.torrent(пределMaxStrLenbencode + наблюдение оBestName/NoName); строка в индексеdocs/research/README.mdи полстроки в его вводной.- Схема БД, конфиг, API и тексты Telegram не затрагиваются; нумерованных артефактов (миграций, ADR) изменение не добавляет.