## Why Ревью приёма (Fable, 2026-07-08) вскрыло два дефекта в дедуп-ветках приёма, оба про инвариант «≤1 активная загрузка на infohash» и про сохранность источника: - **F1 — неохраняемая дозапись хешей.** Дедуп-ветка `CreateDownloadIfNoActive` (`internal/store/download.go`) безусловно дописывает ВСЕ хеши входящего источника в найденную активную задачу (`INSERT OR IGNORE`) без пер-хеш гарда владения — в отличие от `AddInfohashes`, где гард есть. Это единственная неохраняемая запись хешей, и она в авторитетном методе инварианта. Сценарий: активная A владеет `v1`, активная B владеет `v2` того же гибридного торрента; приём гибрида `{v1,v2}`, дедупнувшись на B, допишет `v1` в B → две активные владеют `v1`. Инвариант нарушен. - **F6 — потерянный upgrade-путь `.torrent` поверх magnet.** Пользователь сначала ловит magnet с закрытого трекера (задача `catched`, `source_type=magnet`), понимает, что без DHT метаданные не докачаются, и грузит правильный `.torrent`. Приём дедупит по infohash на magnet-задачу; по текущей спеке байты при дедупе НЕ сохраняются, `source_type` остаётся `magnet`. Worker добавляет раздачу по magnet-URL → вечный metaDL → failed. Ровно тот артефакт, который бы починил загрузку, выбрасывается с «уже в работе». ## What Changes - **F1:** дедуп-ветка `CreateDownloadIfNoActive` применяет тот же пер-хеш гард, что и `AddInfohashes`: хеш, которым владеет ДРУГАЯ активная задача, не дописывается. Транзакция уже открыта — правка внутри неё. - **F6:** при дедупе, где входящее — байты `.torrent`, а активная задача поймана как `magnet` и ещё не добавлена в qBittorrent (состояние `catched`), система сохраняет байты и меняет `source_type` на `torrent` в одной транзакции. Тогда worker добавит раздачу файлом и метаданные не придётся докачивать по DHT. Это ПРОТИВОРЕЧИТ действующему правилу спеки ingest «при дедупликации байты сохраняться SHALL NOT» — правило смягчается этим целевым исключением (MODIFIED-дельта). Схема БД не меняется: таблица `download_torrent` уже есть, `source_type` — существующая колонка; апгрейд — изменение данных, не структуры. ## Capabilities ### Modified Capabilities - `ingest`: уточняется поведение дедупа (пер-хеш гард дозаписи; сохранение `.torrent`-байт и смена источника при апгрейде `catched`-magnet). ## Impact - Код: `internal/store/download.go` (гард F1 + новый guarded-метод апгрейда), `internal/ingest/ingest.go` (вызов апгрейда на обоих дедуп-путях). - Тесты: `internal/store`, `internal/ingest`. - Совместимость: изменение только ужесточает инвариант (F1) и добавляет целевой апгрейд (F6); существующие потоки без `.torrent`-поверх-magnet ведут себя как прежде.