Designs by Duhart All work
Rank
10 of 34
Tier
Tier A 83 of 120

30 · BillboardML, Audio Recognition & Recommendation

Rank 10 of 34 · Tier A · app/BillboardML (billboardml/model/FINGERPRINT/, billboardml/jamzfinder/, billboardml/serve/, PortfolioNotes/), app/workers/billboard_users/wasm/jamz_fft.c Stack: Python, numpy, PyTorch, LightGBM, memory-mapped indexes, HTTP API under systemd, Cloudflare Worker + D1 on the other side of the contract

Where this sits. This is the learned half of the music product: what is this recording, what is it like, what should play next. It is ML work, but the hard parts are systems parts. A cross-language hash contract that fails silently when it drifts. A 4.6 GB index that has to be built with flat memory on a box that is always nearly out of it. A live reader that got corrupted by its own writer. And an evaluation discipline that refuses to ship a model because it lost a paired bootstrap.


One hash contract, four implementations, one gate
Cached audio5,344 tracksfingerprintLandmarksbit-exact Jamz porttmp + os.replaceBucketed index256 buckets, mmap/v1/identify57/60 at 10 dB SNRDuplicatesnear pairs by spikeJamzFinderfused list withheldread-only

The index is append-only and bucketed so a killed build resumes and memory stays flat. Every threshold in identify() was set by a gate run: 57 of 60 noisy clips identified, every foreign clip refused. A rebuild once truncated the inodes a live reader had mapped; writes now go to .tmp siblings and are renamed into place.

The shape of it

cached audio ──► signal engine (DSP) ──► stores: CLAP, AST, MERT, CNN, hybrid, fused
      │                                         │
      ▼                                         ▼
 landmark fingerprint ──► bucketed index    heads, towers, JamzFinder
      │                       │                 │
      ▼                       ▼                 ▼
          /v1/identify      /v1/jamzfinder/related      Track Intelligence record

A batch CLI and a daily cycle produce everything; a small API on loopback serves it. Nothing here is a daemon that owns state except the API, and the API only reads artefacts the batch side wrote. That split matters for the incident further down.

Fingerprinting: a fourth implementation, held bit-for-bit

Jamz is the app's "what is playing" feature. Three implementations of its landmark fingerprint already had to agree exactly: the C compiled to wasm that the Worker's Durable Object runs over the catalogue, the Swift engine on the phone, and the browser's TypeScript. If one constant drifts, the hashes never collide. Recognition then answers "no match" forever, with no error anywhere.

So BillboardML did not invent a fifth hash space. It ported the contract: 4096-point frames at 44.1 kHz, hop 2048, a Hann window carrying the vDSP normalisation, the x2 correction for vDSP's FFT scaling, power dB not amplitude dB, strict interior maxima above -60 dB, five peaks a frame, six targets per anchor within 500 ms, and a 32-bit packed hash whose top bit is set for high anchor bins. The port is tested against a naive-DFT transcription of the wasm harness's reference on its seven signals, peaks bin-for-bin and dB within 0.05. Transcribed, not imported, so a coding error on either side gets caught. A shared misreading would not, and the note says so.

The payoff is that the Worker's fingerprint table and this index describe the same recordings in the same hashes. One client capture can be answered by either side.

Thresholds measured, not inherited

Every decision rule in identify() came from a gate run, and each run changed one rule. On a 35-track smoke index:

  1. The count rule alone is not a rule. Jamz accepts at five matching pairs. A held detuned chord matched a real track at 651 votes, white noise at 7. A 10 s clip carries thousands of pairs, so five agreeing somewhere is chance.
  2. The upstream confidence is always 1.0. The Worker's SQL divides each score by the window's maximum and then takes LIMIT 1, so the top row divides by itself and the MIN_CONFIDENCE 0.75 check can never reject anything. Here confidence is the margin over the best other track. Recorded for the Worker's owner, not fixed from this repository.
  3. The spike straddles two bins. The query's frame grid lands anywhere inside a hop relative to the catalogue's, so a true match fills the neighbouring offset bin nearly as full. Coherence is the bin plus its neighbours against the median far spike, because looped music earns real secondary spikes eight bars later.
  4. Two true clips lost to themselves. The runner-up was the same recording under a second id. A coherent runner-up within half the spike is now a reported near_duplicate, which doubles as a duplicate detector.

