The previous commit only fixed the INITIAL-render transform for
Spotify/Tidal/Deezer discovery rows. User confirmed [object Object]
still appeared after discovery completed — because there are two
additional update paths that do their own row-transform:
- WebSocket live-update handler (populates rows as discovery progresses)
- Poll-based fallback (same shape, runs when socket is disconnected)
Both had the same naive `.artists.join(', ')` on potentially-object
arrays. The poll and socket handlers exist for each of Spotify Public,
Tidal, and Deezer — six occurrences total across three platforms, all
with the same bug class. Now all use the object-aware map-and-join
pattern consistent with the initial-render fix.
Also fixes two more spots in openDiscoveryFixModal that the earlier
sweep missed:
- Missing spotify_public branch in the apply-selected-match handler:
after user picks a replacement track, state lookup failed, the local
row wouldn't refresh even though the backend had succeeded.
- Same artist-join bug in the same handler (track.artists from the
fix-modal search results could be array-of-objects).
Full suite stays at 263 passed. Ruff clean.