Stem-Player Site Categorization

How catalogs like ours get organized, how three rounds of critique tear each fix apart, and how to build the honest version without inventing a single fact. Grounded in a 5-angle survey and a 3-layer adversarial critique, every empirical claim checked against the disk.
corpus: 14 real stem players (registry says 17, 3 are not players) survey angles: 5 critique layers: 3 disk-verified claims: 3 / 3

① The situation, evaluated

Our stem players sit on /stems-board and surface again on /all-sites. The categorization we have today organizes them by how each file was made, which describes our production pipeline rather than what a listener wants.

What the board actually groups by

The top-level axis is pipeline stage. Seven sections, in this order: Stem Players (16 listed), MIDI Built From Stems (3), Stem Audio vs Tab-MIDI Gaps (9), MIDI Corrected Against Stems (11), Bass Bars To Check (6), Charts Rebuilt From Stems (4), Maps & Coverage (2). Inside the Players section the cards are a flat grid with a date caption. The BANDS registry in build_stem_player.py carries slug, title, mode, hosted_dir, and nothing a visitor could browse by.

Problem 1 · no browse facets

You cannot filter by artist, decade, genre, or mood. Past roughly 20 items a flat grid stops being scannable. That is the documented information-architecture threshold, and we are already at it.

Problem 2 · the spine is plumbing

A visitor does not care that something is a stem-vs-tab-MIDI gap. Every shipping stem and DJ tool treats how-it-was-made as hidden plumbing. We lead with it.

Problem 3 · no honest metadata spine

The moment we add facets, the fraud risk appears: invented genres, unverifiable mood tags, fake curation labels. The hard half of the question lives right here.

② What most people do

Five angles, one each from the worlds that have already solved a version of this. The pattern is consistent: a stable identity spine, with browse layered on top, and the honest systems separate measured facts from opinion.

Sample & loop libraries · Splice, Loopcloud, Output Arcade

Faceted orthogonal tagging, never a folder tree. Every item is tagged on independent axes at once and you narrow by intersection. The technical axes (BPM, key, one-shot vs loop) are machine-extracted at ingest, which is the only way it scales to millions of files. The killer move: BPM and key are not just filters, they drive tempo-sync and key-sync, so a facet becomes a live transform.

Breaks for us: it assumes atomic, interchangeable, royalty-free building blocks. It has no field for stem-lane count, guide-track presence, or "this is the owner's own band."

Stem / DJ / karaoke tools · Moises, NI STEMS, djay, Karaoke-Version

Track-as-row, stem-as-control-strip. Everything is organized around the song (artist + title), found by search or sort. Per-stem mute/solo/volume appears only after you open the one track. Browse is by human music metadata, never by the separation process.

Breaks for us, sharply: our current grid leads with date/process, the one axis every one of these tools hides, and omits the axes (artist, genre, key) every one of them leads with. It is the worst of both worlds.

Streaming · Spotify, Apple Music, Bandcamp, Tidal

An immutable identity spine (Artist > Album > Track) with every browsable thing as a secondary index layered on top: genre as a multi-tag, mood/activity promoted to first class, editorial shelves beside algorithmic ones. Process never reaches the user.

Breaks for us: mood playlists and personalization need thousands of tracks and millions of plays. On 14 albums that machinery is overfit theater. Bandcamp is the real analog: pure hierarchy, human editorial, tag browse, almost no algorithm.

Metadata standards · MusicBrainz, Discogs, ID3, RYM

The decisive idea for the honest half. A layered hybrid: a hard identity spine of facts checkable against a real artifact (MusicBrainz IDs, Discogs release/format), a soft folksonomy of opinion on top (Discogs Style, RYM descriptors), and a third layer of model-derived audio features. Honest systems keep the layers in separate columns and never let an estimate pose as a fact. Discogs literally houses Genre (closed, factual-ish) apart from Style (open, opinion).

The rule it hands us: a field is honest only if its value is DERIVED (recoverable from the bytes or an authority) or clearly labeled EDITORIAL.

Information-architecture theory · Ranganathan, Morville, Nielsen

