Скан Jellyfin (POST /Library/Refresh) слался только при входе в done.
После Undo (reverted) и Delete (deleted) наши хардлинки сняты, а Jellyfin
держал битые записи до скана по расписанию.
Гейт скана в едином чекпоинте transitionErr переведён с state == done на
предикат triggersScan(state) по множеству {done, reverted, deleted}: гейт по
состоянию-цели естественно ловит пользовательские Undo/Delete и
reconcile-производный deleted, идемпотентно. target_missing/orphaned —
промежуточный рассинхрон (ждём relink/лечения) — исключены.
OpenSpec: заведена и влита дельта file-layout (требование
«Пересканирование Jellyfin после изменения библиотечных ссылок»); change
архивирован. Синк рукописных доков architecture.md/workflow.md. Тесты:
скан стреляет на reverted и deleted, молчит на входе вне множества.
Закрыта задача беклога jellyfin-skan-posle-udaleniya.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
57 lines
5.1 KiB
Markdown
57 lines
5.1 KiB
Markdown
## ADDED Requirements
|
|
|
|
### Requirement: Пересканирование Jellyfin после изменения библиотечных ссылок
|
|
|
|
При сконфигурированном пересканировании Jellyfin (секция `[jellyfin]` включена) система SHALL при входе задачи в одно из состояний множества `{done, reverted, deleted}` **неблокирующе** просить Jellyfin пересканировать медиатеку (`POST /Library/Refresh`, скан всех библиотек). Эти три состояния — точки, где раскладка задачи **улеглась** так, что видимый Jellyfin каталог мог рассинхронизироваться с диском: `done` — наши хардлинки разложены (или восстановлены сверкой); `reverted` — Undo снял наши ссылки; `deleted` — ссылки сняты (Delete) либо констатировано их отсутствие (сверка), задача терминальна.
|
|
|
|
Условие срабатывания система SHALL проверять **по состоянию-цели перехода** в
|
|
едином чекпоинте записи состояния. Такой гейт SHALL естественно покрывать как
|
|
пользовательские команды (Undo → `reverted`, Delete → `deleted`), так и
|
|
reconcile-производный `deleted` — инициатор перехода роли не играет; повторный/
|
|
лишний скан безвреден (инкрементальный скан дёшев, операция идемпотентна).
|
|
|
|
Состояния **вне** этого множества система сканировать SHALL NOT. Сюда входят как
|
|
входы, не меняющие наши ссылки (`review`, `linking`, `cancelled` через Dismiss),
|
|
так и **промежуточные состояния рассинхрона** `target_missing` и `orphaned`: там
|
|
раскладка ещё не улеглась — задача ждёт relink/восстановления и может
|
|
«залечиться» обратно в `done`, поэтому скан на них система откладывает, а не шлёт
|
|
на каждое колебание сверки. `target_missing` система не сканирует сознательно,
|
|
хотя цель там пропала: это внешняя пропажа при живом источнике, не наше снятие.
|
|
|
|
Скан система SHALL выполнять **вне** блокировки воркера, в фоновом контексте и в
|
|
отдельной горутине, со scoped-логгером задачи для корреляции. Недоступность
|
|
Jellyfin на состояние задачи влиять SHALL NOT — ошибка вызова лишь логируется
|
|
(её пишет клиент Jellyfin как запись внешнего вызова). Если пересканирование не
|
|
сконфигурировано (`[jellyfin]` выключено), скан не дёргается ни в одном из этих
|
|
переходов.
|
|
|
|
#### Scenario: Скан после раскладки
|
|
|
|
- **GIVEN** пересканирование Jellyfin включено
|
|
- **WHEN** задача входит в `done` после успешной раскладки хардлинков
|
|
- **THEN** система неблокирующе дёргает `POST /Library/Refresh`
|
|
|
|
#### Scenario: Скан после отката (Undo)
|
|
|
|
- **GIVEN** пересканирование Jellyfin включено, задача в `done` с разложенными ссылками
|
|
- **WHEN** пользователь выполняет Undo и задача входит в `reverted` (наши ссылки сняты)
|
|
- **THEN** система неблокирующе дёргает `POST /Library/Refresh`
|
|
|
|
#### Scenario: Скан после удаления (Delete)
|
|
|
|
- **GIVEN** пересканирование Jellyfin включено, задача в `done`
|
|
- **WHEN** пользователь выполняет Delete и задача входит в `deleted` (наши ссылки сняты)
|
|
- **THEN** система неблокирующе дёргает `POST /Library/Refresh`
|
|
|
|
#### Scenario: Без конфигурации Jellyfin скан не дёргается
|
|
|
|
- **GIVEN** пересканирование Jellyfin выключено (`[jellyfin]` не сконфигурировано)
|
|
- **WHEN** задача входит в `done`, `reverted` или `deleted`
|
|
- **THEN** система скан не дёргает
|
|
|
|
#### Scenario: Вход вне множества не сканирует
|
|
|
|
- **GIVEN** пересканирование Jellyfin включено
|
|
- **WHEN** задача входит в состояние вне `{done, reverted, deleted}` (например, `review` или промежуточный `target_missing`)
|
|
- **THEN** система скан не дёргает
|