Приём: усыновление присутствующего в qBittorrent торрента вместо дубль-Add (409)

processCatched перед Add проверяет присутствие торрента в qBittorrent (один
листинг на тик): если раздача уже есть — усыновляем (promote catched→downloading
без повторного Add и без LLM-namer, имя из раздачи), иначе добавляем как раньше.
Это убирает бесконечный цикл дубль-Add → 409 → ретрай и лишние вызовы LLM.
Инвариант приёма «одна активная на infohash» делает различие «наш/чужой»
ненужным. source_type перечитывается под замком (сужение гонки апгрейда F6);
при недоступности qBittorrent тик пропускается без вызова LLM.

Дедуп на приёме (дубль на уже активную задачу) теперь отражается явным ответом
бота «дубль уже активной #id — добавление отменено».

Спека download-tracking обновлена (OpenSpec change заархивирован); закрыта
задача беклога review-f2-promote-without-add.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-07-10 18:36:47 +03:00
co-authored by Claude Opus 4.8
parent 0c9421f4c1
commit b8657120fe
13 changed files with 544 additions and 47 deletions
+4
View File
@@ -269,6 +269,7 @@ func (f *fakeStore) SetCandidateChosen(_ context.Context, _, _ string) error { r
type fakeQbt struct {
torrents []qbt.Torrent
torrentsErr error
onTorrents func() // вклинивается в момент листинга (симуляция гонки между снимком и re-read)
added []qbt.AddRequest
addErr error
files []qbt.File
@@ -288,6 +289,9 @@ type renameCall struct {
// регрессии: раздача, усыновлённая по тегу, имеет чужую категорию и не должна
// теряться при поиске по infohash.
func (f *fakeQbt) Torrents(_ context.Context, category string) ([]qbt.Torrent, error) {
if f.onTorrents != nil {
f.onTorrents()
}
if f.torrentsErr != nil {
return nil, f.torrentsErr
}