## 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
  ведут себя как прежде.
