The artist page's "In library" count was a snapshot of the Library feed
taken when the document was built, over a feed that only loads when the
Library view is opened and that never gains a row for a favourite created
afterwards. On a cold session, or after an account switch, every artist
opened with an invisible toggle; hearting an album on the page moved
nothing until the next session.
- library_qt: `artist_library_items` computes the tab's rows with the
Library > Albums/Tracks rule (favourites ∪ purchases, one row per
entity, purchase row representative, `is_favorite` = also hearted);
local/Plex and `following` rows never enter. A track is a member
through its performer OR its album's main artist (new
`FeedItem::album_artist_id`, fed by the new `AlbumSummary::artist`,
which the wire carries — search-results capture).
- library_qt: `reconcile_qobuz_favorite` inserts the row of a freshly
hearted track/album (one `/track/get` or `/album/get`, mapped by the
same producers the full load uses) and drops the `favorites` rows of a
cleared one, keeping a purchase row with its heart cleared.
- artist_qt: the rows ride inside the artist document (`libraryItems`),
and `refresh_library_items` / `apply_favorite_change` republish them
through `publish_patch` when the feed lands or a heart settles. A
debug-level log prints the membership split for the open artist.
- main: `settle_favorite` is the one settle point (reconcile, fan out,
republish on membership change) for the Library and queue-panel
hearts; `open_artist` warms the feed in the background; `reload_library`
hands the open page its rows; `warm_library` serves the toggle from
cache.
Tests: membership by performer or album artist, exclusion of local /
following, dedup on the purchase row, and the `top_queue` contract that
a foreign id starts the popular list at row 0 (the #737 defect class).
cc