Faceted classification beats both a deep folder tree (one fixed path, buries cross-cutting views) and free tags (drift). Define a few orthogonal facets and let them synthesize at query time. Keep the default view flat and shallow, layer facets as progressive disclosure. Findability has two halves: known-item lookup and discovery. A facet earns its place only if it splits the set into roughly 2 to 8 non-trivial buckets.

Its own warning, aimed straight at us: at exactly this size a power user can eyeball the whole grid, so heavy facet chrome can be premature until the catalog roughly doubles.

③ How others critique that, three layers deep

Three independent passes, each one handed the previous solution and told to break it. Each layer went deeper by checking something the layer above only asserted.

The naive fix: "add a genre dropdown, sort A-to-Z by artist"

The cut: genre-first inverts our signal. The corpus is roughly 80% prog / post-rock / alt, so a genre dropdown returns one fat bucket and a scatter of singletons, failing the 2-to-8-bucket test. Genre is also not orthogonal (Mars Volta is prog AND post-hardcore), so a single-select dropdown forces one opinion-label wearing a fact's clothes. Artist A-to-Z is a sort, not a find, and at 13 artists every name is already on one screen.

What it proposed to save: keep the flat grid as the zero-click default, layer a small facet rail drawn only from mechanically-derivable metadata: owner-vs-reference, stem-lane shape, binned decade, audio format. Ship genre last and fenced as opinion.

Residual it admitted: "I have not actually inspected the registry or the player folders," then shipped the facets anyway. Owner-vs-reference is a lopsided 1-vs-15. The mandatory-capture rule has no enforcement mechanism.

Layer 2 went and counted the files

The cut: two of Layer 1's four lead facets are dead on the real data. Of the stem files in our public tree, the count came back all mp3, so the format facet is one bucket. The song folders share an identical six-lane set, so stem-lane shape, billed as "the corpus's real heterogeneity," is its most homogeneous axis. Worse, artist, year, genre, and owner exist nowhere machine-readable. They live only inside the human-typed card title string. So Layer 1's "fraud-check re-derives every value" was checking facts that are not in the bytes.

What it proposed to save: stop faceting 16 items. Re-axis the board to listen-vs-analyze, build one players.json with every value tagged DERIVED or STATED, demote the constant axes (format, lane-count, owner) to badges, ship one decade grouping plus type-ahead, genre as a single closed-vocab label.

Residual it admitted: the STATED-vs-DERIVED tag is only as honest as the human typing it, with no external referent to check year or genre against. It asserted the board re-axis is "a one-line reorder" without reading the generator.

Layer 3 read the generator and the deploy, then left the frame

The cut: Layer 2's one enforceable gate, "verify six mp3 lanes per player folder," is not runnable. The owner's own band and Beach House have zero audio in their folders, served cross-origin from drwu-media, so the gate would fail on the two highest-signal items. Lane-count is not even a player-level property: these are multi-song albums (36, 60, 72 files), so a lane-count varies inside one player. And the "16-player corpus" is a phantom: the real PLAYERS set is 17 slugs including a local-only dashboard and an upload tool. Every prior bucket-count was math on a fiction. Deepest cut: categorization was never the job. At 14 owned records there is no findability problem. There is a point-of-view problem. The shelf asserts nothing.

What it proposed to save: reframe to a curation-argument task with a provenance spine. Resolve the unit (song vs album), reconcile the roster, lead with one owner-written thesis and a curated order, anchor the checkable facts (artist, album, year) to MusicBrainz IDs so a gate can verify them against an external authority, and name every editorial claim as editorial.

Residual it admitted, the most honest of all: the thesis and the order have no gate, because a gate for opinion is a category error. And the deeper worry, straight from our own no-corpus-bullshit rule: if the 14 players are an accretion of whatever got built rather than a deliberate canon, then demanding a thesis manufactures meaning that was never there, which is its own quiet fraud.

④ Verified on disk, not asserted

The whole point of the question is to avoid fraud, so the three load-bearing claims got checked against the filesystem here, not taken on the agents' word.
VERIFIED · THE ROSTER IS NOT 16

