Skip to content

fix(indexer): read the author after a series label so a wrong-author release is rejected (#2863) - #2872

Merged
vavallee merged 1 commit into
mainfrom
fix/2863-series-label-attribution
Sep 29, 2026
Merged

vavallee merged 1 commit into
mainfrom
fix/2863-series-label-attribution

Conversation

@vavallee

Copy link
Copy Markdown
Owner

Closes #2863

Summary

conflictingTitleAuthor only read an attribution straight after the title (<title> by <author>) or after a spaced dash. A series label in between hid it, so "Heart of Glass, Skye Druids (03) by Donna Grant EPUB" was accepted on its title and grabbed for Jennifer Hillier's "Heart of Glass".

Change 1, the parser (title_identity.go): when the release starts with the requested title and neither existing form applies, seriesLabelAttribution looks for the first whole word by in the part after the title, within 8 words, and reads the words after it up to a format, release marker or digit led token (EPUB, retail, 2019...). That string goes through the existing author comparison unchanged, so aliases, initials, surname first order, coauthors and the surname only escape all still work. A by after narrated/read/translated/uploaded and similar is ignored. If nothing parses, the release is accepted on title exactly as today.

Change 2, the wiring (debug.go): on main, filterRelevantDebug never called conflictingTitleAuthor. That is the filter both production paths run (SearchBookWithOutcomes for auto grab, SearchBookWithDebug for the interactive panel); filterRelevant is only the fallback for searchers that cannot report outcomes. So change 1 alone would have been inert in production. filterRelevantDebug now runs the same guard (full and primary title) and records the drop as "release names a different author for this title".

This overlaps draft #2812, which folds both filters into one implementation and also brings over the title identity gate. This PR takes only the author guard. If #2812 lands after this, resolving the conflict is dropping my block in filterRelevantDebug in favour of filterRelevantDetailed; seriesLabelAttribution is untouched by it. #2813 does not touch title_identity.go or debug.go.

Side effect worth knowing: because of change 2, the #2502 author guard (e.g. "Coup D'Etat - Edward Luttwak" for Ben Coes) now also reaches real searches. The #2502 title identity gate still does not; that stays with #2812.

How it was verified

  • New tests in title_identity_test.go:
    • TestFilterRelevantSeriesLabelAttribution: 24 cases through both filterRelevant and filterRelevantDebug. The issue case, the right author in the same shape, initials, "Hillier, Jennifer", surname only, "by A and B", #3, (Series Book 2), 3 ... [retail] 2019, the unchanged Title - Series 03 - Wrong Author form, "Stand by Me" and "Death by Chocolate" with right and wrong authors, narrator credit, and releases with no author.
    • TestConflictingTitleAuthorSeriesLabelAlias: an attribution matching only an alias token set is not a conflict.
    • TestSeriesLabelAttributionReachesSearchEntrypoints: a fake newznab feed through SearchBookWithDebug and SearchBookWithOutcomes; the wrong release is dropped and the right one kept.
  • Fail before, against main's code: 13 subtests fail, all for the stated reason (kept=true, want false on every wrong author series label case in both filters; SearchBookWithOutcomes/SearchBookWithDebug kept the wrong author release; alias test "not read as a conflicting attribution"). filterRelevantDebug also kept Title - Series 03 - Wrong Author, which filterRelevant already rejected, confirming the missing guard.
  • Mutations, each compiles and vets:
    • by detection disabled: all three new tests fail.
    • guard removed from filterRelevantDebug: TestSeriesLabelAttributionReachesSearchEntrypoints fails for both entry points.
    • narrator exclusion removed: .../narrated_by_Donna_Grant_MP3 fails.
    • file token truncation removed: .../(2019)_[for_fans_of_Jennifer_Hillier] fails.
  • go build ./... && go vet ./... clean; go test ./cmd/... ./internal/... exit 0; golangci-lint run ./internal/indexer/... 0 issues.

Checklist

  • Tests added
  • Changelog fragment (changelog.d/2863-series-label-attribution.md)

🤖 Generated with Claude Code

https://claude.ai/code/session_016fJcCVbNnKsmj2MAAMwWj9

…release is rejected (#2863)

conflictingTitleAuthor only read an attribution directly after the title
("<title> by <author>") or after a spaced dash. A series label in between,
as in "Heart of Glass, Skye Druids (03) by Donna Grant EPUB", hid it, so the
release was accepted on its title alone and grabbed for Jennifer Hillier's
"Heart of Glass".

When the release starts with the requested title and neither existing form
applies, look for the first "by" in the part after the title, within a short
series label, and read the words after it (up to a format, release marker or
year) as the attribution for the existing author comparison. A "by" after a
narrator, translator or uploader word is ignored, and a release with no
parsable attribution is accepted as before.

filterRelevantDebug, which both production search paths run
(SearchBookWithOutcomes for automatic search, SearchBookWithDebug for the
interactive panel), never called conflictingTitleAuthor, so the fix would
not have reached a real search. It now runs the same guard and records the
drop reason. Draft #2812 folds both filters into one implementation; this
is the minimal slice of that needed for #2863.

Signed-off-by: vavallee <vavallee@protonmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016fJcCVbNnKsmj2MAAMwWj9

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, focused fix. Two observations, neither blocks.

title_identity.go:114 -- seriesLabelAttribution returns empty on the first credit-role by rather than continuing. A release like Heart of Glass, Skye Druids 03 narrated by Donna Grant by Jennifer Hillier EPUB would have no attribution detected and pass through on title alone. False negative, not false positive -- conservative and correct. The narrator test case at title_identity_test.go:102 shows the intended behaviour; the pathological two-by form is not documented.

title_identity.go:114 -- i == 0 guard is dead code. seriesLabelAttribution is only reached after CutPrefix(normalizedRelease, normalizedTitle plus by ) at line 28 fails. If rest began with by, that prefix check would already have matched; seriesLabelAttribution would never run. Harmless defensive check.

Test coverage is thorough: 24 table cases across both filter paths, an alias test, and end-to-end SearchBookWithDebug and SearchBookWithOutcomes smoke tests. Mutation evidence in the PR description is convincing. Side effect (activating the #2502 guard in filterRelevantDebug) is correctly identified and expected.

— 🤖 Bindery triage bot (automated). Reply to correct me; a human will see it.

@codecov

codecov Bot commented Sep 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.87179% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/indexer/title_identity.go 93.33% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@vavallee
vavallee merged commit 841c1ce into main Sep 29, 2026
42 of 43 checks passed
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.

Wrong-author release grabbed when a series label sits between the title and "by <author>"

1 participant