Files
jellybit/openspec/changes/2026-07-17-retry-reject-broken-torrent/proposal.md
T
avandClaude Opus 4.8 bcc7b2d76b Жизненный цикл: claim-токен распознавания, индексация хешей, retry сломанного торрента
Три мелких фикса из docs/backlog/review-lifecycle-minor.md (ревью Fable
2026-07-08). MINOR-9 (I/O под глобальным w.mu) осознанно waive для
one-user home-сервера — не трогаем.

MINOR-8: claim-токен распознавания. recognizeOne фиксирует updated_at на
момент claim (перечитывая запись после перехода в recognizing), а
finishRecognition коммитит результат, только если токен совпал. Иначе за
время LLM-вызова задачу увели из recognizing и вернули обратно
(cancel → relink revive) — это уже другой эпизод, устаревший результат
отбрасываем, задача остаётся в recognizing для перезапуска поллингом.

NIT-11: lookup-мапы (byHash/live/torrentByInfohash) больше не индексируют
усечённый 40-hex t.Hash v2-only торрентов. Новый хелпер torrentIndexHashes
зеркалит выбор torrentHashes: t.Hash берём только при отсутствии обоих
infohash_v1/v2. Убирает теоретический ложный матч по коллизии длины.

NIT-12: retry живого, но сломанного торрента (error/missingFiles) теперь
отклоняется с подсказкой починить раздачу (recheck) в qBittorrent, вместо
бессмысленной переотдачи источника (сверка тут же вернула бы задачу в
failed). Повторный Add — только когда раздачи в qBittorrent нет. Меняет
спеку state-reconciliation → дельта openspec/changes/2026-07-17-retry-reject-broken-torrent
(не архивировал).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 20:35:14 +03:00

2.6 KiB

Why

Retry задачи в failed/stuck, чей торрент ЖИВ в qBittorrent, но в состоянии ошибки (error/missingFiles), сейчас повторно отдаёт источник. На живом сломанном торренте это бесполезно: qBittorrent отвергает дубль, задача уходит в downloading, а на ближайшем тике сверки classErrored тут же возвращает её в failed (+ дебаунс уведомления). Пользователю retry выглядит сломанным, а реальное лекарство (перепроверка/recheck/восстановление файлов в qBittorrent) не подсказано (находка ревью NIT-12).

What Changes

  • Retry сломанного живого торрента отклоняется, а не переотдаёт источник. Отказ несёт понятное сообщение: починить раздачу (recheck/восстановить файлы) в qBittorrent и повторить. Состояние задачи не меняется, повторного Add не происходит.
  • Повторный Add при retry остаётся только для случая, когда раздачи в qBittorrent НЕТ (перецепка к здоровому живому торренту — без Add, как и раньше).

Capabilities

New Capabilities

Нет.

Modified Capabilities

  • state-reconciliation: требование «Ручной повтор зависшей/упавшей загрузки из транспортов» — ветка живого сломанного торрента меняет исход с «повторно отдать источник» на «отклонить с подсказкой про recheck». Прочие ветки retry (нет раздачи → Add; жив и здоров → перецепка без Add; сброс базиса retried_at) без изменений.

Impact

  • Спеки: дельта state-reconciliation (одно MODIFIED-требование).
  • Код: internal/worker/worker.goRetry (ветка alive && classErrored → отказ ErrConflict с сообщением вместо reAdd).
  • Тесты: internal/worker/worker_test.go — отклонение retry на живом сломанном торренте (error/missingFiles), контроль перецепки здорового.
  • Миграции БД: нет.