Files
avandClaude Opus 4.8 512567c8ba Рефакторинг границ capabilities: цепочка загрузка→матч→ревью→раскладка (openspec)
Привёл набор capabilities в OpenSpec к цепочке обработки, чтобы имя capability
отвечало одному поведению. Чисто по спекам, код и поведение системы не меняются.

Change refactor-capability-boundaries (архивирован):
- recognition разделён на recognition (разбор LLM) + metadata-match (сверка с базами)
- review выделен из web-ui + мигрирован из docs/specs/review-ux.md
- новые capability из docs/specs: file-layout, download-tracking, notifications
- identity очищен до инфра-id; приём (инфохэши, дедуп, ядро приёма) — в ingest
- уведомление о рассинхроне перенесено из state-reconciliation в notifications
- дубль владения путём и безопасного undo оставлен в state-reconciliation

Итог: 11 capabilities, openspec validate --strict проходит (+37/−11 требований).
Источник истины по мигрированным темам переехал в openspec/specs (шапки в docs).
Снят пункт беклога «Пересмотр набора capabilities».

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 21:17:51 +03:00

5.5 KiB
Raw Blame History

ADDED Requirements

Requirement: Поллинг qBittorrent и сопоставление состояний

Worker SHALL периодически (worker.poll_interval, дефолт 5 с) опрашивать qBittorrent и сопоставлять его состояния раздачи с состоянием загрузки в БД. Готовые к раскладке состояния (uploading/stalledUP/pausedUP/stoppedUP/ queuedUP/forcedUP, с учётом различий имён между qBit v4 и v5) SHALL переводить загрузку в completed. Ещё качающиеся состояния (downloading/stalledDL/ metaDL/…) SHALL оставлять её в downloading.

Scenario: Раздача завершилась

  • GIVEN загрузка в downloading
  • WHEN qBittorrent сообщает состояние stalledUP и файлы на месте
  • THEN загрузка переходит в completed

Requirement: Готовность только когда файлы на месте

Переходные состояния qBittorrent система SHALL трактовать как «ждём» (moving/checkingUP/checkingResumeData/allocating): оставаться в downloading и НЕ объявлять готовность, даже если выставлены флаги UP, пока qBit не завершит перенос/проверку. Финальные пути файлов система SHALL брать из API после завершения переноса.

Scenario: Ждём завершения переноса

  • GIVEN загрузка, у которой qBittorrent в состоянии moving
  • WHEN идёт тик поллинга
  • THEN загрузка остаётся в downloading, готовность не объявляется

Requirement: Таймауты-предохранители downloading

Система SHALL переводить metaDL/forcedMetaDL дольше magnet_timeout (дефолт 24h, редкий предохранитель) в failed (error_code magnet_timeout), а stalledDL дольше stuck_after — в stuck (error_code stalled). Возраст система SHALL считать от времени добавления в qBittorrent (added_on), а не от создания задачи, чтобы базис переживал retry и усыновление. Долгий metaDL система НЕ SHALL убивать агрессивно (медленные трекеры — норма).

Scenario: Завис на метаданных дольше таймаута

  • GIVEN раздача в metaDL дольше magnet_timeout от added_on
  • WHEN идёт тик поллинга
  • THEN загрузка переходит в failed с error_code magnet_timeout

Requirement: Ошибка qBittorrent переводит в failed

Состояния error/missingFiles система SHALL трактовать как настоящий провал и переводить загрузку в failed (error_code qbit_error) — в отличие от таймаутов-предохранителей, такой провал сверкой не воскрешается.

Scenario: qBit сообщает об ошибке

  • GIVEN раздача в состоянии missingFiles
  • WHEN идёт тик поллинга
  • THEN загрузка переходит в failed с error_code qbit_error

Requirement: Усыновление раздач по категории или тегу

Worker SHALL периодически сверять раздачи qBittorrent с БД и усыновлять те, у которых наша категория (qbittorrent.category) ИЛИ тег (qbittorrent.tag), а записи в БД ещё нет, заводя для них загрузку в состоянии downloading. Категория ставится на добавляемые нами раздачи (push); тег позволяет подхватить уже существующую раздачу (pull), не трогая её категорию и файлы.

Scenario: Подхват существующей раздачи по тегу

  • GIVEN в qBittorrent есть раздача с тегом qbittorrent.tag, которой нет в БД
  • WHEN worker сверяет qBittorrent с БД
  • THEN для раздачи заводится загрузка в состоянии downloading

Requirement: Переходы состояний под per-download блокировкой

Все переходы состояний загрузки SHALL проходить через worker под per-download блокировкой, чтобы два транспорта не гонялись за одно состояние. Состояние SHALL быть персистентным в SQLite; активность загрузки SHALL выводиться только из state, без отдельного флага.

Scenario: Команды сериализуются

  • GIVEN две одновременные команды к одной загрузке из разных транспортов
  • WHEN они обрабатываются
  • THEN переходы применяются последовательно под блокировкой, без гонки