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.
| Name |
Last commit
|
Last update |
|---|---|---|
| .. | ||
| at | Loading commit data... | |
| bridge | Loading commit data... | |
| foundry | Loading commit data... | |
| pulsar-parvagues-hud | Loading commit data... | |
| pvlint | Loading commit data... | |
| tests | Loading commit data... | |
| README.md | Loading commit data... | |
| analyze_samples.py | Loading commit data... | |
| check-boot-blocks.py | Loading commit data... | |
| check-boot.sh | Loading commit data... | |
| check-mix.py | Loading commit data... | |
| check-tracks.sh | Loading commit data... | |
| control-lens.py | Loading commit data... | |
| fan_check.sh | Loading commit data... | |
| gen_tokens.py | Loading commit data... | |
| gen_ts_types.py | Loading commit data... | |
| gig-log.py | Loading commit data... | |
| gig_record.sh | Loading commit data... | |
| lcxl-init.py | Loading commit data... | |
| lcxl-leds.py | Loading commit data... | |
| mock-lcxl.py | Loading commit data... | |
| mute.tidal | Loading commit data... | |
| orphan-orbits.py | Loading commit data... | |
| probe-chain.py | Loading commit data... | |
| sample_tfidf.py | Loading commit data... | |
| setlist_samples.py | Loading commit data... | |
| shipowiz.py | Loading commit data... | |
| silent-eval.py | Loading commit data... | |
| solo.tidal | Loading commit data... | |
| tempo-lens.py | Loading commit data... | |
| tidal-remote.py | Loading commit data... | |
| tools.png | Loading commit data... | |
| unmute.tidal | Loading commit data... | |
| unsolo.tidal | Loading commit data... |