fix: self-mapping album captures — resolve ISRCs for unmapped tracks

Merged
SW
4mo ago
+376-4

What

Fixes recoupable/chat#1794 (customer-found): the snapshot pipeline never populated song_identifiers, so captures only measured hand-seeded tracks — GET /playcounts served 1/18 K.I.D.S. (Deluxe) tracks and sibling track/stats calls fell back to Songstats, spending the quota the architecture exists to protect.

The fix — writeAlbumPlayCounts self-maps as it captures:

  1. Actor tracks with no mapping → batch ISRC resolution via Spotify GET /v1/tracks (50/call; existing generateAccessToken client-credentials).
  2. Upsert songs (isrc, name, album) + song_identifiers (track_id + album_id) — SpotifyAlbumPlayCounts now carries the album id the actor already returns.
  3. Write measurements for every resolved track.
  4. Bootstrap failure (Spotify down/missing ISRC) degrades to mapped-only capture with a log — never fails the run; the next snapshot retries.

Shared path → both the snapshot workflow and the on-demand stats refresh gain it. After merge, one re-snapshot of the 570-album portfolio (~$1.71) self-maps the entire catalog (#1794 item 2).

Tests

12 new (RED→GREEN): getTracks batching/errors, upsertSongIdentifiers, mapUnmappedAlbumTracks (resolve/skip/degrade), self-mapping wire-in. Suite 623 files pass; tsc error-list diff vs test: 0 new; next build type phase passes locally (the gate that caught #662's regression, now standard).

Verification plan (preview)

The Done-when, exactly: snapshot K.I.D.S. (Deluxe) against the real DB (2 pre-existing mappings) → GET /playcounts returns 18/18 tracks; then track/stats?isrc=<Nikes> serves data_source: apify_spotify_playcount with no Songstats call. Results as a PR comment.

🤖 Generated with Claude Code


Summary by cubic

Self-maps unmapped Spotify album tracks during capture by resolving ISRCs and creating identifier mappings, so every track gets measured and Songstats fallback stops. Also upserts album_id mappings for all captured tracks to heal older track-only mappings. Fixes recoupable/chat#1794.

  • Bug Fixes
    • Self-maps in writeAlbumPlayCounts: new mapUnmappedAlbumTracks resolves ISRCs for unmapped track_ids, batching Spotify GET /v1/tracks via getTracks (50 IDs/call) with existing generateAccessToken.
    • Upserts songs and song_identifiers (track_id and album_id) with per-row uniqueness on song,platform,identifier_type,value; also upserts an album_id row for every captured track (idempotent). SpotifyAlbumPlayCounts includes id. Measurements are written for all resolved tracks; on Spotify errors we capture mapped-only and log. Shared by snapshots and on-demand refresh.

Summary by CodeRabbit

  • New Features
    • Album playcount tracking now auto-resolves previously unmapped album tracks by querying Spotify and persisting identifiers so every touched track gets measurement coverage.
    • Added batched Spotify track lookups and safe upsert of discovered identifiers to the database.
  • Behavior
    • On lookup/upsert failures, the process logs the error and continues with already-mapped tracks.