Skip to content

fix: ff400.sh stops aliasing unstable FF400 port order - #450

Merged
mkovero merged 3 commits into
mainfrom
issue-444
Sep 15, 2026
Merged

mkovero merged 3 commits into
mainfrom
issue-444

Conversation

@mkovero

@mkovero mkovero commented Sep 14, 2026

Copy link
Copy Markdown
Owner

closes #444

what changed

scripts/ff400.sh no 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 any FF400:-prefixed alias an earlier run left behind (leaving jackd's own alsa_pcm:* alias in place), runs that cleanup before any mixer write (so a later set -e failure 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 the output-volume / stream-source-gain control widths live from amixer instead 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 hardcoded CHNAME alias table and its JACK-alias-setting loop; added clear_ff400_aliases() (parses jack_lsp -A, unaliases only FF400:-prefixed entries via jack_alias -u, verifies none remain, exits non-zero on a failed unalias or a leftover); removed the numid=90 phantom-power write and its status line; show drops the ADAT/S/PDIF/AN name column (prints index-only); added _ctl_width() to read live values= width for numid=8 and numid=63..80 instead of a literal 18
  • scripts/ff400_test.sh — new, rig-free test; stubs jack_lsp/jack_alias/amixer on PATH and covers the architect's cases (a)–(g): planted alias cleared, non-FF400: alias untouched, no jack_alias call without -u, no numid=90 write, 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 against origin/main's ff400.sh and green against this branch's.

test output

$ bash scripts/ff400_test.sh
ff400.sh alias handling: all cases as expected

shellcheck clean on both files (pre-existing SC2086 info notices on unquoted $CARD/numid in code this PR didn't touch are unchanged from origin/main). No Rust crates touched; cargo build/clippy/fmt don't apply to this change.

ZMQ schema changed

no

new dependencies

none

related

none

open questions for reviewer

  • The architect's implementation notes named only numid=8 and the 63..80 stream-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.
  • Criteria 7–8 (fail-test on both boot orders, on the rig) are, per the architect's design, satisfied identically either way under option A (no alias is ever published), so the only case that can actually go red is the planted-old-alias check — done here via the manual old-vs-new comparison above, not a live rig run. The architect flagged this as an open verification-gate question for operator/triage, not something this PR resolves.

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>
@mkovero mkovero added needs-work QA requested changes — PR not ready to merge requires-rig labels Sep 14, 2026
@mkovero

mkovero commented Sep 14, 2026

Copy link
Copy Markdown
Owner Author

spec coverage

criterion provenance covered notes
no alias published unless order determined for running driver instance measured (non-numeric) Option A: clear_ff400_aliases never sets an alias, only clears FF400:-prefixed leftovers.
playback mapping never inferred from capture order alone (coupling "not accepted" per architect) measured (non-numeric) No playback alias is set at all, so the un-accepted coupling is never relied on.
no port count assumed; correct at 18 ports (48 kHz) and 14 ports (96 kHz) measured output-volume (numid=8) and stream-source-gain (numid 63–80) now read width live via _ctl_width. analog-source-gain (numid 9–26) and adat-source-gain (numid 45–62) — same class of per-channel ALSA array control, on the same card — still send a literal 18-value string (scripts/ff400.sh:205). See correctness issue 1.
when order can't be determined, script prints that + where to look, no cause, no fixed-table fallback measured (non-numeric) clear_ff400_aliases (lines 86–90) and the JACK-unreachable branch (43–44) both name places to check without asserting a cause.
after run, no FF400 alias (incl. leftovers) names a different port than it's attached to measured (non-numeric) ✓ logic / unverified parser Clear-then-verify logic is right on paper, but see correctness issue 2 — the jack_lsp -A layout and jack_alias -u syntax the parser assumes were never confirmed against a real JACK host, contrary to the architect's explicit instruction.
generic init no longer sets phantom power to a fixed state; never prints an unset/unread state as fact measured (non-numeric) numid=90 write removed; show's phantom row now reads back and is labelled "driver cache, not set by this script" (line 115), matching the architect's allowance for a labelled readback.
fail-test, playback, on both boot orders, on the rig — provenance: measured measured ✗ (open, architect-acknowledged) Architect: under option A the result is identical on either boot order, so only the planted-old-alias case (test case (a)) can go red; a genuine rig run on both orders is not done here.
fail-test, capture, on the same two boots measured (paired with above) ✗ (open, architect-acknowledged) Same gap as above; no capture-side rig run in this PR.
each fail-test run records order/method/rate/port-count/consent n/a until above run Nothing to record — no rig run in this PR.

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 numid=8 and 63..80 as needing the live-width fix and say nothing about 9..26/45..62; the developer flagged this ambiguity honestly in the PR body but shipped the hardcoded value. See "sent back to" below.

standards conformance

standards check: not applicable — scope-none (issue #444 carries scope-none; this is a JACK/ALSA hardware-init shell script, touches no module in docs/architecture/standards.md's document map, implements no clause any indexed standard defines).

correctness issues

  1. scripts/ff400.sh:204-205analog-source-gain (numid 9–26) and adat-source-gain (numid 45–62) loopback-mute writes still send a literal "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0" (18 values), unlike the now-live-width output-volume (numid=8) and stream-source-gain (numid 63–80) writes a few lines above. These are the same class of per-channel ALSA array control on the same card, and the sibling controls are confirmed (by this PR) to narrow to 14 at 96 kHz. If these two also narrow, amixer cset will reject the count-mismatched write and, under set -e, the script aborts before printing Done. — worse, the analog/ADAT hardware-loopback mute (a monitoring-safety measure per the header comment) may be left unapplied on whichever numids ran before the abort. This directly contradicts criterion 3 ("No port count is assumed... behaves correctly... at 96 kHz"). The PR body itself raises this as an "open question for reviewer," so the gap is disclosed, not hidden — but it is unresolved.
  2. scripts/ff400.sh:41-90 (clear_ff400_aliases) — the architect's implementation notes state: "That flag [jack_alias -u] and the jack_lsp -A layout (aliases indented under their port) were not checked here, because jack tools are not installed on this host. Confirm both on a JACK host before writing the parser, and make the test stubs copy the real output. Use the 192.168.9.25 dev box." The PR body's test-output section shows only bash scripts/ff400_test.sh against the committed stubs, which the same PR wrote — there's no mention of confirming either assumption against a real jackd. If real jack_lsp -A indents aliases differently, or jack_alias -u <port> <alias> isn't the real unset invocation, the entire clear-and-verify routine could silently do nothing (or error in an unhandled way) against real JACK, defeating criterion 5 — while the committed test stays green because its stubs encode the same unverified assumption the script does.

test coverage gaps

  • scripts/ff400_test.sh's amixer stub's cset arm (exit 0 unconditionally, see the stub's *"cset"*) branch) never checks that the csv sent matches the control's width. A real amixer cset rejects a count-mismatched value list; this stub can't reproduce that rejection, so no test built on it — now, or a future one covering numid 9–26/45–62 — can ever fail on the exact defect named in correctness issue 1. Same shape as the agents refresh #325 ring-regression precedent this repo already knows: a fake missing the field under assertion can't fail on it no matter what the test asserts.
  • No test exercises numid 9–26 / 45–62 at 14 vs. 18 ports at all. AMIXER_WIDTH only changes what cget numid=8 / 63..80 answer; the loopback-mute cset calls are unconditional regardless of $AMIXER_WIDTH, and nothing in ff400_test.sh inspects $AMIXER_LOG for them.
  • Test case (e) asserts the numid=8 (output-volume) csv width against n, but not the numid=63..80 (stream-source-gain) rows' width. A regression that got output-volume's width right but a stream-source-gain row wrong would pass silently.

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 issues

none. Touches only scripts/ff400.sh and the new scripts/ff400_test.sh, matching the architect's file manifest.

verdict

request-changes: design
Criterion 3 (measured) is not met for numid 9–26/45–62, and closing that gap needs an architect call on whether the live-width read the architect explicitly scoped to numid=8/63..80 extends to analog-source-gain/adat-source-gain too — the developer correctly declined to make that call unilaterally and flagged it, but shipped the unresolved code anyway; separately, the alias parser (clear_ff400_aliases) was written without the real-jackd confirmation the architect's notes required, which is a rig gap, not a design one.

sent back to

architect — decide whether criterion 3's live-width fix extends to numid 9–26 (analog-source-gain) and 45–62 (adat-source-gain), the same way it now applies to numid=8 and 63..80, or whether those two ranges are known fixed-width by evidence not in this PR. (scripts/ff400.sh:204-205, PR body's own "open questions for reviewer" section already names this.)

rig verification required

Two distinct items, neither obtainable from this tree:

  1. On a real jackd (192.168.9.25 dev box, per the architect's note — no FF400 needed for this half): capture real jack_lsp -A output with an alias set, and confirm jack_alias -u <port> <alias> is the real unset invocation. Falsifies clear_ff400_aliases's parsing if the real indentation/argument order differs from what lines 49–70 assume.
  2. On the FF400 at 96 kHz (pupu): amixer -c 0 cget numid=9 and numid=45, read the values= width. Falsifies criterion 3's remaining gap if width < 18 (script would then abort under set -e on the still-hardcoded 18-value cset at line 205).
  3. Criteria 7–8's planted-boot-order fail-test, as the architect describes it (test case (a) is the rig-free proxy already committed; a genuine both-boot-orders run is still open per the architect's own note).

No existing entry in $AC_HOME/rig-verify-queue.md covers any of the three — the queue's only FF400-adjacent entry is PR #441's preflight.sh port-order gate against a genuinely ADAT-first-booted pupu, which is a different script and a different check. This needs a new block.

…=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>
@mkovero

mkovero commented Sep 14, 2026

Copy link
Copy Markdown
Owner Author

Design superseded under this branch — revised to match

The architect comment on #444 was edited (23:37:56Z) after both this
branch's original commit (22:57:29Z) and this PR's qa review (23:03:18Z).
The qa review was written against the pre-edit note, which said mixer
widths were an "open assumption" and told the developer to "leave the
numid layout itself alone." The edited note replaces that: widths are now
established from upstream snd-firewire-ctl-services source
(former_ctls.rs / ff400.rs), fixed per control family and not
tied to sample rate or JACK port count — analog-source-gain /
adat-source-gain (numid 9..26 / 45..62) are 8 wide, not 18. This commit
implements the edited note, not the one qa reviewed against.

Point-by-point

Correctness issue 1 (numid 9..26/45..62 hardcoded 18-value write,
criterion 3 gap) — fixed. The script now reads and validates every array
control's width (numid=8, 9..26, 45..62, 63..80) before its first mixer
write via check_all_ctl_widths, and writes exactly that width. An
unreadable or (for 63..80) too-narrow width exits non-zero, names the
numid, and writes nothing — no more silent-skip, no all-zero fallback row.

Qa's premise that a count-mismatched amixer cset gets rejected doesn't
hold, per the architect's evidence (snd_ctl_ascii_value_parse drops
extra values / repeats short ones, no error) — so this isn't a "the write
aborts" fix, it's "the write sends the wrong width and silently mutates
the wrong slots," which is what's actually fixed now.

Correctness issue 2 (alias parser assumptions — jack_alias -u
syntax, jack_lsp -A indentation — never checked against real jackd)
— resolved by the architect, not by a code change here: both are now
confirmed against jack2 on the 192.168.9.25 dev box (three-space alias
indent, jack_alias -u portname alias), matching what clear_ff400_aliases
and the test stubs already assumed. Still open per the architect's note:
whether jackd lets a client unalias a system: port it doesn't own — the
post-clear verify pass + rig case (a) is the guard for that, unchanged.

Test coverage gaps (amixer stub's cset can't fail on a width
mismatch; nothing exercises 9..26/45..62 at different widths; stream-
source-gain row width unasserted) — addressed, but not via qa's suggested
rejecting-stub. The architect's re-entry explicitly did not adopt that
approach ("Case (h) replaces it... a stub that rejects would test a
behaviour the real tool does not have"). Instead: reset_state's port
count and the amixer stub's per-family widths (WIDTH_8 / WIDTH_ANALOG
/ WIDTH_ADAT / WIDTH_STREAM) are now independent knobs; case (e) is
revised to assert mixer writes are byte-identical at 14 vs 18 JACK ports
(the coupling qa's case (e) had was the false one); new case (h) asserts,
for every cset in the log, that the sent value count equals the width
amixer reported for that numid, across all four control families
(closes the "stream-source-gain row width unasserted" gap too); new case
(i) covers an unreadable control width aborting before any cset. Both
(h) and (i) verified red against the pre-revision ff400.sh
(ee7b573d), green against this commit.

"sent back to: architect" — answered by the architect's edit: widths
are fixed-by-model, not sample-rate/port-count-linked, and every array
family gets the same read-and-check-first treatment as numid=8/63..80.

Criteria 7-9 / rig verification items 1-2 — unchanged, still open,
still not something this PR resolves per the architect's original and
re-entry notes. Item 2 in qa's "rig verification required" section
(amixer -c 0 cget numid=9/45 width check) is answered by the architect's
derived table (8, from upstream source) rather than requiring a live
read, but the script itself still reads live rather than trusting the
table (comment in _ctl_width explains why: the ctl-service version
actually installed hasn't been checked against upstream).

Files touched (this commit)

  • scripts/ff400.shcheck_ctl_width/check_all_ctl_widths: read + validate
    numid 8, 9..26, 45..62, 63..80 widths before any mixer write; output-volume,
    stream-routing, and analog/adat-loopback-mute loops now use the validated
    width instead of a live-only read (numid=8/63..80) or a hardcoded 18 (numid
    9..26/45..62); show's stream-source-gain diagonal prints "(could not be
    read)" instead of silently skipping a row; _ctl_width comment corrected
    (width is fixed by the ctl-service model, not sample-rate/port-count linked)
  • scripts/ff400_test.sh — decoupled reset_state's JACK port count from the
    amixer stub's control widths (WIDTH_8/WIDTH_ANALOG/WIDTH_ADAT/
    WIDTH_STREAM, FAIL_NUMID); case (e) revised to assert identical mixer
    writes at 14 vs 18 ports; cases (h) and (i) added

Test output

$ bash scripts/ff400_test.sh
ff400.sh alias handling: all cases as expected

shellcheck --severity=warning clean on both files.

No disagreement with any qa finding — all addressed above, either by this
commit or by the architect's re-entry.

@mkovero

mkovero commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

Re-review. Commit range: ee7b573d34ad7aa338bdbb42af1aa702b95673eb..019621bed9bcb3adf97ec3fdf46beaa6474d5b24 (one commit: "fix: read mixer control widths for every array family, not just numid=8/63..80"). Read against my own prior review (posted 2026-09-14T23:03:18Z) and the architect's re-entry comment on #444 (2026-09-14T22:50:33Z), which supersedes the note my prior review was written against.

gate (full workspace, re-run at this tip)

  • cargo test --workspace (in ac-rs/) — all green: every crate's suite passed, only the pre-existing wgpu-only snapshot tests ignored (run on 192.168.9.25 per A3 policy), no new ignores.
  • cargo clippy --workspace -- -D warnings — clean, no warnings.
  • cargo fmt --check — clean.
  • shellcheck --severity=warning scripts/ff400.sh scripts/ff400_test.sh — clean (dev's claim verified independently, not just cited).
  • bash scripts/ff400_test.sh at tip — all cases as expected.
  • Regression check I ran myself: swapped scripts/ff400.sh back to ee7b573d's content, ran the current ff400_test.sh unmodified against it, restored via git checkout. Result: FAILED, with the exact defect named — 36× FAIL: (h) numid=NN cset sent 18 values, amixer reported width 8 (numid 9–26, 45–62) and 3× FAIL: (i) for the unreadable-width case. Confirms the dev's claim that (h)/(i) are red against the pre-revision script and green against this one — not just a self-report I took on faith.

point-by-point on my prior review

  1. Spec criterion 3 gap (hardcoded 18-value write to numid 9–26/45–62) — fixed. check_all_ctl_widths now reads and validates every array family's width (8, 9–26, 45–62, 63–80) before any mixer write; loopback-mute writes use ${CTL_WIDTH[$numid]} instead of a literal.
  2. Correctness issue 1 (same defect, as a correctness finding) — fixed, same commit, verified by the regression run above.
  3. Correctness issue 2 (jack_alias -u syntax / jack_lsp -A indentation never checked against real jackd) — addressed, not by this commit: the architect's re-entry reports both checked against jack2 ("JACK example tools version 4") on the 192.168.9.25 dev box — three-space alias indent, jack_alias -u portname alias — matching what clear_ff400_aliases and the stubs already assumed. I could not reproduce this independently: no jack_alias/jack_lsp on this host, consistent with the architect's own earlier note that jack tools aren't installed here either. Taking the architect's report at face value for this pass since it's specific (exact tool-version string, exact flag), not a bare assertion — but I did not open a primary source for it, so read this as documented-not-reverified, not as a citation I checked myself. Still explicitly open per the architect: whether jackd lets a client unalias a system: port it doesn't own.
  4. Test coverage gap — stub's cset can't fail on a width mismatch — addressed, differently than I suggested: architect explicitly declined my rejecting-stub (real amixer cset doesn't reject a count mismatch — cites snd_ctl_ascii_value_parse's silent-drop/repeat behaviour). New case (h) instead asserts, for every logged cset, that the sent count equals the width amixer reported. My original suggested addition rested on a wrong premise about amixer's behavior; the architect's fix is the correct shape and I verified it fails on the named defect (see gate section).
  5. Test coverage gap — no test exercises 9–26/45–62 at different widths — fixed: WIDTH_ANALOG/WIDTH_ADAT are now independent stub knobs, exercised by case (h).
  6. Test coverage gap — stream-source-gain row width unasserted — fixed: case (h) checks every cset, all four families, not just numid=8.
  7. "Sent back to: architect" (does the live-width fix extend to 9–26/45–62, or are they known fixed-width) — answered: architect's re-entry gives a derived table from upstream snd-firewire-ctl-services source (former_ctls.rs/ff400.rs): 9–26 and 45–62 are 8 wide, fixed by the ctl-service model, not by sample rate or JACK port count. The script does not trust the table directly — it still reads live and refuses on an unusable width — so a wrong table only breaks the test fixture, not the running script (architect's own mitigation, and one I can confirm from reading the code: _ctl_width is called unconditionally regardless of the table).
  8. Rig verification item 1 (jack2 tool assumptions) — see point 3 above: reported resolved, not independently reproduced by me.
  9. Rig verification item 2 (amixer width at 9/45 on hardware) — downgraded, not closed: no longer gates criterion 3 the way I'd framed it, because the script now self-validates and refuses rather than assuming; still worth a rig confirmation to check the fixture defaults (WIDTH_ANALOG/WIDTH_ADAT = 8) against the actually-installed ctl-service version, per the architect's own risk note, but a mismatch there is a fixture-quality issue, not a running-script correctness issue.
  10. Rig verification item 3 (fail-test on both boot orders, criteria 7–9) — unchanged, still open, architect reconfirms this PR does not resolve it (same as my prior pass — this was never something the delta could address).
  11. Scope issues — none then, none now: only scripts/ff400.sh and scripts/ff400_test.sh touched, matching the architect's manifest both times.

spec coverage (updated)

criterion provenance covered notes
no alias published unless order determined measured (non-numeric) unchanged from prior pass
playback mapping never inferred from capture order alone measured (non-numeric) unchanged
no port count assumed; correct at 18/14 ports measured ✓ (was ✗) Now closed: mixer-control width (fixed by ctl-service model) is read live and validated independently of JACK port count (kernel-side, separate quantity per architect); case (e) now asserts mixer writes are byte-identical at 14 vs 18 JACK ports, which is the correct shape of this criterion once the two quantities are properly separated.
order-undetermined message names where to look, no cause measured (non-numeric) unchanged
no stale FF400 alias after run measured (non-numeric) ✓ (parser now reported checked against real jack2, not independently reverified — see point 3) unchanged from prior except the parser-assumptions half of correctness issue 2 is now claimed resolved
no fixed phantom-power state measured (non-numeric) unchanged
fail-test, playback, both boot orders measured ✗ (open, architect-acknowledged) unchanged; not in scope of this delta
fail-test, capture, both boot orders measured ✗ (open, architect-acknowledged) unchanged
each fail-test run records order/method/rate/count/consent n/a until above run unchanged

standards conformance

standards check: not applicable — scope-none (issue #444 still carries scope-none; this delta touches only ALSA mixer-control width validation in a hardware-init shell script — no measurement, output-formatting, or display-unit change, and no module in docs/architecture/standards.md's document map).

correctness issues

none found in this delta.

test coverage gaps

none 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 issues

none. 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)

verdict

approve
Every correctness and test-coverage finding from my prior review is either fixed in this commit (criterion 3 / correctness issue 1, all three test-coverage gaps) or resolved by the architect's design re-entry (correctness issue 2's parser half, the "sent back to architect" question) and I could independently verify the code-level claims (workspace gate green, shellcheck clean, and — the one I didn't just take on the dev's word — reran the current test suite against the pre-revision script and watched it go red on exactly the named defect, then green at tip). What remains open (criteria 7–9, the jack2-tool-assumption report, the fixture-vs-installed-version width check) is unchanged rig-gated territory the architect already carved out as not this PR's job, not a new gap this delta introduced.

sent back to

no

rig verification required

Unchanged from prior pass except item 1 is reported (not independently reproduced) resolved, and item 2 is downgraded from correctness-gating to fixture-quality:

  1. jack2 jack_alias -u / jack_lsp -A output confirmation — architect reports this run on 192.168.9.25 dev box (jack2, "JACK example tools version 4"); I could not reproduce it here (no jack tools on this host). A human who can reach that dev box should confirm the architect's report stands before this is treated as closed.
  2. On the FF400 at 96 kHz (pupu): amixer -c 0 cget numid=9 and numid=45, read the values= width, compare against the architect's derived table (expect 8, not the test fixture's other possible values). This no longer falsifies a script-correctness claim (the script self-validates either way) — it only tells you whether the test fixture's defaults match the installed ctl-service version.
  3. Criteria 7–8's planted-both-boot-orders fail-test on the rig, as the architect describes it (test case (a) is the rig-free proxy already committed; a genuine both-boot-orders run is still open).

