4.7 KiB
🐞 Не оставлять задачу в done, когда ссылки сняты, а раздача не снесена
- Тип: fix
- Категория: Ядро продукта
- Зачем: при недоступном qBittorrent задача весь простой соседа показывает done, хотя тайтла в Jellyfin уже нет: сверка падает на первом шаге и до коррекции не доходит
- Теги: goal:state-integrity
Delete снимает библиотечные ссылки раньше, чем зовёт qbt.Delete. Если сосед
недоступен, локальный шаг проходит, внешний падает, и задача остаётся в done.
Спека рассчитывает, что расхождение живёт «до тика сверки», но Poll
возвращается на первой же ошибке qbt.Torrents и до reconcileDesync не
доходит вовсе — значит, расхождение живёт весь простой qBittorrent.
Двигает у цели state-integrity ту же строку завершения — «ни один известный
сегодня путь не оставляет состояние, которое не объясняется историей
переходов»: done держится сколь угодно долго и историей переходов не
объясняется.
Воспроизведение
- Довести задачу до
doneс существующими библиотечными ссылками. - Погасить qBittorrent (в тесте — клиент на несуществующий адрес).
- Выполнить удаление — поштучно или пачкой.
Видно вместо ожидаемого: ссылки сняты, строки file_link удалены, раздача цела,
место не освобождено, а карточка, список и Telegram показывают done. Пока
qBittorrent лежит, ни один тик сверки этого не исправит. Замер ревью: отказ
приходит за 524.545µs, то есть пачка успевает пройти по всем выбранным раньше,
чем человек поймёт, что сосед недоступен.
Отчёт ревью —
openspec/changes/archive/2026-08-10-bulk-delete-page/review/report.md,
находка 4.
Затрагивает
Worker.Delete(internal/worker/review.go) — порядок шагов и переход после отказа внешнего шага;Worker.Poll(internal/worker/worker.go) — ранний возврат по отказуqbt.TorrentsпередreconcileDesync;- спека
state-reconciliation, требование «Полное удаление загрузки пользователем» — формулировка «кратковременное рассогласование до тика сверки ожидаемо» сегодня неверна; - граф переходов:
done → target_missingуже легален, нового состояния не надо.
Критерии приёмки
- После отказа внешнего шага при снятых ссылках задача не остаётся в
done(оракул: тестinternal/worker— клиент qBittorrent отказывает, задача оказывается вtarget_missing, а не вdone). - В
deletedпри этом задача не переходит: место не освобождено (оракул: тот же тест). - Повторное удаление после подъёма соседа идемпотентно дожимает раздачу (оракул:
тест — второй вызов при живом клиенте уводит задачу в
deleted). - Формулировка спеки приведена к тому, что код делает (оракул:
openspec validate --strictиtask gate).
Рамки
Порядок шагов менять можно, но снос раздачи раньше снятия ссылок — отдельное
решение с ценой: оно убирает необратимый локальный шаг при мёртвом соседе, но
меняет поведение при отказе на втором шаге. Ранний возврат Poll по отказу
qbt.Torrents трогать осторожно: на нём стоит вся сверка.