Commit 06039c8a by PLN (Algolia)

feat(rig): the doctor can name what a fresh box is missing, before the audio arrives

rig-doctor's samples check had a structural hole I only saw once it ran: it
shells out to sample-pack, which resolves bank names by walking the Dirt-Samples
tree of the box it is running on. On PLN's laptop that is 281 banks and looks
fine. On an empty XPS24 it reports "0 banks resolve" — true, and useless. The
check could never say "281 missing", which is the only thing a fresh machine
needs to hear.

The fix is an EXTERNAL reference, committed: sample-manifest.json at the repo
root (463 KB, 281 banks, 9385 filenames, generated by tools/sample-pack.py
--all). rig-doctor now falls back to it when no --bundle is given, and --bundle
accepts a manifest FILE as well as a bundle directory. So the ordering that
makes a same-day setup possible works: git clone, run the doctor, get the exact
list of missing banks — all before 15 GB of audio has moved anywhere.

Committed deliberately, not gitignored. A generated artifact that nothing ever
compares against reality is how preload.scd drifted for weeks and made its
debut as a crackle at a venue. This one is diffable, and its own freshness is
visible in git.

Mutation-verified rather than assumed, because a checker that cannot report
absence is exactly the failure being fixed here: planted two nonexistent banks
in a copy of the manifest, confirmed the check goes FAIL, names them, counts
2/281 with sizes, and flips the final verdict from "yes" to "no".

That test also exposed a fix-pointer that could not be followed — with a
manifest file it said "see <manifest.json>/README.md", a path that cannot
exist. Now _bundle_fix() distinguishes the three cases: you have the bundle
directory (cp from it), you have a bundle's MANIFEST.json (cp from its parent),
or you have only the committed list (rsync from the freebox staging copy, or
rebuild with sample-pack on a box that has the samples). A fix you cannot follow
is not a fix.

The carry-on bundle it describes is built and verified: 281 banks, 9385 files,
15,108,195,468 bytes, checked file-by-file against its own manifest with 0
mismatches, and staged to /mnt/freebox/PLN/parvagues-carryon byte-identical
(9387 files both sides, 21m53s over SMB at ~11 MB/s).

903 passed, 0 failed.
parent 58371350
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -481,6 +481,29 @@ def check_scd_sample_roots() -> None:
f"create {checkdir}, or fix the path in start_and_midi.scd")
def _bundle_fix(bundle: Path, dirt: Path) -> str:
"""Where to actually GET the missing banks.
The manifest and the audio are deliberately separate: the manifest is
committed so a fresh box knows what it lacks the moment it has the clone,
while 15 GB of audio arrives by other means. So the fix text has to
distinguish "you have the bundle, copy from it" from "you only have the
list, go fetch the bundle" — pointing a reader at MANIFEST.json/README.md
is a dead end, and a fix that cannot be followed is not a fix.
"""
tail = ("every folder travels WHOLE — never subset one, because bank:N "
"indexes files in glob order and dropping one renumbers the rest")
if bundle.is_dir():
return f"cp -r {bundle}/<bank> {dirt}/ ({tail})"
if bundle.name == "MANIFEST.json":
return f"cp -r {bundle.parent}/<bank> {dirt}/ ({tail})"
# The committed repo manifest: the list, not the audio.
return ("this is the committed bank LIST, not the audio. Get the bundle: "
f"rsync -a /mnt/freebox/PLN/parvagues-carryon/ {dirt}/ "
"— or rebuild it on a box that has the samples with "
f"tools/sample-pack.py --all --pack DEST ({tail})")
def check_sample_coverage(bundle: Path | None) -> None:
"""Does this box have the banks the set needs?
......@@ -523,6 +546,18 @@ def check_sample_coverage(bundle: Path | None) -> None:
return
if bundle is None:
# Fall back to the manifest COMMITTED at the repo root. This is the
# ordering that makes a same-day setup possible: a fresh box can be
# told exactly which banks it lacks the moment it has the git clone,
# BEFORE the 15 GB of audio arrives. Without it this check is
# structurally self-referential -- sample-pack resolves names against
# the box it runs on, so an empty machine reports "0 banks resolve"
# rather than "281 missing", which is true and useless.
default = REPO_ROOT / "sample-manifest.json"
if default.is_file():
bundle = default
if bundle is None:
mapped = report["banks"]["mapped"]
extra = report["banks"]["extra"]
n = len(mapped) + len(extra)
......@@ -536,7 +571,11 @@ def check_sample_coverage(bundle: Path | None) -> None:
f"overridden downstream ('#' is '|>').")
return
manifest_path = bundle / "MANIFEST.json"
# Accept either a bundle DIRECTORY or a manifest FILE. The committed
# sample-manifest.json at the repo root is the whole point: a fresh box can
# be told exactly which 281 banks it is missing BEFORE the 15 GB arrives,
# which is the one ordering that makes a same-day setup possible.
manifest_path = bundle if bundle.is_file() else bundle / "MANIFEST.json"
if not manifest_path.is_file():
add("SAMPLES", "sample coverage", WARN,
f"--bundle {bundle} given but no MANIFEST.json there")
......@@ -575,9 +614,7 @@ def check_sample_coverage(bundle: Path | None) -> None:
f"{len(missing_names)}/{total} banks missing "
f"(~{human(missing_bytes)}, {missing_files} files): "
f"{sample_names}{more}{unresolved_note}",
f"drop the missing folders from {bundle} into "
f"{dirt}/ (see {bundle}/README.md — every folder travels whole, "
f"never subset one: bank:N indexing depends on file order)")
_bundle_fix(bundle, dirt))
# --------------------------------------------------------------------------- #
......
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