Skip to content

fix(monitoring): keep every series membership and its identifier when a monitored author or series adds a book - #961

Open
m4bard wants to merge 2 commits into
Listenarrs:canaryfrom
m4bard:fix/monitoring-series-memberships
Open

m4bard wants to merge 2 commits into
Listenarrs:canaryfrom
m4bard:fix/monitoring-series-memberships

Conversation

@m4bard

@m4bard m4bard commented Sep 11, 2026

Copy link
Copy Markdown

Fixes #962.

Two commits, backend only.

The first makes the author and series monitoring jobs keep what the catalog gives them. Both mappers took book.Series?.FirstOrDefault() and wrote its name and position into the legacy Series and SeriesNumber fields, never setting SeriesMemberships, so every book that arrived through monitoring got one membership built from the legacy fallback with no identifier, and any further series was discarded. They now build the full list through the same MetadataConverters.BuildSeriesMemberships the search conversion uses, and the legacy fields are read off the primary membership after normalization so the two cannot disagree. BuildSeriesMemberships goes from private to internal for that; same assembly.

The second gives AudibleBookMetadata a SeriesAsin property and passes it as the legacy identifier at the four places that already pass Series and SeriesNumber (ToAudiobook, the add workflow, the rescan patch, the naming preview). The frontend has declared and sent seriesAsin all along; it never bound. A payload that only carries the legacy fields can now keep its identifier. The rescan guard is deliberately not widened to a payload carrying only an identifier, because the helper's fallback needs a series name and an identifier alone would wipe the book's existing memberships.

Tests: six on the mappers (two series with identifiers kept in order with the first primary, legacy fields equal to the primary, no series, blank identifier), one on the metadata model, and the existing suites unchanged. dotnet format --verify-no-changes clean.

Validated on a running install, but for the wizard add path only. Importing a fixture book through the library import wizard produced one new membership with the series identifier from the catalogue lookup on it, and its name and position matched the legacy fields. The control is the rest of the membership table: a couple of thousand pre-existing rows, none of them with an identifier, none of them changed. On the previous build the same import wrote a null identifier. The monitoring mapper half is covered by tests only, since the author sync cannot be triggered from outside and runs on a 24 hour interval. The repair of existing rows I deliberately did not run; it waits on a separate bulk refresh.

Related: #847 does the same for the import wizard and the unmatched-files add, and #768 for the Audnexus lookup and converter. With all three, every add path keeps identifiers and memberships; existing rows need a metadata rescan to pick them up.

Disclosure: drafted with Claude Code at my direction; I read the cited code at the stated commit and reviewed this before posting.

m4bard and others added 2 commits September 10, 2026 12:54
…itored author or series adds a book

Both monitoring mappers took only the first entry of the catalog's series list
and copied its name and position into the legacy Series/SeriesNumber fields.
They never set SeriesMemberships, so AudibleBookMetadata.ToAudiobook fell back
to building a single membership out of those two legacy strings, with
SeriesAsin null. Every series past the first was dropped, and the identifier
the catalog had already supplied on each entry was thrown away.

What that looks like in a library: books that arrived through a monitored
author or a monitored series carry no series identifier at all, and a book
belonging to more than one series shows only one of them. Since the series
identifier is what lets two spellings of the same series collapse onto one
tile, a localised name and its English original stay as separate tiles with
nothing to join them on.

Both mappers now build memberships from the whole catalog list through the
same MetadataConverters.BuildSeriesMemberships the search add path uses, so a
book added by monitoring gets the same shape as one added by hand. The legacy
Series/SeriesNumber columns are still populated, now read off the primary
membership so the two can't disagree.

This only changes what is written when a book is added. Rows already in the
library keep the memberships they were given; a metadata refresh re-reads them
from the provider and repairs them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ntifier

The frontend has been sending seriesAsin on the add payload for a while, and
the type it builds from declares the field, but AudibleBookMetadata had no
such property, so the value never bound to anything. It was dropped at the
model boundary and no one could see where.

The property is added beside Series and SeriesNumber and passed as the legacy
series ASIN wherever those two are already passed. Every one of those four
sites passed the pair and stopped there: ToAudiobook, the add workflow, the
metadata rescan patch and the path preview. All four pass the identifier now,
so a payload that describes its series with the three legacy fields and no
membership list lands with an identifier on the single membership built out of
them, instead of a name-and-number pair nothing can be matched on later, and
it does so whichever door it came through.

The rescan patch still rewrites an audiobook's series only when the incoming
record carries memberships, a series name or a series number, and that guard
is deliberately not widened to a payload carrying an ASIN alone. The helper's
legacy fallback needs a name to build a membership from, so an ASIN by itself
would clear the memberships the book already has rather than improve them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.

Author and series monitoring keep only the first series of a book and drop its identifier; a legacy-only add payload cannot carry one either

1 participant