- Раскладка docs/ приведена к канону 2: заведены passport/architecture/ database/security/review и research; docs/specs, drafts, backlog, review/ и BRIEF.md разобраны и удалены, беклог переехал в docs/tasks (34 задачи, 6 целей, слаги на английский). - Нарративы specs удалены как дубли openspec-спек после поимённой сверки; остаток заведён задачами (редактор маппинга ревью, крайние случаи именования), отказ от сущности title промоутнут в ADR. - Проектные копии агентов и скиллов ревью/пайплайна удалены в пользу плагинов av-dev-pm и av-dev-pipeline; в task gate добавлен шаг canon вместо er-schema.
58 lines
4.0 KiB
Markdown
58 lines
4.0 KiB
Markdown
## Why
|
||
|
||
Пойманная (`catched`) загрузка, чей торрент **уже присутствует в qBittorrent**
|
||
(добавлен раньше вручную/другим клиентом или прошлой попыткой jellybit), уходит в
|
||
бесконечный цикл: `processCatched` на каждом тике зовёт `qbt.Add`, qBittorrent
|
||
отбивает дубль (`409 Conflict`), сбой трактуется как транзиентный → задача
|
||
остаётся в `catched` → повтор, и на каждом безнадёжном тике впустую вызывается
|
||
LLM-namer. Диагноз: `docs/tasks/items/review-f2-promote-without-add.md`.
|
||
|
||
Решение: перед добавлением проверять присутствие торрента в qBittorrent. Раз
|
||
инвариант приёма гарантирует, что до воркера доходит лишь загрузка, для которой в
|
||
jellybit нет другой активной задачи (дубль на активную отсекается ещё на приёме),
|
||
присутствие торрента в qBittorrent означает «его надо **усыновить**» — довести до
|
||
`downloading` без повторного `add` и разложить, а не пытаться добавить дубль и
|
||
ловить 409.
|
||
|
||
Отдельно: повторное добавление торрента, который jellybit **уже ведёт активной
|
||
задачей**, транспорт должен явно отражать как дубль (сообщение «добавление
|
||
отменено»), а не молчаливым «уже в работе».
|
||
|
||
## What Changes
|
||
|
||
- В `processCatched` перед `qbt.Add` — **проверка присутствия торрента в
|
||
qBittorrent** (один листинг на тик). Присутствует → `catched → downloading`
|
||
**без `add`** (усыновление; `display_name` из имени раздачи, без LLM); нет →
|
||
прежний путь добавления. Проверка — **до namer**, чтобы не жечь LLM.
|
||
- При недоступности qBittorrent (листинг не удался) тик пропускается без вызова
|
||
LLM; предел ретрая — существующий предохранитель `catch_timeout`.
|
||
- Гонка апгрейда F6 сужается: `source_type` перечитывается под блокировкой
|
||
переходов перед добавлением.
|
||
- Транспорт Telegram на дедуп приёма (дубль на уже активную задачу) отвечает
|
||
явным «дубль уже активной #id — добавление отменено» (+ лог), без создания
|
||
новой записи.
|
||
|
||
## Capabilities
|
||
|
||
### New Capabilities
|
||
|
||
<!-- нет новых capability -->
|
||
|
||
### Modified Capabilities
|
||
|
||
- `download-tracking`: требование «Добавление пойманной загрузки в qBittorrent»
|
||
дополняется проверкой присутствия и усыновлением (promote без повторного
|
||
`add`) при наличии торрента, перечитыванием источника под замком и пропуском
|
||
тика при недоступности qBittorrent.
|
||
|
||
## Impact
|
||
|
||
- Код: `internal/worker/worker.go` (`processCatched`, presence-check,
|
||
усыновление вместо повторного `add`), `internal/tgbot/bot.go` (текст ответа на
|
||
дедуп).
|
||
- Внешние вызовы: убирает лишние `qbt.Add` (и 409) и `chat.completions`
|
||
(LLM-namer) на повторах; добавляет один `qbt.Torrents`-листинг на тик в
|
||
`processCatched`.
|
||
- Тесты: `internal/worker/catched_test.go`.
|
||
- **БД-миграции, новых состояний, конфигурации и внешнего API — нет.**
|