fix(cache): build_disc_cache wrote NULL artists it did not have to

The builder read release.artists_sort alone, which is NULL for roughly 9.1M of
the 10.4M releases in this dump, and cached that NULL. Not merely a blank column:
recordgod's admin inventory list runs its artist SEARCH and SORT on dc.artist
too, so an affected record becomes unfindable by artist name. Genre, style, label
and country all looked fine on the same row because those read disc_release_*;
the artist is the one catalog field where this cache is the only source.

Seen on release 447087 - cached as title "Mezcal", artist NULL, showing a dash in
the admin list, while Discogs plainly says Urban D.K.

The name was never missing. release_artist has it regardless of artists_sort, so
fall back to that. extra=0 is the RELEASE artist: extra=1 rows are credits, and
447087 also lists Carl Clarke and Jim Eliot as Producers, so folding those in
would be worse than the blank. Comma-joined rather than reconstructing Discogs
join_strings, since this only fires where artists_sort is already NULL.

Verified against the mirror: 447087 to Urban D.K. and 564101 to Idjut Boys are
recovered, while 3018249 (Skirt (7)) and 314753 (Dahlback & Dahlback) still come
from artists_sort unchanged. No credits leak in.

This mattered urgently because the builder TRUNCATEs disc_cache and rebuilds, so
the next run would have silently undone the prod backfill of those two rows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
type-two 2026-08-22 13:50:04 +10:00
parent dfd3221617
commit fce64c72d3

View File

@ -20,9 +20,28 @@ def main():
rg.execute("TRUNCATE disc_cache") rg.execute("TRUNCATE disc_cache")
n = 0 n = 0
for i in range(0, len(ids), 5000): for i in range(0, len(ids), 5000):
# artists_sort is NULL for most of this dump (~9.1M of 10.4M releases), and reading it
# alone silently cached a NULL artist — which is not merely a blank column in the admin
# list: dc.artist is also what the admin SEARCH and SORT run on, so an affected record
# becomes unfindable by artist name. Seen live on release 447087, cached as title
# "Mezcal" with no artist while its genre/style/label/country all populated, because
# those read disc_release_* and only the artist reads this cache.
#
# The name is in release_artist regardless. extra=0 is the RELEASE artist; extra=1 rows
# are credits — 447087 also lists Carl Clarke and Jim Eliot as Producers, and folding
# those into the artist name would be worse than leaving it blank.
#
# Comma-joined rather than reconstructing Discogs' join_string ("&", "Featuring"): this
# only fires where artists_sort is already NULL, and a predictable "A, B" beats both NULL
# and a dangling separator.
rows = dg.execute( rows = dg.execute(
"SELECT id, title, artists_sort, COALESCE(thumb_local_url, thumb), estimated_weight " "SELECT r.id, r.title, "
"FROM release WHERE id = ANY(%s)", (ids[i:i + 5000],)).fetchall() " COALESCE(r.artists_sort, ("
" SELECT string_agg(ra.artist_name, ', ' ORDER BY ra.position, ra.id) "
" FROM release_artist ra "
" WHERE ra.release_id = r.id AND ra.extra = 0)), "
" COALESCE(r.thumb_local_url, r.thumb), r.estimated_weight "
"FROM release r WHERE r.id = ANY(%s)", (ids[i:i + 5000],)).fetchall()
with rg.cursor() as c: with rg.cursor() as c:
c.executemany( c.executemany(
"INSERT INTO disc_cache (release_id, title, artist, thumb, weight) " "INSERT INTO disc_cache (release_id, title, artist, thumb, weight) "