Обсудили: для сервиса одного окна основное действие — удалить всё разом (раздачу + файлы в библиотеке), чтобы освободить место. Из-за хардлинков иначе место и не вернуть — снять надо обе ссылки на инод. Задача udalenie-edinoe-okno переписана в одну конкретную: - действие «Удалить» на загрузке: снять живые хардлинки (undo-механика, superseded пропускаем) + удалить раздачу с файлами из qBittorrent (новый метод qbt); осознанно обходим предохранитель последней копии; обязательное подтверждение; - undo (перераспознать, гард включён) vs delete (освободить место, гард выключен) зафиксированы как разные действия; - терминальное состояние — переиспользуем deleted, инициатора (user/reconcile) пишем в лог перехода; в граф добавить ребро done→deleted; - тайтл-группа и экран состава выкинуты как оверинжиниринг; мультивыбор в списке — опциональный шаг. Реализовать как OpenSpec-change. Приоритет высокий (недостающая половина одного окна, частый сценарий «досмотрел → освободить место»). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.0 KiB
Полное удаление загрузки из 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.