No entry in $AC_HOME/rig-verify-queue.md covers any of these (checked again at this tip — still nothing FF400/#444-specific there). Item 3 still needs a new block; items 1–2 are optional confirmations, not blockers.

@mkovero

mkovero commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

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 ketunkolo). Read-only; jack_alias -u was not run.

jack_lsp: JACK example tools version 4
Usage: (null) [options] portname alias
        -u, --unalias         remove `alias' as an alias for `port'
--- jack_lsp -A (first lines):
system:capture_1
   alsa_pcm:hw:Pro71990237:out1
system:capture_2
   alsa_pcm:hw:Pro71990237:out2

jack2 with example tools v4. jack_alias supports -u. jack_lsp -A prints each alias on its own line, indented under its port. That matches the architect's report, and nothing here contradicts it. The (null) program name in the usage text is a jack2 example-tools quirk, not a failure.

Item 2: FF400 control widths on pupu at 96 kHz (JACK rate 96000; cget only, nothing written). Addressed by card name (-c Fireface400), not -c 0: on pupu, card 0 is the HDA PCH.

numid=9,iface=MIXER,name='mixer:analog-source-gain'
  ; type=INTEGER,access=rw---RW-,values=8,min=0,max=65536,step=1
  : values=0,0,0,0,0,0,0,0
