-
fix(boot): the #55 seed NEVER RAN — Pulsar fused three statements into one (#79) · 2648074d
PLN this morning: "moving to track 2, wap.. no bass? when i move the knob C5 it starts sounding". And on do_it_right: "ctrl_enter, i hear the 4-bar pattern each bar lower, 4th barely audible, its clearly a xfade". Both sentences are the same bug, and the second one hid the first for days. THE MASK. Every dN is `xfade N` with xfadeIn 4, so the four bars you hear after an eval are the PREVIOUS pattern leaving. A silent eval gets a graceful exit and reads as a "drift to silence". The sound after ctrl+enter is not evidence the eval worked — it is evidence the last one did. THE BUG. Pulsar does not feed BootTidal.hs to ghci verbatim. boot-tidal.js splits it on BLANK LINES and strips the `:{`/`:}` it finds; repl.js tidalSendExpression then wraps each chunk in its OWN `:{ ... :}`. A ghci `:{ ... :}` accepts exactly ONE statement. The #55 seed was written as :{ let _seed = concat [ ... ] :} mapM_ (\(k, v) -> setF k (pure v)) _seed putStrLn "[BootTidal] seeded ..." — correct for a file read line-by-line, and fused by Pulsar into a single statement that dies with "parse error (possibly incorrect indentation or mismatched brackets)". So THE SEED NEVER RAN. Not once between 2026-07-27, when it was written, and today. Every boot left the control map empty. An untouched "^NN" yields NO EVENTS — not 0, nothing — so any `# param (range a b "^NN")` emptied its whole orbit, and the rig only made those sounds after a knob was physically moved. Which is precisely what PLN described, in the sentence I had filed as a separate question about crush ranges. MEASURED, with tools/silent-eval.py (added earlier today) over the OPAL setlist: empty control map 23 orbits silent across 10 of 10 buildable tracks, including desire d1-d6 — the ENTIRE track with the seed ZERO silent. Every declared orbit emits events. The seed is necessary AND sufficient. The tracks were never the problem. THE FIX is two blank lines. They are load-bearing and the file now says so. Verified through the real seam, not by inspection: replicating Pulsar's exact chunking and wrapping and feeding it to ghci now yields 51 setF calls with the right values (13=0.0, 49=0.5, 77=0.769, 78=1.0 ...) and prints the boot banner. Before the fix the same harness produced only the parse error. WHY EVERY EXISTING GUARD MISSED IT. check-boot.sh passes 1-3 prove the helper block typechecks, the seed block typechecks, and the helpers emit events against an empty control map. All three were green throughout. They test the Haskell; the failure was in how the file is CHUNKED AND FED. Green checks on a component say nothing about whether the data reaches it — the rig's signature failure, and this is the purest instance of it yet. #61 was closed on exactly that false comfort. So this adds check-boot.sh pass 4 / tools/check-boot-blocks.py, which replicates Pulsar's chunking bug-for-bug (the non-global .replace included), feeds every block to a bare ghci, and fails on parse errors only — "not in scope" and type errors are expected without Tidal and are ignored. Negative-tested against the pre-fix file: it names block 26 at BootTidal.hs:663 and exits 1. One bug found in the guard before trusting it: capturing stdout and stderr separately and concatenating them put every marker before every error, so each parse error was attributed to the LAST block rather than its own — it confidently blamed block 28. Now one interleaved stream.PLN (Algolia) authored2648074d
×