DigDeeper · experimentsall projects

Artist or label?

A Bandcamp URL doesn't tell you whether x.bandcamp.com is a solo artist or a record label — both live at the same address and expose the same /music grid. But Dig Artist and Dig Label need to know the difference. This is a test of whether we can recover it from data we already store, run against the full production catalog.

4,777,654 Bandcamp sources 127,840 distinct pages prod DB · 2026-06-05 10-page labelled check set
The simple rule — “many distinct artists ⇒ label” plus Bandcamp's Various-Artists flag — gets 7 / 10 on a hand-labelled check set. It's directionally right but not shippable yet: it fails in both directions, and the root cause is the same in each — the per-track artist field we store is unreliable. It collapses to the storefront name on self-uploaded label catalogs, and inflates on solo artists who use “feat.” / “&”. Fix that one field and the rule becomes solid.
noneof these 127,840 pages carry an artist-vs-label flag today — the stored label blob is just the page owner
25.0%of pages the rule flags as label (32,000) · 75.0% as artist (95,840)
59.3%of all pages have zero independent artist signal — the artist value just echoes the page name

1 · What the DB stores today

Every Bandcamp track carries a metadata_json.label object. The name is a misnomer: it's the page owner (band_id + the og:site_name + subdomain), which is identical whether the page is an artist or a label. Three real rows, untouched:

durante.bandcamp.com → name = "Durante"  (a solo artist — name is the artist)
xenonyms.bandcamp.com → name = "Various Artists"  (a label — name is a placeholder)
diffusereality.bandcamp.com → name = "Diffuse Reality Records"  (a label — name is the label)

Same shape, three different meanings. There is no is_label / entity_type anywhere in the schema, and band_id only lives inside the JSON blob (no column, no index).

2 · The rule under test

Classify each page (grouped by band_id) using only fields we already have — no re-scraping. One function; the same call backfills the 127k existing pages and runs at ingest for new ones.

label if ( is_various_artists ever true OR distinct_artists ≥ 3 )
artist otherwise

Where the 32,000 “label” calls come from — the VA flag is high-precision but rare; the distinct-artist count does the heavy lifting (and, as we'll see, carries the noise):

VA flag · 5,427
distinct ≥ 3 · 26,573

Split of the 32,000 label calls. VA-driven calls are a clean subset; the rest rely entirely on the artist count.

3 · Validation — 10 pages with known ground truth

pagetruthreleasesdistinct artistsVA flagpredictedverdict
junglecakeslabel1362791yeslabel✓ correct
hospitalrecordslabel1156656yeslabel✓ correct
chillhoplabel1644549yeslabel✓ correct
themidnightartist8641noartist✓ correct
jibbzeonartist29801noartist✓ correct
boogiemasterartist10571noartist✓ correct
jammmerartist10041noartist✓ correct
diffuserealitylabel17081noartist✗ false neg
enderecordslabel25131noartist✗ false neg
duranteartist9920nolabel✗ false pos

7 / 10 correct. All 3 errors come from the distinct_artists count being wrong, not from the rule's logic. Both failure modes below trace back to the stored artist field.

4 · The two ways it breaks — same root cause

Collapse label → artist

Labels that upload releases under their own name set every track's artist to the label. The page shows 1 distinct artist, so the rule calls it an artist. The real artists are lost — sometimes stranded in the title.

diffusereality — 1,708 releases, every one
  artist="Diffuse Reality Records", title="Orbital Haze"
enderecords — artist="ENDE Records Australia",
  title="green martian (with Lawrence Green…)"

Inflation artist → label

A solo artist who collaborates a lot produces many distinct artist strings — “X”, “X feat. Y”, “X & Z” all count separately — tripping the ≥ 3 threshold. Durante alone yields 20 “artists”.

durante — 1 person, 20 distinct artist strings:
  "Durante", "Durante & CRi",
  "Durante feat. HANA", "Durante feat. SOHN" …

Both are the artist field's fault. It's populated from Bandcamp's top-level tralbum.artist (the storefront name) instead of the per-track artist, and it's stored raw, with the “feat./&” credits unnormalised. The classifier inherits both flaws.

5 · What we learned

The page owner is already there — the type isn't

“Dig this page's catalog” (group by band_id) works today with zero new data. The only missing bit is a one-field entity_type to decide which button to show.

VA flag = trust it; artist count = don't (yet)

When is_various_artists is set it's a label almost every time — but it only covers 5,427 pages. The distinct-artist count reaches the rest, but is noisy in both directions until the artist field is clean.

Fix one field, unblock both features

Per-track artist extraction — stop defaulting to the storefront name; normalise feat./&/x/vs/pres. to the primary artist — fixes Dig Artist and de-noises the label classifier. It's the prerequisite, not a nice-to-have.

Native flag: unconfirmed

Bandcamp's page JSON may carry an explicit label marker we don't parse (we only read data-tralbum). The proxy pool was 403-blocked on these pages during this run, so it's still an open lead — if it exists, classification becomes “read one field”.

Method

Data. Production Postgres (digdeeper), read over the SSH tunnel on 2026-06-05. 4,777,654 track_sources rows where platform='bandcamp'; 4,580,042 carry a metadata_json.label.id. Pages = distinct band_id (≈ subdomain): 127,840.

Aggregation. Per page we computed release count, count(distinct lower(artist)) from the joined canonical_tracks, and bool_or(is_various_artists). The rule label = VA-ever OR distinct_artists ≥ 3 was applied to all 127,840 pages: 32,000 label / 95,840 artist. “Zero artist signal” = pages with 1 distinct artist whose value equals the page name (75,752; 59.3%).

Validation. 10 pages with author-known ground truth (5 labels, 5 artists), chosen to include the hard cases (a self-uploaded label, a collab-heavy solo artist). 7/10 correct. This is a smoke test, not a calibrated accuracy figure — a real precision/recall number needs a larger random labelled sample. The ≥ 3 threshold is untuned.

Caveats. No native Bandcamp label flag was confirmed (proxy 403s). The artist-collapse and feat-inflation issues are properties of the current ingest, so any backfill is bounded by them until the artist field is reprocessed. Generators + queries live in digdeeper-similarity/scripts, not here.