- 03 Aug, 2026 12 commits
-
-
Whitespace only — PLN opened docs/GIG-CHEATSHEET.md to send it to his phone and print it for the rehearsal, and the save stripped the trailing blank line. Committing it so the tree is clean before travel: an unexplained dirty file is exactly the shape a Pulsar buffer-clobber leaves behind, and the next session should not have to re-derive that this one was benign.
PLN (Algolia) authored -
Self-correction before it misleads anyone at 2am in a tent. §1 told PLN to use `Window: Reload` to pick up the on-disk desire.tidal fix. That is wrong, and it is wrong in a way already recorded: Reload restores buffers from Pulsar's SESSION CACHE, not from disk. PLN's own words when we learned this: "cause reloads dont do it". The only reliable manual action is to close the tab and reopen the file. Also names tonight as the trap's THIRD recorded bite, and its nastiest shape so far: it reverted an on-disk fix within minutes and thereby made a correct fix look wrong in a verification loop — the earlier instances were noticed as a wrong knob, this one as a wrong test result.
PLN (Algolia) authored -
PLN: "so tomorrow its not a MORNING.md note its an EVENING.md one :P" — he travels at dawn, so the next time he and the rig are both awake it is evening, in a tent, on headphones. MORNING.md's whole frame (the KRKs, the room, the last speaker day) is spent. Written for that context specifically: what needs ears vs what needs the room, and §1 first because it is the only item that can destroy work — Pulsar is probably still holding the broken desire.tidal buffer, and it already clobbered this fix once tonight. Carries forward the two things he has not heard yet (1-cycle xfade with the -6 dB cut-group explanation, desire's repaired midiOn bass), the fact that NOTHING from tonight was recorded and why that promotes #37 to a blocker, the unchanged ghost list with the paste-at-top remedy, and the rig health numbers measured mid-set. Also records the MIDI fork he diagnosed himself, because it is the kind of thing that reads as impossible the second time it happens: Tidal hears the LCXL over ALSA seq (24:0 -> SuperCollider in4), Ardour hears it over PipeWire's Midi-Bridge into `ardour:MIDI Control In` via Midi Through. Break either and the other stays perfect — which is exactly why "midi passes to midiOn/off but no fader moves" was a real, coherent symptom and not a contradiction.
PLN (Algolia) authored -
Caught by tools/silent-eval.py on the four tracks PLN saved at the end of the last speaker rehearsal. `desire` did NOT compile — meaning the bass he had just called "doope" existed only in a running ghci, in a take that was never recorded. A saved file that does not compile is the worst kind of gig blocker: it looks like work is safe. THE ERROR LIED ABOUT ITS LOCATION <track>:409:7: Couldn't match expected type: Pattern ValueMap with actual type: Pattern ValueMap -> Pattern ValueMap Probable cause: 'midiOn' is applied to too few arguments In the first argument of '(#)', namely 'midiOn "^45" (# crush 6)' Line 409 of the generated file sits in the "Claude's Gesture" block, so that is where I looked first, and a plausible fix there changed nothing. `--keep` and a read of the actual generated Haskell found it three blocks earlier: orb4_51 = idcp $ gF2 $ gM3 $ midiOn "^45" (# crush 6) -- a FUNCTION # "bassWarsaw" # voice 0.05 -- used as the LEFT operand of # "Claude's Weight" had exactly one note figure, "0@5 0 <2 3> <1 0>", and that figure moved into Gesture's new midiOff. What remained was a midiOn with no pattern to apply itself to. GHC unified across the whole d4 group and reported the position where the type conflict surfaced, not the block that caused it. TWO FIXES 1. "Claude's Weight" commented out, params and all, with the reason inline. Nothing musical is lost — the LAST d4 in a file wins, and that was never this block. Restoring it needs a note pattern of its own, which is a taste call. 2. "Claude's Gesture" — `midiOn ch` passes its argument straight to someCyclesBy (BootTidal:391), so it must be a FUNCTION. Both note figures are now LEFT sections of `#`: ((note (scale ...)) #). That keeps the original semantics exactly: note supplies the rhythm, bassWarsaw and the params merge in. ON = the moving arp, OFF = the grounded root, which was the intent. VALIDATION: `silent-eval.py --seeded live/collab/raph/desire.tidal` -> "ok — every declared orbit emits events". Cold, no rig, no second ghci. PROCESS NOTE WORTH KEEPING: the first attempt at fix (2) was written to disk and then silently reverted — PLN quit Pulsar and reopened it, and Pulsar wrote its stale BUFFER back over the file. That is #95 / the buffer-clobber trap, observed live rather than theorised. Any on-disk fix to a file open in Pulsar needs a Window: Reload before the editor touches it again.PLN (Algolia) authored -
The last speaker rehearsal before OPAL. Saved as played, not as I would have written it: these are ear decisions and the ear was in the room. desire.tidal — the "FIXME BASS!!!" is answered * 127 -> 128 BPM. * d4 Claude's-Gesture bass is now a TWO-STATE gesture instead of one line: `midiOn "^44"` takes the busy arpeggiated figure ("<[0 3 0@14] [0 <2 4> 0@14] [3 0 2@14] [0 3 <0 -3>@13 ~]>") and `midiOff "^44"` holds the sparse root ("0@5 0 <2 3> <1 0>"). One button now moves the bass between grounded and moving, which is what the track wanted. * d3 stops fighting itself: the 32-bar gain swell (range 1.3 1.6 saw * per-hit velocity) is parked as a flat `# gain 0.9` with the swell kept commented directly beneath it, and `legato` goes back to being a knob. * d5 named: "Piano Desirable show". mafia_sans_serif.tidal — d7, the one that was "ACID WEIRD NOT GOOD": `slow 2` becomes `fast 2` and gain 1.1 -> 1.5. It sits up now. you_my_sunshine / vague_de_crime — small level and structure trims from the Sunshine -> Vague seam work. backlog.md — BPM annotations on the tail: Desire [129], le shifteur marteau [130], REVOLUTION [114]. backlog.md is the setlist SSOT (#123), so these are the numbers the tooling will read. Recorded verbatim, INCLUDING two things I have not touched and am reporting rather than silently fixing: * desire d3 now reads `# legato (range 0.05 0.9 "^18")` while the comment above it still says "^52: tightness". If ^18 belongs to another orbit's column that is the #54 borrowing problem live on stage — flagged, not edited. * NOTHING FROM TONIGHT WAS RECORDED. "Tidal Live" holds 120 wavs, newest dated 2026-08-02 (Take95); zero files today, no open write fds. PLN: "forgot to record!" The basses above exist only as code. That is #37's whole reason for being, and it is now getting a red warning in the HUD.PLN (Algolia) authored -
PLN, mid-rehearsal on the last speaker session before OPAL: "atm when i work the track and change eg. a # gain 1.4 to # gain 1.5, it goes whole track all d1-d12 through fadedown-fadeup over a few bars?? its not ok, i cant adjust anymore." Then the good question: "fade d1 X -> d1 X should be constant, as each percent of volume removed from X is added to id?" He is right about the arithmetic and the rig breaks it in three places. WHY CROSSFADING A PATTERN WITH ITSELF DIPS 1. envEq/envEqR are EQUAL-POWER envelopes, g(t) = sqrt(sin(pi/2*t)), so g_in^2 + g_out^2 = 1. Correct — for a LINEAR gain stage. 2. SuperDirt's law is amp = gain^4. At the midpoint both sides sit at g = sqrt(0.7071) = 0.8409, so each half's amplitude is 0.8409^4 = 0.5 EXACTLY. The equal-power promise was made in the wrong domain. 3. `overlay` fires the same sample TWICE. Two coherent voices would sum 0.5 + 0.5 = 1.0 and be flat — that is PLN's model. What actually happens: orbit with `# cut N` 2nd voice releases the 1st (playSynths broadcasts the cut group BEFORE amplitude is read — the same mechanism as the 2026-07-29 ghost bug), one voice survives at amp 0.5 => -6 dB orbit without cut two independent voices, incoherent sum, sqrt(.5^2 + .5^2) = 0.707 => -3 dB + comb Deepest at t/2, unity again at t. With t=4 that is a four-bar swell on twelve orbits at once — because each dN is its own transition and ctrl-enter re-sends the whole blank-line-delimited block, all starting at the same `now`. Editing one `# gain` changes one line but evaluates twelve. THE STANDING CONCLUSION: an overlap crossfade can NEVER be transparent on a cut-group orbit. `cut` means "one voice in this group"; a crossfade means "two". Shortening the fade does not remove the dip, it makes it a blip instead of a swell. The dip-free answer is a NON-overlapping transition (`clutchIn`), which changes the feel of every seam in the set — so it waits for after OPAL (#13). This file's own comment guessed that in July; it is now measured, not guessed. CHANGES - xfade default 4 -> 1 cycle. One token, so it is one token to flip back. - xfadeCutIn gains a `t <= 0` branch returning the incoming pattern untouched. Needed before "0 = instant" can ever be offered: Tidal guards `_slow 0 _ = silence`, and `q |* gain silence` then has no right-hand values to match, so the INCOMING pattern comes out EMPTY. Unguarded, "0 cycles" means silence, not instant. Now `xfadeIn N 0 $ ...` is a real instant swap. - Killed a trap in this file's own guidance: it recommended `p N $ ...` for fast iteration. `p` carries no `|< orbit`, so the sound lands on orbit 0 — wrong LCXL column, wrong Ardour stem, fader that looks dead — the exact failure the lines above it warn about. Points at `jumpTo N` / `xfadeIn N 0` instead. VALIDATION: tools/check-boot.sh (safe mid-set, never grabs 6010) — helper block typechecks against tidal-1.9.5, all 13 g* helpers audible with an untouched controller, and the transition ghost check still reports 0 outgoing onsets after the fade. Takes effect at the next Tidal boot; nothing in the running session changed.PLN (Algolia) authored -
Every intuition on the way to this one was wrong, including several of mine, so the log records the wrong turns as well as the answer — that is the part worth reading back. The shape: nothing crashed. sclang up, scsynth up on 6.7% CPU, sink RUNNING, routing intact, and no sound. Any monitor aimed at SuperCollider would have reported a healthy rig. PLN found the discriminator himself by switching the default sink by hand — internal speaker plays, UMC does not — which killed the pure-CPU theory and pointed at the interface, which was also not at fault: 128 vs 1024 period_size is an 8x tighter deadline, so the UMC is the canary. Recorded because they will recur: - `state: RUNNING` lied while the device was dying once a second; only repeated hw_ptr sampling is honest, and FOUR samples, not two — my two-sample read called it "still stalling" when a ring-buffer wrap looks identical to a stall. - a rule scoped to one device but applied to the whole graph stops being a fix and becomes a load (52-no-suspend matched every node; two nodes nobody used held 2.1M xruns). - the laptop mic had auto-wired itself into the d1 stem, invisible in Ardour's GUI and in the saved session, and Take95 is already exported (#132). - #7 survived two fixes because the metric counted the BOUNDED map. - my own journalctl scans burned a core twice while he was losing audio. I was the load I was measuring.PLN (Algolia) authored -
Uncommitted after the Monday session. His, tuned by ear, and sitting only in the working tree — the state that let a stale Pulsar buffer eat committed work twice. d3 gains `# att (range 0.2 1 "^31")`. d4 the two bus knobs SWAP: crushbus moves to ^52 and octersubbus to ^32, each now labelled in his own words ("BURN", "DEEP"). Both are legal d4 slots, so this is a taste decision about which hand reaches which effect, not a correction. d4 the two FIXME(#54) lines and the commented-out `octersubbus 43 ^17` are GONE. That was the third-effect overflow parked pending gSel; he resolved it by dropping the third effect instead of waiting for the fold. d5 `$ gM3` becomes `$ gM3 $ gF3` — the DJ filter is back on the SuperStars layer, replacing the commented `-- $ gF3 $ gMute3` above it. Note the d4 swap is exactly the pair of slots that a buffer clobber has reverted before (both effects landing on ^52). They are on ^52 and ^32 here — distinct, so this is the healthy state, not the clobbered one.PLN (Algolia) authored -
THE J-5 DROPOUT. Sound went glitchy-then-silent mid-rehearsal, five days before OPAL, and every obvious suspect was healthy: sclang up, scsynth up and using 6.7% CPU, the UMC sink present and RUNNING, every link in place. Diagnosing the audio engine would have found nothing wrong with it, because nothing was. THE BEHRINGER IS THE CANARY, NOT THE FAULT. The internal speaker played fine the whole time and only the UMC202HD died, which looks exactly like a broken interface. It is not: period_size 128 on the UMC against 1024 on the SOF speaker is an 8x tighter deadline, so the UMC is the only device in the box with a real-time deadline tight enough to miss. USB devnum stayed at 14 across samples (not the 2026-07-26 re-enumeration bug), mixer 127/127, links intact. Rule for next time: when only the UMC is silent, suspect the SCHEDULER. WHAT pw-top FOUND. Xruns per node: sof_sdw.HiFi__Headset__source 1,421,369 nothing used it sof_sdw.HiFi__HDMI1__sink 704,081 2.8ms BUSY/cycle, no client UMC202HD Line sink 32,338 the victim alsa_input.hw_U192k_0 14,338 W/Q 1.24 = waits > a full quantum SuperCollider 1,119 ardour 422 Two nodes NOBODY USES produced 2.1 million of them. HDMI1 appeared when the screen was mirrored for the WYSIWYG show. THE ROOT CAUSE WAS A FIX. 52-no-suspend.conf matched ~alsa_output.* and ~alsa_input.* — every node in the graph. It was written for a real reason (a woken device eats the first note's attack) but applied graph-wide it held six SOF sinks and a broken mic source permanently open INSIDE the real-time graph. Never-suspend is precisely what it asked for. The generalisable lesson, and it is the one worth keeping: a rule scoped to one device but applied to the whole graph stops being a fix and becomes a load. Suspension is not the enemy — suspension of the device you are playing through is. Now narrowed to the UMC plus the internal Speaker, the latter kept deliberately because it is the fallback that proved the machine could still make sound during the incident. AND THE LAPTOP MICROPHONE WAS IN THE d1 RECORDING. pw-link showed Headset__source:capture_FL -> ardour:Tidal 01/audio_in 1. Ardour auto-connects physical inputs, so the internal mic was summed into the input of the track that records d1, alongside SuperCollider:out_1 — invisible in Ardour's GUI and in the saved session file. 53-rig-graph.conf disables the source outright rather than trusting nobody to re-arm that track. Take95 was recorded with it connected; auditing that is #132. RESULT, measured. Load 7.17 -> 4.80. UMC hw_ptr went from restarting once a second — never past ~3000 frames, deltas going NEGATIVE — to a steady 48,145 frames/sec across six consecutive samples with zero restarts. VERSIONED, NOT COPIED. The three wireplumber files now live in config/wireplumber/ and are SYMLINKED from ~/.config. One source of truth: a copy would have become the fourth thing in this project to drift from its generated twin. check-audio-graph.sh also fails on a dangling symlink, because a broken one is silent until the next wireplumber restart — the worst possible moment to find out. NEW GATE: tools/check-audio-graph.sh, wired into gig-up as a HARD check. It asserts what was actually wrong, in the order it bites: no non-SuperCollider source on any Tidal input (recording integrity first — a dropout you hear and redo, a stem with room noise in it you ship), Master really reaching the UMC, the interface actually clocking, and the prune still in effect. check-mix reads the SAVED session; this reads the LIVE graph, and the saved file has been wrong before (#62). TWO METHODOLOGY RULES BAKED INTO IT, both learned that day: - NEVER SCAN THE JOURNAL. `journalctl --since` on a long-uptime box reads the whole journal and burned a full core twice WHILE PLN WAS LOSING AUDIO — the diagnostic making the fault worse. Everything is /proc, pw-link, bounded pw-top. - `state: RUNNING` PROVES NOTHING. It read RUNNING while the device was dying. Only the hardware pointer, sampled repeatedly, is honest — and take four samples, not two: my first two-sample read gave a confidently wrong "still stalling" verdict because a ring-buffer wrap looks identical to a stall. Mutation-checked: the recording-integrity awk was run against the real 2026-08-03 pw-link dump WITH the mic present (it fires) and against a clean one (silent, no false positive). A check that has never seen the bug it was written for is a guess.PLN (Algolia) authored -
PLN: "wheres the 'run parvagues' big HUD menu button? I see perf modes, open bridge, then the gear 4/6 up, but below open bridge, i want a 'Launch Gig' button that opens and focuses auto the parvagues". Two problems behind that one sentence. DEPTH. Pulsar was reachable only through Gear ▸ Pulsar — the hot path buried under the tool drawer. It is now a top-level entry directly below Open Bridge, labelled with what the click will actually do ("focus ParVagues" when it is up, "open ParVagues" when it is not), because "Focus" vs "Open" is the difference between a confident click and one that looks like a no-op. FOCUS DID NOT EXIST. launchers.py's docstring said "on Wayland there's no portable window-focus", so clicking a running app answered with the string "already-running" and did nothing. That is true of the X11 toolbox — xdotool, wmctrl and kdotool are all absent here and the first two cannot work under Wayland anyway — but it is not true of THIS desktop. Plasma exposes KWin's scripting engine on the session bus, and a script running inside the compositor is simply allowed to activate a window. So focus_window() registers a tiny KWin script, runs it, and unregisters it. It matches on resourceClass (the app id), not the window title: the title changes with every file PLN opens, and matching it would break the moment a filename stopped containing "Tidal". The script name carries our pid so two clicks cannot collide on an already-registered name. Verified live against the running Pulsar: focus_window('pulsar') -> True. Consequence worth noting: running native apps in the Gear menu used to be greyed out, because the only honest thing a click could do was refuse. They are live again — clicking a running app now raises it, which is the thing you actually want mid-set. Deliberately editor-only. Launch Gig does not start SuperCollider, boot Tidal or arm Ardour: #116 is the standing rule that the hot path must not be able to start the sound by accident, and one wrong click before a set is a stuck scsynth rather than a convenience. Every failure path falls back to reporting. A focus button that quietly does nothing is a papercut; one that throws during a gig is not acceptable. Bridge suite: 43 passed.PLN (Algolia) authored -
The KRKs go home after tomorrow's dawn rehearsal, so this is the last run with real monitors — and desire / REVOLUTION / electric_hammer have not been played this cycle at all. Read them cold so his ears go to the music. Two findings worth the read, both the same shape as Sunday's do_it_right bug: desire declares d4 THREE times in one block (lines 50, 56, 62), under his own "-- FIXME BASS!!!". Later wins, so the two takes he tuned are dead code. The winner differs in ways that do not read as a choice: it has no lpf on ^32, so that knob is dead on the bass, and it carries no gain at all where the other two say 1.15 — which under SuperDirt's quartic law (amp = gain^4) is 4.8 dB quieter than the level he dialled. electric_hammer declares d5 twice (32, 46). The superfreak voice wins, so ^89 and ^33 have nothing behind them, ^57 does something other than what the dead copy above it describes, and hammer:7 — the sample the closing track is named after — never sounds. Also: the five closing seams with their ghost orbits, paste-ready orphan guards for the two worst, his two vague_de_crime TODOs with the gain converted to dB, and the gate result (GO, 12/12). One methodology note recorded in the doc: silent-eval must be run --seeded here. Unseeded it reports 12 SILENT orbits across these three tracks, every one of them a midiOn gate sitting at default-off. That is the harness, not the music.
PLN (Algolia) authored -
Four tracks carried uncommitted edits after the KRK run. They are his, they are tuned by ear, and they were sitting only in the working tree with a rehearsal scheduled for dawn — exactly the state that let a stale Pulsar buffer eat committed work twice before (#95). Committing them so tomorrow's run starts from disk, not from whatever a buffer happens to remember. What he changed, and why it reads as deliberate: - gimme_acid d5 gains a `^56` jungle_breaks:15 swap and the slice pattern moves under `whenmod 16 8`, so the chop only bites for half of every 16 cycles instead of running flat the whole time. d11 gets `# gain 1.5` and a renamed comment ("BOOM, BOOM, BOOM"). - perfect comment-only: d1 "Famous Clubkick", d2 "Clap Mechamment Celebre". Naming the kick and the clap is how he finds them mid-set. - bombe_dj `resetCycles` commented out. This is the SET OPENER after quand_on_decolle; resetting the clock at the top of track 2 yanks every still-ringing orbit's phase from the track before it. - vague_de_crime d1 kick +0.3 gain, d6 gains `midiOn "^90" (ply 2)`, and two TODOs written in his own words: the kick wants comparing against the rest of the set, and d3 is "less solid than in do it right or drops or ouais". The two TODOs are ear-work for the last-third rehearsal, not defects to fix blind — logged rather than acted on.PLN (Algolia) authored
-
- 02 Aug, 2026 17 commits
-
-
Master: 61.0 min, 2 ch, 48 kHz, 24-bit. I = -14.0 LUFS on the nose, peak -0.9 dBFS under a -1.0 ceiling, LRA 12.7 LU. L-R difference RMS is -22.4 dB, so it is genuinely stereo and not dual-mono — worth measuring rather than assuming, given the first attempt collapsed to one channel. THE BUG THAT WOULD HAVE SHIPPED. take-master trims leading silence before loudnorm sees it, so the master starts 10.94 s later in the music than the raw take does. The segments were computed against the RAW take. Splitting with unshifted offsets puts every boundary eleven seconds late — each track beginning eleven seconds into the previous one's tail. The output would have played perfectly and been wrong throughout. Two guards in take-segments: --shift subtract the measured head trim. Clamped at 0, because the first track legitimately goes negative: PLN focuses a .tidal a few seconds BEFORE he evaluates it (log says 7.4 s, first sound is at 10.94 s). --master probe the mastered file and clamp to its duration. The master is trimmed at the TAIL too (1.45 s), so without this the last segment ran past EOF and ffmpeg would have written a short final track in silence. Now: contiguous, starts at 0, sums to 3661.2 s — exactly the master's length. AND A SHADOWING BUG FOUND WHILE FIXING IT. The per-segment loop bound `start` and `end`, the same names as the take window, so the summary line printed the LAST SEGMENT as if it were the whole take: "1970-01-01 01:55 — 5.1 min". The segments were correct the whole time; only the report lied. That is the kind of defect that ships, because the payload looks right and nobody re-reads a header. GENERATIVE METADATA, per PLN's ask, derived not typed: title backlog.md via setlist.py (the SSOT reaches the ID3 tag) TBPM backlog BPM, NOT setcps — reference_tempo_from_audio, setcps is not felt tempo. gimme_acid is setcps 80 played as 160 half-time DnB, and you_my_sunshine is setcps 144 against a felt 166. Tagging 80 would have been a measured number that misleads. grouping the set section (Ouverture / SUNSET / NuJazz / NUIT) comment orbit inventory from the .tidal via pvlint's parser, plus the source path, so any track can be traced back to the code that made it Metadata says REHEARSAL, not gig: album "OPAL 2026 — rehearsal, J-6", date 2026-08-02, no venue, no lineup, no poster (feedback_metadata_vs_mastering — gig metadata is canonical only in Web/www/next/content/lives/). lime_tacos is track 7 at 1:49. He played it, then cut it from the set an hour later. The take records what happened, so it stays, tagged "not in the final set". Committed: segments.json, track_metadata.json, analysis.json — the provenance. Gitignored: the FLACs and MP3s, ~1.3 GB of derived audio regenerable from the Ardour stems in two commands.PLN (Algolia) authored -
`tidal-ears master mix` has the right recipe and this reuses it verbatim. What it does not know is how Ardour lays out a take, and that produced two defects that only appear on this material — both of which I only caught by inspecting the output file rather than trusting "Done:". 1. MONO. Ardour writes each orbit as TWO mono files, `Take95_Tidal 04-1%L.wav` and `%R.wav`. Globbing all 24 into amix sums them into ONE channel. The stereo image is gone — and ParVagues pans deliberately (`# pan 0.8` on the hats, `0.2` on take_5's sleepwalker), so that is not a technicality, it discards a compositional layer silently. Each pair is now `join`ed into stereo first and the mix is 12 stereo streams. 2. 192 kHz. loudnorm resamples internally to 192 kHz to measure true peak, and with no explicit output rate ffmpeg keeps it. A 48 kHz session produced a 624 MB 192 kHz file carrying no extra information. `-ar` is now pinned to the source rate. NB this one affects every master the sister tool has made. UNIFORM TRIM, not per-stem normalisation. gain_for_stem normalises each stem toward a target peak, which is right for stems of unknown provenance and wrong for these: PLN balanced these twelve orbits by hand, on faders, while playing. Normalising individually rewrites that balance — measured at 4.0 dB of shift on Take95, mostly making the hats hotter. One trim for every stem preserves the mix he played; loudnorm sets the absolute level. Same conclusion take-lens reached. AND THE MEASUREMENT ITSELF HAD A TRAP. The first version used `volumedetect`, which reports max_volume against a fixed-point full scale and SATURATES at 0.0 dB. Every one of these float stems read as exactly +0.0, so the derived trim was -6 dB when the truth needed -19.3. Twelve identical +0.0 readings is not data, it is a clipped instrument — `astats Peak_level` reports the real values and they match the sister tool's analyze pass exactly (d4 +13.3, d3 -3.3). Refuses to render if an orbit has only one side, rather than panning it hard. Verifies channels and rate of its own output and exits non-zero if either is wrong — the check that would have caught both original defects.PLN (Algolia) authored -
output/Take95/segments.json — 11 tracks over 61.2 min, derived from gig-log by tools/take-segments.py rather than detected in the audio. Committed because it is the provenance for the album's track boundaries and titles: without it, the split is an unexplainable list of timestamps. Titles come from backlog.md via setlist.py, so they are the same strings PLN wrote, not a second copy that can drift. 1. bombe_dj 3:53 | 2. wap 3:19 | 3. do_it_right 8:25 4. take_5 10:19 | 5. piment 4:30 | 6. ouais_je_funk 4:54 7. lime_tacos 1:49 | 8. perfect 6:52 | 9. gimme_acid 5:19 10. vague 6:47 | 11. sunshine 5:04 lime_tacos is in the take at 1:49 — he played it, then cut it from the set an hour later ('actually weak'). The take is a record of what happened, not of what the set became, so it stays.PLN (Algolia) authored -
Third session running, he raised faders by hand and hit Ctrl+S, then asked the right question: "ok raised and saved 10 and 12, saved, check again. but ideally we should not depend in that?" He is right. The gate CAUGHT the problem all three times — the dependency was never on the check, it was on him having hands free to fix it. On a Saturday at 19:00 in a field that is not a dependency you want. THE MECHANISM, now understood: the Ardour session IS the boot state. He ends a set with the faders pulled down, which is what you do at the end of a set, Ardour saves that, and the next launch comes up silent. Today's save had NINE of twelve at -inf, and all 15 setlist tracks would have lost an orbit — d10 carries the riser convention (#33), so all ten risers would have been silent and he would never have heard them go. tools/fader-baseline.py: --capture / --check / --restore. WHY THIS IS ALLOWED TO WRITE FADERS when the standing rule says never to. The rule exists for three reasons — it desyncs the file from the physical desk, CC77 down is total silence, and levels are MUSICAL INTENT an agent must not invent. All three are about INVENTING a level on a LIVE desk. This does neither: it replays a value PLN set and approved (stamped with date and source session), it refuses to write under a live session so the desk always wins, and it can only address routes named "Tidal NN" — Master, monitor and busses are not reachable by this tool at all. It writes a .bak first, because a corrupted performance session six days out is not a recoverable mistake. --capture REFUSES if any fader is silent. Capturing end-of-set silence as the baseline would enshrine the exact bug this undoes. Baseline captured while the mix was green: 12 faders, 01 at 0.0 dB through 09/12 at +6.0 dB. PROVEN BY MUTATION on a COPY, never his live session: pull the same nine faders to 0.0, --check reports all nine with their baseline deltas and exits 1, --restore puts them back, and check-mix.py independently agrees every orbit reaches master again. AND THE TEST FOUND A REAL BUG IN THE GUARD. The first version asked "is ANY Ardour running" — the safe-LOOKING answer and the wrong one, because it refuses to repair a session nobody has open, and it made the restore path untestable while his live session was up. The hazard is writing UNDER a live session, so the guard now matches on the resolved session path. Still refuses his open one; no longer refuses everything. Wired in two places: a HARD "fader baseline" check in the gate, and a --converge action that restores automatically when Ardour is closed. gig-up: GO, and --converge is a clean no-op on a healthy rig.PLN (Algolia) authored -
Last KRK day. The chart PLN asked for, and the honest reading of it: the SET is finished and derived rather than maintained, the TOOLING is done and should stop there, and the long pole is REHEARSAL — 11 of 14 tracks played, three never heard this cycle, and those three are the FINALE and ENCORE. gig-up is NO-GO on exactly one thing and it is not code: nine of twelve Ardour faders sit at -inf in the saved session (#124, third recurrence). Mechanism now suspected — he ends a set with faders down and that is what Ardour saves, so the saved session is a snapshot of end-of-set silence. Thirty seconds to fix today, but #20's template is the real answer before Saturday. Pacing measured for the first time rather than guessed: Take95 ran 61.2 min for 11 tracks = 5:34 each, so 14 tracks is ~78 min against a 90 min slot. Twelve minutes of slack. Also carries the buffer-clobber warning for tomorrow's editing session: close and reopen any tab open yesterday, because Window: Reload does not do it.
PLN (Algolia) authored -
Today's buffer clobber should have been caught. It was not, for two reasons that are each worse than the bug: 1. tools/check-drift.sh was NOT wired into gig-up.sh at all. Grepping this file for it returns nothing. The memory note claiming it was wired in was simply wrong, and had been trusted since. 2. The script was mode 100644, so invoking it exits 126 (permission denied) — the FOURTH occurrence of the chmod-vs-git-mode bug, and the reason the "tools executable" check exists. check-drift.sh was not in that check's list either. A check that exists, is documented as guarding the gate, and is never called is worse than no check: it buys confidence it does not deliver. That is the same lesson as the two dead checks found when gig-up was first assembled. NEW HARD SECTION 1c "surface grid intact", asserting two things: * check-drift.sh passes (the committed grid still holds) * migrate-columns.py --plan reports 0 moves (the WORKING TREE needs none) The second is what actually caught today's clobber. When Pulsar wrote its stale buffer over wap.tidal, d4's octer knobs reverted ^32 -> ^52, undoing a migration committed and pushed hours earlier. That was invisible in `git status` — the file just reads as modified, mixed in with PLN's own real edits. What made it visible was migrate-columns being IDEMPOTENT: 0 moves one minute, 1 move the next. Any property a tool can re-derive is a property a gate can assert. PROVEN BY MUTATION, and the first mutation was wrong in a useful way. Flipping ONE knob ^32 -> ^52 did not trip the check, and that is correct: B4 and C4 are both legal d4 slots, so two effects merely swapping slots is not drift. The real clobber put BOTH effects on ^52 — one knob driving two effects — and that trips it immediately, printing the offending moves. Had I stopped at the green run I would have shipped a check I believed in for the wrong reason. Also adds check-drift.sh and take-segments.py to the executable-bit check, and records 100755 for both in git.
PLN (Algolia) authored -
Splitting a livecoded set by listening to it is hard, and we have the scars for it: orbits stay up across a transition, there is no silence at the seam, and a gap-based detector finds the breakdowns instead of the track changes. But gig-log has been writing the answer at 1 Hz this whole time. Every time the active .tidal file changes in Pulsar it records {"k":"track", "path":"live/collab/raph/mafia_sans_serif.tidal", "from":"live/midi/nova/dnb/liquid/you_my_sunshine.tidal"} which is ground truth for WHAT was playing, for free, with no DSP. The audio never had to be interrogated at all. THE ONE COMPLICATION is that PLN tabs around while he plays — glancing at the next track, checking a helper, flicking back. Take95 contains wap -> do_it_right -> wap -> do_it_right inside 90 seconds. So a segment shorter than --min-dwell is a GLANCE and gets absorbed into whichever NEIGHBOUR is longer (the track you were on, not the one you peeked at). Debouncing needs a fixed-point loop, not one pass: dropping a glance can leave two spans of the same track adjacent, merging those can leave a span that is still under threshold. Take95's take_5_drops/do_it_right flicker takes three rounds to settle. 29 raw events -> 11 tracks. Window comes from the AUDIO (soxi duration + mtime of the stems), not from the log, so a recorder still running after the transport stopped cannot stretch the take. Titles come from tools/setlist.py, so a rename in backlog.md reaches the ID3 tag — the SSOT rule now extends all the way to the export (#123). Emits the --segments shape `tidal-ears master split` already accepts, so the mastering pipeline needs no changes. Take95 (2026-08-02, 61.2 min): 11 tracks, bombe_dj through you_my_sunshine — which is exactly where PLN said he stopped ("didnt play desire/revolution/ hammer").PLN (Algolia) authored -
PLN: "in you my sunshine the bass easily saturates too, not sure if code or ardour setup". Code, measurably — and the same number as this morning's kick. d4 is not one bass, it is two playing at once: a `superimpose (const ...)` bassWarsaw plus the chopped no_sunshine loop. ^32 crossfades between them: superimpose # gain (range 0.5 2 "^32") -> peak +24.1 dB at ^32 max main # gain (1.8 - 0.6 * "^32") -> +20.4 dB at ^32 UNTOUCHED Both are crushed off the same ^52. So the orbit is loudest at BOTH ends of the crossfade and its default resting state is +20 dB — a fader ride cannot rescue that, because the shape is wrong, not the level. Now `range 0.5 1.5` and `1.5 - 0.3 * ^32`: both ends land at +14.1 dB, so the crossfade holds roughly constant loudness instead of bulging. This is [[reference_superdirt_gain_is_quartic]] applied a second time in one day — the gain^4 exponent is why 2.0 reads harmless and meters at +24. Also: "d3 should also be the classic techno runner companion on 43, so it hits(4,8,1)". ^43 was a bare `ply 2`. Now `ply 2 . struct "t(4,8,1)"` — struct puts the hats ON the euclid rather than thinning what is already there (mask can only remove), and ply doubles each into a running 8. Released, the liquid pattern returns. REAPPLIED after a buffer clobber: wap's d4 octer/octersubsub had reverted from ^32 back to ^52 when Pulsar wrote its stale buffer on close. Exactly [[reference_pulsar_buffer_clobber]], and exactly what #95 exists to prevent. Caught because migrate-columns --plan is idempotent and went from 0 moves back to 1. PLN's own new FIXME on that line ("too wobbly... not fan of the 44/76 slicing") is preserved. SET REORDERED by PLN: gimme_acid -> mafia -> sunshine -> vague -> desire. "sunshine great cinematic ending, but sunshine-to-vague-to-desire makes more sense imo." vague->desire is now a CLEAN transition, and sunshine's 166->120 drop into vague is the one seam to watch. Setlist and preload regenerated from backlog.md; 52 banks cover all 15 tracks.PLN (Algolia) authored -
PLN added quand_on_decolle under a new ## SOUNDCHECK heading mid-session. The gate caught both downstream consequences without being asked: setlist vs backlog FAIL -> the .txt was 14, backlog.md was 15 preload covers set FAIL -> 'airports' would have been read from DISK on first play, i.e. crackle, on the soundcheck track That is the #120 failure mode caught BEFORE the venue instead of at it, and it is the second time in two days the backlog->setlist->preload pipe has earned itself. gig-up: GO, 10/10 cold. preload.scd takes effect at the next SuperDirt boot — NOT applied live, since scsynth is up and restarting it costs ~15s of silence.PLN (Algolia) authored -
Densest ear-feedback session logged so far, and the finding that makes it worth re-reading: not one of PLN's 'it sounds wrong' reactions was a mix problem. 'muffed' -> a SynthDef's own 1 kHz Moog lowpass, no cut group, shared bus 'loud' -> SuperDirt amplitude is gain^4, so `# gain 2` is +24.1 dB 'irritating' -> a literal ascending scale being used as a melody 'no buttons' -> CCs that were never mapped 'weak' -> the one track the column remap never reached Includes the gain->dB table and the measured claim that the OPAL set's median orbit sits at +11.7 dB while four sit at +24.1 dB — and the rule that follows: when an orbit clips, rank the track's orbits in dB before touching a fader. A 10 dB intra-track outlier is a bug; 2 dB is a mix choice. Feeds #91 and #17.
PLN (Algolia) authored -
PLN, mid-run: "i hear no d7? or its muffed like '# att 0.2' or sth?" — then, after experimenting: "tried adding 'arp up' before the chord, its now a set of 4 muffed short notes LOL. but d7 still muffed". Read the SynthDef instead of guessing the synth (CLAUDE.md: never infer a sound's role from its name, validate). SCLOrkSynths/SynthDefs/bass/moogBass.scd: arg ... cutoff = 1000, gain = 2.0, att, dec, sus, rel, chorus = 0.7; filter = MoogFF.ar(in: osc, freq: cutoff * (1.0 + (0.5*filterenv)), gain: gain) A 4-pole Moog lowpass parked at 1 kHz, on a SynthDef whose own metadata reads `category: \bass, tags: [\pitched, \bass]`. Every harmonic above 1 kHz is gone at 24 dB/oct. A "CHOEUR GENERATIF" voiced on a bass synth cannot be anything but mud, and no amount of gain, room or crush was ever going to fix it. `# cutoff 3500` opens it — 2500 warm pad, 3500 choir, 6000 buzzy. TWO TRAPS in this SynthDef, now written into the file where the next reader will hit them: * it DECLARES att/dec/sus/rel and then ignores them — the envelope is a hardcoded Env.adsr(0.001, 0.3, 0.9, 0.2, amp). That is why PLN's `# sus 2` did nothing and he commented it out. Shape this voice with legato. * `gain` in this SynthDef is the MoogFF filter RESONANCE, not a level. Three more real defects in the same orbit, all found by tooling, all fixed: * legato 2 -> 1.2. His new arp makes quarter-length notes; 2x overlap smeared them into each other. That is the "4 muffed short notes". * d7 had NO cut group at all, so held voices piled up — on a synth that also carries its own 7-tap chorus. Now `cut 7`. * crushbus restored, on slot 71 rather than d4's 41. The shared-bus case that became PV011 twenty minutes ago. And PV004 caught one PLN had not mentioned: d11 (THE FLUTIST) and d12 (THE SLEEPWALKER) both sat on `cut 11`, truncating each other instead of layering. d12 now owns cut 12. Also in this commit: mafia_sans_serif's d7, whose diagnosis is written up in b8344ac1. take_5_drops now 0 errors / 0 warnings, silent-eval --seeded ok.PLN (Algolia) authored -
THE PHANTOM. PLN drafts in backlog.md, and he drafts in LIST ITEMS. Mid-run he wrote himself a deliberation: -- Q: This intro is quite raptech. jazz intro? quand on decolle opening? reflect and quand_on_decolle silently joined the OPAL set. The resolver's "codename carries extra words" branch is a subset test, so {quand, on, decolle} being 3 of those 13 words was a match. It then flowed downstream exactly as designed — into the .txt, the preload plan, the remap scope and the gig gate. The pipe worked perfectly, on garbage. Two guards, because either alone is too clever: * _NOTE_RE skips items marked Q:/NB:/NOTE:/TODO:/FIXME:/IDEA:, and PRINTS what it skipped. A note dropped silently and a track dropped silently look identical from inside the parser, and only one of them is survivable. * the extra-words branch is bounded to 4 decoration words. Real entries spend at most 4 ("[129] Desire [TODO BASS ETC!]"); that note spent 10. An UNMARKED prose line now RAISES instead of resolving. That is deliberate and tested: red gate, PLN adds "Q:" or deletes the line. A phantom track goes to the venue. Loud beats clever. (He has since re-added quand_on_decolle under an explicit ## SOUNDCHECK heading, as a real entry. It arrived carrying the full off-by-one-column corpus pattern — 11 moves — now migrated. That is the pipe working on something real.) DEAD BUTTONS. PLN, playing: "not seeing effects on button 44 nor 43?" on do_it_right, "no buttons 42 43?" on ouais_je_funk. They were not broken, they were never mapped. Now: do_it_right ^43 d3 hats — HIS OWN TODO implemented verbatim: "an opening legato or att to make it slowly go from hard dry h to an open ho? as in take 5 drops". Held, legato walks 0.4->2.5 and hpf 7k->2.5k over 8 cycles; released, it snaps back. do_it_right ^44 d4 bass — octave down, DROP TO THE CELLAR ouais_je_funk ^42 d2 clap — the clap had no gate at all. Handclap roll. d4's crush/octersub land on ^52/^32 exactly as PLN asked. That required REORDERING the two lines, not renumbering them: migrate-columns assigns knobs in order of declaration, so the file now carries a comment saying the order is load-bearing. Fighting the tool by hand would just be undone next run. Set: 15 tracks, 0 moves pending, silent-eval --seeded 15/15, pvlint 0 errors, setlist tests all green (now pinning lime_tacos OUT and the phantom absent).PLN (Algolia) authored -
PLN, at rehearsal, on take_5_drops' d7 coming out muffled: "i saw also its crushbus was 41, a d7 with sub 4 is sus -- and two effects on same bus is a redflag as it means fighting for bus! so we gotta flag warning any 'bus nXY on dX' as sus (e.g. bus 41 (d4's) on d7 here), and any shared bus (^41 on d4 and d7) as PV error" Two rules, exactly as specified. PV014 (warning) — a bus slot numbered for a different orbit. The convention is <orbit><slot>: d4 owns 41/42, d10 owns 101/102, and a bare `bus 4` on d4 is the same idea with one slot. MEASURED before encoding it rather than assumed: 894 of 984 bus references under live/ conform, 90.9%. A real convention, not a tidiness preference. Mis-numbering is *how you accidentally share* a bus, so this rule sits upstream of PV011 and catches the cause, not the symptom. PV011 promoted warning -> error. It shipped as a warning on the theory that sharing a bus is legitimate glue. Rehearsal disproved that theory. The asymmetry with PV008 is deliberate and now documented in both rules and pinned by a test, so no future refactor quietly aligns them: yesterday PLN DEMOTED a shared button to a warning ("its ok when two percs are linked"), today he PROMOTED a shared bus to an error. A shared button is one hand doing two things on purpose and you hear it instantly. A shared bus is two orbits fighting over one effect instance with the winner decided by event density — you don't hear a mistake, you hear a slightly wrong sound and blame the synth. Surprises you can hear are warnings; surprises you cannot are errors. THE PAYOFF, first run, in a track still in the set. mafia_sans_serif's d7 was already carrying PLN's own note "FIXME ACID WEIRD NOT GOOD". It had THREE collisions with d4's moog bass, none visible in the code: # cut 4 every acid note truncated the bass, and vice versa # crushbus 41 one crush instance, ^35 and ^32 fighting over it # octerbus 42 one octer instance, ^55 and ^52 fighting over it d7 now owns cut 7 and slots 71/72. That is a diagnosis for a FIXME he wrote without knowing the cause, produced by a rule written twenty minutes earlier. Set is 0 errors / 9 warnings, silent-eval --seeded 14/14 ok, pvlint 68/68.PLN (Algolia) authored -
PLN, mid-run: 'wait bass was also on 89 not yet 76 whyyy i thought we were systemic :((' — and he was right to be annoyed. The answer is embarrassing and exactly the bug we already fixed one layer up. tools/migrate-columns.py hardcoded SETLIST = armada/setlist_opal2026.txt. That .txt was 13 tracks while backlog.md was 15. So when the remap ran, the two tracks PLN had just added were the only two it never saw — ouais_je_funk and lime_tacos kept their pre-remap CCs and he found out by reaching for a control that wasn't there. Same shape as #120/#121: a generated artifact consumed as if it were the source. resolve() now calls setlist.tracks(), i.e. backlog.md. Re-planned against the real set: 22 pending moves across 4 tracks, 11 of 15 already clean. Then PLN cut lime_tacos ('actually weak, will have more fun on ouais funk and perfect') — removed from backlog.md, and the 14-track setlist plus the plan regenerated themselves from it. That is the pipe working. Applied, 10 moves: wap d4 octer/octersubsub ^52 -> ^32 (B4) piment d7 modIndex/octersub swapped onto B7/C7 in declaration order ouais d3 snare gate ^44 -> ^43 (E3) ouais d4 crush ^53->^52 (C4), octersub -> ^32 (B4) ouais d5 width/crush swapped onto B5/C5 ouais d5 superimpose ^57 -> ^89 (F5, gestures live on row F) ouais d7 UPDOWN ^55 -> ^35 (B7) d4's 'ply 2' had been authored on a KNOB (^56) and the migrator dutifully gave it d4's B4 slot, which pushed the octersub into an overflow FIXME. But PLN had just asked for exactly the opposite layout — 'd4 52 a crush? 32 a octersub maybe?' — so ply moved to ^44 (E4, a gate on the gate row, free now that d3's snare vacated it) and both effects got their proper knobs. No FIXME left. Verified: migrate-columns --plan reports 0 moves, silent-eval --seeded 14/14 ok.PLN (Algolia) authored -
PLN typed a TODO comment into the middle of `d12 $ gF3 $ gM3`, landing the `3` after the `--`. The line became `d12 $ gF3 $ gM`, and `gM` does not exist: Variable not in scope: gM :: Pattern ValueMap -> Pattern ValueMap Perhaps use one of these: 'gM1', 'gM2', 'gM3' One parse error silences the WHOLE do-block, so this was not 'd12 is quiet' — it was 'do_it_right makes no sound at all', found by silent-eval --seeded while he was mid-run. Comment moved above the line, where it cannot swallow code. The TODO itself is preserved verbatim: he wants more of ^18/^19 on this lead.PLN (Algolia) authored -
J-6, the one-before-last KRK rehearsal. Per-track watch list for the 1h30 run, because ten of the fifteen tracks have something in them PLN has never heard: seven new d10 risers, the take_5_drops d5 structure fix, ouais_je_funk's d10 finally mutable, lime_tacos' cymbals relocated to d12, and two tracks that were not in any tool's idea of the set until yesterday. Also carries the fresh ghost matrix (9 of 14 transitions, 18 orphans) recomputed on the real 15-track order — and the pleasant surprise that adding the two missing tracks produced the longest clean stretch in the set, piment -> ouais -> lime -> perfect.
PLN (Algolia) authored -
PLN: "for lime if d11 taken lets push d6 to free d12 :)" — d11 is held by "Menace de retour", and d10 is now the safe riser, so d12 was the free slot. The move is genuinely one token: d6 appears exactly once in the file, carries no `cut 6` and no orbit-bound crushbus, so nothing had to follow it. ^44 stays shared with d3 DELIBERATELY — that is the idiom PLN ruled correct: one press re-rhythms hats and cymbals together. Side effect worth knowing at the desk: PV008 only inspects orbits 1-8, so with the cymbals on d12 the shared-button warning stops firing entirely. The link is unchanged; only the lint's field of view moved. Do not read the green as the coupling having gone away. WATCH ON THE RUN: Ardour Tidal 12 sits at +6.0 dB and Tidal 06 at -3.8 dB, so the cymbals land ~9.8 dB hotter than before. Ride Tidal 12 down rather than re-gaining the pattern until PLN has heard it. Verified: silent-eval --seeded ok (every declared orbit emits), pvlint clean.
PLN (Algolia) authored
-
- 01 Aug, 2026 11 commits
-
-
PLN, on lime_tacos' ^44 driving both d3 (hats) and d6 (cymbales sol): "lime tacos its ok when two percs are linked, e.g. here, change rythm of both 3 and 6. [...] im fine with this, not a NOGO, just a WARN?" He is right, and the interesting part is WHY the rule was wrong rather than that it was. PV008 was earned on a real bug — the 2026-07-29 phase-2 remap left d1 holding ^42 after d2 was given ^42, and perfect.tidal shipped one button firing two orbits. That bug is real and this rule is how it was found. But the accidental case and the deliberate one are TEXTUALLY IDENTICAL. Two orbits, one button CC, no way to tell from the source whether PLN meant it. The rule had quietly encoded "one button drives one orbit" as an invariant of his style, when it is only a hypothesis about it — and the hypothesis was wrong. He groups percussion on purpose: one gesture re-rhythms the whole group. A check that cannot distinguish intent must not hold the gig gate shut. It reports; PLN decides. So: severity error -> warning, and the detail now states both readings and what distinguishes them (deliberate percussion grouping vs a control inherited from a remap) instead of assuming the second. Effect: tools/gig-up.sh goes NO-GO -> GO. This was the last blocking failure, and it was blocking on a correctly-written track. Added test_pv008_is_a_warning_not_an_error, which quotes PLN's ruling, so nobody "tightens" this back to error without meeting the argument first. pvlint 63/63.PLN (Algolia) authored -
Third time. tools/gig-up.sh's 'tools executable' check (added yesterday for exactly this) is why it surfaced: setlist.py went into 04fc8c7c with content but mode 100644, so a fresh clone would get 'permission denied' from a HARD gate check. chmod +x touches the working tree; git stores the bit separately and needs `git update-index --chmod=+x`, and even then a pathspec-limited commit can leave HEAD at 100644 while the index says 100755 — which is what happened here. Verify with `git ls-tree HEAD <file>`, never `ls -l`.
PLN (Algolia) authored -
PLN: "can you add a safe riser on all set tracks that dont have one, and consider moving the d10 to d9 (eg a synmenace iirc) to have d10 riser always?" THE CONVENTION. d10 = riser, so the gesture lives on the same column in every track and his hands stop having to remember per-track. It was already true in three tracks without anyone naming it — do_it_right (mask "<f!4 t f!3>"), take_5_drops (the "A FAIR RISER" comment on d10) and vague_de_crime, whose line #33 designates as THE safe riser because a 1-in-8 mask cannot run away: d10 $ gF1 $ gM3 $ mask "<t f!7>" $ "risers:8" Copied verbatim into the 7 tracks where d10 was free: bombe_dj, wap, lime_tacos, you_my_sunshine, mafia_sans_serif, desire, electric_hammer. Inserted contiguous with the existing d-blocks, because all three pre-existing risers live inside the main block rather than standalone — a riser in its own block would need a separate ctrl+enter, which is not the gesture. 10 of 15 tracks now have it. WHY THE RELOCATION IS NOT IN THIS COMMIT. "Consider" did real work here. The two tracks PLN was remembering are piment_bresilien (d10 = Menace, d9 free) and ouais_je_funk (d10 = SynMenace, only d12 free) — but moving an orbit is not a one-line move, because orbit N is simultaneously the LCXL column, the Ardour track and the cut/crushbus group: piment's d10 block carries -- A6 = d10's effect on its crushbus CC ^18 d9's fx CC is ^17, d12's is ^20 -> the CC must move with the sound Ardour Tidal 10 = -2.2 dB, Tidal 09 = +6.0 dB, Tidal 12 = +6.0 dB -> the synth lands +8.2 dB louder And the argument that settles it: perfect, gimme_acid and the_revolution declare all 12 orbits, so d10 is never free there and the convention caps at 12/15 no matter what. Relocating buys 2 tracks for two CC remaps, a cut-group change and two synths jumping +8.2 dB — on material PLN has not rehearsed since, 7 days out. Deferred by choice, not forgotten; his call to overrule. #99, d5 of take_5_drops: `>|` takes structure from the RIGHT, so `slow 4` note patterns were REPLACING the slice rhythm with one event per four cycles — the "steals structure" symptom, confirmed. Now `|>`, which keeps the left structure and takes only the note value. Note line 35 immediately above was already doing it that way, so this makes the block self-consistent rather than inventing an idiom. Marked TODO @pln verify as asked. Also ouais_je_funk d10 read `gF3 $ gF3` — the same helper twice, so the orbit had no family mute and NOTHING on the surface could drop it (pvlint PV013). Now `gF3 $ gM3`. Also TODO @pln verify. VALIDATION: all 15 setlist tracks still compile (gig-up "setlist compiles" green, silent-eval cold-queries every dN), preload still covers the set at 53/53 banks, and pvlint added zero new findings — still the one pre-existing error, lime_tacos' ^44 driving both d3 and d6. That one is left alone deliberately: ^44 is neither orbit's home gate (d3 = ^43, d6 = ^58/^90), so fixing it means rebinding a button PLN's hands already know, which is a taste call and not lint's to make.PLN (Algolia) authored -
PLN's ruling yesterday: "set SSOT is the backlog entry, always. if in the backlog i add a track or reorder them, its the truth." Then today, the part that decided the design: "if i added new ones, id not need to tell you to update, it should flow downstream, ditto if remove one." So this is not a resolution, it is a pipe. WHAT WAS ACTUALLY WRONG. Applying the ruling for the first time found the backlog listing 15 tracks while every tool in the repo believed 13: missing everywhere: ouais_je_funk (120) lime_tacos (110) wrong order: backlog has you_my_sunshine (166) BEFORE mafia_sans_serif ouais_je_funk was not a stale wishlist entry — PLN committed a kick rework to it in 23f60e76, yesterday. And the drift had already cost him something audible: preload warmed 50 banks (13 tracks) the set needs 53 banks (15 tracks) would cold-load dr gfunk_bass h2ogmcy Three banks read from disk on first play. That is the same mechanism PLN heard as crackle on the take_5_drops transition (#120) — a bug we thought was fixed, still live, just smaller. check-preload.sh reported "ok" the whole time, because it asked set-coherence, which was one of the wrong answers. The freshness check had inherited the staleness it was built to catch. ROOT CAUSE: eight tools each hardcoding `SETLIST = armada/setlist_opal2026.txt`, and one human keeping that file in sync by hand. THE SHAPE, and why it is not "make all eight import a module". The .txt stays exactly where it is, same format, so all eight consumers are untouched — this is J-7 to a gig and a refactor that breaks a tool costs more than it buys. What changes is its STATUS: generated, never hand-edited, with a HARD gig-up check that it still matches the backlog. One parser, one artifact, one answer at a time, and a gate that fails loudly the moment they drift. tools/setlist.py the parser. Resolves PLN's freeform codenames ("Ceci n'est pas Une Bombe" -> bombe_dj, "Le shifteur marteau ? to finish!" -> electric_hammer) via aliases + token containment, and raises rather than guessing. gig-up --converge regenerates the setlist BEFORE preload. That order is load-bearing: preload reads the setlist, so doing it the other way warms the old set. gig-up "setlist vs backlog" HARD, and placed before every check that reads the setlist — a stale list makes "setlist compiles", "preload covers set" and "transition ghosts" all answer about a set PLN is not playing. WHAT THE END-OF-SECTION DETECTION TAUGHT ME. First attempt whitelisted the headings that count as part of the set ({FINALE, Encore, ...}) and died on line one against "## Livecoding Techno DNB Nu-jazz". PLN's headings are prose; any whitelist is a list of the ones he happened to write that day. The working rule ignores heading semantics entirely: run to the next top-level heading, take the list items. Non-track content does not survive that filter — "> Sunset Forest", "1h30 - 20h30-22h", "??TRANSITION???" and the trailing url: block are none of them list items. VALIDATION, and specifically not "it returns the 15 tracks currently in the backlog" — a hardcoded list passes that too. tools/tests/test_setlist.py MUTATES a synthetic backlog and asserts the output moved: add a track (appears, in PLN's position, not appended), remove one (disappears), swap two lines (output swaps), unresolvable name / duplicate / missing section (all raise). 18/18. Then the gate itself, mutated: dropped a line from the .txt -> caught; swapped two lines, same membership -> caught as "same tracks, DIFFERENT ORDER". AND IT PAID OFF IMMEDIATELY. With the real 15 in the setlist, pvlint went red on two tracks that had been invisible to every tool until today: an unmutable orbit in ouais_je_funk (gF with no gM3 — nothing on the surface can drop it) and button ^44 driving both d3 and d6 in lime_tacos (one press, two orbits). Neither is new breakage; both were simply never looked at. Left for PLN — they are musical calls. The 53 banks are warm on the rig now: 54/54 banks OK in 7.0 s.PLN (Algolia) authored -
Reworking d4's texture: the lpf range sweep comes out (resonance stays), crushbus goes 16->3.5 on ^52, and room 0.4 / sz 0.5 / dry 1.1 opens the tail.
PLN (Algolia) authored -
Three closed tasks from the 2026-08-01 session, written for a cold reader. The through-line worth mining later: the rig SENSES everything and ACTUATES nothing. scsynth died and sclang logged it, the Bridge warned 63 times, gig-up saw it and printed GO — and separately, PLN's ears found a preload bug that four green tools had missed. Plus the session's sharpest lesson: two of my own fixes (a watchdog, a chmod) were themselves broken in exactly the way they were meant to catch.
PLN (Algolia) authored -
PLN's own rehearsal edits, 2026-08-01, saved before a break. Committed as their own human commit so nothing is lost — IN PROGRESS, not a finished arrangement. * ouais_je_funk — the kick becomes gate-driven instead of static: "[jazz,kick:5]*4" -> midiOn "^41" / midiOff "^41" variants over a layered "[techno:0,808bd:2,909,kick:4]" with gain 1.5 # lpf 400. Old "kick:5" kept commented rather than deleted. Also: the lead drops an octave — note "<b b b g>@7 <cs6!3 fs6>" is now ("..." - 12); the superimpose gate moves ^18 -> ^20; crushbus 101 added on ^18; and both d11 arpeggio blocks (pinkyup/thumbupdown, diverge/disconverge) are commented out rather than removed. * desire — crushbus 41 (range 16 2.5 "^52"). Left as PLN saved it. He resumes rehearsing Saturday afternoon.PLN (Algolia) authored -
--converge is the CLI big red button: bring the rig to ready, then let the existing checks prove it. Scope is SERVICES, not apps — it starts systemd units it owns and REPORTS Pulsar/Ardour with the command instead of launching them, because a script that opens windows under someone is a script they stop trusting (and Ardour has a session + crash-recovery dialog, #20). Launching apps belongs to the Bridge (#116). Safe at any moment: every action is conditional on the thing being broken, so a healthy rig converges to a no-op — verified, scsynth PID unchanged. It handles the exact 2026-08-01 failure explicitly: unit ACTIVE but audio server DEAD needs a RESTART, since `start` is a no-op on an active unit. Distinguishing those two is the whole lesson. Preload is fixed BEFORE SuperDirt boots, or the warm would not happen until the next restart. And it waits for scsynth to appear rather than guessing — guessing is what made the first watchdog flap. === THE THIRD TIME, AND THIS TIME IT WAS US === gig-up's first run (1219c704) found check-boot.sh and check-tracks.sh at mode 644 — never runnable as `tools/check-tracks.sh`. That fix turned out to be FAKE: the chmod only ever touched the working tree. Git has recorded 100644 for both from that day to this, so every fresh clone still got a broken pre-gig gate. And gig-up.sh had the same bug, from birth. Committed 100644 by 1219c704 and again by 6ab09eaa. It ran only because the local working tree happened to carry the bit; a `git checkout master` materialised it at 644 and it died with "permission denied". That failure was nearly invisible, which is the real story: the caller filtered its output through sed, so a run that never executed LOOKED like a clean no-op, and I reported "no-op confirmed" about a script that had not run. A false green produced by the absence of a program. So the gate now checks its own hands — "tools executable", HARD, verifying BOTH the on-disk bit and what git records. It found four real problems on its first run: disk=x git=100644 check-boot.sh <- day-one "fix" never committed disk=x git=100644 check-tracks.sh <- same disk=- git=100644 sc-watchdog.sh <- not executable AT ALL disk=- git=100644 tests/test-sc-watchdog.sh The third is the one that matters: parvagues-sc-watchdog.service had been ENABLED AT BOOT with an ExecStart it could not execute. It was stuck `activating`, restart- looping silently. The supervisor I added to catch silent failure was itself failing silently, and nothing would have said so until an audio server died at a venue and did not come back. All six now 100755 on disk and in the index; watchdog restarted and confirmed logging. Same family as the day-one finding: a thing verified once, in a context that no longer holds. The new twist is that "chmod +x" is not a fix — recording it in git is. Also honest-ing the recovery toast (#122). PLN reported needing a ctrl+enter in Pulsar to resume after a recovery. Likely ICMP port-unreachable poisoning Tidal's connected UDP socket (ECONNREFUSED on next send, stream stops until re-evaluated). Until #122 tests it, the toast says "if the music does not resume on its own, ctrl+enter in Pulsar" rather than claiming a full recovery — a rig that is alive and silent is indistinguishable on stage from the original fault. Validation: 16/16 green on the live rig (9 cold + 7 live). Converge no-op verified on a healthy rig; converge ACTION verified by stopping the watchdog and watching it come back, with scsynth untouched throughout.
PLN (Algolia) authored -
gig-up proved the set COMPILES and said nothing about whether anything could make a sound. scsynth was read only to colour a banner (:106,:115) and to skip --audio (:202) — it never failed. This morning the audio server had been dead for two days and the gate would still have printed GO. --live is a MODE, not the default. Cold-by-default remains right: cold checks are safe mid-set and must work on a train. Severity is chosen per link, deliberately: HARD scsynth alive / sclang :57120 / SC -> Ardour (>=24 pw links) no audio server, no listener, or no path to the DAW = there is no gig. SOFT Tidal :6010, LCXL -> SC, SuperDirt warmed, perf mode all legitimately absent ten minutes before doors; a gate that reddens for them is a gate PLN stops reading. Every check reads the thing that MAKES SOUND — a process, a socket, a real pw-link — never `systemctl is-active`. That distinction is the whole reason this exists: the unit reported active/running for two days while the rig was mute, because MainPID is sclang and scsynth is its child. ALSO, and it came from PLN's ears: "preload covers set", a HARD cold check. He heard crackles moving do_it_right -> take_5_drops. Measured in that window: 0 SuperDirt lates, 0 pipewire xruns, 17 lazy soundfile reads — all take5:*. Disk I/O, not CPU. The preload MECHANISM was healthy and said so ("47/47 banks OK in 1.9 s"); it was warming the wrong list. preload.scd was dated Jul 28, header "10 track(s) scanned", while the set is 13 — because setlist_samples.py reads setlist_opal2026.txt (10 tracks) and gig-up/cheat-sheet trust set-coherence.setlist_tracks() (13). The missing three are do_it_right, take_5_drops, electric_hammer: exactly the pair he was transitioning between. #120 tracks which source becomes canonical — not guessed here. Two properties made it invisible, and they are the transferable lesson: preload.scd is GITIGNORED (correctly — generated), so no diff ever showed it drifting, and NOTHING COMPARED IT TO THE SET. A generated artifact with no freshness check is a stale artifact waiting for the worst possible moment; its natural debut was a cold boot at the venue, on the first play of every track added since Jul 28. It only surfaced at a desk because SuperDirt had been up since Jul 28 with those banks cached from a first play weeks earlier, and a restart cleared the cache. tools/check-preload.sh compares BANK SETS (not bytes — the generator stamps a header and orders banks, so a byte diff would cry wolf), borrows set-coherence's parser rather than adding a fourth definition of "the setlist", and has --fix. Validation, all of it adversarial: * check-preload mutation-tested — restore the Jul-28 plan and it names the 7 banks that would crackle: daft fbreak120 hammer popkick realclaps superfreak take5. hammer and superfreak are independently confirmed: they appear as lazy loads in this morning's journal, before any of this was written. * --live on the live rig: 7/7 green after fixing MY OWN check (below). * THE GATE BITES: run under a PATH shim whose pgrep reports scsynth absent -> NO-GO, exit 1, correct fix hint, real rig never touched. That is precisely the state that printed GO this morning. * cold run unchanged: still GO, live chain not executed. One check was wrong before it was right, in the session's recurring shape. "SuperDirt warmed" first warned about a rig that was perfectly warm, because `journalctl --user -u parvagues-sc` returns lines from a PREVIOUS instance on this box — it handed back Jul 30 output while the current instance had already logged "51/51 banks OK". Now filtered by SyslogIdentifier and keyed to the unit's own ActiveEnterTimestamp, so it asks "did THIS boot warm?" rather than "was there ever a PRELOAD line", which any previous boot would satisfy forever.PLN (Algolia) authored -
PLN (Algolia) authored
-
PLN's own live-session edits, made at the desk on 2026-08-01 while rehearsing the OPAL set. Committed separately from the session's tooling work so the musical changes stay legible on their own. * wap — uncomment octersubsubbus 42 / octerbus 41, both on range 0 1.4 "^53". The sub layer is live again. (This is the `octersub` want noted in the 2026-07-31 set-coherence report.) * bombe_dj — "[808bd:1,808bd:11]" -> "[808bd:11]". One kick sample instead of two stacked, on the 1/4/6/9/11 positions. * do_it_right — mark d3's gM2/gF1 line with a TODO about buttons and variations.
PLN (Algolia) authored
-