Commit 51f1189e by PLN (Algolia)

fix(install): the installer shipped non-executable, and the doctor sent you to the wrong tool

Both found the only way they could be found: by running the documented
procedure on a machine that was not the one it was written on.

**tools/rig-install.sh was committed as mode 100644.** It is the first command
in SETUP.md's fast path. It worked for its whole life on the authoring laptop
because the author had chmod'd it there and never committed that — a local
chmod fixes your tree, not the repo, and the index is the only mode that
travels. So `tools/rig-install.sh` on a fresh clone died with "permission
denied", on the one machine the script exists to serve. Five other tracked
shell scripts had the same mode (gpu-mode.sh, init_midi.sh, viz/launch.sh and
two under armada/); all six are now +x in the index.

Fixing the six without a guard would just wait for the seventh, so
tools/tests/test_scripts_are_executable.py reads modes out of `git ls-files -s`
— the index, not the working tree — and fails on any tracked *.sh at 100644.
It also pins the five named entrypoints explicitly so a rename cannot quietly
drop one, and it guards itself: an empty file listing must not read as
success. Mutation-verified in both directions (set gpu-mode.sh back to 644 →
1 failed naming the file and printing the git update-index fix; restored →
3 passed).

**The doctor's fix text for missing units pointed at rig_units.py.** On a
fresh box that is wrong in a way that wastes real time: rig_units.py only
enables and starts units that are ALREADY symlinked into
~/.config/systemd/user/, so `--ensure --apply` returns fifteen consecutive
"Unit file does not exist" lines and reads like a broken reconciler. It isn't
— rig-install.sh is what creates the symlinks. The check now looks at whether
the units are merely not-enabled or genuinely not-found, and points at the
installer in the second case.

That distinction was already in the data (rig_units.py --status prints
"not-found" in the enabled column, and the doctor already parsed that column
into rows) — nobody had read the two facts together, because on a box where
the symlinks have existed for months the not-found branch never fires.

901 passed before, 309 in tools/tests after adding the new file.
parent b130508c
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -891,9 +891,18 @@ def check_systemd_units() -> None:
"journalctl --user -u <unit> -n 50 ; systemctl --user reset-failed")
elif not_enabled:
names = ", ".join(r["unit"] for r in not_enabled)
# NB: rig_units.py only enables/starts units that are ALREADY
# symlinked into ~/.config/systemd/user/ — it does not install them.
# On a fresh box every line comes back "Unit file does not exist",
# which reads like a broken reconciler and isn't. rig-install.sh is
# what creates the symlinks, so it has to come first here.
nf = sum(1 for r in not_enabled if r.get("enabled") == "not-found")
fix = ("tools/rig-install.sh --yes # installs the unit symlinks FIRST; "
"rig_units.py alone cannot, it only enables what already exists"
if nf else "tools/rig_units.py --ensure --apply")
add("INSTALL SURFACE", "systemd --user units", WARN,
f"{len(rows)} units known; not enabled at boot: {names}",
"tools/rig_units.py --ensure --apply")
fix)
else:
add("INSTALL SURFACE", "systemd --user units", PASS,
f"{len(rows)} units known to rig_units.py, none failed")
......
File mode changed from 100644 to 100755
"""Every tracked shell script must be executable IN THE INDEX.
Why this exists: `tools/rig-install.sh` — the first command in SETUP.md's
fast path — shipped as mode 100644 for its whole life. It worked on the
laptop it was written on because the author had chmod'd it locally and never
committed that, so `tools/rig-install.sh` on a FRESH CLONE died with
"permission denied" on the one machine the script exists to serve. Found
2026-09-06 by running it on a second box for the first time.
A local chmod fixes your tree, not the repo. The index is the only mode that
travels, so the index is what this test reads.
"""
from __future__ import annotations
import subprocess
from pathlib import Path
REPO = Path(__file__).resolve().parents[2]
def _tracked_modes() -> list[tuple[str, str]]:
out = subprocess.run(
["git", "ls-files", "-s"], cwd=REPO, capture_output=True, text=True, check=True
).stdout
rows = []
for line in out.splitlines():
meta, _, path = line.partition("\t")
parts = meta.split()
if len(parts) >= 1:
rows.append((parts[0], path))
return rows
def test_the_scan_actually_saw_the_repo() -> None:
"""Guard the guard: an empty listing must not read as success."""
rows = _tracked_modes()
assert len(rows) > 100, f"only {len(rows)} tracked files — git ls-files failed?"
assert any(p == "tools/rig-install.sh" for _, p in rows), "installer not tracked?"
def test_every_shell_script_is_executable_in_the_index() -> None:
offenders = [
p
for mode, p in _tracked_modes()
if p.endswith(".sh") and mode == "100644"
]
assert not offenders, (
"shell scripts tracked as non-executable — a fresh clone cannot run them:\n "
+ "\n ".join(offenders)
+ "\nFix in the index, not with a local chmod:\n"
" git update-index --chmod=+x -- " + " ".join(offenders)
)
def test_shebanged_scripts_meant_to_be_run_directly() -> None:
"""The named entrypoints, spelled out — so a rename can't silently drop one."""
entrypoints = [
"tools/rig-install.sh",
"tools/tidal-ardour-autoroute.sh",
"tools/midi-autoconnect.sh",
"gig-up.sh",
"perf.sh",
]
modes = dict((p, m) for m, p in _tracked_modes())
for p in entrypoints:
assert p in modes, f"{p} is not tracked — was it renamed?"
assert modes[p] == "100755", f"{p} is {modes[p]}, must be 100755"
File mode changed from 100644 to 100755
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