Hard/soft fail handling and release blacklist #87
Merged
naps62-yolo
merged 2 commits from 2026-08-22 23:42:36 +01:00
issue/24-fail-handling into main
Labels
Clear labels
area/api
area/ci
area/compat
area/core
area/daemon
area/db
area/dl
area/indexer
area/infra
area/meta
area/parse
area/probe
area/subs
area/web
difficulty/easy
difficulty/hard
difficulty/moderate
difficulty/trivial
phase/1-skeleton
phase/2-logic
phase/3-sourcing
phase/4-movies
phase/5-ui
phase/6-tv
phase/7-people
phase/8-compat
phase/9-subtitles
type/bug
type/chore
type/feature
type/test
arr-api
CI and test harness
arr-compat
arr-core
arr-daemon
arr-db
arr-dl
arr-indexer
workspace and tooling
arr-meta
arr-parse
arr-probe
arr-subs crate: providers, extraction, translation, sync
web/
bounded, obvious approach, few files
subtle correctness or cross-cutting
multiple files, judgement, an interface to design
one file, mechanical, no design decisions
workspace, CI, config, database, empty API and SPA
parsing and policy engine, pure, no network
TMDB and Prowlarr, read-only
movies end to end
search, buckets, library views, queues
seasons, episodes, tracking, derived status
owner tags and notifications
Jellyseerr shim
build order: subtitles, DESIGN.md §15
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: yolo/arr#87
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #24. DESIGN.md §5.7, §6.3.
The blacklist moves out of the grab loop into
arr-db::blacklist, and is applied where a release is classified rather than where one is picked. That gets §6.3's "including by RSS" for free — RSS sync will call the samestore_release— and it makes the stored row say why: a blacklisted release isrejectedunder the ruleblacklisted, so §9.3's manual view names it instead of offering it as a clean match.Both keys now do work. The normalised name catches a re-upload; the infohash catches the same torrent re-listed under a new name. A
.torrentlink hides its infohash until Transmission has fetched it, so that case is caught after the add: the name is blacklisted too, nograbsrow is written, and the torrent is removed only when this tick added it — a duplicate is left seeding (§7.3).Soft fails already stored a waiver.
GET /api/movies/{movie_id}/filesis what carries it out, as the relaxed rule's name, sharing its vocabulary withRelease::rejected_rule.A hard fail still blacklists, fails the grab and reopens the gap; the next candidate comes from the next tick's search. Neither failure mode touches the torrent.
Not in scope: a grab whose torrent has vanished from Transmission. Two comments deferred that to this issue, but a hand-removed torrent is neither a hard nor a soft fail — filed as #86 and the comments now point there.
Verification
just ci— 237 tests, all passing. New coverage:arr-db blacklist::tests— both keys recorded and matched, no duplicate rows per failure, magnet infohash blocks a renamed candidategrab::tests::a_blacklisted_release_is_cached_as_rejectedgrab::tests::a_blacklisted_infohash_never_becomes_a_grabimport::tests::an_english_only_kids_import_carries_a_waivermovies::tests::a_movie_file_carries_its_waiversearch::tests::manual_releases_are_classified_and_name_rejection_rulesextended with the blacklisted case🤖 Generated with Claude Code
The blacklist moves to arr-db so every trigger that classifies a release shares one check — targeted search today, RSS matching when it lands. Applying it during classification rather than at selection also makes the stored row say `blacklisted`, which is what keeps §9.3's manual view from offering a hard-failed release as a clean match. Both §6.3 keys now do work: the normalised name catches a re-upload, and the infohash catches the same torrent re-listed under a new name — the latter only after Transmission has fetched a `.torrent`, so that grab is undone rather than recorded. Soft-failed imports already stored a waiver; `GET /api/movies/{id}/files` is what carries it out. Closes #24 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>@@ -393,0 +421,4 @@release_name: &str,added: &arr_dl::AddedTorrent,) -> Result<(), GrabError> {blacklist::add(The post-add hash check blacklists the release name but leaves the
releasesrow written duringstore_releasemarked eligible. Until another search overwrites it,GET /api/movies/{id}/releasesoffers this known-blacklisted.torrentas eligible. Updatewinner.idto rejected withblacklistedhere.@@ -393,0 +421,4 @@winner: &Eligible,added: &arr_dl::AddedTorrent,) -> Result<(), GrabError> {let release_name = &winner.name;Fixed in
b224136.drop_blacklisted_torrentnow writes the row back asrejectedwith ruleblacklistedbefore it decides what to do with the torrent, so the cached row stops reading eligible in the same tick that refuses the release rather than waiting for the next search to overwrite it.a_blacklisted_infohash_never_becomes_a_grabasserts the verdict and the rule alongside the existing grab and torrent assertions.