Обработка рассинхрона состояния с реальностью (state-reconciliation)
Распознаём ручное удаление источника (раздача в qBittorrent) и/или цели (разложенные хардлинки) и отражаем его в состоянии задачи, без автодействий. - Новая capability state-reconciliation (OpenSpec): фоновая сверка по матрице «источник × цель» → состояния target_missing/orphaned/deleted, переходы и самовосстановление (healing). - worker: reconcileDesync в Poll (только разложенные/desync-задачи), дебаунс пропажи источника (порог [worker].source_missing_threshold) и синхронный preflight перед действиями (relink/recognize/apply/undo) — не доверяем state в БД. - layout.Undo: отказ снять последнюю копию (nlink<=1 или нет источника), отказ всего батча без частичного отката (ErrLastCopy). - store: единый список terminalStates для IsTerminal и FindActiveByInfohash (иначе семантика «активности» разъезжается), столбец source_miss_count, миграция 0003. - httpapi/web и Telegram: показ новых состояний и уведомления о рассинхроне. - Доки: workflow.md, jellyfin-layout.md, database.md (+0003), config. Change заархивирован в openspec/changes/archive, дельта влита в openspec/specs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+15
-28
@@ -25,38 +25,25 @@
|
||||
матч в базе), [jellyfin-layout.md](specs/jellyfin-layout.md) (папка
|
||||
сериала с провайдер-id).
|
||||
|
||||
### Рассинхрон состояния с реальностью (удалённый торрент / файлы)
|
||||
### Удаление средствами jellybit («единое окно», path 2)
|
||||
|
||||
Состояние jellybit может разойтись с тем, что реально лежит на диске.
|
||||
Несколько сценариев разной остроты:
|
||||
Распознавание **ручного** удаления (источник из qBittorrent / цель из
|
||||
Jellyfin) и пометка рассинхрона уже сделаны: фоновая сверка по матрице
|
||||
«источник × цель» → состояния `target_missing`/`orphaned`/`deleted`,
|
||||
безопасный `undo` (не снимает последнюю копию, `nlink <= 1`), синхронный
|
||||
preflight перед действиями. См. `openspec/specs/state-reconciliation/`,
|
||||
[workflow.md](specs/workflow.md) → «Сверка с реальностью».
|
||||
|
||||
- **Жёсткий — удалён источник.** Раздачу удаляют (вручную или авто по
|
||||
достижении seed limit), и qBittorrent стирает скачанные файлы. Тогда
|
||||
хардлинк в библиотеке становится **последней** ссылкой на inode, и
|
||||
обычный `undo` (`unlink` цели + чистка пустых каталогов) сотрёт
|
||||
единственную копию насовсем — прямая потеря данных. Инвариант «источник
|
||||
неприкосновенен» молчаливо перестаёт держаться: источника уже нет.
|
||||
- **Мягкий — удалена цель.** Файлы убрали из библиотеки Jellyfin (вручную
|
||||
или из самого Jellyfin), а jellybit по-прежнему числит загрузку в
|
||||
`done`. Состояние врёт: ссылок уже нет, а сервис думает, что всё
|
||||
разложено.
|
||||
|
||||
Нужно продумать сверку записанного состояния (`file_link`, состояние
|
||||
загрузки) с фактом на ФС:
|
||||
|
||||
- как `worker` реагирует на исчезновение раздачи из qBittorrent
|
||||
(состояние/пометка загрузки);
|
||||
- как `undo` защищается, когда источник недоступен — например,
|
||||
отказываться удалять, если у целевого файла счётчик ссылок == 1 (нет
|
||||
второй копии) или исходный путь не существует, и явно об этом сообщать.
|
||||
Откат снимает **лишний** хардлинк, а не последнюю копию файла;
|
||||
- как ловить пропажу целевых файлов и отражать её в состоянии (напр.
|
||||
периодическая сверка или проверка при показе — «разложено, но файлов
|
||||
нет»), чтобы можно было осознанно перепривязать/переразложить.
|
||||
Осталось (path 2) — продолжение «единого окна»: удалять просмотренное
|
||||
**из самого jellybit**, не идя руками в qBittorrent/Jellyfin. Нужно
|
||||
продумать: команду удаления (снять наши хардлинки + опц. удалить раздачу из
|
||||
qBittorrent с файлами), подтверждение осознанности (а не случайный клик) и
|
||||
как это сочетается с инвариантом «источник неприкосновенен», когда
|
||||
пользователь сам просит убрать источник.
|
||||
|
||||
Связано: [ADR-2026-06-13-hardlinks](adr/ADR-2026-06-13-hardlinks.md),
|
||||
[architecture.md](specs/architecture.md) → «Раскладка файлов» (undo,
|
||||
инвариант источника), [workflow.md](specs/workflow.md) (`done → reverted`).
|
||||
[architecture.md](specs/architecture.md) → «Раскладка файлов»,
|
||||
[workflow.md](specs/workflow.md).
|
||||
|
||||
### Наблюдаемость: метрики и учёт стоимости LLM
|
||||
|
||||
|
||||
Reference in New Issue
Block a user