numid=45,iface=MIXER,name='mixer:adat-source-gain'
  ; type=INTEGER,access=rw---RW-,values=8,min=0,max=65536,step=1
  : values=0,0,0,0,0,0,0,0

Both are values=8, as the architect's table expects. The all-zero gains match the documented baseline: no hardware monitor path.

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 $AC_HOME/rig-verify-queue.md. requires-rig stays for a human to clear.

@mkovero

mkovero commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

codex qa — PR #450 at 019621b

verdict: fail

spec coverage

  • Criteria 1–3 are covered on the initialization paths: no mapping is published or inferred, and JACK port count is independent of live-validated mixer widths. The measured 14/18-port cases are exercised by case (e).
  • Criterion 4 is only partially covered: initialization prints the required “none set / where to look” guidance, but show does not.
  • Criterion 5 is not covered for every script invocation: show leaves aliases from older versions untouched.
  • Criterion 6 is covered: no numid=90 write remains, and the readback is explicitly identified as driver-cache state.
  • Criteria 7–9 remain rig-gated and unexecuted for both boot orders; requires-rig correctly remains present. The numeric values in those criteria (−60 dBFS, 18 ports at 48 kHz, 14 at 96 kHz) are tagged measured. For the derived control-width table, the separating measurement is amixer cget on the installed ctl service; the PR discussion records 8-value reads for numids 9 and 45 at 96 kHz.

