feat(1493): export popularity field from album_popularity (Phase-2 Track 3)#1503
Merged
Conversation
…ack 3) Projects the attribution-corrected, master-collapsed `popularity` signal into the catalog export (`GET /library/catalog`) — the final delivery step of BS#1486 Phase-2. Track 2 (#1492) built the `album_popularity` table; this consumes it. - catalog-export.service.ts: add `popularity` to the private `CatalogExportRow` type + `projectRow`, and LEFT JOIN `album_popularity` by the row's logical key — the `discogs:`-stripped `canonical_entity_id` (`discogs:master:<id>` -> `master:<id>`, verbatim for any other non-null scheme, else `library:<id>`), mirroring the CASE the rebuild groups on. Projected RAW (`::int`, nullable), NOT COALESCEd to 0 like `plays`: null means the logical album has no plays at all (linked or free-text), per the merged SSOT contract. - Bump `@wxyc/shared` ^1.13.0 -> ^1.15.0 (the release that published `popularity` to the SSOT); the parity drift-guard reads the installed dist, so the bump is load-bearing. - Integration: two pressings of one master collapse to the same popularity; the multi-pressing logical album's popularity >= a single pressing's plays; an unsignaled row ships raw null (not 0). - app.yaml (Swagger display) kept consistent. Closes #1493
…n branches The serialize unit test hardcoded the 14-field contract and would have failed CI now that projectRow emits popularity as a 15th key; add popularity to the contract array, to the sampleRow fixture, and assert it round-trips raw-null (the field's distinguishing contract vs COALESCEd plays). The integration spec only seeded discogs:master rows, so the reader's logical-key CASE was exercised on just the master branch even though the service comment claims "the pg integration spec guards it". Seed a discogs:release row and a NULL-canonical row each with a matching album_popularity entry so the release-form (substring) and library-fallback (ELSE) join-success branches are proven, not just the master form. NULL-canonical is the largest class in prod (~34k rows) and was previously only covered on the null-output path. Use probe id 7061 rather than 7060 to avoid colliding with library-query-sort-plays.spec.js under the shared-schema --runInBand pg suite.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
The final delivery step of BS#1486 Phase-2: the catalog export (
GET /library/catalog) now ships apopularityfield — the attribution-corrected, master-collapsed signal from thealbum_popularitytable that Track 2 (#1492) built. Consumers (the deferred ranked-bundle seed in WXYC/wxyc-dj-ios#44) can rank releases by real popularity, whileplaysstays the honest per-pressing linked count.How
apps/backend/services/catalog-export.service.ts:popularityadded to the privateCatalogExportRowtype +projectRow.album_popularityon the row's logical key, derived by the same CASE the rebuild groups on: strip thediscogs:namespace offcanonical_entity_id(discogs:master:<id>→master:<id>), keep any other non-null scheme verbatim, elselibrary:<id>. Cross-referenced toalbum-popularity-refresh.service.ts(the writer); a divergence would silently null popularity, so the pg integration spec guards the join end-to-end.::int, nullable), notCOALESCE(...,0)likeplays:nulldistinguishes "the logical album has no plays at all (linked or free-text)" from a genuine 0, per the merged SSOT contract (wxyc-shared#198).Dependency
@wxyc/sharedbumped^1.13.0→^1.15.0— the release that publishedpopularityto the SSOTCatalogExportRow. The parity drift-guard (catalog-export.parity.test.ts) reads the installed dist, so this bump is load-bearing (it goes red without it).Tests
pg): two pressings of one Discogs master collapse to the samepopularity(validates the logical-key join); the multi-pressing logical album'spopularity≥ a single pressing'splays(the Catalog export popularity field + wiring (Phase-2 Track 3) #1493 acceptance criterion); a pressing with no plays of its own still shows the collapsed popularity; an unsignaled row shipspopularity: null(raw, not 0).Scope
No migration (reads the existing
album_popularity). No new endpoint. iOS / Kotlin decoders pick uppopularityon their next@wxyc/sharedregen — additive + nullable, so existing decoders keep working.Closes #1493