Привёл набор 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>
7.4 KiB
ADDED Requirements
Requirement: Приём источника и заведение загрузки
Приём SHALL быть единым use-case, общим для всех транспортов (HTTP, Telegram,
CLI): по источнику (Ф1 — magnet) и текстовому контексту система SHALL извлечь
инфохэши, дедуплицировать по активной задаче, при отсутствии дубля завести
загрузку (download в состоянии downloading + записи download_infohash) и
отдать источник в qBittorrent (категория qbittorrent.category, savepath). Если
добавление в qBittorrent не удалось, система SHALL перевести уже заведённую
загрузку в failed (error_code qbit_add) и уведомить автора. Заведение
загрузки и запись её хешей SHALL выполняться атомарно (см. «Атомарность возврата
загрузки в активное состояние»).
Scenario: Успешный приём magnet
- GIVEN валидная magnet-ссылка и контекст
- WHEN вызывается приём
- THEN создаётся
downloadвdownloadingс записямиdownload_infohash - AND источник отдан в qBittorrent с нашей категорией
Scenario: Падение добавления в qBittorrent
- GIVEN заведённую загрузку не удалось добавить в qBittorrent
- WHEN обрабатывается ошибка добавления
- THEN загрузка переходит в
failedсerror_codeqbit_add - AND автор загрузки уведомляется
Requirement: Множество инфохэшей загрузки
Загрузка SHALL иметь одну или более записей инфохэша (download_infohash:
infohash lowercase hex, kind ∈ v1|v2). При приёме magnet-ссылки
SHALL записываться ВСЕ известные из неё хеши — гибридный magnet несёт и
btih (v1), и btmh (v2); kind определяется по длине hex (40 — v1, 64 —
v2). Когда qBittorrent сообщает для раздачи оба хеша (infohash_v1,
infohash_v2), система SHALL дописывать недостающие записи загрузке;
усечённый хеш v2-only раздачи (поле hash qBittorrent, 40 hex от v2)
записываться SHALL NOT. Сопоставление раздачи qBittorrent с загрузкой
(поллинг, discover) SHALL выполняться по любому из известных хешей. Один и
тот же infohash MAY принадлежать нескольким загрузкам во времени (повторный
приём после терминального состояния), но активной из них MUST быть не более
одной.
Scenario: Гибридный торрент раскрывает оба хеша
- GIVEN загрузка принята по magnet с v1-хешем
- WHEN qBittorrent отдаёт раздачу с заполненными
infohash_v1иinfohash_v2 - THEN у загрузки появляются обе записи (
kind=v1иv2)
Scenario: Сопоставление по v2-хешу
- GIVEN загрузка с записями v1- и v2-хешей
- WHEN поллинг находит раздачу, совпавшую только по v2-хешу
- THEN раздача сопоставляется с этой загрузкой
Requirement: Дедупликация приёма по любому из хешей
При приёме система SHALL искать активную (нетерминальную) загрузку по
любому из известных хешей и, найдя, SHALL возвращать её вместо создания
новой. Проверка активности и вставка новой загрузки с её хешами SHALL
выполняться атомарно (в одной write-транзакции), поддерживая инвариант «не
более одной активной загрузки на infohash». Отдельного снимаемого/
восстанавливаемого ключа идемпотентности в схеме быть SHALL NOT — активность
выводится только из state.
Scenario: Повторный приём при активной загрузке
- GIVEN активная загрузка с infohash
h - WHEN принимается magnet с тем же
h - THEN новая загрузка не создаётся, возвращается существующая
Scenario: Повторный приём после завершения
- GIVEN загрузка с infohash
hв терминальном состоянии (done) - WHEN принимается magnet с тем же
h - THEN создаётся новая загрузка со своим ULID и записью
h
Requirement: Атомарность возврата загрузки в активное состояние
Система SHALL атомарно (в одной write-транзакции) проверять на каждом пути, возвращающем загрузку из терминального состояния в активное (ручной retry, воскрешение фоновой сверкой, повторная раскладка/relink) или создающем её (приём, adopt чужой раздачи), что никакая другая активная загрузка не владеет любым из хешей этой, и при владении SHALL отказывать в переходе, сохраняя инвариант «не более одной активной загрузки на infohash». Отказ SHALL происходить до побочных эффектов во внешних системах (повторного добавления торрента в qBittorrent).
Та же проверка SHALL применяться к дозаписи хешей загрузке (раскрытие гибридного торрента): хеш, которым владеет другая активная загрузка, дописан быть SHALL NOT. Прямой перевод терминальной загрузки в активное состояние в обход этой проверки SHALL отклоняться хранилищем (механический бэкстоп вместо удалённого unique-индекса).
Scenario: Retry при занятом хеше
- GIVEN загрузка #1 в
failedс хешемh, и другая активная загрузка #2 с тем жеh - WHEN пользователь вызывает retry для #1
- THEN переход отклоняется с пояснением, #1 остаётся в
failed - AND активной по
hостаётся #2