Commit 5ee9395c by PLN (Algolia)

docs(tasks): archive #26 — the silent-orbit hunt, and why the fix was one line in our own preload

Written for a cold reader and for the blog: the two-part mechanism (upstream header-only
reads + our own flag left flipped), why whitelist-by-mtime made it look haunted, the
count assertion catching its own counting bug on the AppleDouble twins, the 'Required
0 MB' red herring, and the two harness failures (zsh word-splitting, an early readiness
gate) that cost more time than the bug itself.
parent 0ae4116a
......@@ -392,3 +392,75 @@ memory `project_fourier_api`. Named after Joseph Fourier — the transform behin
- **Done:** fixed 2026-07-28 (`66af326`, pulsar-tidalcycles). Nothing was breaking. `activationHooks: ["source.tidalcycles:root-scope"]` plus `activationCommands` made Pulsar DEFER loading the package, so a reload landed in a window where the Tidal package was simply DORMANT — no ghci, none of its three UDP ports bound, and nothing saying so. `tidalcycles:reboot` happened to be the first *activationCommand* in the list, so "rebooting Tidal" worked by WAKING the package, not by fixing anything. Removed both keys; the package is now eager.
- **Learnings:** the remedy worked for a reason unrelated to the story we told about it, which is exactly why the cause stayed hidden for so long — a reliable workaround stops anyone asking why. Proof was structural rather than inferred: the renderer's `~/.pulsar/blob-store` contained no compiled tidalcycles code at all, so `lib/tidalcycles` had never been required (a good general check for "did this package actually load?"). Design consequence worth keeping: lazy activation and remote control are mutually exclusive on principle — a channel whose purpose is removing the manual keypress cannot itself require a keypress to come into existence. And shipping package JS always costs exactly one reload, because new code cannot be injected into a running Electron renderer.
- **Deps:** found while debugging why the new remote channel (#44/a43f428) wasn't listening; unblocks unattended launch work (#44).
---
## #26 — GIG-CRITICAL: silent orbits (root cause was OUR preload, not SuperDirt)
**Description.** For two evenings, orbits went silent mid-set. *Which* ones changed every
boot. The boot log looked perfect — every bank registered with the right file count — and
19,741 `Buffer UGen: no buffer data` messages piled up in one 6h session where no
performer would ever see them. Six orbits of `the_revolution_will_be_sampled` were dead on
stage. J-7 to OPAL 2026.
**Done.** `b4f6275` (branch `claude/preload-eager-banks`), in `tools/setlist_samples.py`'s
emitter, plus `setlist_opal2026.txt` and `gig-up.sh`. Also `0ae4116` (probe timeline +
check-mix session resolution) and, in the fork, `374d8a3` (stop swallowing GHC errors).
**Learnings.**
*It was a two-part interaction, and part two was ours.* Upstream, `doNotReadYet = true`
registers banks from WAV **headers only**; the audio read is fired *asynchronously* by
`readFileIfNecessary` (`DirtSoundLibrary.sc:268-274`), which returns immediately — so the
synth for the very event that triggered it gets a bufnum with no samples. That alone is a
first-hit glitch. What made it fatal: our generated `preload.scd` set
`doNotReadYet = false` and **never set it back**, and that flag gates the *only* caller of
`readFileIfNecessary` (`:259-261`). Flag false ⇒ a header-only buffer is never read. Not
late — **never**. So any bank the whitelist missed was permanently silent.
*And the whitelist missed banks by design.* `gig-up.sh` built it from the N
most-recently-**edited** tracks. `the_revolution_will_be_sampled` hadn't been touched
recently, so `like_sugar` and `the_revolution` were never warmed — exactly the banks
feeding the six dead orbits. Whitelist-by-mtime is also why *which* orbits died changed
every boot. The thing that made this feel haunted was file timestamps.
*The load-bearing line is one line.* Restoring `doNotReadYet = true` after warming demotes
the whitelist from load-bearing to a mere optimisation: a miss becomes a slow first hit
instead of a dead orbit. That is the only thing it is safe to be on stage.
*A reload REPLACES a bank, it does not append.* `addBuffer` defaults
`appendToExisting = false` and frees the old bank on the first file (`:42-46`), so a plain
re-load is index-stable — `like_sugar:21` keeps its meaning. An earlier session's worry
about *doubled* indices was wrong, and that wrong belief had made the fix look far more
delicate than it was. Measured: **0 of 1428** bank names even collide across the three
loaders.
*The count assertion caught a bug in itself on its first run,* which is the best possible
outcome for a guard: `jbk_kick: expected 508, got 254`. Exactly 2×, and the *tool* was
wrong. That folder symlinks into the rhadamanthe pack, which carries an AppleDouble
`._X.wav` beside every real `X.wav`; `glob('*.wav')` matches both, SuperDirt's
`pathMatch("*")` skips dotfiles, and `ls` hides them so the folder looks clean.
*Red herring worth remembering:* SuperDirt's "Required 0 MB of memory" is not evidence the
eager read failed — `memoryFootprint` counts frames from the header, so header-only
buffers already report full size. Only audio measurement can prove a preload worked.
**Validation (instrumental, no ears — PLN was at work).** Before: d4/d5/d9/d10/d11/d12 all
`-inf` at source. After: all 11 declared orbits carry signal *and still do* on a second
probe ~95 s later with no re-eval (stable to ~0.2 dB) — the two-timepoint check being
mandatory for this bug class. `no buffer data` 19,741-in-6h → **1** (a boot artifact at the
instant the preload completed). Preload asserts **47/47** banks, 2352 files, 2.2 s, 1.2 GB.
Also green: `perfect` 12/12, `gimme_acid` 10/10, `mafia_sans_serif` 7/7, `wap` 5/5. Bare
`s "like_sugar*4"` audible. Confirmed by PLN's ears later that day: *"i hear indeed all
sounds in the track, so it sounds good to me!"*
*Two harness failures during validation, both worth more than the fix.* A batch loop
returned four EMPTY results that read exactly like "nothing is playing" — cause: **zsh does
not word-split unquoted variables**, so `-d $ORB` passed one bogus argument and the tool
exited 2 with a usage error my grep hid. And the readiness gate passes ~4 s too early,
because `listening to Tidal` is printed by `~dirt.start` well before the warm-up. *When a
batch of measurements all come back empty, suspect the harness before the rig.*
**Deps.** Closed #26 and #63. Unmasked #61 (which then measured *clean* for the OPAL set —
all 41 seeded CCs cover it). Spawned #65 (an undefined `crackles` silencing nine orbits,
which is a compile error, not audio), #66, #67. Feeds #44 (readiness gate) and #24.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment