Отмена задачи (catched→cancelled) в окно, пока worker вне блокировки выводит имя (LLM) и делает qbt.Add, оставляла добавленный торрент в qBittorrent без задачи-владельца: PromoteCatched корректно пропускал переход, но источник уже качался/сидировал вечно, а усыновить его назад нельзя (хеши принадлежат отменённой задаче). Спека покрывала переход состояния, но не побочный эффект. Комбинированная защита в processCatched: - re-read состояния под w.mu прямо перед qbt.Add — при отмене источник не добавляется вовсе (сужает окно гонки); - свежий листинг перед add подтверждает отсутствие infohash — признак «своего» торрента; при сбое листинга/присутствии add не делаем (усыновит следующий тик); - при отмене в окне после add (промах PromoteCatched, подтверждённый re-read'ом state != catched) — уборка добавленного нами торрента qbt.Delete(_, true); - WARN/ERROR-логи по этому пути с корреляцией по download_id, без секретов. Гарантия «удаляем только своё»: удаление-с-данными достижимо ТОЛЬКО после подтверждённого отсутствия infohash перед add, поэтому пред-существующий/чужой торрент с тем же хешем никогда не сносится (негативный инвариант). Обоснование по инварианту «источник неприкосновенен» — в design.md изменения. Дельта — download-tracking (требование «Добавление пойманной загрузки в qBittorrent»): re-read перед add, подтверждение отсутствия, уборка при отмене, негативный сценарий. Тесты покрывают все ветки (skip-before-add, cleanup после add, пред-существующий не удаляется, сбой БД не удаляет, сбой листинга не добавляет). Change archived: 2026-07-17-cancel-during-add-cleanup. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.4 KiB
4.4 KiB
Why
На шаге добавления пойманной загрузки (catched) worker выводит имя (LLM,
секунды) и вызывает qbt.Add вне блокировки переходов. Если в это окно
пользователь отменяет задачу (catched → cancelled), запись перехода
PromoteCatched корректно пропускается (гард state='catched'), НО источник
уже добавлен в qBittorrent под нашей категорией. Такой торрент качается/сидирует
вечно, ест диск, а видимой задачи-владельца нет: усыновить назад его нельзя —
adopt проверяет ExistsByInfohash (любое состояние), а хеши уже принадлежат
отменённой задаче. Спека покрывает переход состояния, но не этот побочный эффект
(находка ревью F3/NIT-13).
What Changes
- Re-read состояния прямо перед
qbt.Add(под блокировкой переходов, после медленного вывода имени): если задача уже не вcatched(отменена) — источник в qBittorrent НЕ добавляется вовсе. Сужает окно гонки до промежутка между re-read и записью перехода. - Scoped cleanup: если отмена случилась в оставшемся окне (уже ПОСЛЕ
успешного
add, но до записи перехода), worker удаляет только что добавленный торрент из qBittorrent вместе с данными — уборка собственного мусора. - Гарантия «удаляем только своё»: удаление-с-данными допустимо ТОЛЬКО для
торрента, который worker создал именно этим
add. Признак — подтверждённое отсутствие infohash в qBittorrent непосредственно передadd. Если infohash уже присутствовал до нашегоadd(внешний клиент раздаёт тот же торрент), worker источник не добавляет и чужие данные не трогает. - WARN-логи на этом пути (торрент оставлен после отмены → удаляем; факт
удаления), с корреляцией по
download_id, без секретов.
Capabilities
New Capabilities
Нет.
Modified Capabilities
download-tracking: требование «Добавление пойманной загрузки в qBittorrent» — добавляется re-read состояния передadd, подтверждение отсутствия infohash передaddкак признак «своего» торрента и уборка добавленного торрента при отмене в окне послеadd. Сценарий «Отмена во время добавления» уточняется и дополняется сценариями уборки и негативного инварианта.
Impact
- Спеки: дельта
download-tracking(одно MODIFIED-требование + сценарии). - Код:
internal/worker/worker.go—processCatched(re-read state и проверка присутствия передAdd; уборка добавленного при промахеPromoteCatched). Новых методовqbt/storeне требуется (переиспользуемTorrents,Delete). - Тесты:
internal/worker/catched_test.go— обновление сценария отмены во время namer (Add не вызывается) + новые: уборка после Add, негативный инвариант (пред-существующий торрент не удаляется с данными). - Миграции БД: нет.
- Инвариант «источник неприкосновенен»: обоснование удаления-с-данными и
негативная гарантия — в
design.md.