Skip to content

Retarget cross-provider duplicate book rows to the grabbed book on shared edition identity - #113

Open
jbob06 wants to merge 1 commit into
Chaptarr:developfrom
jbob06:fix/111-cross-provider-duplicate-retarget
Open

Retarget cross-provider duplicate book rows to the grabbed book on shared edition identity#113
jbob06 wants to merge 1 commit into
Chaptarr:developfrom
jbob06:fix/111-cross-provider-duplicate-retarget

Conversation

@jbob06

@jbob06 jbob06 commented Aug 31, 2026

Copy link
Copy Markdown

Fixes #111

Problem

RetargetSameWorkMatchesToGrabbedBook only retargets an import decision back to the grabbed book row when the two rows share a work-level provider ID (WorkIdMatcher.WorkProviderIdMatches - hc:/gr:/ol: intersection). Two rows created for the same real book via different metadata providers (one Hardcover-sourced, one Goodreads-sourced, with no cross-reference between them) never share a work ID.

Concrete repro from my own library: a monitored book (BookId 29083, hc:585413) was grabbed and downloaded successfully. A separate, never-monitored duplicate row for the same real book (BookId 29100, gr:200474660) existed from an unrelated author-bibliography re-discovery pass. Import matched the completed download to BookId 29100 instead of BookId 29083, and since there's no work-ID overlap between the two rows, the retarget safety net declined to fix it up - the import was permanently rejected:

Rejected: Completed download was grabbed for 'Fate Hollow Academy: Term 1' (BookId 29083, work hc:585413),
but import matched 'Fate Hollow Academy' (BookId 29100, work gr:200474660).

No retry ever succeeds, since the matcher makes the same choice every time. Full writeup in #111.

Fix

Add a second, independent signal alongside the existing work-ID check: if the matched edition already exists under the grabbed book row via a shared edition-level identifier (ISBN, ASIN, Audible ASIN, or a provider edition ID), that's sufficient proof the two rows represent the same book - two different books can't share an ISBN/ASIN. The retarget still only ever lands on a concrete edition the grabbed row already owns (via the existing FindEquivalentEditionForTargetBook lookup) - no cloning or synthesis of editions. The existing same-author and same-media-type guards in the baseline identity check are unchanged.

WorkIdMatcher.cs itself is untouched, so its other callers (EbookColocateOnAudiobookImportHandler, EbookColocationPlanner, BookService, BookController, ReleaseController) are unaffected. The change is scoped to one method in DownloadedBooksImportService.cs.

Known limitation

This only rescues the case where the duplicate rows' editions actually share an edition-level identifier. If they share neither a work ID nor any edition ID, the import still (correctly, conservatively) gets rejected - no safe signal remains to retarget on, and no regression from that path.

Testing

Two tests added to DownloadedBooksImportServiceFixture.cs, using the real incident's BookIds:

  • should_retarget_cross_provider_duplicate_row_match_to_grabbed_book_when_edition_identity_matches - the repro; fails on develop, passes with this fix.
  • should_not_retarget_cross_provider_row_match_when_no_shared_work_or_edition_identity - the safety boundary: no work-ID overlap and no edition-ID overlap still rejects, with the original error message, and the decision's book is left untouched (no misfiling).

Verified via Docker (mcr.microsoft.com/dotnet/sdk:10.0):

  • dotnet build src/Chaptarr.sln - clean, 0 errors.
  • dotnet test src/Chaptarr.Core.Test/Chaptarr.Core.Test.csproj - 2854/2854 passing, 0 failures (full suite, no regressions).

…ared edition identity

RetargetSameWorkMatchesToGrabbedBook only retargeted an import decision
back to the grabbed book row when the two rows shared a work-level
provider ID (WorkIdMatcher.WorkProviderIdMatches). Two rows created for
the same real book via different metadata providers (e.g. one
Hardcover-sourced, one Goodreads-sourced) never share a work ID, so a
completed, tracked download could permanently fail to import if the
matcher happened to resolve to the wrong (unmonitored duplicate) row -
no retry ever succeeds, since the matcher makes the same choice every
time.

Add a second, independent signal: if the matched edition already exists
under the grabbed book row via a shared edition-level identifier (ISBN,
ASIN, Audible ASIN, or a provider edition ID), that's sufficient proof
the two rows represent the same book, since two different books cannot
share an ISBN/ASIN. The retarget still only ever lands on a concrete
edition the grabbed row already owns - no cloning or synthesis. The
existing same-author and same-media-type guards are unchanged.

Fixes Chaptarr#111
@jbob06
jbob06 requested a review from robertlordhood as a code owner August 31, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate book row (from author-bibliography re-discovery) hijacks import matching for the correctly-monitored row

1 participant