findings

[severity: major] [confidence: high]

  • location: scripts/ff400.sh:137-170, scripts/ff400.sh:183-186
  • problem: The show mode exits before stale FF400: aliases are cleared and before the required “no aliases set / where to look” message is printed.
  • mechanism: exit 0 is inside the show) branch, while clear_ff400_aliases is called only after the mode switch; the branch even directs the operator to “see JACK aliases below,” but that output is unreachable.
  • failure scenario: An old script run leaves FF400:capture_ADAT1 on an analog-first system:capture_1; the operator later runs ./ff400.sh show to verify the device, and the misleading alias remains attached with no warning or lookup guidance. This violates acceptance criteria 4 and 5 and preserves the drive-path hazard the issue is meant to remove.
  • evidence: Full source/control-flow inspection at the reviewed tip; scripts/ff400_test.sh invokes only the default initialization mode and contains no show case. A targeted run with exported jack_lsp/jack_alias mocks capable of exposing a planted stale alias produced no JACK-alias section, confirming neither function is reached.
  • disproof attempted: I looked for cleanup before the mode switch, a show-specific cleanup/report path, and a test that plants an alias then invokes show; none exists. The architect’s decision explicitly requires the not-set line on every run, so the early exit is not a deliberate exception in the governing design.
  • recommendation: Run alias cleanup/reporting on show as well (without introducing mixer writes), and add a regression case that invokes show with a planted stale alias and verifies both removal and the lookup guidance.

