fix: LEFT-join artists in catalog-songs read (materialized tracks were hidden)
What
GET /api/catalogs/songs (selectCatalogSongsWithArtists) inner-joined song_artists!inner → accounts!inner. Valuation-captured tracks have songs + song_measurements but no song_artists, so a freshly materialized catalog read back as 0 songs — verified live on recoupable/api#677 (claim → songs_added: 23, but GET /api/catalogs/songs → total_count: 0).
Drop the two !inner so artist-less songs surface with artists: []. songs!inner stays — the catalog_songs.song FK guarantees the song row. The existing transform already handles empty artists (song_artists?.map(...) || []), and count: "exact" now reflects all catalog songs.
Scope
Only selectCatalogSongsWithArtists (the catalog-songs read powering the chat /catalogs/[id] page). GET /api/songs has the same inner-join trait but is out of scope here. Longer term (option a on the issue): the capture pipeline should write song_artists for measured tracks so they have real artist linkage.
Verification
tsc clean · eslint clean · lib/catalog + lib/songs → 58 tests, no regression. Live preview check against a real materialized catalog to follow in a comment.
Closes the read-path half of the song_artists follow-up in recoupable/chat#1801.
🤖 Generated with Claude Code
Summary by CodeRabbit
- Bug Fixes
- Fixed catalog song retrieval to display songs even when artist or account information is unavailable, ensuring users can access the complete song collection.
Summary by cubic
Fixes hidden songs in GET /api/catalogs/songs by switching artist joins to LEFT joins. Materialized tracks without song_artists now show up and are counted, with artists: [].
- Bug Fixes
- Use LEFT joins for
song_artistsandaccountsinselectCatalogSongsWithArtists, so songs without artists are included andcount: "exact"reflects all songs. - Keep
songs!inner(FK ensures the row); other endpoints unchanged.
- Use LEFT joins for