Commit 5b0ad50d by PLN (Algolia)

docs(gig): green gate, and the rehearsal is the whole remainder

0 fail / 3 warn / 39 ok with the rig warm, 132/132 banks, 0 xruns per hour —
the 457/hour this morning was the dead NVIDIA sink, not the CPU.

Five learnings archived from the morning, all one shape: a check that asks the
wrong question reports success. A resolver matching hardware by product name
outlived the hardware in three files at once; a capability check that asked
'is the tool installed' wrote midi:true over nine empty sessions; a probe
gated on a precondition it did not need skipped the entire setup window; an
availability flag structurally incapable of being false hid a disconnected
cable for months; and a unit's start time is the only thing that distinguishes
running code from readable code.
parent a606d992
......@@ -460,3 +460,39 @@ correct whether or not the driver runs.
- [ ] **YOU: the 2h run with Ardour recording.** Unmoved since Sunday. It is the
only check that has never been run, and the only one that can still
surprise you.
## Wed 23, 10:40 — the rig is green and the rehearsal is the whole remainder
`check-gig`: **0 fail, 3 warn, 39 ok, 1 skipped.** `xrun rate 0/hour` — the
457/hour reading this morning was the dead NVIDIA sink, not a perf problem.
SuperDirt: `PRELOAD: 132/132 banks OK in 6.8 s`, server ready.
Fixed today, all pushed (a606d99): the audio (laptop card back on HiFi, NVIDIA
pin retired), the LCXL3 driver (started; its 1077 failures were a resolver
looking for the ORIGINAL board's name), midiviz (v3 map moved into the grid, so
any reader of the board is right), the gate's painter probe (was skipping every
cold run), gig-log's MIDI leg (had never bound a port in nine sessions), and a
stale-build detector.
### The three remaining warns, none blocking
- **audio profiles** — `50-alsa-config.conf` is 0.5 format on an 0.4.17
install, so it is dead config that looks like protection. Post-gig.
- **cpu governor** — daytime mode on a work laptop. `gig-up` does the perf pass.
- **monitor path** — headphones fold shows 2/28 links, d2-d14 unreachable
without Ardour. Expected with Ardour closed; the rig routes through it.
### YOURS, and it is the only thing left
- [ ] **The 2h arc, with Ardour recording.** This afternoon, or tonight after
the speaker dinner. Never once run. Everything else is green.
- [ ] **Plug the UMC202HD for the last stretch** and run
`tools/check-audio-graph.sh` with it present. Thursday's output path, and
the only one nobody has tested — the same UCM failure that ate the sof
card's HiFi can hit the UMC's when it enumerates.
- [ ] **Master fader**: `check-mix` reads the SAVED session, and Ardour OSC is
still off, so Ctrl+S before trusting a green fader line.
- [ ] After the run: the MIDI log is now real. `~/.local/share/parvagues/gig-log/`
carries `cc` records with `n / v0 / v1 / lo / hi` per control per second,
in corpus numbering — so "minute 23:30 the bass is too saturated" is
answerable from the file afterwards.
......@@ -2,7 +2,7 @@
{
"date": "2026-09-17",
"task": "GUI launcher did not spawn the MIDI lens or the tray",
"learning": "The launcher (gig-up.sh) and the unit converger (rig_units.py --ensure) disagreed on SuperDirt topology — raw sclang vs parvagues-sc.service — so the launcher never called ensure; the fix is ensure()'s proof-process skip, not another hand-copied unit list."
"learning": "The launcher (gig-up.sh) and the unit converger (rig_units.py --ensure) disagreed on SuperDirt topology \u2014 raw sclang vs parvagues-sc.service \u2014 so the launcher never called ensure; the fix is ensure()'s proof-process skip, not another hand-copied unit list."
},
{
"date": "2026-09-17",
......@@ -12,16 +12,16 @@
{
"date": "2026-09-18",
"task": "tray GIG UP did nothing + midimon silent",
"learning": "The Bridge ran 'gig-up.sh --converge --quiet' but gig-up.sh's arg guard only knew --headphones/--help, so every tray GIG UP died on flag 1 (exit 2, output captured). Flags now parsed: --converge boots SuperDirt + converges units with NO app windows, --quiet mutes ok/info. midimon watches 132:0 (the lcxl3-driver's translated virtual port), not the raw surface — silence there just means the driver had no input yet."
"learning": "The Bridge ran 'gig-up.sh --converge --quiet' but gig-up.sh's arg guard only knew --headphones/--help, so every tray GIG UP died on flag 1 (exit 2, output captured). Flags now parsed: --converge boots SuperDirt + converges units with NO app windows, --quiet mutes ok/info. midimon watches 132:0 (the lcxl3-driver's translated virtual port), not the raw surface \u2014 silence there just means the driver had no input yet."
},
{
"learning": "Two gig-up.sh exist: root (1-click, owns leds()) and tools/ (the GO/NO-GO gate the Bridge calls, where lcxl3-driver is boot=manual so nobody starts it). The v3 LCXL3 enumerates as 'LCXL3 1', breaking every v2 'Launch Control XL' grep — present/LEDs/path checks all silently misread. lcxl-path must match the driver's virtual PORT name 'ParVagues LCXL3' (under RtMidiOut client), never chase the PipeWire relay mesh (everything reaches everything via 143)."
"learning": "Two gig-up.sh exist: root (1-click, owns leds()) and tools/ (the GO/NO-GO gate the Bridge calls, where lcxl3-driver is boot=manual so nobody starts it). The v3 LCXL3 enumerates as 'LCXL3 1', breaking every v2 'Launch Control XL' grep \u2014 present/LEDs/path checks all silently misread. lcxl-path must match the driver's virtual PORT name 'ParVagues LCXL3' (under RtMidiOut client), never chase the PipeWire relay mesh (everything reaches everything via 143)."
},
{
"learning": "WirePlumber 0.4.17 ignores wireplumber.conf.d SPA-JSON rules (0.5 syntax) — this box reads Lua from main.lua.d only, and a partial alsa_monitor.rules reassignment clobbers the built-in table by index (dropped the card to profile off). Every wireplumber restart tears down Ardour's JACK client; recovery needed a full Ardour relaunch. pactl/wireplumber restart restored the missing HiFi profile after a UCM probe failure (card showed only off/pro-audio)."
"learning": "WirePlumber 0.4.17 ignores wireplumber.conf.d SPA-JSON rules (0.5 syntax) \u2014 this box reads Lua from main.lua.d only, and a partial alsa_monitor.rules reassignment clobbers the built-in table by index (dropped the card to profile off). Every wireplumber restart tears down Ardour's JACK client; recovery needed a full Ardour relaunch. pactl/wireplumber restart restored the missing HiFi profile after a UCM probe failure (card showed only off/pro-audio)."
},
{
"learning": "A generated boot file is only as good as the list it is generated FROM. gig-up.sh rewrote preload.scd on every launch from a default naming the PREVIOUS gig (setlist_opal2026.txt): measured 132 banks -> 45, leaving 41 of Thursday's banks to be read off disk mid-set — the exact 'crackle at the venue' failure the check was built for, re-armed by a stale default. Two structural lessons. (1) Name the set ONCE and have every consumer read that; the plan generator and the gate disagreeing about 'the set' is the whole bug. (2) An unconditional write is destructive in the quiet direction: the plan in place was a deliberate 132-bank UNION and regeneration could only narrow it, so gen_preload now asks check-preload first and leaves a covering plan alone. Corollary from the same pass: merging two tools that share a name means diffing what they DO, not just what they check — the root launcher span raw sclang while the other started parvagues-sc.service, so repointing the Bridge at 'one launcher' would have silently taken it off systemd (losing rlimits, the journal, supervision and OOM protection)."
"learning": "A generated boot file is only as good as the list it is generated FROM. gig-up.sh rewrote preload.scd on every launch from a default naming the PREVIOUS gig (setlist_opal2026.txt): measured 132 banks -> 45, leaving 41 of Thursday's banks to be read off disk mid-set \u2014 the exact 'crackle at the venue' failure the check was built for, re-armed by a stale default. Two structural lessons. (1) Name the set ONCE and have every consumer read that; the plan generator and the gate disagreeing about 'the set' is the whole bug. (2) An unconditional write is destructive in the quiet direction: the plan in place was a deliberate 132-bank UNION and regeneration could only narrow it, so gen_preload now asks check-preload first and leaves a covering plan alone. Corollary from the same pass: merging two tools that share a name means diffing what they DO, not just what they check \u2014 the root launcher span raw sclang while the other started parvagues-sc.service, so repointing the Bridge at 'one launcher' would have silently taken it off systemd (losing rlimits, the journal, supervision and OOM protection)."
},
{
"learning": "A launcher's exit code cannot tell 'it worked' from 'it did nothing'. gig-up.sh --help prints its usage and exits 0, and the window wrapper closed on that zero exactly as it closes on a good launch -- so the rig had never once been started from the icon, and the only evidence was the LCXL staying dark. The log had been written faithfully all along and held nothing but the usage text. Structural lesson: for any wrapper that closes on success, the success test must be a POSITIVE marker the wrapped thing prints on its real path ('gig-up done'), never the absence of an error. And hold the coupling from both ends in tests, because the day someone rewords that last line, every real launch starts reporting a failure."
......@@ -31,5 +31,30 @@
},
{
"learning": "A fix that trades a wrong setting for no function is not a fix, and the fence belongs in the tool rather than in the judgement of whoever runs it. check-audio's textbook repair -- clear the stale pin, take WirePlumber's own pick -- would have switched off the only four sinks on the box, because the laptop codec was pinned off and the USB interface unplugged. So --fix counts the sinks it would leave behind and refuses at zero. Also: a config fragment in a neighbouring version's format (0.5 .conf.d on an 0.4.17 install) is worse than a missing one, because it looks exactly like protection that is in force -- the July DMIC guard had never applied, and what had kept the box safe was the card being switched off."
},
{
"date": "2026-09-23",
"task": "LCXL3 name-resolver sweep",
"learning": "A resolver that matches hardware BY PRODUCT NAME outlives the hardware it names, and it fails silently in every tool that copied it. 'Launch Control XL' -> 'LCXL3 1' broke three independent things the same way: the driver crash-looped 1077 times, midiviz drew v3 numbers into v2 cells, and gig-log's MIDI leg never bound a port in nine recorded sessions. The generation change was one event; the breakage was three, because the string was in three files. Grep the product name across the tree the day the hardware changes, and put the translation table in the GRID rather than in one of its readers -- then a reader is right whether or not the translator is running."
},
{
"date": "2026-09-23",
"task": "gig-log MIDI capture",
"learning": "A capability check that asks 'is the tool installed' instead of 'did it bind' produces a feature that reports itself ON while doing nothing. MidiReader.available() returned shutil.which('aseqdump'), so the header wrote midi:true for nine sessions that contain zero cc records. The honest test is always the OUTPUT, not the precondition: count what landed. And record WHICH source was bound (an 'mbind' line) -- the nine silent sessions were unexplainable precisely because nothing wrote down that the answer was 'none'."
},
{
"date": "2026-09-23",
"task": "the gate's own blind spots",
"learning": "A probe gated on a precondition it does not need skips exactly when it matters. check-gig's painter probe carried needs=('scsynth',), so the one check that asks 'is the surface actually lit' stayed silent through every cold run -- which IS the setup window. Ask of every precondition: does the answer become MEANINGLESS without this, or merely inconvenient to obtain? The painter has nothing to do with the audio engine."
},
{
"date": "2026-09-23",
"task": "the sink that went nowhere",
"learning": "pro-audio reports available:yes unconditionally, because it maps raw PCMs and asks no questions about cables. So a GPU HDMI card pinned to pro-audio offered four healthy-looking sinks while every ELD read monitor_present 0 and every connector read disconnected -- audio converted and discarded, for months. When a subsystem's own availability flag is structurally incapable of being false, go around it to the kernel (ELD, /sys/class/drm) rather than trusting the layer that has an opinion."
},
{
"date": "2026-09-23",
"task": "stale unit builds",
"learning": "A systemd unit holds whatever the interpreter read at ExecStart, so from outside a unit running three-day-old code is indistinguishable from a healthy one: same active(running), same journal. A pass was lost debugging a midiviz that predated the fixes being debugged. The only honest test is the unit's ActiveEnterTimestamp against its ExecStart file's mtime -- deliberately NOT a git comparison, because the question is 'is the process executing what I can read', so an uncommitted edit counts."
}
]
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