[severity: minor] [confidence: high]

  • location: scripts/ff400.sh:158-168
  • problem: An unreadable diagonal row after index 0 terminates show instead of printing (could not be read) for that row.
  • mechanism: With set -e, diag=$(... python3 ... v[$idx] ...) is an unguarded assignment. Empty or too-short cget output makes Python fail for idx >= 1; the assignment returns non-zero and exits the script before the following empty-value branch can run.
  • failure scenario: amixer cget numid=64 emits no values= line; show prints ch00, exits 1 at ch01, and never reports the unreadable row or the remaining settings.
  • evidence: Targeted execution with an amixer mock returning no data for numid 64 exited 1 immediately after ch00. The committed suite has no show failure-path test.
  • disproof attempted: I checked whether the assignment is used as a conditional or has an || guard that suppresses errexit; it has neither. Redirecting Python’s stderr suppresses only the traceback, not its non-zero status.
  • recommendation: Guard the extraction so failure yields an empty value without triggering errexit, then exercise an unreadable nonzero-index row and assert show continues with the explicit unreadable marker.

gate

Claude QA workspace gate: inherited at current tip 019621bed9bcb3adf97ec3fdf46beaa6474d5b24
Codex targeted tests: bash scripts/ff400_test.sh — pass; targeted show/numid-64 mock — exit 1 after ch00 (reproduced finding); shellcheck scripts/ff400.sh scripts/ff400_test.sh — only pre-existing SC2086 informational notices