The PLAYERS set in build_topic_boards.py:95 holds 17 slugs. Three are not stem players: m4auploadbelieveyoume-chord-railmashup-dashboard. Real count: 14 players. Every facet bucket-count in the survey and the first two critique layers was computed against a phantom set.

VERIFIED · THE TOP TWO ITEMS HAVE NO LOCAL AUDIO

believeyoume-stems/ and beachhouse-stems/ contain exactly index.html and index.md and 0 audio files. Their stems are served cross-origin from drwu-media. Layer 2's "verify lanes on disk" gate would fail on precisely the owner's own band.

VERIFIED · LANE COUNT IS PER-SONG, NOT PER-PLAYER

Audio files on disk: rush-stems 36, mars-volta-stems 60, dream-theater-stems 72. These are multi-song albums, so "5-stem vs 6-stem" is a song attribute living inside the manifest, not a single value for "Rush." The honest registry needs a song row, which neither early layer had.

⑤ How we innovate here, authentically

The survey says faceting. The critique says faceting is premature at this size and most of our facets are constants or opinion. The synthesis is not a fancier filter rail. It is a small, honest, two-level spine that lets the shelf say something true and lets the machine prove the parts that are provable.

Move 1 · reconcile the roster before any math

Drop the three non-players from the player set so the count is real (14). Nothing downstream can be honest while the roster is a fiction. This is the cheapest, highest-integrity fix on the page and it is a one-set edit in build_topic_boards.py.

Move 2 · resolve the unit: a two-level registry

Build players.json at the album level (artist, album, year, owner-bool) with a child songs[] array carrying the facts that actually vary per song (lane_count, has_guide). Derive lane_count from the manifest the player actually loads, not the empty public folder. Now stem-lane shape has an honest home, the song.

Move 3 · lead with a thesis, sort by meaning

At 14 owned records the top object is one sentence the owner writes and owns, for example a through-line about how these bands use space, with his own band placed deliberately among its influences. Then one curated order that serves that sentence. This is the Bandcamp and 33⅓ model the survey flagged as the only real analog to a small owned catalog. Owner-vs-reference becomes the emotional center of the layout, not a lonely boolean badge.

Move 4 · make provenance real, not flagged

For facts with an external authority (artist, album, year) capture the MusicBrainz release-group ID per album, a few minutes of paste across 13 artists. Now the closeout gate can hit the API and confirm the stated year matches the ID. That is a re-derivable check. For facts with no authority (the thesis, the order, the genre read) label them the owner's editorial claim and never let them sort as if measured. Wire the check into ship.py so a player added without its registry row blocks the deploy.

The two caveats that keep it honest

  • Test the null hypothesis first. The honest answer at 14 items might be even less than this: a flat grid in a deliberate owner-chosen order, one caption on top, no spectrum, no facets. Build the thesis only if the grid genuinely needs more than a caption.
  • Do not manufacture a canon. If the 14 players are just whatever got stemmed, a forced thesis is corpus bullshit. The thesis is only honest if the curation is real. The owner is the only one who can answer that, so that sentence is his to write, not ours to generate.

⑥ The fraud line

The reusable principle under all of it. Every categorization choice falls on one side of a single line.
The fraudulent moveThe honest move
Auto-genre a track with a model and present it as the track's genreShow genre as the owner's stated read, in a closed vocabulary, labeled as a claim
Ship a facet because Splice has itShip a facet only if it splits THIS set into 2 to 8 real buckets
Tag a field DERIVED when it lives in a human-typed stringCall it DERIVED only when a gate can recompute it from bytes or an authority
Invent mood, energy, or play-count numbers to fill a cardLeave the field off until real data exists to fill it
Count buckets on a roster you never reconciledReconcile the roster first, then count
Assert a stem-lane badge per playerStore lane-count where it is true, on the song
Manufacture a thesis to look curatedWrite a thesis only if the curation is genuine, and sign it as opinion
The one rule that survived all three critique layers:

Categorization is a provenance problem, not a taxonomy problem. A field is honest only when its value is either re-derivable from the bytes or from an external authority, or it is plainly labeled as the owner's claim. Anything in the middle is opinion wearing a fact's clothes, and that is the whole of the fraud.
🛍️ Get the printable