Commit 796afa6b by PLN (Algolia)

docs(ardour): the session is a jig, not an archive — plan + a stale command caught

Tonight's launch died on the Missing File modal, so the references got counted
properly: 294 missing sources, 270 of them alive on the Freebox mirror (53G, no
file under 1MB), and 24 that exist nowhere — all of Take101, 12 orbits x L/R,
already written off in 041 as "tests at best".

The plan promotes the drop-missing-sources doctrine from a one-off repair to a
standing invariant: the session holds tracks, routing and levels, and zero audio
sources at rest. Structure comes from a template (correct by construction, rather
than mutating a session back to empty and having to be right about what to
remove); state is kept by an idempotent sweep that runs at LAUNCH as well as
close, because a close-only hook is bound to the least reliable moment there is
and a crashed gig would either strand stems or eat them.

Also names the tension it has to live with: the tool refuses to drop a reference
whose audio survives elsewhere, which is exactly the state deliberate archival
creates. --allow-archived is the answer, and the rule is that only a caller which
has itself verified the copy may pass it. A human running it blind stays refused.

And a correction 043 could not have known it needed: the one-liner recorded there
now refuses, because the eleven other takes moved to the mirror after it was
written. The doc was right when written and wrong now — drift a plan should catch
instead of a gig.
parent 13764f73
......@@ -43,6 +43,16 @@ is gone. One command, once Ardour is quit:
It backs the session up first, refuses while Ardour is running, and refuses if the
Freebox is unmounted. Dry run verified: `would drop: 24 source(s), 24 region(s)`.
> **CORRECTION, 2026-09-06 — the command above now REFUSES.** When this was
> written only Take101 was missing. Since then the other eleven takes' audio moved
> to the Freebox (decision 4 below got resolved), so the session now has **294
> missing sources, of which 270 are recoverable** on the mirror — and the tool
> rightly declines to drop a reference to audio that still exists. Clearing the
> modal now requires `--allow-archived` as well, which is only safe because the
> mirror was verified intact (53G, 270 files, none < 1MB). Take101 remains the
> only genuinely dead take. Full reasoning and the standing fix:
> `docs/2026-09-06-ardour-fresh-jig.md`.
**4. The Freebox is 7 days behind, and today's take is not on it.**
The mirror's audiofiles dir last changed **2026-08-29 22:41** and holds up to
Take100. Take102 was recorded today (13:36) and exists ONLY on the laptop. Given
......
# The Ardour session as a jig, not an archive
*2026-09-06. Plan, not yet applied. PLN's framing: "no-data-loaded ardour
project, and on close monitored, we dump the stems and it stays fresh."*
## The problem, stated honestly
`Tidal Live` has quietly become the archive it was created not to be. It now
references **294 audio sources and every one of them is missing locally**, so
Ardour raises its "Missing File" modal before the session loads — a
focus-stealing dialog standing between one click and a playable rig (#136), on
the hot path, at gig time. Tonight it cost a launch.
The references break down, verified 2026-09-06:
| Sources | Where the audio is | Verdict |
|---|---|---|
| 270 (Takes 91-100, 102) | Freebox mirror, **53G, no file < 1MB** | alive, already archived |
| 24 (Take101, 12 orbits × L/R) | nowhere — local, Freebox, `Tidal Multi` all searched | audio gone; `.mid` survives |
Take101 is already adjudicated. `armada/tasks/041`: *"PLN: 'idontcare for todays
takes they were tests at best' — cleared and saved, no action."*
## The invariant to enforce
> **`Tidal Live` holds tracks, routing and levels — and zero audio sources at rest.**
Everything else follows from that one sentence. A session that never *acquires* a
stale reference cannot ever raise the modal. This is the tool's own doctrine
("the honest fix is to stop referring to files that do not exist") promoted from
a one-off repair to a standing property.
## Mechanism: a template for structure, a sweep for state
Two parts, because they answer different questions.
### 1. The template — what "fresh" *means*
A pristine `Tidal Live.template` holding the 12 orbit tracks, orbit→track
routing, the fader baseline and the master chain, with no regions and no
sources. It is the definition of a fresh jig and the recovery path if the
session file is ever corrupted.
**Why a template rather than "reset the session on close":** mutating a session
back to empty has to be *correct* about what to remove, every time, forever.
Instantiating from a known-good structure is correct by construction. Keep the
stable path (`Tidal Live/Tidal Live.ardour`) — `gig-up.sh`, `check-mix.py` and
`tidal-ardour-autoroute.sh` all resolve against the running process or that
path, so the path stays and only its *state* becomes derived.
### 2. The sweep — idempotent, and it runs at LAUNCH as well as close
If any `.wav` sits in `interchange/Tidal Live/audiofiles/`: archive it, verify
it, then drop its source and region references and save.
**Close-only is the trap.** A close-time hook is bound to the least reliable
moment there is: end of gig, tired, and quite possibly a crash instead of a
clean quit. If the sweep only runs on exit, a crash either leaves stems for the
next launch to trip over, or — far worse — a later "make it fresh" step runs
with unarchived stems still present and eats a take. So the sweep is
**idempotent and runs at launch too**, in `gig-up.sh` *before* `launch_bin
"Ardour"`. Close-time is the fast path; launch-time is what makes a crashed gig
safe. This is the same belt-and-braces shape already used for the midiviz close
latch, where one layer stops systemd and the other stops `rig_units.ensure()`,
and having only one looked like having neither.
### Order of operations — non-negotiable
copy -> verify (size + checksum, not cp's exit code) -> drop refs -> save (timestamped backup)
Never drop-then-copy. Never trust a return code as proof a file arrived.
## The guard tension, and why `--allow-archived` is correct here
`ardour-drop-missing-sources.py` **refuses** when the missing files survive
somewhere else, and that refusal is right: it protects the last breadcrumb
pointing at a recoverable take. It is written for *accidental* loss.
But the sweep's whole purpose is *deliberate archival* — it copies the audio
away and then wants the reference gone. After archiving, the audio survives
elsewhere by design, which is exactly the condition that triggers the refusal.
That is what `--allow-archived` is for, and why the docstring calls it
"deliberately loudly".
**The guard must not be weakened.** The rule is: `--allow-archived` is only ever
passed by a caller that has *itself verified* the archive copy. A human running
it blind still gets refused. The sweep earns the flag; a person does not.
## Applying it to today's state
One run, with Ardour quit, clears all 294 and yields the fresh jig:
python3 tools/ardour-drop-missing-sources.py \
~/Work/Sound/Ardour/"Tidal Live"/"Tidal Live.ardour" --apply --allow-archived
Safe because: the 270 are verified intact on the Freebox (53G, none < 1MB), and
the 24 are Take101, confirmed unrecoverable and already written off. The tool
backs the session up beside itself first.
### Correction to `armada/tasks/043`
Decision 3 there records the remedy as `--apply` alone, described as "One
command, once Ardour is quit". **That command now refuses.** When 043 was
written only Take101 was missing; since then the other eleven takes' audio moved
to the Freebox, so the tool sees 270 recoverable sources and correctly declines.
The flag is now required. The doc was right when written and is wrong now — the
sort of drift a plan should catch rather than a gig.
## Open questions for PLN
1. **Per-gig sessions, or one stable jig?** This plan keeps the single stable
path. The alternative — a new session per gig, named by date, instantiated
from the template — makes each gig self-contained and the sweep trivial, at
the cost of touching `ARDOUR_SESSION` and anything assuming a fixed path.
2. **Where do swept stems land?** The Freebox mirror is the established target
(53G already there). `tools/take-master.py` and `take-lens.py` exist; the
sweep should hand off to them rather than reinvent take handling.
3. **Does the local 53G come back?** Right now local `audiofiles/` is empty and
the mirror holds everything. If the mirror is the archive of record, that is
already the steady state and the sweep just maintains it.
## Sillage
Once the invariant holds, `gig-up.sh` gains a launch that cannot be interrupted
by a modal, and "did we lose a take?" stops being a question answered by reading
a session file at gig time.
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