unaddressed open questions

  • The both-boot-order playback/capture rig runs and their required records are still outstanding; the latest rig comment says they cannot currently force an ADAT-first boot.
  • Whether a foreign JACK client can actually unset an alias owned by a system: port remains unmeasured. The verify pass makes refusal loud, but only the queued rig check can establish successful removal.

scope

none

@mkovero mkovero added the needs-work QA requested changes — PR not ready to merge label Sep 15, 2026
@mkovero

mkovero commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

codex qa — PR #450 at 019621b

verdict: fail

spec coverage

  • Criteria 1–3 are covered on initialization paths: the script publishes no mapping, infers no playback mapping, and keeps measured 14/18 JACK port counts independent from live-read mixer widths.
  • Criteria 4–5 are not covered for every invocation: show exits before alias cleanup and before the required “none set / where to look” guidance.
  • Criterion 6 is covered: no numid=90 write remains and the readback is labelled as driver-cache state.
  • Criteria 7–9 remain rig-gated and unexecuted for both boot orders; requires-rig remains appropriate. The −60 dBFS and 14/18-port criteria are tagged measured. For the derived control-width table, the separating live measurement is amixer cget; the PR discussion records 8-value reads for numids 9 and 45 at 96 kHz.

findings

[severity: major] [confidence: high]

  • location: scripts/ff400.sh:137-170, scripts/ff400.sh:183-186
  • problem: show exits before stale FF400: aliases are cleared and before the required alias-status/lookup guidance is printed.
  • mechanism: The exit 0 inside the show) branch precedes the only call to clear_ff400_aliases; the branch directs the operator to “see JACK aliases below,” but that section is unreachable.
  • failure scenario: An older run leaves FF400:capture_ADAT1 attached to analog-first system:capture_1; an operator runs ./ff400.sh show to verify the device, but the misleading alias remains and no warning or lookup guidance appears.
  • evidence: Full control-flow inspection and repository-wide search found no alternate cleanup path. The committed test invokes only initialization modes and has no show alias case.
  • disproof attempted: Checked for cleanup before mode dispatch, a show-specific cleanup/report path, callers that clean first, and a test planting an alias before show; none exists. The governing architect decision says the not-set line is printed on every run.
  • recommendation: Run alias cleanup/reporting for show too, without mixer writes, and add a planted-alias show regression.

[severity: major] [confidence: high]

  • location: scripts/ff400.sh:81-125
  • problem: Alias cleanup can return success and claim aliases were cleared when either jack_lsp -A call fails after the initial reachability probe.
  • mechanism: Failure of the first jack_lsp -A occurs inside process substitution and is not propagated by the while; failure of the verification call is masked by the succeeding awk at the end of a pipeline because pipefail is not enabled. Both paths therefore produce empty data and reach the success messages.
  • failure scenario: The initial jack_lsp succeeds, JACK becomes unreachable before enumeration, a stale wrong FF400: alias remains, and the script exits 0 after printing both “cleared” and “none set here.”
  • evidence: A targeted run with jack_lsp succeeding once and failing on subsequent calls exited 0 and printed the success claims. Source inspection confirms neither -A status is checked.
  • disproof attempted: Checked whether set -e propagates process-substitution failure, whether the verification pipeline has pipefail, and whether the later remaining/stale checks detect an empty failed query; none does.
  • recommendation: Guard and capture each jack_lsp -A result explicitly; on either failure, print “did not check aliases” and return non-zero or otherwise avoid any cleared/no-alias claim.

[severity: minor] [confidence: high]

  • location: scripts/ff400.sh:158-168
  • problem: An unreadable or too-short diagonal row after index 0 terminates show instead of printing (could not be read) and continuing.
  • mechanism: diag=$(... python3 ... v[$idx] ...) is an unguarded assignment under set -e; Python exits non-zero for an absent index, so the following empty-value branch is never reached.
  • failure scenario: amixer cget numid=64 emits no values line; show prints ch00, exits 1 at ch01, and never reports that row or the remaining rows.
  • evidence: A targeted amixer mock returning no data for numid 64 reproduced exit 1 immediately after ch00. The committed suite has no show failure-path case.
  • disproof attempted: Checked for conditional use or an || guard around the assignment; neither exists. Redirecting Python stderr suppresses only the traceback, not the exit status.
  • recommendation: Guard extraction failure so it yields an empty value, then test an unreadable nonzero-index row and continuation through the remaining rows.

gate

Claude QA workspace gate: inherited at current tip 019621bed9bcb3adf97ec3fdf46beaa6474d5b24
Codex targeted tests: bash scripts/ff400_test.sh — pass; bash -n scripts/ff400.sh scripts/ff400_test.sh — pass; targeted show/numid-64 mock — reproduced exit 1 after ch00; targeted post-probe JACK-failure mock — reproduced exit 0 with false success claims; shellcheck scripts/ff400.sh scripts/ff400_test.sh — only SC2086 informational notices
GitHub checks: none reported for this branch

