Conversation
closes #444 snd_fireface's ADAT/analog block order is not stable across boots, so ff400.sh's hardcoded 18-port alias table mislabels every analog port as ADAT (or vice versa) on the boots where its assumed order is wrong. Per architect option A: stop publishing channel-name aliases entirely, clear any FF400:-prefixed alias an earlier run left behind, and leave jackd's own alsa_pcm:* alias untouched. Also drop the generic phantom-power write (numid=90); that belongs to a rig profile, not a generic init. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
spec coverage
Criteria 7–9 are flagged by the architect as an open verification-gate question for operator/triage, not something this PR was meant to resolve, and the spec-coverage gap here is reported rather than treated as a developer miss. Criterion 3's gap is not architect-acknowledged in the same way — the architect's implementation notes name only standards conformancestandards check: not applicable — scope-none (issue #444 carries correctness issues
test coverage gaps
suggested test additions# make the amixer stub able to fail on the defect correctness-issue-1 names:
# reject a cset whose value count doesn't match the control's own reported width
cat > "$bindir/amixer" <<'STUBEOF'
#!/usr/bin/env bash
echo "$*" >> "${AMIXER_LOG:?}"
case "$*" in
*"cget numid="*)
numid=$(echo "$*" | grep -oE 'numid=[0-9]+' | grep -oE '[0-9]+')
n="${AMIXER_WIDTH:-18}"
vals=$(python3 -c "print(','.join(['0']*int(\"$n\")))")
echo ": values=$vals"
exit 0
;;
*"cset"*)
numid=$(echo "$*" | grep -oE 'numid=[0-9]+' | grep -oE '[0-9]+')
vals=$(echo "$*" | grep -oE '[0-9]+(,[0-9]+)+' | tail -1)
want="${AMIXER_WIDTH:-18}"
got=$(echo "$vals" | awk -F, '{print NF}')
[[ "$got" == "$want" ]] || { echo "amixer: wrong value count ($got, want $want) for numid=$numid" >&2; exit 1; }
exit 0
;;
esac
exit 0
STUBEOF
# then, once ff400.sh reads live width for numid 9-26/45-62 too:
for n in 14 18; do
reset_state "$n"
out="$(bash "$FF400" 2>&1)"; rc=$?
[[ $rc -eq 0 ]] || fail "(h) loopback-mute write rejected at $n ports: $out"
done
# and independently assert stream-source-gain row width, mirroring the
# existing numid=8 check:
routewidth=$(grep -oE '^-c 0 cset numid=63 [0-9,]+' "$AMIXER_LOG" | tail -1 | awk '{print $NF}' | awk -F, '{print NF}')
[[ "$routewidth" == "$n" ]] || fail "stream-source-gain row width was $routewidth, want $n"The stricter stub also makes the existing suite honest about numid=8/63–80: it will fail today only if a future edit reintroduces a width bug there, which the current stub can't catch either. scope issuesnone. Touches only verdictrequest-changes: design sent back toarchitect — decide whether criterion 3's live-width fix extends to rig verification requiredTwo distinct items, neither obtainable from this tree:
No existing entry in |
…=8/63..80 Revised per architect re-entry on issue #444 (comment edited after this branch's original commit). Upstream snd-firewire-ctl-services source fixes the FF400's array-control widths at 18 (output-volume, stream-source-gain) and 8 (analog-source-gain, adat-source-gain) — none of them follow sample rate or JACK port count, which is a separate kernel-side quantity. The script now reads and validates every one of those widths (numid=8, 9..26, 45..62, 63..80) before its first mixer write, exits non-zero naming the numid on an unreadable or too-narrow one, and writes exactly the width each control reports — replacing the literal 18-value string previously sent to the 8-wide analog/adat-source-gain controls. ff400_test.sh: decouples control-width stubbing from JACK port count (case (e) now asserts mixer writes are identical at 14 vs 18 ports, not that a width tracks port count); adds case (h) (every cset's value count matches the width amixer reported, for all four control families) and case (i) (an unreadable control width aborts before any cset, naming the numid). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Design superseded under this branch — revised to matchThe architect comment on #444 was edited (23:37:56Z) after both this Point-by-pointCorrectness issue 1 ( Qa's premise that a count-mismatched Correctness issue 2 (alias parser assumptions — Test coverage gaps (amixer stub's "sent back to: architect" — answered by the architect's edit: widths Criteria 7-9 / rig verification items 1-2 — unchanged, still open, Files touched (this commit)
Test output
No disagreement with any qa finding — all addressed above, either by this |
|
Re-review. Commit range: gate (full workspace, re-run at this tip)
point-by-point on my prior review
spec coverage (updated)
standards conformancestandards check: not applicable — scope-none (issue #444 still carries correctness issuesnone found in this delta. test coverage gapsnone found in this delta. (Verified case (h)/(i) are reachable and fail on the named defect — see gate section above, not just read as present.) scope issuesnone. Same two files as the architect's manifest. new issues filed (outside this PR's scope, per architect's own risk list on #444 — not this PR's fault, filed so they don't get lost)
verdictapprove sent back tono rig verification requiredUnchanged from prior pass except item 1 is reported (not independently reproduced) resolved, and item 2 is downgraded from correctness-gating to fixture-quality:
No entry in |
rig record — optional confirmations for #444 (2026-09-15 ~00:05Z, Claude Code session, read-only / silent)Item 1: jack2 tool output on 192.168.9.25 (host jack2 with example tools v4. Item 2: FF400 control widths on pupu at 96 kHz (JACK rate 96000; Both are Item 3: planted both-boot-orders fail-test on the rig. Not run. It needs the FF400 to actually enumerate ADAT-first. That order cannot be forced from a session: the operator describes it as varying between boots. Queued in |
codex qa — PR #450 at 019621bverdict: fail spec coverage
findings[severity: major] [confidence: high]
[severity: minor] [confidence: high]
gateClaude QA workspace gate: inherited at current tip unaddressed open questions
scopenone |
codex qa — PR #450 at 019621bverdict: fail spec coverage
findings[severity: major] [confidence: high]
[severity: major] [confidence: high]
[severity: minor] [confidence: high]
gateClaude QA workspace gate: inherited at current tip unaddressed open questions
scopenone |
) show exited before clear_ff400_aliases ran, so a stale FF400: alias survived `./ff400.sh show` with no cleanup or guidance printed. clear_ff400_aliases also trusted jack_lsp -A's success without checking it: the enumeration read it via process substitution (invisible to set -e) and the verify pass piped it into awk without pipefail (awk's own exit status masked jack_lsp's), so either call failing after the plain reachability probe passed could still print "cleared"/"none set here" having never actually looked. Also guard show's per-channel diagonal extraction so an unreadable row (empty amixer output, python IndexError) no longer aborts the whole listing under set -e instead of printing "(could not be read)" and continuing. Adds test cases (j)-(m) to ff400_test.sh, each confirmed red against 019621b (this branch's prior tip) and green here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Revision: codex-qa findings addressed (commit 20a787b)Checked issue #444 for an architect/ux comment newer than this branch's prior tip ( Addressing the newest [major] [major] [minor] unreadable diagonal row aborts All four new cases (j)/(k)/(m)/(l) were run against this branch's prior tip ( No disagreement with any finding — all three addressed as described. verifyNo Rust files touched; note on labelsPer this task's explicit instruction I did not touch labels — |
|
Re-review. Commit range reviewed: mechanical gate (workspace, fresh at tip)
delta review (
|
codex qa — PR #450 at 20a787bverdict: pass spec coverageCriteria 1–6 are covered by the implementation and rig-free tests: the script publishes no channel mapping, does not infer playback order, handles 14/18 JACK port counts independently of live mixer-control widths, clears stale Numeric provenance checked: 14/18 capture-port counts and the −60 dBFS probe level are tagged gateClaude QA workspace gate: inherited at current tip unaddressed open questions
scopenone |
Conflict in ac-daemon/src/audio/fake/mod.rs, import list only: this branch added hooks::next_capture_block_xruns_delta (#428 xrun injection), main (PR #384, #368) added hooks::tau_gain_override and tau_noise_amplitude_override. Resolved as the union. capture_block merged cleanly and keeps both changes: #428's xrun delta, then #368's gain scaling of the synthesized block. Also brings in PR #449, #384 and #450. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FuCG3RuLHArnC8snRZVDYG
closes #444
what changed
scripts/ff400.shno longer publishes any FF400 JACK channel-name alias: snd_fireface's ADAT/analog block order is not stable across boots (measured both orders on pupu, 2026-09-14), so a fixed table mislabels ports on whichever boot has the other order, and the label then reads as driver-confirmed routing. Per the architect's option A, the script now only clears anyFF400:-prefixed alias an earlier run left behind (leaving jackd's ownalsa_pcm:*alias in place), runs that cleanup before any mixer write (so a laterset -efailure can't leave a stale alias), and prints where to actually find the order instead of guessing. It also stops forcing phantom power (numid=90) off — that's now rig-profile territory — and reads theoutput-volume/stream-source-gaincontrol widths live fromamixerinstead of assuming 18, since the port count differs by sample rate (18 at 48 kHz, 14 at 96 kHz).files touched
scripts/ff400.sh— removed the hardcodedCHNAMEalias table and its JACK-alias-setting loop; addedclear_ff400_aliases()(parsesjack_lsp -A, unaliases onlyFF400:-prefixed entries viajack_alias -u, verifies none remain, exits non-zero on a failed unalias or a leftover); removed thenumid=90phantom-power write and its status line;showdrops the ADAT/S/PDIF/AN name column (prints index-only); added_ctl_width()to read livevalues=width fornumid=8andnumid=63..80instead of a literal 18scripts/ff400_test.sh— new, rig-free test; stubsjack_lsp/jack_alias/amixeronPATHand covers the architect's cases (a)–(g): planted alias cleared, non-FF400:alias untouched, nojack_aliascall without-u, nonumid=90write, correctness at 14 and 18 ports, JACK-unreachable wording, and non-zero exit on a failed unalias. Verified manually (not part of the committed test) that these cases go red againstorigin/main'sff400.shand green against this branch's.test output
shellcheckclean on both files (pre-existingSC2086info notices on unquoted$CARD/numidin code this PR didn't touch are unchanged fromorigin/main). No Rust crates touched;cargobuild/clippy/fmt don't apply to this change.ZMQ schema changed
no
new dependencies
none
related
none
open questions for reviewer
numid=8and the63..80stream-source-gain rows as needing a live-read width fix, and explicitly said "leave the numid layout itself alone." The loopback-mute writes (numid=9..26,45..62) still send a hardcoded 18-value string; if those controls also narrow at 96 kHz the same way, they weren't in this PR's scope per that note — flagging in case that's an oversight rather than a deliberate exclusion.