Then the full index: 3,158 tracks, 457 million pairs, 4.57 GB. Three more gate rounds moved the rules again (query phases, even sampling of common hashes, a floor on distinct coherent votes). The confirmatory gate in data/fingerprint/gate.json: 57 of 60 clips identified at 10 dB SNR, the weakest true clip at 156 votes, every foreign clip refused at 42 or fewer, 99 of 99 byte-identical duplicate pairs found. The three misses are shared audio, the same loop under another id, not chance.

Flat memory on a box that has none

The host is a shared 31 GB machine that is usually within a few GB of the OOM killer. The index was designed around that:

Two OOMs still happened, both read and fixed. A whole query expanded at once was 9 GB and was killed under the API's 3 GB cap, so lookups now run in 4,096-pair slices and keep only deduplicated votes between slices. And a build worker died alongside Cassandra in a global OOM wave; because the log is append-only, the build lost nothing.

The incident: a writer that truncated a live reader's mmap

The next morning the daily cycle rebuilt the index to 5,362 tracks and 781 million pairs. finalise_index opened the arrays with "wb". That truncates and rewrites the same inodes the running API had memory-mapped the night before, under the old length and the old bucket offsets. Nothing crashed. The API kept answering, against a mismatched index: two known clips scored 1,014 and 1,279 votes in-process on the fresh files, and 8 and 5 through the API. Both refused.

The fix is the old Unix rule. Write .tmp siblings, os.replace them into place, metadata last. A running process keeps its old inode until it restarts, so a reader sees either the whole old index or the whole new one. Tests went to 16 of 16, the API was restarted, and four clips (two old tracks, two newly indexed) identified themselves at 1,014 to 1,520 votes.

Recommendation, and the discipline that keeps models out

The yardstick is same-artist recall@10 with album-excluded queries and artist-grouped folds, against a stated chance level (0.52 on the current catalogue), because random splits leak the same album into train and test. Every learned store must match a frozen CLAP reference under a paired bootstrap before it serves.

So far nothing does, and the notes say so. The best student, a pretrained Cnn14 distilled from CLAP over five folds, reads album-excluded R@10 0.711 [0.684, 0.736] against the teacher's 0.825, a paired difference of -0.114. Better than ResNet18 and the from-scratch CNN, and still out. The two-tower retriever loses to the centroid baseline and is gated out. JamzFinder's fused list (0.7 cosine, 0.3 a written-down musical distance) does not beat the plain embedding (CI [-0.037, 0.020]) and is withheld, served only when the lower bound clears zero. Along the way one "music" CLAP checkpoint on the Hub turned out to be untrained, found from its own evidence chain, and replaced by its trained sibling.

Metadata coverage, where the gate is the unit's exit status

A separate batch sweep keeps artist and genre filled across the catalogue. The owner's rule: at least 80 percent coverage, fill blanks only, never overwrite. The sweep runs from a systemd timer, and the unit's exit status is the gate: a failed unit means coverage fell below 80 percent or a step raised.

The finding that moved coverage: the pipeline had only ever read filenames. The files' own ID3 tags named the artist for most of the "unidentifiable" rows. Tags and the web crawler agreed only 46 percent of the time, and in 9 of 10 hand-checked disagreements the tag was right, the crawler having picked a cover act. Tags now outrank the crawler. Measured 2026-09-24: artist 97.8 percent, genre 87.8 percent of the music tracks, audiobooks excluded from the denominator. Provenance lives in an append-only ledger, and training excludes the model's own earlier guesses so it never learns from itself.

Honest gaps