unaddressed open questions

  • Both-boot-order playback/capture rig runs and their required records remain outstanding; the latest rig comment says an ADAT-first boot cannot currently be forced.
  • Whether a foreign JACK client can successfully unset an alias owned by a system: port remains unmeasured. The verification pass makes a stable refusal loud, but the rig check is still needed to establish successful removal.

scope

none

)

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>
@mkovero

mkovero commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

Revision: codex-qa findings addressed (commit 20a787b)

Checked issue #444 for an architect/ux comment newer than this branch's prior tip (019621be, 2026-09-14T23:42:50Z) before touching anything: none exists. The architect's re-entry that the last dev round already incorporated is still the current design; nothing changed under me this time.

Addressing the newest <!-- agent: codex-qa --> review (2026-09-15T01:05:16Z), point by point:

[major] show exits before alias cleanup / guidance (ff400.sh:137-170,183-186) — fixed. show now calls clear_ff400_aliases (same function the init path uses) before its exit 0, so a planted FF400:-prefixed alias is cleared and the "none set here / where to look" guidance the mode's own text already promised ("see JACK aliases below") actually prints. New test case (j): plants an alias, runs show, asserts both the alias is gone and the guidance text is present.

[major] clear_ff400_aliases can claim "cleared"/"none set" when jack_lsp -A actually failed (ff400.sh:81-125) — fixed. Both call sites now capture output into a variable via if ! out=$(jack_lsp -A); then exit 1; fi instead of a process substitution (invisible to set -e) or a pipe into awk (masked by awk's own exit status, no pipefail). Either failure now prints an explicit "did not clear/confirm" message and exits non-zero. New test cases (k) and (m): a stubbed jack_lsp fails the 1st vs. 2nd -A call respectively (reachability probe still passes first), asserting no false "cleared"/"none set" claim and non-zero exit in both cases.

[minor] unreadable diagonal row aborts show instead of printing "(could not be read)" (ff400.sh:158-168) — fixed. Appended || true to the diag=$(...) assignment so a python3 IndexError on a short/empty read no longer trips set -e; the existing [[ -n "$diag" ]] fallback already prints "(could not be read)" correctly once the abort is gone. New test case (l): FAIL_NUMID=64 (ch01) makes that row unreadable, asserts the marker prints and ch02 still follows.

All four new cases (j)/(k)/(m)/(l) were run against this branch's prior tip (019621be) and confirmed red on exactly the named defect, then green at this commit — not just read as present.

No disagreement with any finding — all three addressed as described.

verify

$ bash scripts/ff400_test.sh
ff400.sh alias handling: all cases as expected
$ shellcheck --severity=warning scripts/ff400.sh scripts/ff400_test.sh
(clean)

No Rust files touched; cargo/clippy/fmt don't apply to this delta (same as prior rounds on this PR).

note on labels

Per this task's explicit instruction I did not touch labels — claude-approved is still on this commit's ancestor state, not this one. Flagging since the role's normal rule is to drop claude-approved on any push to an approved PR (it attests to a specific commit); leaving that call to whoever re-reviews this push.

@mkovero mkovero removed the needs-work QA requested changes — PR not ready to merge label Sep 15, 2026
@mkovero

mkovero commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

Re-review. Commit range reviewed: 019621bed9bcb3adf97ec3fdf46beaa6474d5b24..20a787b56f7c337b6f31cee1d80ccc024ad62137 (tip 20a787b5). My prior review approved at 019621be; that approval is void per the post-approval-push rule — ran a fresh full gate and re-reviewed the delta rather than trusting the old pass.

mechanical gate (workspace, fresh at tip)

  • cargo test --workspace — pass (all test result: ok, no failures, checked every summary line not just the tail).
  • cargo clippy --workspace -- -D warnings — pass, zero warnings.
  • cargo fmt --check — pass.
  • Delta touches no Rust file (scripts/ff400.sh, scripts/ff400_test.sh only — confirmed via git diff --stat), so this gate is a not-broken-by-coincidence check, not a check on the diff itself.
  • shellcheck scripts/ff400.sh scripts/ff400_test.sh — same 6 pre-existing SC2086 (info) notices as at 019621be, diffed line-for-line, no new ones. Unchanged from PR body's claim.
  • bash scripts/ff400_test.sh — pass at tip.

delta review (019621be..20a787b5)

This commit fixes three defects a separate agent (codex-qa) found at 019621be, distinct from anything in my own prior review:

  1. scripts/ff400.sh:80-96,120-126clear_ff400_aliases's two jack_lsp -A calls now go through if ! out=$(jack_lsp -A); then ...exit 1; fi instead of a process substitution (enumeration: done < <(jack_lsp -A) → invisible to set -e) or a bare pipe into awk (verify: masked by awk's own exit status, no pipefail). Read the full function (lines 80-146): both failure paths now print an explicit "did not clear/confirm" message and exit non-zero rather than silently falling through to the success message. Correct.
  2. scripts/ff400.sh:153-189show now calls clear_ff400_aliases (line 187) before its exit 0, matching the mode's own pre-existing text ("see JACK aliases below") that previously went unfulfilled. Non-destructive ordering — all show diagnostics print before the call, and a JACK-unreachable condition still returns cleanly (line 81-85) rather than aborting the listing.
  3. scripts/ff400.sh:176-179diag=$(... | python3 -c "...") || true stops one unreadable diagonal row (empty values=, causing a Python IndexError) from tripping set -e and killing the rest of the show listing; falls through correctly to the existing (could not be read) branch.

