## Why Команды ревью, которым нужен источник, проверяют лишь **наличие** раздачи в qBittorrent (`ensureSourcePresent`), но не её **готовность** (файлы докачаны). Недокачанную задачу можно легально припарковать в `deferred` (граф допускает `*→deferred`), а затем «Распознать заново»: она уходит в `recognizing`, LLM видит имена ещё не докачанных файлов (qBittorrent отдаёт их до завершения) и при уверенном матче срабатывает авто-раскладка (Rerecognize/Refine/SetType не ставят `force_review`) — хардлинки создаются на **неполные файлы**, задача уходит в `done`, Jellyfin сканирует половину. Даже ручной `review → Применить` не имеет preflight завершённости. Это обходит смысл состояния `completed` («готовность только когда файлы на месте») и портит целостность медиатеки — самый опасный из выявленных дефектов жизненного цикла. ## What Changes - Ввести синхронный preflight **готовности** источника `ensureSourceReady`: источник должен не только присутствовать, но и быть в готовом к раскладке классе (`classify(t.State) == classReady`). - Заменить `ensureSourcePresent` на `ensureSourceReady` во **всех** командах ревью, которым нужен источник: `Rerecognize`, `Refine`, `SetType`, `Relink`. Единый инвариант — команда, вводящая задачу в активную обработку (`recognizing`) или в раскладку, работает только с готовым источником. - Добавить ту же проверку готовности в `Apply` (сейчас он берёт торрент inline и не смотрит на его класс) — последний рубеж перед созданием хардлинков. - Недокачанный источник → отказ отдельным sentinel `ErrNotReady` (409) с actionable-сообщением «торрент ещё качается», **без** `reconcileToReality`: состояние `deferred`/`review`/… легитимно, приводить к реальности нечего — просто не даём действовать. Транспорты (HTTP/htmx и Telegram) показывают конкретный текст, а не генерик «действие недоступно». ## Capabilities ### New Capabilities ### Modified Capabilities - `review`: команды ревью, которым нужен источник, SHALL проверять его **готовность** (файлы докачаны), а не только наличие; недокачанный источник → отказ без разрушающих действий. ## Impact - Код: `internal/worker/errors.go` (новый sentinel `ErrNotReady`), `internal/worker/reconcile.go` (новый `ensureSourceReady`, удаление `ensureSourcePresent`), `internal/worker/review.go` (замена вызовов в `Rerecognize`/`Refine`/`SetType`/`Relink`, добавление проверки в `Apply`). - Транспорты: `internal/httpapi` (`classifyErr` — кейс `ErrNotReady` → 409 с текстом «торрент ещё качается»), `internal/tgbot` (ветка `ErrNotReady` в обработчике действий). Пользователь видит конкретную причину вместо тихой авто-раскладки неполных файлов; трансляция — на внешней границе. - Тесты: `internal/worker/review_test.go` — сценарии недокачанного источника для затронутых команд. - Данные: устраняет создание хардлинков на неполные файлы (целостность медиатеки Jellyfin).