Единое окно: полное пользовательское удаление загрузки (delete)
Вторая половина «единого окна»: команда «Удалить» снимает наши библиотечные хардлинки (гард последней копии осознанно выключен, в отличие от Undo) и сносит раздачу с файлами из qBittorrent (deleteFiles=true) → терминальный deleted. Доступна из done/orphaned/target_missing, идемпотентна к отсутствующей стороне; инициатор различается через error_code=user_delete. Подтверждение обязательно: веб — danger-секция внизу страницы (hx-confirm + details), Telegram — двухшаговый inline-confirm. qbt.Delete + layout.Remove (unlink без ErrLastCopy, только свои ссылки под movies/series). Граф переходов не менялся — рёбра уже были. OpenSpec: state-reconciliation +1 требование; синк workflow.md; беклог закрыт. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,6 @@ Tududi (проект `jellybit`) больше **не** держит беклог
|
||||
|
||||
- [Проблема второго сезона (сходимость папки сериала)](vtoroy-sezon-shodimost-papki.md) — Второй/третий сезон должен ложиться в ТУ ЖЕ папку сериала, а не заводить рядом почти…
|
||||
- [Раздачи с докачиванием (merge при повторном добавлении)](merge-dokachivanie.md) — Свежий сериал раздают по мере выхода: торрент с 5 из 10 эпизодов позже перезаливают…
|
||||
- [Полное удаление загрузки из jellybit («единое окно», path 2)](udalenie-edinoe-okno.md) — Действие «Удалить»: снять хардлинки + снести раздачу+файлы из qBittorrent → освободить место (отдельно от undo)
|
||||
- [Ретеншн и очистка БД](retention-ochistka-bd.md) — Терминальные задачи (done/cancelled/failed/reverted), их попытки recognition с сырыми…
|
||||
- [Eval-харнес распознавания (корпус кейсов + метрика точности)](eval-harness-raspoznavaniya.md) — Распознавание — ядро продукта, но смена модели или правка промпта сейчас вслепую…
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
# Полное удаление загрузки из jellybit («единое окно», path 2)
|
||||
|
||||
**Приоритет:** высокий
|
||||
|
||||
Безопасная половина «единого окна» уже в проде: распознавание ручного удаления и
|
||||
пометка рассинхрона (state-reconciliation — `target_missing`/`orphaned`/`deleted`,
|
||||
undo с nlink-гардом, preflight). Осталась вторая половина — **удалять из самого
|
||||
jellybit**, не идя руками в qBittorrent/Jellyfin.
|
||||
|
||||
Основной сценарий одного окна — «досмотрел → освободить место»: удалить и раздачу,
|
||||
и файлы в библиотеке разом. Из-за хардлинков иначе место и не вернуть — файл в
|
||||
`downloads/` (qBittorrent) и наша ссылка в библиотеке указывают на **один инод**,
|
||||
диск освобождается только когда исчезает последняя ссылка. Значит delete обязан
|
||||
снять **обе** стороны.
|
||||
|
||||
## Действие «Удалить» (одна загрузка)
|
||||
|
||||
- Снять живые хардлинки загрузки (переиспользуем undo-механику: `superseded`
|
||||
пропускаем) **+** удалить раздачу с файлами из qBittorrent (новый метод в `qbt`,
|
||||
`deleteTorrents` с `deleteFiles=true`).
|
||||
- **Осознанно обходим** предохранитель последней копии (undo при «источник удалён,
|
||||
цель — последняя копия» отказывает — `worker/review.go:499`; здесь мы наоборот
|
||||
хотим снять последнюю копию).
|
||||
- Обязательное **подтверждение** — это выход за инвариант «источник
|
||||
неприкосновенен», не по случайному клику. Логировать как осознанное удаление
|
||||
источника.
|
||||
|
||||
## undo vs delete (зафиксировать различие)
|
||||
|
||||
- **undo** — «перераспознать»: снимает только наши ссылки, раздачу в qBittorrent
|
||||
сохраняет, данные бережёт (гард включён). Уже готов.
|
||||
- **delete** — «убрать окончательно, освободить место»: снимает наши ссылки И
|
||||
сносит раздачу+файлы, гард выключен, состояние терминальное.
|
||||
|
||||
## Терминальное состояние
|
||||
|
||||
Переиспользуем существующий `deleted` (исход тот же: и источник, и цель сняты) —
|
||||
**без** нового статуса. Инициатора (`user` против reconciliation) пишем в причину/
|
||||
лог перехода. В граф переходов добавить явное пользовательское ребро
|
||||
`done → deleted` (сейчас `deleted` выводит только сверка с реальностью).
|
||||
|
||||
## Опционально (если понадобится)
|
||||
|
||||
Мультивыбор в списке + «удалить выбранное» — тонкая обёртка над тем же действием
|
||||
для редкого случая «снести сериал целиком». Вычисляемую группу-«тайтл» и экран
|
||||
состава **не** делаем — оверинжиниринг ради редкого сценария.
|
||||
|
||||
Оформить как OpenSpec-change (дельта `state-reconciliation`/`review` + метод `qbt`
|
||||
+ ребро графа + action в UI/боте).
|
||||
|
||||
Связано: drafts/logical-title-model.md §5.3/§6.4, ADR-2026-06-13-hardlinks,
|
||||
openspec/specs/state-reconciliation, specs/workflow.md, пакеты qbt, worker, layout.
|
||||
+17
-3
@@ -51,10 +51,11 @@ stateDiagram-v2
|
||||
|
||||
done --> target_missing: сверка — цель удалена
|
||||
done --> orphaned: сверка — источник пропал
|
||||
done --> deleted: Удалить (delete)
|
||||
target_missing --> recognizing: Привязать заново
|
||||
target_missing --> orphaned: источник тоже пропал
|
||||
target_missing --> deleted: источник тоже пропал
|
||||
orphaned --> deleted: цель тоже удалена
|
||||
target_missing --> deleted: Удалить / источник тоже пропал (сверка)
|
||||
orphaned --> deleted: Удалить / цель тоже удалена (сверка)
|
||||
target_missing --> done: healing (цель вернулась)
|
||||
orphaned --> done: healing (источник вернулся)
|
||||
|
||||
@@ -96,7 +97,8 @@ stateDiagram-v2
|
||||
[architecture.md](architecture.md) → «Раскладка файлов».
|
||||
- **done** — при входе неблокирующе дёргаем пересканирование Jellyfin
|
||||
(опц., см. [architecture.md](architecture.md) → «Пересканирование
|
||||
Jellyfin»); доступен **Undo** → `reverted` (убрать созданные ссылки).
|
||||
Jellyfin»); доступен **Undo** → `reverted` (убрать созданные ссылки) и
|
||||
**Удалить** → `deleted` (полное удаление, см. ниже).
|
||||
- **stuck / failed / cancelled** — не качается дольше таймаута; ошибка
|
||||
(ретраибельна); «Отклонить».
|
||||
- **reverted / cancelled → recognizing** — «Привязать заново»: после
|
||||
@@ -120,6 +122,18 @@ stateDiagram-v2
|
||||
- **deleted** — нет ни источника, ни цели; **терминально**: сверка его
|
||||
больше не переоценивает (см. ниже).
|
||||
|
||||
**Undo vs Удалить (delete).** Это разные пользовательские операции. **Undo**
|
||||
(из `done`) — «перераспознать»: снимает только наши библиотечные ссылки, раздачу
|
||||
в qBittorrent бережёт, гард последней копии включён (не сотрёт единственный
|
||||
файл) → `reverted`. **Удалить** (из `done`, `orphaned`, `target_missing`) —
|
||||
«убрать окончательно, освободить место»: снимает наши ссылки **и** сносит раздачу
|
||||
с файлами из qBittorrent, гард последней копии осознанно выключен (обход
|
||||
инварианта «источник неприкосновенен» — только по подтверждению) →
|
||||
терминальный `deleted`. Идемпотентно к отсутствующей стороне, так что подчищает
|
||||
остатки из любого из трёх состояний. Инициатор в `deleted` различается по
|
||||
`error_code`: пользовательское удаление — `user_delete`, вывод сверкой —
|
||||
`reconcile`. Полные требования — `openspec/specs/state-reconciliation/`.
|
||||
|
||||
Сверка трогает только `done`/`target_missing`/`orphaned` — терминальный
|
||||
`deleted`, активные и пользовательски-терминальные (`reverted`/`cancelled`/
|
||||
`failed`/`stuck`) состояния не задевает. Реальность «лечится» сама: при
|
||||
|
||||
Reference in New Issue
Block a user