- выбор → поимённое подтверждение → отчёт: пачка до 20 загрузок, гарды входа на обеих границах, потолок времени и остановка после трёх подряд отказов внешнего сервиса - допуск полного удаления сведён в единую точку store.State.CanDelete() — worker, страница загрузки и Telegram больше не держат своих перечней
53 lines
4.4 KiB
Markdown
53 lines
4.4 KiB
Markdown
# Отметка «последняя копия» на подтверждении удаления выводится из состояния, а не из файловой системы
|
||
|
||
- **Дата:** 2026-08-10
|
||
- **Источник:** openspec/changes/archive/2026-08-10-bulk-delete-page/design.md
|
||
|
||
## Решение
|
||
|
||
Экран подтверждения группового удаления помечает загрузку как последнюю копию
|
||
данных по её **состоянию** (`orphaned`), не спрашивая файловую систему. Случай,
|
||
когда байты источника исчезли с диска, а раздача осталась в списке qBittorrent,
|
||
такой отметки не получает — и это записано границей в спеке `web-ui`, а не
|
||
оставлено умолчанием.
|
||
|
||
## Почему
|
||
|
||
Гард последней копии в `Delete` выключен сознательно (инвариант «источник
|
||
неприкосновенен», исключение 1), поэтому осведомлённость человека — единственный
|
||
оставшийся предохранитель. Отсюда решение D2 источника:
|
||
|
||
> Признак берётся из состояния (`orphaned` по определению значит «источник
|
||
> пропал, цель — последняя копия»), а не обходом файловой системы.
|
||
|
||
Враждебный проход ревью построил путь, где это неверно: сверка берёт присутствие
|
||
источника из ответа `torrents/info`, а не с диска, поэтому задача с пропавшими
|
||
байтами остаётся `done` сколько угодно долго и отметки не получает. Дыра
|
||
признана и оставлена открытой по решению человека: поштучное удаление такой
|
||
отметки не несёт **вовсе**, то есть групповой путь не ухудшил положение, а
|
||
улучшил его не до конца. Закрывать её обходом файловой системы на экране
|
||
подтверждения значит завести чтение диска в транспорте ради предупреждения,
|
||
которое и сегодня лучше прежнего.
|
||
|
||
## Рассмотренные варианты
|
||
|
||
- **Спрашивать файловую систему на подтверждении** (`nlink` по живым ссылкам
|
||
последнего батча) — отметка стала бы правдой, но транспорт начал бы ходить в
|
||
файловую систему ради показа, а пачка ограничена двадцатью строками только
|
||
сегодня.
|
||
- **Вернуть гард последней копии в `Delete`** — отменяет само назначение
|
||
команды: она затем и существует, чтобы снять последнюю копию осознанно.
|
||
- **Убрать отметку совсем** — честно, но теряет полезный сигнал про пропавший
|
||
источник, который в подавляющем большинстве случаев и есть последняя копия.
|
||
|
||
## Последствия
|
||
|
||
- `+` Подтверждение предупреждает о последней копии там, где раньше не
|
||
предупреждало ничто; признак берётся из домена, второго перечня состояний не
|
||
заводится.
|
||
- `+` Транспорт не ходит в файловую систему ради показа.
|
||
- `−` Случай «`done` с пропавшими байтами источника» отметки не получает. Дыра
|
||
названа в спеке прямо, чтобы отметка не читалась как гарантия.
|
||
- `−` Пока сверка берёт присутствие источника из списка раздач, а не с диска,
|
||
закрыть дыру нельзя ни на одном экране.
|