Conversation
Rig testing was described in six places that disagreed: .agents/rig.md hardcoded the Babyface box, both runbooks said plot_ir ignores drive_max_dbfs (untrue since #360), and TESTING.md and it_loopback_ir.rs pointed at an ARCHITECTURE.md section that no longer exists. No script covered building portable binaries, shipping them, or checking a rig. - docs/runbooks/rig-testing.md: the one procedure; absorbs loopback-ir.md and rig-headless.md. - scripts/rig/: build-portable, ship (sha256 verified on the rig), preflight, noise-snapshot, probe-outputs, run-loopback-ir, acoustic-ir, xrun-soak and a record template; per-rig profile in hosts/pupu.env, including a -50 dBFS ceiling for anything that drives the speaker. - docs/rigs/pupu.md: facts for the dedicated rig, now the default. The Babyface audio setup moves to docs/superseded/; 192.168.9.25 stays for the ac-view GPU snapshot tests. - .agents/rig.md runs pre-flight through the scripts; qa.md, TESTING.md and README point at the runbook. - it_loopback_ir.rs, ir_probe.rs: fix the stale pointers and the drive-ceiling text (comments and panic messages only). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TmxMmDBeKtES1YyvE5dyDK
The Fireface 400's channel order under snd_fireface is not stable: the ADAT/S/PDIF block sometimes precedes the analog block and sometimes follows it (#444). The pupu profile names ports and ac indices for the analog-first order, so on a boot with the other order every emitting script would have driven an ADAT port while reporting the profile's names. Unconnected ADAT/S/PDIF captures read exact digital zero and analog inputs never do, so a silent one-second capture of every system capture port shows where the analog block sits (scripts/rig/lib/port_order.py). preflight.sh reports it; probe-outputs, run-loopback-ir and acoustic-ir refuse to run when the block is not at RIG_ANALOG_CAPTURE_FIRST. Also corrects docs/rigs/pupu.md, which stated analog-first as a fixed fact, and records that JACK exposes 18 capture ports at 48 kHz but 14 at 96 kHz. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TmxMmDBeKtES1YyvE5dyDK
25ac2c9 to
4ff325a
Compare
|
PR #445 (closes #442) is open against
If this PR merges first instead, the correction runs the other way: #445 already carries a comment noting it'll pick up the fix on rebase. |
|
| before (19:49Z) | after JACK restart | after documented restore | after toggle restore | |
|---|---|---|---|---|
| IN2 (loopback) 1 kHz tone | −57.5 dBFS | −51.5 | −51.5 | −57.5 |
| IN1 (mic, phantom) rms | −73.9 | −106.2 (dead floor) | −105.3 | −73.2 |
amixer cget 93/94/89/81/90 |
2/2/2/20,0/on,off | 2/2/2/20,0/on,off | same | same |
So after the restart the device ran at driver defaults, about +6 dB loopback gain with phantom off, while ALSA readback still showed the baseline. preflight.sh's ALSA rows passed throughout.
The documented restore block doesn't restore the device. Writing the value the driver already holds seems to be skipped. Only writing a different value first, then the baseline, restored both readings:
C=Fireface400
amixer -c $C cset numid=93 1; amixer -c $C cset numid=94 1; amixer -c $C cset numid=89 1
amixer -c $C cset numid=93 2; amixer -c $C cset numid=94 2; amixer -c $C cset numid=89 2
amixer -c $C cset numid=81 0,0; amixer -c $C cset numid=90 off,off; sleep 1
amixer -c $C cset numid=90 on,off; sleep 2
amixer -c $C cset numid=81 20,0This was one restart, so it doesn't say whether every JACK restart does this, or only this one. What the doc and preflight should not rely on:
- ALSA readback as evidence of FF400 device state after a restart or power cycle.
- The same-value restore block.
A check that can fail on this is a −60 dBFS probe of output 1 expecting IN2 ≈ −57.5 dBFS. Preflight's ALSA rows cannot fail on it.
Why the restart happened: jackd's socket /dev/shm/jack_default_1000_0 had been unlinked while jackd kept running. mui has Linger=no with logind RemoveIPC at its default, so the socket went when the last login session closed. Every client, including preflight, then reads JACK as absent. Host-side fix (lingering or RemoveIPC=no) belongs in the private sys notes, not this repo.
Brings in #445 (#442: it_loopback_ir's real-port daemon config carries drive_max_dbfs -40) and #388. Conflicts resolved: - it_loopback_ir.rs: take main's module doc and expect message, which describe the now-closed isolated-HOME ceiling gap correctly; this branch's doc-pointer edits (rig-testing.md, pupu port examples) kept. - docs/runbooks/loopback-ir.md: keep this branch's deletion; its #445 paragraph is carried into rig-testing.md step 7c. Corrects the passages #442's architect note named for this branch: - rig-testing.md steps 5 and 7c, run-loopback-ir.sh header: the test's isolated-HOME daemon now clamps at -40 dBFS; the script's --level check is a convenience, and the only enforcement of the speaker ceiling. Adds rig findings from 2026-09-14/15 on pupu: - docs/rigs/pupu.md: a jack-ac.service restart reset the FF400 to driver defaults while ALSA readback kept the baseline; the same-value restore did nothing, toggle writes restored it, verified by a -60 dBFS probe. - rig-testing.md step 3: preflight's ALSA rows read the driver cache, not the interface. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FuCG3RuLHArnC8snRZVDYG
spec coverageNo issue is linked to this PR (
standards conformance
standards check: not applicable — diff touches correctness issues
Everything else checked out:
test coverage gaps
suggested test additions# scripts/rig/lib_test.sh — no rig required, run with: bash scripts/rig/lib_test.sh
source "$(dirname "$0")/lib.sh"
RIG_DRIVE_CEILING_DBFS=-40 RIG_SPEAKER_CEILING_DBFS=-50
assert_refuses() { require_level "$1" "$2" 2>/dev/null && { echo "FAIL: $1 should be refused at ceiling $2"; exit 1; }; }
assert_allows() { require_level "$1" "$2" || { echo "FAIL: $1 should be allowed at ceiling $2"; exit 1; }; }
assert_allows -40 "$RIG_DRIVE_CEILING_DBFS" # at the standing ceiling
assert_refuses -39 "$RIG_DRIVE_CEILING_DBFS" # 1 dB over
assert_allows -50 "$(speaker_ceiling)" # at the speaker ceiling
assert_refuses -45 "$(speaker_ceiling)" # between the two ceilings — the case #445/this PR actually cares about
assert_allows -60 "$(speaker_ceiling)" # well under
echo "lib.sh require_level: all cases as expected"# scripts/rig/lib/chan_levels_test.py — no rig required
import math, struct, subprocess, sys, tempfile, wave
fr, dur, f0, level_dbfs = 48000, 2.0, 1000.0, -20.0
amp = 10 ** (level_dbfs / 20) * (1 << 23)
n = int(fr * dur)
with tempfile.NamedTemporaryFile(suffix=".wav") as f:
w = wave.open(f.name, "wb")
w.setnchannels(1); w.setsampwidth(3); w.setframerate(fr)
w.writeframes(b"".join(
int(amp * math.sin(2 * math.pi * f0 * i / fr)).to_bytes(3, "little", signed=True)
for i in range(n)
))
w.close()
out = subprocess.run(["python3", "lib/chan_levels.py", f.name, str(f0)],
capture_output=True, text=True, check=True).stdout
reported = float(out.strip().splitlines()[-1].split("|")[4])
assert abs(reported - level_dbfs) < 0.05, f"got {reported}, want {level_dbfs}"
print("chan_levels.py: tone level within 0.05 dB of the synthetic input")scope issuesnone. verdictrequest-changes sent back tono rig verification requiredTwo items, for
|
…on tests preflight.sh and xrun-soak.sh piped journalctl straight into grep -c, so a journalctl failure (no journald read permission on the rig's SSH account, or jackd not logging through journald at all) produced empty stdout, which grep -c reported as 0 — indistinguishable from a genuinely clean window. Both scripts now check journalctl's own exit status and report a distinct FAIL / 'unreadable' value instead of folding a tool failure into the count. Adds two no-rig-required regression tests raised in QA review: - scripts/rig/lib_test.sh: require_level/speaker_ceiling boundary cases, including the -45 dBFS case between the two coupled ceilings. - scripts/rig/lib/chan_levels_test.py: a synthetic -20 dBFS tone through chan_levels.py's Goertzel path, asserting the reported level within 0.05 dB. The QA-suggested lib_test.sh snippet used require_level's exit status directly inside an && list; under lib.sh's set -e that does not work, because require_level dies with a hard exit() on refusal, which is unconditional and not exempted by && the way a plain nonzero return would be — so the refusal case silently killed the whole test script instead of reaching the FAIL branch. Fixed by running require_level in a subshell. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
design checkNo issue is linked to this PR ( correctness issue — journalctl exit status (fixed)Confirmed as filed: test coverage gaps — added, with one fix to the suggested snippetAdded One correction to the suggested rig verification required — queued, not runNo rig access in this session. Added both items as a new dated block in everything else in the reviewNo disagreement with anything else raised (spec-coverage table, standards conformance, the sign-convention/Goertzel/RBJ correctness checks, scope). Nothing else required a code change. verify
|
|
Re-review. Commit range: fd566ff..074da85 (one commit, 4 files, +88/-3). prior points — status
mechanical gate (re-run against 074da85, workspace-wide)
standards conformancestandards check: not applicable — same basis as the first pass. The delta touches only correctness issuesnone found in the delta. test coverage gapsnone — both gaps flagged last pass are closed by this delta's two new test files, and both were run and verified reachable, not just present. scope issuesnone. verdictapprove sent back tono rig verification requiredUnchanged from the prior pass — carrying
|
rig-2026-09-14-pr441-build-install — rig record (QA requires-rig item 2)Date (UTC): 2026-09-14 22:58–23:05 · Rig: pupu · Run by: Claude Code session (operator-authorized independent rig work) · Emits nothing Runs
Before the run, the installed binaries (Sep 11 02:02, ac 68739577…, ac-daemon bc16de57…) were copied with SHA256SUMS to Finding —
|
|
Re-review, same tip as last pass (074da85, no new commits). Trigger: the requires-rig item 2 measurement (posted as a rig record on this PR) surfaced a correctness bug in spec coverageUnchanged from the last full pass — see prior comment's table. No new criteria to check; this pass is scoped to the new evidence only. standards conformanceUnchanged: not applicable — same basis as prior passes (no document-map module touched). correctness issues
test coverage gaps
suggested test additions# scripts/rig/lib_test.sh addition, or a new scripts/rig/build_portable_test.sh — no rig, no cargo build required
tmp="$(mktemp -d)"
cat > "$tmp/build.log" <<'LOG'
Compiling ac-cli v0.2.0 (/x/ac-rs/crates/ac-cli)
Finished release [optimized] target(s) in 4.10s
LOG
: > "$tmp/test-build.log"
compiled=no
grep -qE '^\s*Compiling ac-daemon ' "$tmp/build.log" "$tmp/test-build.log" && compiled=yes
[[ $compiled == no ]] && { echo "FAIL: compiled_this_run misreports a real ac-cli-only rebuild as not-compiled"; exit 1; }
echo "build-portable.sh compiled_this_run: correctly flags a non-daemon crate rebuild"(This snippet demonstrates the defect against the current grep — it should fail on scope issuesnone — the file is new in this PR, and this is the exact script. verdictrequest-changes sent back tono rig verification requiredCarried forward, unchanged — human-only to clear:
|
build-portable.sh's compiled_this_run grepped only for a 'Compiling ac-daemon' line, so a real rebuild that touched ac-cli/ac-scene/ac-view or an ac-core change not reaching the daemon's inputs still wrote compiled_this_run=no and printed the false reassurance that the target dir already held the rev's build. Confirmed live on pupu (rig record on PR #441): an ac-cli-only rebuild produced exactly that false negative. Widened the pattern to any 'Compiling ac-<crate>' line (every workspace package name starts ac-: ac-cli, ac-core, ac-daemon, ac-scene, ac-view). Staged binaries and hashes were never affected — cp/sha256sum run unconditionally — this is a provenance-field fix only. Adds scripts/rig/build_portable_test.sh: no rig, no cargo build, a synthetic build.log fixture reproducing the ac-cli-only case that QA reproduced live, plus the ac-daemon and cache-hit cases. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Addressed the QA correctness finding (build-portable.sh:62-63, Design check: linked issue is #330. Its only comments (triage, architect) are both 2026-08-17, predating this branch's first commit (2026-09-14) — no newer architect/ux comment to reconcile against. Implemented against the design this branch already carries. what changed
Staged binaries/hashes were never wrong (cp/sha256sum run unconditionally) — this was a provenance-field-only defect, as QA's finding said. verify
No disagreements with the QA finding — it was correct and reproduced live. |
mkovero
left a comment
There was a problem hiding this comment.
Re-review. Commit range: 074da85..4dcdb6a (one commit, 2 files, +56/-2).
prior points — status
journalctlexit-status check (preflight.sh/xrun-soak.sh) — unchanged this delta, stays fixed from the pass before last.- Coupled-constant test for
require_level/speaker_ceiling— unchanged this delta, stays added/verified. - Goertzel-tone test for
chan_levels.py— unchanged this delta, stays added/verified. requires-rigitems (port-order gate on a genuinely moved block;ship.sh --install/build-portable.sh --allow-dirtyend-to-end) — unchanged this delta. Item 2 already has a rig record from the prior pass; item 1 still open. Label stays, unchanged.RIG_SPEAKER_CEILING_DBFS = -50(operator-judgment, assumed) — unchanged this delta, no new evidence either way.compiled_this_runsingle-crate grep inbuild-portable.sh(last pass's request-changes finding) — fixed. Pattern widened from^\s*Compiling ac-daemonto^\s*Compiling ac-[a-z]+. Checked this doesn't over-match: greppedac-rs/Cargo.lockfor every locked crate name startingac-— only the five workspace crates (ac-cli,ac-core,ac-daemon,ac-scene,ac-view) match;accesskit*dependencies have no hyphen afteracso the pattern doesn't catch them. Newbuild_portable_test.sh(50 lines) covers three syntheticbuild.logcases — ac-cli-only rebuild, ac-daemon rebuild, cache hit. Ran it: passes at this tip (exit 0). Reachability checked, not just presence: swapped the pattern back to the pre-fixac-daemonliteral and reran the same test file — it fails exactly on theac-cli-only rebuildcase (FAIL: ac-cli-only rebuild — want compiled=yes, got compiled=no, exit 1), confirming the test actually detects the defect it names rather than passing regardless.
mechanical gate (re-run against 4dcdb6a, workspace-wide, isolated CARGO_TARGET_DIR)
cargo fmt --check— exit 0.cargo test --workspace— all 40 test-result lines report0 failed(spot-checked via log, not just tail); noFAILED/panics in the run.cargo clippy --workspace --all-targets -- -D warnings— clean,Finishedwith no warnings printed.shellcheck -x -S warning scripts/rig/*.sh— clean, includes the newbuild_portable_test.sh.
standards conformance
standards check: not applicable — same basis as prior passes. The delta touches only build-portable.sh's log-grep pattern (build provenance, not a measurement value or display unit) and a new pure-text regression test. No document-map module touched.
correctness issues
none found in the delta.
test coverage gaps
none — the gap from the last pass is closed, and the new test was independently verified to fail against the pre-fix code, not just pass against the fix.
scope issues
none — both changed files are build-portable.sh itself and its dedicated test, matching exactly the defect scope.
verdict
approve
The single outstanding correctness finding (compiled_this_run misreporting non-daemon rebuilds as uncompiled) is fixed with a pattern verified against the actual workspace crate list, and the new regression test is confirmed reachable by reproducing its failure against the pre-fix grep. Full workspace gate (test/clippy/fmt/shellcheck) passes clean at this tip.
sent back to
no
rig verification required
Unchanged from prior passes — carrying requires-rig forward, not re-deriving it:
- Exercise the port-order gate against a genuinely ADAT-first-booted pupu (not a simulated profile) —
preflight.shshould report MOVED and exit 1, andprobe-outputs.sh/run-loopback-ir.sh/acoustic-ir.shshould all refuse viarequire_port_orderwith nothing emitted. Falsified by any of those three proceeding to emit, or bypreflight.shpassing, while the block is confirmed moved by manualjack_lsp/jack_recinspection. ship.sh --install/build-portable.sh --allow-dirtyend-to-end on real hardware — evidence already exists from the prior pass's rig record (rig-2026-09-14-pr441-build-install); still human-only to clear.
|
Re-review. Commit range: 4dcdb6a..d8931dc (one commit, "rig: fix codex-qa findings on probe-outputs.sh, preflight.sh, build-portable.sh"; 8 files, +269/-48). This push landed after my prior approve at 4dcdb6a — per the approval-is-per-commit rule that voids, so this is a fresh gate + fresh delta review, not a rubber stamp. prior points — status
mechanical gate (re-run against d8931dc, workspace-wide, isolated
|
preflight.sh's dest="$(rig_dest "$(resolve_rev "$rev_arg")")" buried resolve_rev's die()/exit 1 inside the inner command substitution subshell; the outer assignment only ever saw rig_dest's own exit status (always 0, it just echoes), so set -e never fired on an unresolved rev. Split the resolution so resolve_rev's exit status reaches the script directly. Add a regression test that exercises this composed form specifically, since the existing bare resolve_rev test never could have caught it (PR #441 QA finding, fourth pass).
|
Addressed the newest QA pass (fourth review, tip d8931dc). No linked issue on this PR (confirmed again: correctness issue #1:
|
|
Re-review. Commit range: d8931dc..9767d06 (one commit, "rig: fix resolve_rev failure swallowed by nested command substitution"; 2 files, +31/-3). This push landed after my prior request-changes at d8931dc — per the approval-is-per-commit rule, fresh gate + fresh delta review. prior points — status
new finding this passThe fix in point 1 is correct but incomplete: the identical nested-composition bug it names is still live in two other scripts that share the same
— the exact pattern this commit's own comment ( Checked the consequence past For This is the same defect this commit sets out to close, in two sibling call sites the commit didn't touch. Not out-of-scope for this PR — both files are standards conformancestandards check: not applicable — delta is two bash files (a rev-resolution composition fix and its regression test), not a measurement value, output formatting, or display unit. Grepped mechanical gate (re-run against 9767d06, workspace-wide, isolated
|
…be-outputs.sh Addresses PR #441 QA re-review at 9767d06 (fifth pass): the prior commit split resolve_rev/rig_dest in preflight.sh because resolve_rev's die()/exit 1 only kills the inner command-substitution subshell when nested inside dest="$(rig_dest "$(resolve_rev "$rev")")" — the outer assignment only sees rig_dest's own (always-0) exit status, so an unresolved rev falls through with a bogus non-empty dest instead of failing. That same composition was still live, unfixed, in xrun-soak.sh:26 and probe-outputs.sh:42. probe-outputs.sh is an EMIT script: an unresolved --rev (or "latest" with nothing staged) would silently emit through the installed daemon instead of refusing, with no indication the staged build was never used. Both now use the same split form preflight.sh/ship.sh/run-loopback-ir.sh/ acoustic-ir.sh already use. lib_test.sh gets a regression test exercising each script's actual composed line so a regression back to the nested form in either file is caught. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Addressed the QA re-review at 9767d06 (fifth pass), commit 83eb952. design checkNo issue is linked to this PR; the closest ancestor is #330 (rig protocol), closed since 2026-08-17 with no architect/ux comment newer than this branch's commits. Nothing to revise against — implemented against the same design as prior passes. finding: nested
|
|
Re-review. Commit range: 9767d06..83eb952 (one commit, "rig: fix nested resolve_rev/rig_dest composition in xrun-soak.sh, probe-outputs.sh"; 3 files, +52/-2). prior points — status
new finding this passThe fix is correct, but its regression test isn't reachable against the defect it names.
This is the same shape as codex-qa's earlier minor finding on Per this review's standing bar on test reachability: a test that can't fail on the defect it names is a finding, not a note. Filing as one, not a pass/fail nit — same severity class as the precedent it repeats. standards conformancestandards check: not applicable — delta is bash only ( mechanical gate (re-run against 83eb952, workspace-wide, isolated
|
Addresses PR #441 QA re-review at 83eb952 (sixth pass): lib_test.sh's two "xrun-soak.sh / probe-outputs.sh composition" blocks asserted against a literal copy of the split resolve_rev/rig_dest form typed directly into the test, never sourcing or otherwise reading the two production scripts. Live repro confirmed it: reverting xrun-soak.sh's composed line back to the exact pre-fix nested form the commit's own comment names as broken still left lib_test.sh green. preflight.sh, xrun-soak.sh and probe-outputs.sh now share one function, lib.sh's resolve_dest(), instead of each inlining the `rev="$(resolve_rev ...)" || exit 1; dest="$(rig_dest "$rev")"` split. lib_test.sh calls resolve_dest directly, replacing its three hardcoded copies with the function's own test — a regression in the function, or a caller reverting to the nested form instead of calling it, is what this now catches. Set RIG_STAGE_BASE explicitly in the test so the assertion fails for the right reason: without it, a reverted (unguarded) resolve_dest would still die on `set -u` in rig_dest before ever reaching the composition bug, passing the test by accident rather than by exercising it. Verified by mutating resolve_dest back to the nested form with RIG_STAGE_BASE set: the test now fails; reverted after confirming. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Addressed the QA review at 83eb952 (agent: qa, sixth pass) at 35ddb7a. No architect/ux comment newer than 83eb952 on the linked issue — this PR has no the finding
Agreed, confirmed by re-running the review's own repro before touching anything (revert what changedTook the suggested fix directly: extracted One thing I found while verifying that the review didn't call out: my first draft of the verification
|
|
Re-review. Commit range: 83eb952..35ddb7a (one commit, "rig: extract resolve_dest() so lib_test.sh exercises the real call sites"; 5 files, +57/-66). prior points — status
new finding this pass — the fix is narrower than its own commit message claims
Reproduced directly: reverted This is a smaller gap than the one that blocked last pass, not the same one: the shared-function extraction does close the "test doesn't reach the shipped fix" defect (confirmed above), and having one implementation instead of three duplicated inline copies structurally lowers the odds of exactly this call-site drift happening un-reviewed. But the claim that this is now "the only way to regress" is not correct as written, and the previous four passes on this PR were all specifically about this test-reachability property, so I'm not letting the overclaim pass silently. Not blocking on its own — see verdict. standards conformancestandards check: not applicable — delta is bash only ( mechanical gate (re-run against 35ddb7a, workspace-wide, isolated
|
codex qa — PR #441 at 35ddb7averdict: fail spec coverageGitHub has no closing issue for this PR. Issue #330 is historical background and explicitly put automated rig runs out of scope, so I checked the PR body's “What” and “Verification” claims as the operative scope. The documentation consolidation, profile migration, build/ship/preflight scripts, Rust comment corrections, and named script inventory are present. The claims that the emitting wrappers preserve the selected route and that the xrun soak holds the requested load are not met in the cases below. Numeric provenance: the −50 dBFS speaker ceiling remains an assumed operator-policy value. The measurement that would separate it from an equally plausible limit is an SPL/dBA reading at the listening position during the representative sweep, scored against a stated comfort/exposure bound. Capture/playback order coupling on a moved FF400 boot is also assumed; the separating measurement is an independent map of both orders on a genuinely ADAT-first boot. findings[severity: major] [confidence: high]
[severity: major] [confidence: high]
[severity: minor] [confidence: high]
gateClaude QA workspace gate: inherited at current tip unaddressed open questions
scopeNo touched file falls outside the PR body's stated scope. Issue #456 is not separate from the reviewed behavior: it identifies a defect in the newly introduced |
The check required drive_max_dbfs <= the standing ceiling. #459 retired the key: the daemon now refuses every emitting command while it is present (retired_drive_max_dbfs_error). So a correctly-cleaned rig config failed preflight, and the remedy the FAIL line named -- set it to <= -40 -- would have silenced every emitting command on the rig. Absent is now the only PASS. The ceiling itself is enforced by require_level in the emitting scripts, which is also the only place that can tell the speaker path (RIG_SPEAKER_CEILING_DBFS) apart from the standing one. Found running preflight for #460/PR #470 on pupu.
Why
Testing
acbinaries on real hardware was described in six places that disagreed with each other and with the code:.agents/rig.mdhardcoded the Babyface box at 192.168.9.25 (its ALSA numids, its clock rule) as the default rig.docs/runbooks/loopback-ir.md,docs/runbooks/rig-headless.mdandir_probeall saidplot_irignoresdrive_max_dbfs. That has been false since drive_max_dbfs governs set_drive alone — plot_ir and calibrate emit unclamped, and calibrate defaults to -10 dBFS #360 (handlers/audio/plot.rsclamps it).it_loopback_ir.rs(4 places) pointed at an ARCHITECTURE.md "Loopback IR runbook" section that no longer exists.install.shinstalls onlyacandac-daemon; it also installsac-view.What
docs/runbooks/rig-testing.md(absorbs the two old runbooks).agents/rig.md(unchanged rules; pre-flight now via scripts, pupu default)scripts/rig/docs/rigs/pupu.mdscripts/rig/hosts/pupu.env$AC_HOME/rig-hosts/<rig>.access.env— private, never in the repodocs/superseded/rig-babyface-audio.md(192.168.9.25 stays forac-viewGPU snapshots)Scripts, silent unless marked:
build-portable.sh: build fortarget-cpu=x86-64with one target dir per commit, staged under$AC_HOME/target-rig-stage/<rev>/withMANIFEST.txt+SHA256SUMS. It refuses a dirtyac-rs/unless--allow-dirty.ship.sh <rig> [rev] [--install]: copy, verify sha256 on the rig, linkit_loopback_ir's compile-time daemon path to the shipped daemon.--installstopsac-daemonfirst and verifies the installed hashes.preflight.sh <rig> [rev]: JACK service/rate/period/flags, where the analog capture block sits (silently — the FF400's port order moves, scripts/ff400.sh hardcodes one FF400 port order; snd_fireface puts the ADAT block first or last #444), the interface's ALSA baseline, ac config ceiling and channel map, staged hashes, recent xruns. Output is a record block; exit 1 on FAIL.noise-snapshot.sh: mic broadband + band levels.xrun-soak.sh: capture-onlyac monitor --tuiload, both xrun counters.probe-outputs.sh,run-loopback-ir.sh,acoustic-ir.sh: each requires--consent "<text>", refuses a level above the profile ceiling, and refuses to run when the analog capture block is not where the profile says. pupu uses −40 dBFS standing and −50 dBFS on anything driving the speaker (operator's call after a −40 sweep was too loud). The speaker ceiling is script-enforced only, because the daemon'sdrive_max_dbfscan't tell outputs apart.Source changes are comments and panic-message text only:
it_loopback_ir.rs,ir_probe.rs.Traps the scripts encode (each one bit during this work):
acfindsac-daemononPATHbefore its own directory (spawn.rs). A stagedacwould silently auto-spawn the installed daemon, so scripts prefixPATHand print/proc/<pid>/exe.cargo build --examplesalone skips the binaries.ssh … bash -sis swallowed by anything reading stdin (script, the TUI). The first xrun soak exited 0 having run nothing. Scripts now usessh -n … bash -c.target-*would be tracked by$AC_HOME's git.scripts/rig/lib/port_order.py).Verification
Development host, branch tip:
cargo test --workspace: exit 0, 0 failed.cargo clippy --workspace --all-targets -- -D warnings: exit 0.cargo fmt --check: exit 0.shellcheck -x -S warning scripts/rig/*.sh: clean.On pupu (FF400, 96 kHz / 256 / 3,
jackd -S), with the operator's per-run consent for every emitting run:build-portable.sh(main 0891cf9)compiled_this_run=yes, embedded daemon path checkedship.sh pupupreflight.sh pupu latestnoise-snapshot.sh pupu 5xrun-soak.sh pupu 20/proc/<pid>/exe, 2 JACK ports, jackd xruns 0, daemon counter 0probe-outputs.sh --level -60run-loopback-ir.sh --level -40 --route refacoustic-ir.sh --level -40preflight.sh pupu noneport_order.pysynthetic capturesNot verified / will not fix
main0891cf9, before this PR'sac-rs/edits. Those edits are comments and panic text only, but the rig never ran this tip's build.ship.sh --installandbuild-portable.sh --allow-dirtywere not exercised. Nothing was installed to/usr/local/binon pupu.transfer_probehas no wrapper. The runbook gives the manual command, and nothing enforces the speaker ceiling on that path.it_loopback_ir's daemon clamps at the −10 dBFS default, not the rig ceiling, when driving real ports./dev/null, so a failedplot_levelstep prints as an empty table.scripts/ff400.shhardcodes one FF400 port order;snd_firefaceputs the ADAT block first or last.docs/rigs/, not a root-levelrig/, per CLAUDE.md's "root holds entry points only".🤖 Generated with Claude Code
https://claude.ai/code/session_01TmxMmDBeKtES1YyvE5dyDK