fix(rig): make a duplicate Ardour spawn structurally impossible, and log the decision
The parked blocker was wrong about its own cause, which turned out to be the
more useful finding.
RIG UP answered one press with "ardour: launched — launched Ardour" while Ardour
was already up. The two instances collided over the session lock and BOTH exited,
taking all twelve orbit links with them mid-evening. The obvious suspect was
is_running()'s `exe` regex, so the GIG UP rewire was parked behind "fix the
detection first".
Measured cold, the detection is fine. With Ardour running, is_running() returns
True: argv0 is `ardour-9.7.0` (the wrapper /usr/bin/ardour9 is a shell script
that exec's /usr/lib/ardour9/ardour-9.7.0) and `[Aa]rdour[-\d.]*$` matches it.
Two presses in a row now correctly answer "running -> focus". The false negative
is not reproducible, and -- the actual defect -- nothing anywhere recorded the
decision, so the cause cannot be recovered. The incident had to be reconstructed
from a chat transcript.
So stop repairing a probe that measures correctly, and remove the probe's veto
over an irreversible action:
- A spawn guard keyed on a pidfile in $XDG_RUNTIME_DIR, consulted only after
is_running() says no. It blocks while the pid we spawned is alive, plus a 20s
window covering fork->exec->/proc visibility -- the one interval in which
is_running() is legitimately blind. A pidfile rather than a module global
because the two faces are two processes: the web Bridge and the perf-tray both
call launch(), and an in-memory note in one is invisible to the other.
- The guard re-checks process IDENTITY, not just liveness, so a recycled pid
cannot jam it shut forever. A guard that fails closed permanently is its own
outage.
- _log() writes every launch decision to stderr -> the journal.
- Ardour additionally sweeps a SUPERSEDED .pending aside before launching. No
flag suppresses the "recover from crash?" modal -- only the file's absence does
-- and that modal is exactly what the hot path must not contain (#136). It
moves (never deletes, into the session's own dead/) and only when the session
was SAVED AFTER the pending was written, i.e. a later save already superseded
it. A .pending newer than the save holds unsaved captures; that one deserves a
human, so its dialog is left to appear.
Verified live, in this order:
1. cold launch -> SPAWNED pid 2708769, session path passed, 1 ArdourGUI
2. immediate 2nd press -> "running -> focus", still 1 ArdourGUI
3. is_running monkeypatched to lie False (the incident's exact condition)
-> "NOT spawning -- we started pid 2708769 14.9s ago",
still 1 ArdourGUI
4. same, 52s later (past SPAWN_GRACE) -> still refuses, on pid liveness
5. dead pid + old timestamp -> guard stands down, launching is possible again
Also: the session chooser is gone from every entry point. Stock ardour9.desktop
runs `ardour9` with no argument, so every launch from the menu asked "Tidal Live
or Tidal Multi?" -- a modal in the hot path, and a chance to open the ARCHIVE by
mistake (that same mixup produced a confidently wrong fader report on
2026-07-28). A user-local override sends the default click straight into Tidal
Live and keeps the chooser as a right-click action.
Stale comment corrected: the real binary is 9.7.0, not the 9.2.0 recorded there.
Showing
tools/ardour-tidal-live.desktop
0 → 100644