Independent verification, not just reading the commit message's claim: I checked out scripts/ff400.sh at 019621be into the working copy, ran the current scripts/ff400_test.sh (which only exists at tip) against it, then restored — cases (j), (k), (m), (l) all failed for exactly the reasons the commit message states (show left the alias and printed no guidance; both jack_lsp -A failure points produced false "cleared"/"none set" claims with exit 0; the numid=64 row aborted the whole listing after ch00). Ran the same suite against the current tip afterward: all pass. These four tests are reachable and fail on the defects they name — not just present.
4. scripts/ff400_test.sh stub (JACK_A_DOWN/JACK_A_DOWN_AFTER, lines 82-90) — confirmed by reading: the call counter only increments inside the -A branch, so the plain reachability probe (jack_lsp no args) is unaffected, matching the documented intent that the masked failure hits after reachability already passed. JACK_A_DOWN_AFTER=0 fails the 1st -A call (case k, enumeration); =1 lets the 1st succeed and fails the 2nd (case m, verify) — checked the arithmetic against the stub, not just the comment.

No correctness issues found in this delta.

prior review points — status

  • Correctness issue 1 (hardcoded 18-width writes on analog-source-gain/adat-source-gain) — already fixed at 019621be, unchanged (still correct) at this tip.
  • Correctness issue 2, parser half (jack_lsp -A layout / jack_alias -u syntax never confirmed on real JACK) — not addressed by this delta, still open. This delta fixes failure detection around those calls, not the unconfirmed assumption about their output shape/syntax. Rig item 1 below is unchanged.
  • requires-rig item 2 (fixture width vs. installed ctl-service version at 96 kHz) — not addressed, unchanged, already downgraded to fixture-quality in the prior pass.
  • requires-rig item 3 (both-boot-order fail-test on the rig) — not addressed, unchanged. PR comment confirms: "the latest rig comment says an ADAT-first boot cannot currently be forced."
  • "sent back to: no" — still no design-level finding; this delta is implementation-only.

spec coverage

Unchanged from my prior pass at 019621be — this delta doesn't touch any of the nine criteria from issue #444's design breakdown (it fixes robustness of already-covered behavior, not new coverage). Criteria 7-9 (both-boot-order rig fail-tests + records) remain open and architect-acknowledged, gated behind requires-rig, not a developer miss. See my 019621be review for the full per-criterion table; no row's status changes here.

standards conformance

standards check: not applicable — scope-none (issue #444 carries scope-none, unchanged; this delta touches only scripts/ff400.sh/scripts/ff400_test.sh, no module in docs/architecture/standards.md's document map, no measurement value or display unit — the diagonal read-out this delta guards was already unguarded raw amixer passthrough before, nothing new formatted or computed).

correctness issues

none found.

test coverage gaps

  • Minor, non-blocking: no test combines show mode with JACK_DOWN (JACK unreachable). The code path is shared with the already-tested default-mode case (clear_ff400_aliases returns early identically regardless of caller), so risk is low, but a case like (n) show with JACK unreachable prints the reachability message and still exits 0 would close it explicitly rather than by inference from a shared function.

scope issues

none — same two files as the architect's manifest, same two files as 019621be.

verdict

approve
Fresh workspace gate is green, the delta independently verified to fix three real bugs (reachable tests confirmed red at 019621be and green at tip, not taken on the commit message's word), and every point from my prior review either remains correctly fixed or remains open exactly where it was (rig-gated, unaddressed by design, not regressed).

sent back to

no

rig verification required

Unchanged from prior pass (items 1-3 as listed there); this delta neither closes nor adds to them. Re-stating without re-deriving: (1) real-JACK confirmation of jack_lsp -A layout / jack_alias -u syntax — architect reports this run on the 192.168.9.25 dev box, unconfirmed by me (no jack tools on this host); (2) fixture-width-vs-installed-version check at 96 kHz on pupu, now fixture-quality only; (3) both-boot-order fail-test on the rig, still open per the architect's own comment that an ADAT-first boot can't currently be forced.

@mkovero

mkovero commented Sep 15, 2026

Copy link
Copy Markdown
Owner Author

codex qa — PR #450 at 20a787b

verdict: pass

spec coverage

Criteria 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 FF400: aliases without touching other aliases, and no longer writes phantom power. Criteria 7–9 remain explicitly rig-gated under requires-rig.

Numeric provenance checked: 14/18 capture-port counts and the −60 dBFS probe level are tagged measured; the derived mixer-width model is separated from JACK port count and read live by the script. The recorded 96 kHz rig read confirms 8-value controls at numids 9 and 45.

gate

Claude QA workspace gate: inherited at current tip 20a787b56f7c337b6f31cee1d80ccc024ad62137
Codex targeted tests: bash scripts/ff400_test.sh — pass; bash -n scripts/ff400.sh scripts/ff400_test.sh — pass; git diff --check origin/main...HEAD — pass; shellcheck scripts/ff400.sh scripts/ff400_test.sh — exit 0 with six pre-existing SC2086 informational notices
GitHub checks: none reported for this branch

unaddressed open questions

  • The required playback/capture fail-tests on both analog-first and ADAT-first boots, with order/method/rate/port-count/consent records, remain unrun because an ADAT-first boot cannot currently be forced. Human rig verification must clear requires-rig.
  • A real jack_alias -u against an alias on a system: port has not been attempted, so foreign-client unalias permission remains unmeasured. The post-clear verification makes refusal loud, but successful removal still needs the queued rig check.

scope

none

@mkovero
mkovero merged commit 190c51b into main Sep 15, 2026
mkovero added a commit that referenced this pull request Sep 15, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

scripts/ff400.sh hardcodes one FF400 port order; snd_fireface puts the ADAT block first or last

1 participant