Инбокс Tududi разгружен: четыре открытые задачи проекта оформлены файлами в docs/backlog и помечены выполненными в Tududi. - режиссёр в блоке «Распознано как» на странице загрузки (средний); - карточка информации о торренте вылезает за экран на мобильном (средний); - сигнал Jellyfin после отката и удаления файлов (средний); - кнопки выглядят как кнопки: btn-ghost и рассогласование весов (низкий). Каждая задача проверена по коду: все четыре актуальны, ни одну не закрыли прошлые коммиты. В телах — точки правки, развилки и нужные дельты спек. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4.5 KiB
Сигнал Jellyfin после отката и удаления файлов
Приоритет: средний
Сейчас пересканирование Jellyfin шлётся только при входе в done. После
отката (reverted) или удаления (deleted) хардлинки сняты, а Jellyfin
продолжает показывать записи с битыми путями до следующего скана по расписанию.
Интеграция уже есть целиком, клиент писать не надо:
internal/jellyfin/jellyfin.go— клиент,RefreshLibraries()(:76) →POST /Library/Refresh. Тесты —internal/jellyfin/jellyfin_test.go.- Конфиг:
internal/config/config.go:99-107(Jellyfin{Enabled,URL,APIKey,Proxy,Timeout}), валидация:305-308, примерconfig.example.toml:59-64. - Проводка:
cmd/jellybit/serve.go:137-152→wrk.SetScanner(jf); интерфейсinternal/worker/worker.go:171-176.
Точка правки — гейт в transitionErr (internal/worker/worker.go:846-852):
if w.scanner != nil && state == store.StateDone. Оба пути удаления уже проходят
через ту же transition: Undo() (internal/worker/review.go:535 → :574) и
Delete() (:601 → :657). То есть база правки = расширить условие; фоновый
ctx, capFileLayout-скоуп и неблокирующая горутина переиспользуются как есть.
Что учесть
StateDeletedприходит не только от пользователя.internal/worker/reconcile.go:30-41deriveState()возвращаетStateDeletedпри!sourcePresent && !targetPresent(авто-сверка). Скан там формально уместен, но это уже не «после удаления файлов нами». Решить: гейтить по состоянию (просто, ловит и reconcile) или по факту снятия ссылок (точнее — вUndo/Deleteесть счётчик снятого, но тогда триггер уезжает из единого чекпоинтаtransitionErr).StateTargetMissing(reconcile.go:35) — цель пропала мимо нас. Кандидат по той же логике, надо явно решить, входит или нет.Dismissидёт мимо чекпоинта:internal/worker/worker.go:944пишет состояние напрямую черезw.store.SetDownloadState, минуяtransitionErr. Для dismiss это корректно (файлы не трогаются), но если вешать скан наcancelled— не сработает.Delete()при ошибке qBittorrent (internal/worker/review.go:650-652) возвращается доtransition→ ссылки сняты, скана не будет. Идемпотентный повтор дожмёт, но окно рассинхрона есть.- Порядок верный:
layouter.Undoотрабатывает доtransition, так что скан увидит уже снятые ссылки.
Спеки — здесь дыра
Про Jellyfin-скан в openspec/specs/ нет ни слова (грепом
Library/Refresh|RefreshLibraries|пересканир — ноль попаданий). Живёт только в
рукописных доках: docs/specs/architecture.md:182-196 («Пересканирование
Jellyfin», прямо сказано «После успешной раскладки (вход в done)»),
docs/specs/workflow.md:100-102.
→ Задача тянет дельту в file-layout (пакет jellyfin отнесён к этой capability —
architecture.md:44, код скоупится capFileLayout) + правку
docs/specs/architecture.md:182 и docs/specs/workflow.md:100, где формулировка
«при входе в done» станет неверной.
Тесты: internal/worker/review_test.go:88 TestScanner_FiresOnDone +
recordingScanner (:81-86). Негативных тестов «не стреляет на других состояниях»
нет → расширение безопасно, но тесты на reverted/deleted надо дописать.