fix: self-mapping album captures — resolve ISRCs for unmapped tracks
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:
- Actor tracks with no mapping → batch ISRC resolution via Spotify
GET /v1/tracks(50/call; existinggenerateAccessTokenclient-credentials). - Upsert
songs(isrc, name, album) +song_identifiers(track_id + album_id) —SpotifyAlbumPlayCountsnow carries the albumidthe actor already returns. - Write measurements for every resolved track.
- 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: newmapUnmappedAlbumTracksresolves ISRCs for unmappedtrack_ids, batching SpotifyGET /v1/tracksviagetTracks(50 IDs/call) with existinggenerateAccessToken. - Upserts
songsandsong_identifiers(track_idandalbum_id) with per-row uniqueness onsong,platform,identifier_type,value; also upserts analbum_idrow for every captured track (idempotent).SpotifyAlbumPlayCountsincludesid. Measurements are written for all resolved tracks; on Spotify errors we capture mapped-only and log. Shared by snapshots and on-demand refresh.
- Self-maps in
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.