закрыта задача bulk-delete-page, заведены три задачи из урожая ревью
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# 🐞 Не оставлять задачу в done, когда ссылки сняты, а раздача не снесена
|
||||
|
||||
- **Тип:** fix
|
||||
- **Категория:** Ядро продукта
|
||||
- **Зачем:** при недоступном qBittorrent задача весь простой соседа показывает done, хотя тайтла в Jellyfin уже нет: сверка падает на первом шаге и до коррекции не доходит
|
||||
- **Теги:** goal:state-integrity
|
||||
|
||||
`Delete` снимает библиотечные ссылки раньше, чем зовёт `qbt.Delete`. Если сосед
|
||||
недоступен, локальный шаг проходит, внешний падает, и задача остаётся в `done`.
|
||||
Спека рассчитывает, что расхождение живёт «до тика сверки», но `Poll`
|
||||
возвращается на первой же ошибке `qbt.Torrents` и до `reconcileDesync` не
|
||||
доходит вовсе — значит, расхождение живёт весь простой qBittorrent.
|
||||
|
||||
Двигает у цели `state-integrity` ту же строку завершения — «ни один известный
|
||||
сегодня путь не оставляет состояние, которое не объясняется историей
|
||||
переходов»: `done` держится сколь угодно долго и историей переходов не
|
||||
объясняется.
|
||||
|
||||
## Воспроизведение
|
||||
|
||||
1. Довести задачу до `done` с существующими библиотечными ссылками.
|
||||
2. Погасить qBittorrent (в тесте — клиент на несуществующий адрес).
|
||||
3. Выполнить удаление — поштучно или пачкой.
|
||||
|
||||
Видно вместо ожидаемого: ссылки сняты, строки `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` трогать осторожно: на нём стоит вся сверка.
|
||||
Reference in New Issue
Block a user