# 🐞 Не сносить раздачу, которой владеет другая активная загрузка - **Тип:** fix - **Категория:** Ядро продукта - **Зачем:** удаление старой закрытой задачи уничтожает файлы живой загрузки с тем же инфохэшем; воспроизведено падающим тестом на ревью bulk-delete-page - **Теги:** goal:state-integrity `Delete` зовёт `torrents/delete` с `deleteFiles=true` по хешам своей записи и не спрашивает, не владеет ли этим инфохэшем другая **активная** загрузка. Человек подтверждает удаление одной записи, а необратимое действие применяется к чужим живым данным. Двигает у цели `state-integrity` строку завершения «ни один известный сегодня путь не оставляет состояние, которое не объясняется историей переходов»: живая загрузка B уходит в `failed` по пропаже источника, и по её записи не видно, что файлы снесла чужая операция. ## Воспроизведение 1. Довести задачу A по инфохэшу H до `done`. 2. Добавить тот же релиз заново: `CreateDownloadIfNoActive` ищет владельца только среди активных, A терминальна, дедупа нет — заводится активная задача B по тому же H. Файлы на диске у A и B общие, qBittorrent дедуплицирует раздачу по хешу. 3. Удалить A — со страницы загрузки, из Telegram или со страницы группового удаления. Видно вместо ожидаемого: раздача снесена с файлами, B продолжает считать себя качающейся и уходит в `failed` после дебаунса. Если B ещё не дошла до раскладки, копии не остаётся нигде. Прогнанные оракулы ревью (отчёт — `openspec/changes/archive/2026-08-10-bulk-delete-page/review/report.md`, находка 2): `TestAdversaryDeletablePageOffersHashOwnedByActiveDownload`, `TestAdversaryDeleteWipesSourceOfAnotherActiveDownload`. ## Затрагивает - `Worker.Delete` (`internal/worker/review.go`) — вызов `qbt.Delete`; - предикат `store.FindActiveByInfohash` — существующий, новый заводить не надо; - спека `state-reconciliation`, требование «Полное удаление загрузки пользователем» — сегодня оно про такую проверку молчит; - строка выбора и подтверждения на странице группового удаления, если решено показывать признак чужого владения; - qBittorrent `torrents/delete` с `deleteFiles=true` — необратимая операция. ## Критерии приёмки - Удаление задачи, чьим инфохэшем владеет активная загрузка, отклоняется конфликтом и раздачу не сносит (оракул: тест `internal/worker` — задача A в `done` и активная B по тому же хешу, `Delete(A)` возвращает `ErrConflict`, у подставного клиента qBittorrent ноль вызовов `Delete`). - Отказ виден человеку причиной, а не общим «внутренняя ошибка» (оракул: тест `internal/httpapi` — строка отчёта называет, что инфохэшем владеет активная задача). - Удаление задачи, чей инфохэш никем больше не занят, работает как прежде (оракул: существующие тесты `Delete` остаются зелёными). - Поведение записано дельта-спекой `state-reconciliation` (оракул: `openspec validate --strict` и `task gate`). ## Рамки Необратимое: снос раздачи с файлами. Проверка ставится в ядре, а не в транспорте — допуск обязан держаться без транспорта. Правило дедупа при приёме («владелец ищется среди активных») эта задача не меняет: связывание v1/v2 и доверие к паре `xt` разбирает `infohash-identity-integrity`.