Commit 2efc7575 by PLN (Algolia)

CLAUDE.md, CHANGELOG, TODO.d: the wiring rules, the recording fixes, what is left

Rules a future session must see: SuperDirt takes no microphone (and the knob to
change that), Master follows the default output and respects hand-wiring, the
black box records whenever the rig is up, lcxl3-driver stays manual. The TODO
now holds the stem auto-take design with real numbers (16 GB/hour for 12
strips) and the retention decisions it needs.
parent ec722018
......@@ -28,6 +28,23 @@ while the real fault sat unread.
resting rung. It now judges them against the rung the pilot declares. A dead
surface driver is now a blocking failure, because that is "there is no gig".
- **Nothing was recording, and nobody could tell.** `gig-record` (the master black
box) was `on-demand`, its unit was not even installed on this machine, and the gate
showed it as one ignorable WARN: two hours of playing were recorded nowhere. Now
SuperDirt starts it (`Wants=`), it stops with SuperDirt, the gate BLOCKS when the rig
is up and nothing is capturing, and the health check goes red in ~30 s with a
one-click start in the tray. Two silent bugs inside it, found by actually running it:
it listened to a spectrogram tap (a source that does not exist) while reporting
RUNNING, and a large graph killed it with a SIGPIPE.
- **Two Ardours on one session.** The launcher could not recognise Ubuntu's Ardour
(`ardour-8.4.0~ds1`), so it believed Ardour was down and started a second one; the
gate's "Ardour is open" precondition had been false on every run, skipping the
`SC -> Ardour` probes. Both fixed.
- **Master follows your output.** Ardour's Master now follows the default output
(HDMI, jack, Bluetooth) and leaves hand-wiring alone; the black box is re-pointed
when it moves. SuperDirt takes no microphone: those links are cut (knob documented in
`CLAUDE.md`).
### Added
- **Rig health, in the tray and the Bridge.** `gig-log` now publishes
`~/.cache/parvagues/health.json`: is the graph hardware-clocked, does the
......@@ -42,9 +59,9 @@ while the real fault sat unread.
issues `pw-link` only for links that are actually missing.
### Still open
See `TODO.d/2026-10-11-rig-health-followups.md`: which sinks Master should feed
(three at once is the leading suspect for the xruns), whether SuperDirt needs the
built-in mics, the idle CPU of the other watchers, and the witnessed drills.
See `TODO.d/2026-10-11-rig-health-followups.md`: Ardour stem recording that starts by
itself (a design with real numbers, needs your retention call), the replug drill, the idle
CPU of the other watchers, and the edits waiting on uncommitted work in `gig-up.sh`.
## Sprint 11 — 2026-09-17 · the tray learns which click is which
......
......@@ -64,6 +64,27 @@ ParVagues' main livecoding workspace.
Verify there and cite the path — don't copy strings from intermediate scripts (e.g.
`split_bandcamp.py`'s ALBUM was wrong). If a fact isn't in the canonical source, ask.
## Rig wiring rules (2026-10-11): read before you re-wire anything
- **SuperDirt takes NO microphone.** `tidal-ardour-autoroute` cuts every physical capture
port -> `SuperCollider:in_*` within 2 s (the laptop mics threw `Broken pipe` xruns from
the moment the rig launched; Ardour has its own Mic track). If you ever want SC to listen
again (live input, sampling), set `TIDAL_AUTOROUTE_SC_MICS=1` on that unit, or the links
are cut again. Sinks' own monitor ports are never touched.
- **Ardour Master follows the DEFAULT OUTPUT** (HDMI, the jack, a Bluetooth headset), but
only while its wiring is the one autoroute made. Wire anything else in qjackctl or
Ardour's connection matrix (several sinks, a different one) and it is custom: hands off.
To hand control back, disconnect all of Master's outputs. Ctrl+S in Ardour if you want
its own session to agree. Off switch: `TIDAL_AUTOROUTE_MASTER=0`.
- **The black box records whenever the rig is up.** `parvagues-sc` Wants `gig-record`
(opus master, ~72 MB/h, 14 days kept by `gig_record.sh prune`). The gate BLOCKS with
SuperDirt running and nothing capturing. A practice take recorded by mistake costs disk;
a gig take not recorded costs the gig. Do not make it opt-in again.
- **`lcxl3-driver` is `manual` on purpose** (`rig_units.py`): with no board it crash-loops.
`midi-autoconnect` starts it when a raw LCXL3 is on the bus. Never enable it at login.
- Rig health lives in `~/.cache/parvagues/health.json` (written by `gig-log`, read by the
tray and the Bridge). Owners repair, `gig-log` observes, the faces only read.
## Ethos — the zen art of simple maintenance
- **"Is this screw useful?"** Before adding a file, check, flag, service or
......
# Rig health: what is deliberately still open (2026-10-11)
# Rig health and recording: what is deliberately still open (2026-10-11)
Everything shipped today is committed and tested (see CHANGELOG, Sprint 12). These
are the threads left, in the order they cost to leave. Two need a human decision.
Everything shipped today is committed and tested (CHANGELOG, Sprint 12). Resolved with the
owner today: Master follows the default output and respects hand-wiring; SuperDirt takes
no microphone (links cut, knob documented in CLAUDE.md); the black box records whenever the
rig is up. What is left, in the order it costs to leave:
## 1. Decisions (blocking the xrun A/B)
## 1. Ardour stem recording that starts by itself (needs a retention decision)
- **Which sinks should Ardour Master feed, at home and on stage?** It was linked to
Headphones + Speaker + HDMI 1 at once. On 2026-10-11 the xruns sat on the two
*follower* sinks (HDMI 14, Headphones 13) and almost none on the driver (Speaker 3),
and they did not track heat (0 s of overlap with throttling). Leading hypothesis:
the fan-out forces adaptive-resample followers. Hypothesis, not finding: A/B it,
one variable at a time, ten minutes each.
- **Does SuperDirt need the built-in mics?** SC's JACK driver auto-connects the
SoundWire mic captures to `in_1/in_2` and Ardour has its own Mic track. The mic
capture streams threw `Broken pipe` xruns from the moment the rig launched. If SC
does not need them, stop the auto-connect at the source (SC's JACK input
connect, via the parvagues-sc drop-in) rather than cutting links afterwards.
Verify against SuperCollider's docs first.
Principle, agreed: a recording missed at a gig is unrecoverable and a practice take
recorded by mistake only costs disk, so default to recording and handle the extras in UX.
The black box (opus master, 72 MB/h) already does this for the mix. Stems are the hard
part because of size: the session is 32-bit float WAV at 48 kHz, a stereo strip is
~1.4 GB/hour, so 12 Tidal strips are ~16 GB/hour and 131 GB free is under 8 hours.
"Always rolling" is therefore not sustainable without a retention rule.
## 2. Witnessed drills (need a quiet moment and the owner's OK, not mid-play)
Proposed shape (owner = a small unit that arms and rolls through the existing
`take-rec.py arm/verify/halt`; the observer stays gig-log):
- **Trigger:** first sign of playing with the rig up (an eval, a MIDI move, or signal on
Master), not "rig up", so an idle hour does not cost 16 GB.
- **Stop:** N minutes of silence (suggest 5), then `halt`; a new activity starts a new take.
- **Verify:** `take-rec verify` already checks the stem files grow; a track whose file is
absent or flat is an alarm in the tray (the D8 lesson: one orbit silently never recorded).
- **Practice by mistake:** every auto-take is *unclaimed*. The tray offers keep / discard;
unclaimed takes are pruned after a window (suggest 48 h). The opus master is kept 14
days regardless, so the mix is never lost even if a stem take is pruned.
- **Disk guard:** below 40 GB free, stop rolling and say so loudly (hard floor 25 GB).
The unit tests prove the logic; only these prove the wiring.
1. **Observer drill.** Stop `midi-autoconnect` FIRST, then stop `lcxl3-driver`.
(With the repairer running, it restarts the driver on its next 2 s tick, which
beats the 5-tick debounce: the tray never goes red and the death shows only in
the journal. That is the repair working, not the observer failing.) Expect a red
dot and a critical notification within ~10 s, and a "recovered" one after you
start the driver again.
**Repair drill.** With `midi-autoconnect` running, stop the driver: it must be
back within a few seconds. Open question for the owner: a self-healed death is
invisible in the tray by design; say if you want it surfaced.
2. Unlink Master from every sink: autoroute re-links it within 2 s.
3. Freeze `gig-log` (`kill -STOP` its MainPID, then `-CONT`): after ~30 s the tray
shows "observer stale" (red dot). A *stopped* gig-log reads "not observed" (no
badge), which is correct: the rig is simply not being watched.
4. Unplug and replug the LCXL3 with `lcxl3-driver` stopped: the driver starts on its
own within a few seconds.
5. `check-gig.py` returns GO at pilot rung 1 and a BLOCK with the driver stopped.
Decisions needed: trigger (eval/MIDI vs signal), silence timeout, unclaimed retention
window, disk floor, and which strips (all Tidal strips only, or Mic/Keys too).
## 3. Blocked on someone else's uncommitted work
## 2. Drills
`gig-up.sh`, `tools/gig-up.sh`, `tools/rig_units.py`, `tools/check-stale-units.py`
carry uncommitted changes that are not from this work (the tree had 22 modified files
at the start). Editing them would sweep that work into a commit. Once it is landed:
- `gig-up.sh` `leds()`: call the same chooser midi-autoconnect now uses, and wait a
bounded time for the surface before giving up (today it decides once, instantly).
Witnessed today, all passed: observer freeze (stale in ~41 s), Master follows the default
(1-5 s), custom wiring left alone, hand-back, dangling Master relinked (2.1 s), mic link
cut (2.1 s), driver self-heal (2.1 s, silent), driver observer (red in 4.5 s, recovered in
3 s), recorder stopped (red in ~31 s, gate BLOCK, recovered in 4 s).
Not done: **replug the LCXL3 with `lcxl3-driver` stopped** (physical; the driver should
start on its own within a few seconds), and the graph-clock stall itself (cannot be
reproduced on demand; the evidence snapshot will capture it when it recurs).
A self-healed driver death is invisible in the tray by design (journal only); say if you
want it surfaced.
## 3. Blocked on uncommitted work in the tree
The tree had 22 modified/untracked files at the start of the session, none from this work
(15 share the timestamp Oct 7 10:15, which looks like one git operation, not editing).
`gig-up.sh`, `tools/gig-up.sh`, `tools/rig_units.py`, `tools/check-stale-units.py` are
among them, as is the whole "music mode" feature (`tools/music-mode.sh` untracked,
`install-protect.sh`, `parvagues-protect.sh` modified; music mode is ON and the protector
is active and working). Editing those files would sweep that work into a commit. Once it
is landed:
- `gig-up.sh` `leds()`: call the same chooser midi-autoconnect uses and wait a bounded time
for the surface (it decides once, instantly, today).
- `gig-up.sh` line ~168 detects Ardour with `pgrep -x ardour/ardour8/ardour9`, blind on
this machine for the same reason the launcher and the gate were (process name is
`ArdourGUI`). `tools/fold-orbits.py` line ~315 has the same `startswith("ardour")` on a
case-sensitive comm.
- `rig_units.py`: document that lcxl3-driver is started by midi-autoconnect rule 4.
## 4. Idle CPU of the watchers (measured 2026-10-11, no one playing)
## 4. Idle CPU of the watchers (measured with nobody playing)
About 48% of one core in total. `xpswatch` 8.6, `lcxl3-driver` 8.1,
`fipindicateur-watchdog` 7.9, `midiviz` 5.0, `midi-autoconnect` 4.6, autoroute 3.6
(was 14.9), `gig-log` 3.6, `perf-tray` 2.3, `sc-watchdog` 2.2, SuperDirt 1.9.
Cheapest win: `midi-autoconnect` forks ~8 times per 2 s tick; drive it from
`System:Announce` events with a slow heartbeat instead of polling. This matters for
the fan: the heat source in play is Pulsar (~105% mean, 228% peak), see SRE TODO.d #92.
About 48% of one core in total. `xpswatch` 8.6, `lcxl3-driver` 8.1, `fipindicateur-watchdog`
7.9, `midiviz` 5.0, `midi-autoconnect` 4.6, `gig-log` 3.6, autoroute 3.6 (was 14.9),
`perf-tray` 2.3, `sc-watchdog` 2.2, SuperDirt 1.9. Cheapest win: `midi-autoconnect` forks ~8
times per 2 s tick; drive it from `System:Announce` with a slow heartbeat. The heat source
in play is Pulsar (~105% mean, 228% peak), see SRE TODO.d #92.
## 5. Small, independent
## 5. Small and independent
- `tools/bridge/tests/test_perf_tray_midi.py` fails on a clean checkout: midiviz grew a
`devcon` theme the tray never offers (and `midimon-devcon` has no launcher row).
Also failing before today: `test_one_tidal_parser`, `test_gearbox::test_label_falls_back_to_the_raw_key`.
- `test_surface_state` fails in a combined run and passes alone: an ordering flake.
- Optional udev rule so a plug event starts the driver with no polling (needs sudo, and
midi-autoconnect already covers it during a rig session).
- The rtmidi client is named `RtMidiOut Client`, which is why 'ParVagues LCXL3' is hard
to find in qjackctl. Naming it would end that confusion. First `rg` for anything that
matches on `RtMidiOut`.
`devcon` theme the tray never offers (`midimon-devcon` has no launcher row). Also failing
before today: `test_one_tidal_parser`, `test_gearbox::test_label_falls_back_to_the_raw_key`.
`test_surface_state` fails in a combined run and passes alone (an ordering flake).
- `rig-install.sh` never repairs an existing install: this machine was set up before
`gig-record` was added, so its unit was never linked. A "missing rig units" line in
`rig-doctor` / the gate would have caught it.
- Optional udev rule so a plug event starts the driver with no polling (needs sudo).
- The rtmidi client is named `RtMidiOut Client`, which is why 'ParVagues LCXL3' is hard to
find in qjackctl. First `rg` for anything that matches on `RtMidiOut`.
- Starting SuperCollider with `SC_JACK_DEFAULT_INPUTS` set would stop the mic auto-connect
at the source instead of cutting links afterwards. The docs only describe a port list,
nothing about an empty value: test it empirically at the next SC restart before relying on it.
......@@ -87,5 +87,10 @@
"date": "2026-10-11",
"task": "Rig signal-path health: surface driver on hot-plug, Master relink, pilot-aware gate, health.json in tray + Bridge",
"learning": "A green unit is not a live signal path: all four faults left every unit active. Observe the path from data the recorder already reads (pw-top follower-of-alsa-driver, /proc/asound/seq driver port), owners repair, observer notifies on transitions only. And check rig_units.py before enabling any unit: lcxl3-driver is 'manual' because it crash-loops with no board. Measure the watchers: autoroute re-issued 24 pw-link per tick = 15% of a core."
},
{
"date": "2026-10-11",
"task": "Recording made unmissable: black box follows the rig, gate blocks when nothing records, launcher and gate can see Ardour",
"learning": "Run the safety net, do not trust that it exists: gig-record had never run on this machine (unit not installed, gate WARN-ignored), then it ran and listened to a spectrogram tap and died of SIGPIPE under pipefail. Also: a presence probe matching process NAME is blind when the comm differs (Ardour is ArdourGUI, binary ardour-8.4.0~ds1 cut to 15 chars): the launcher spawned a 2nd Ardour and the gate silently SKIPPED SC->Ardour on every run."
}
]
\ No newline at end of file
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