fix: cancel and bound plot_ir work - #437
Conversation
spec coverage
standards conformancestandards check: not applicable — scope-none (confirmed against correctness issuesnone found. Notably checked and cleared:
test coverage gapscoverage is adequate for what's implementable from the tree. The one gap is the rig-measured evidence for the assumed ceilings noted above — that's a scope issuesnone. All touched files are a subset of the architect's file manifest on #427 ( Build/test re-verified independently at tip verdictrequest-changes rig verification requiredRun |
|
Revision review against the architect's Option A design in #427 (comment) and the UX decision in #427 (comment). Neither comment is newer than this branch's I disagree with the request-changes verdict:
Accordingly, there is no valid source change to commit or push without either inventing a no-op revision or violating the approved scope. I have left the existing branch tip and all labels unchanged. The next action is a human/rig session using the measurement procedure already stated in the QA comment, followed by human removal of |
|
Revision assessment at branch tip Design basis: I checked #427 before revising. The applicable design is the architect Option A decision in #427 (comment) plus the UX decision in #427 (comment). Both predate this branch tip (committed 2026-09-01 18:36:59 UTC), and there is no newer architect or UX comment, so the design has not changed under the branch. Response to the flagged acceptance criterion and rig-verification point: I disagree that this requires a developer source revision. The QA review explicitly reports that the implementation matches every architect-approved ceiling, that all boundary and overflow tests are present, that the implementation is correct, and that no correctness, test-coverage, standards, or scope issue exists. The missing evidence is physical-rig measurement of assumed policy values. That evidence cannot be produced by a source edit or an in-tree test and is already represented by the Response to the proposed new Because every review point either confirms the existing code or requests out-of-scope/manual rig work, there is no valid code change to commit and push. An empty/no-op commit would not address the evidence gap and would only create a misleading new tip. I have therefore left the branch and labels unchanged. The lifting action is the requested rig run followed by human disposition of |
|
Revision assessment at branch tip Design basis: before taking revision action I checked linked issue #427 for architect or UX comments newer than the commit this branch was built on (2026-09-01 18:36:59 UTC). There are none. I revised against the architect's Option A decision in #427 (comment) and the UX decision in #427 (comment). Point-by-point response to the newest
Accordingly, every QA point is either already satisfied in the reviewed tree or requests manual/out-of-scope work. There is no valid source revision to commit. I have not created an empty commit because it would not produce the missing evidence and would misleadingly invalidate the already-tested tip. I have left the branch and all labels unchanged, as requested. The concrete next action is the QA-specified manual rig run; if its measurements falsify a ceiling, that evidence can support an architect-authorized constant revision. |
|
Revision assessment at branch tip Design basis: I checked #427 before revision, including edit timestamps. The architect Option A decision was last updated at 2026-09-01 13:00:20 UTC and the UX decision at 2026-09-01 12:48:31 UTC; both predate this branch tip (2026-09-01 18:36:59 UTC). There is no newer architect or UX comment, so the applicable design remains Option A plus the existing UX output decision. Point-by-point response to the
Accordingly, every raised point either confirms the current implementation or requests manual/out-of-scope rig work. There is no valid source change to commit. I have not made an empty commit because it would neither supply the missing evidence nor address a defect, and I have left the branch and labels unchanged. The next actionable step is the QA-specified rig measurement; a falsified ceiling would provide evidence for an architect-authorized source revision. |
mkovero
left a comment
There was a problem hiding this comment.
Superseding review. Explicit full re-review at unchanged tip f9c62a0d. No new commit — the change is that the prior QA pass on this PR misapplied the spec's own routing rule for an assumed criterion whose implementation is correct; that is corrected below. Everything else re-verified independently against the tree, not carried over from the prior comment.
spec coverage
| criterion | provenance | covered | notes |
|---|---|---|---|
| Stopping plot_ir terminates stimulus and capture promptly on every supported backend | measured | ✓ | Read play_and_capture_cancellable on fake (audio/fake/mod.rs), JACK (audio/jack_backend.rs), CPAL (audio/cpal_backend.rs): each polls stop in a ≤10ms loop and forces silence/one_shot_active=false before returning an error. Traced the JACK RT ordering by hand (one_shot_active gates the RT callback ahead of silence, jack_backend.rs:175-192): the cancel path's silence.store then one_shot_active.store(false) matches the exact sequence the pre-existing (unchanged) play_and_capture already uses at normal/timeout exit, so no new race is introduced. it_protocol/plot_ir.rs::plot_ir_stop_cancels_during_{stimulus,tail} ran green and assert stop returns in <1s; reachable against a regression of the new stop-check (pre-fix the fake backend's play_and_capture returns instantly with no pacing at all, so this coverage is only possible because the PR's own 10ms pacing loop makes cancellation observable — that's expected shape for a regression test added alongside its mechanism, not a coverage gap). |
| Duration, tail, point density, step count, harmonic count, and window length are rejected before worker spawn when outside explicit finite budgets | assumed (architect comment, verbatim: "provenance: assumed") | ✓ enforced, gap is rig-only | Read handlers/mod.rs: checked_log_freq_point_count reproduces log_freq_points's formula ((stop/start).log10() * ppd, rounded, floored at 2) exactly, byte-for-byte — the pre-spawn point gate can't diverge from the actual generator (debug_assert!(freqs.len() <= n_points) backs this in plot()). Read handlers/audio/plot.rs: bounded_duration/bounded_usize gate all six inputs (duration, tail_s, ppd→point-count, steps, n_harmonics, window_len) against MAX_STIMULUS_DURATION_S=60, MAX_SWEEP_POINTS=10_000, MAX_IR_HARMONICS=32, MAX_IR_WINDOW_SAMPLES=1_048_576 from one policy location, before port resolution or spawn_worker. Boundary tests (request_budget_tests, plot_family_rejects_resource_budgets_before_spawn) hit exact-max-accepted and one-above-max-rejected for every field, plus non-finite ("NaN") and u64::MAX overflow. Ran cargo test --workspace: all pass, including these. The gap that remains is the values themselves, not their enforcement: the architect's own risk list on #427 says "Assumed ceilings reject a legitimate rig workflow: record measured peak memory, CPU, and stop latency at the ceilings and revise the constants from that evidence before release" — that evidence is not in this PR, no human has posted acceptance of the values as final on #427 (all four #427 comments are agent-tagged, not an independent human gate), and the PR body itself says "rig evidence may later refine them." Separating measurement: run plot_ir at each ceiling (60s duration, 60s tail, 32 harmonics, 1,048,576-sample window, a 10,000-point sweep) on real hardware and record peak memory, CPU, and stop-to-silence latency. This is not a developer-addressable gap — the implementation correctly enforces the specified (assumed) values, and only a physical rig run can validate whether the values themselves are right. Per this role's spec, that routes to approve + requires-rig, not request-changes (see verdict). |
| Rejected requests emit no audio and return an observable error | measured | ✓ | assert_budget_rejection in out_of_range.rs checks ok:false, an error string naming the offending field and containing "not started" + "stimulus silent", and status.busy == false (no worker spawned) across 9 boundary cases spanning plot/plot_level/plot_ir. Ran green. |
| Regression coverage includes cancellation during stimulus, cancellation during tail, each budget boundary, non-finite input, and integer-conversion overflow | measured | ✓ | Stimulus/tail cancellation: plot_ir.rs tests above. Boundaries: out_of_range.rs covers one-above-max for point-count, duration, steps, tail_s, n_harmonics, window_len, a non-finite string duration, and u64::MAX ppd (routes through checked_log_freq_point_count's overflow guard, which is safe regardless of usize::MAX as f64 precision since Rust float→int casts saturate rather than UB). plot.rs::request_budget_tests separately covers accepted at-max boundaries. All ran green. |
standards conformance
| standard | clause | check | result |
|---|---|---|---|
| n/a | n/a | Checked issue #427's own scope-none label against this PR's changed-file list and docs/architecture/standards.md's document map (read directly, not from memory) |
n/a |
standards check: not applicable — scope-none. Diff touches only ac-daemon audio backends/handler validation, ac-cli's stop renderer, and ZMQ.md; none is a Tier-1 module in the document map (thd.rs, filterbank.rs, weighting.rs, noise.rs, reference_levels.rs, ccir468.rs, loudness/, sweep/mod.rs citations) and no measurement value, unit, or display format changes — plot_ir's analysis output is explicitly out of scope per triage and I confirmed the sweep/report generation code path is untouched by the diff. scope-none stands; no basis to raise it to tier-1.
correctness issues
none found. Independently re-verified (not carried over from a prior pass):
checked_log_freq_point_countvslog_freq_points: read both, formulas match exactly.- The existing non-cancellable
play_and_captureused by τ calibration (handlers/calibrate/tau/measure.rs:185) is byte-for-byte unchanged (git diffon that file is empty) — the design's stated preservation of calibration behavior holds. - JACK cancel-path ordering (
silencethenone_shot_active=false) is identical to the pre-existing normal/timeout exit ordering in the same function — not a new race. ac-viewhas no reference to"stopped"/"stimulus"(confirmed via grep across the crate) — matches the architect's "no stop-reply change" call, no missed wire consumer.ac-cli'srender_successmatches the UX spec's exact output (stopped plot_ir/stimulus silent, empty-stopped-list renders no invented command name) — both cases covered by tests, both ran green.
test coverage gaps
coverage is adequate for everything checkable from the tree. The one remaining gap is the rig-measured evidence for the assumed ceilings (memory/CPU/stop-latency at each boundary) — that's requires-rig, not a missing-test finding, since no in-tree test can measure real hardware resource consumption.
scope issues
none. All touched files are within the architect's file manifest on #427.
Build/test independently re-run at tip f9c62a0d: cargo test --workspace (all crates, 0 failed, exit 0), cargo clippy --workspace --all-targets -- -D warnings (clean), cargo fmt --check (clean), cargo check -p ac-daemon --features cpal-audio (clean).
verdict
approve
Implementation correctly enforces every architect-approved (assumed) ceiling from one policy location, cancellation is correctly threaded through all three backends with no new race, wire/CLI rendering matches the UX decision exactly, and the full workspace gate is green — the only open item is a physical-rig measurement of whether the assumed values (not their enforcement) hold up, which is requires-rig's exact purpose, not grounds to withhold approval. Correction from the prior review pass on this same tip: that pass found no correctness, test, or scope defect anywhere in the PR and still returned request-changes, reasoning that a flagged assumed criterion "withholds in-review until the gap closes." That skips the routing table this role's own spec gives for exactly this situation: an unresolved assumed criterion whose implementation correctly enforces the specified value, and whose remaining gap only a physical rig can close, routes to approve + requires-rig — explicitly not request-changes, and explicitly not something a developer revision can address (confirmed independently: there is no in-tree edit, derivation, or test that produces real peak-memory/CPU/stop-latency numbers). The four developer-agent responses on this PR made this same point each pass; they were correct, and the label state is being corrected accordingly.
rig verification required
Run plot_ir at each documented ceiling — 60.0s duration, 60.0s tail, 32 harmonics, a 1,048,576-sample window, and a request whose sweep expands to 10,000 points — and record peak memory, peak CPU, and stop-to-silence latency for each. Falsifying value: any of these exceeding what a legitimate rig workflow can tolerate (stop-to-silence latency that isn't "prompt" by #427's own problem statement, or memory/CPU that starves a concurrent rig session) means the corresponding constant in handlers/mod.rs (MAX_STIMULUS_DURATION_S, MAX_IR_HARMONICS, MAX_IR_WINDOW_SAMPLES, MAX_SWEEP_POINTS) needs revision. No existing block in rig/rig-verify-queue.md covers this — needs a new one. requires-rig stays on this PR; only a human clears it, and only after that measurement exists.
codex qa — PR #437 at f9c62a0verdict: fail findings[severity: major] [confidence: high]
gateClaude QA workspace gate: inherited at current tip unaddressed open questionsNone. The architect-approved numeric ceilings remain scopenone |
|
Revision completed at Design basis: before revising I checked linked issue #427 for architect or UX comments newer than the branch's original Point-by-point response to the
Verification at the revised tree:
No review point is left disputed. Per the invocation instruction, I left all PR labels unchanged. |
|
Codex QA did not proceed: the current tip |
|
Re-review. Commit range reviewed: mechanical gate (re-run at tip
|
codex qa — PR #437 at 28a051averdict: pass gateClaude QA workspace gate: inherited at current tip unaddressed open questionsNone. The architect-tagged numeric ceilings remain scopenone |
rig-2026-09-14-pr437-plot-budget — rig recordDate (UTC): 2026-09-14 · Rig: pupu · Operator: Markus Kovero · Run by: Claude Code session Build under testrev 28a051a (dirty 0), rustflags -C target-cpu=x86-64 -C link-arg=-fuse-ld=mold, Pre-flight (19:44:10Z) — all PASSJACK active 96000/256/-S; port order analog block capture 1-8 (14 captures); ALSA baseline 93=2 94=2 89=2 81=20,0 Physically connected (probed 19:49:24Z, probe-outputs.sh --level -60 --outputs 1)ac output 1 = system:playback_2 → IN2 tone −57.5 dBFS (+2.5 dB loopback gain); IN1 mic tone −145.6 dBFS Clock stateFF400 internal clock, snd_fireface, jackd -S 96 kHz period 256; unchanged. Emission consent
Methodpyzmq over SSH tunnel to ac-daemon --local :15556/15557. Rig-side per run: pidstat -h -r -u -p 1; Silent pre-checks — one past each ceiling refused with "stimulus silent": duration 60.001, tail_s 60.001, Runs (all −40 dBFS nominal, loopback)
Pass stated before running: completes or stops with silence attested and IN2 at floor within one round trip of Finding 1 — FAIL: MAX_STIMULUS_DURATION_S = 60 admits plot_ir requests the JACK backend cannot completeRuns 1 and 3 emitted, then timed out with no IR. jack_backend.rs:28 RING_CAPACITY = 16*192_000 = 3,072,000 Finding 2 — pass: stop-to-silence is promptplot_ir mid-sweep: reply 27 ms, last above-floor block 12 ms after reply (within JACK/converter round trip). Finding 3 — readout: resourcesLargest completing plot_ir 414 MiB RSS, 116 % CPU burst (~4 s deconvolution), mean 9 %. All else ≤ 185 MiB, Confound
Rig state left behind (after #437 runs)Daemon stopped; no jack_rec/pidstat; jackd xrun lines last 25 min: 0. ~/.config/ac/config.json untouched What should happen next
|
Conflicts resolved: - audio/mod.rs: keep this branch's AtomicBool import (cancellable play_and_capture) and main's anyhow::bail (ee88b15, fail closed on unavailable audio backend). - handlers/audio/plot.rs imports: main's cal_guard and make_engine_for_state plus this branch's MAX_* budget constants. - plot_ir worker tail: main's eng.stop() and "backend" on the done frame. cargo fmt --check and cargo clippy -- -D warnings pass. cargo test --workspace: one failure, it_protocol modes::loudness_lkfs_drops_by_curve_db_when_mic_correction_on, which panicked at its fixed 1500 ms frame window under three concurrent cargo test runs and passes when run alone; it does not touch plot code. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FuCG3RuLHArnC8snRZVDYG
|
Re-review. Commit range reviewed: mechanical gate (re-run at tip
|
| criterion | provenance | covered | notes |
|---|---|---|---|
| Stopping plot_ir terminates stimulus and capture promptly on every supported backend | measured | ✓ | Unchanged by this delta. |
| Duration, tail, point density, step count, harmonic count, and window length are rejected before worker spawn when outside explicit finite budgets | assumed (architect, #427) |
✓ (mechanism), ceiling values still open | This delta closes a real hole in this criterion — start_hz could bypass the duration ceiling via the per-point floor — but the numeric ceiling values remain rig-unverified, unchanged from prior passes. |
| Rejected requests emit no audio and return an observable error | measured | ✓ | Extended to the new rejection path; assert_budget_rejection checks both busy == false and error text. |
| Regression coverage includes cancellation during stimulus, cancellation during tail, each budget boundary, non-finite input, and integer-conversion overflow | measured | ✓ | Strengthened — the new tests cover a boundary this criterion implies (a "budget boundary" on the derived per-point duration) that was previously unexercised. |
standards conformance
standards check: not applicable — scope-none (issue #427's own label, unchanged from every prior pass on this PR). This delta is a resource-budget validation guard and its test; it does not touch a measurement formula, unit, or displayed value.
correctness issues
ac-rs/ZMQ.md:1215-1234(plotsection) — not touched by this delta. It documentsduration(≤60s) and the derived point-count ceiling (≤10000), but not the new implicit rejection: astart_hzlow enough that3.0/start_hzalone exceedsMAX_STIMULUS_DURATION_Sis now rejected, even whendurationitself is in range. ZMQ.md is called out in this repo as authoritative for both the Rust and Python clients, and this PR's own description states it "document[s] the protocol limits." Non-blocking (the code and test are correct; a client constructing astart_hzin the sub-Hz range is not a realistic path — CLI default is 20 Hz), but worth a one-line addition toplot's request docs so a wire client isn't surprised by an undocumented rejection reason.
test coverage gaps
none in the delta — both new cases (the boundary at start_hz: 0.001 and the exact codex-qa repro at start_hz: 1e-300) are reachable and exercise the actual panic path, verified above rather than assumed from the commit message.
scope issues
none.
verdict
approve
The delta is a correct, narrowly-scoped fix for a real daemon-panic path (traced independently through capture_block → Duration::from_secs_f64, not just trusted from the commit message), its guard formula is provably the worst case over the sweep grid, and its regression tests are reachable — verified to fail against the pre-fix behavior, not just pass against the post-fix code. Full workspace gate (fmt, clippy -D warnings, test --workspace) is clean at tip cf491623. All open items from prior passes (assumed numeric ceilings, requires-rig) are unchanged by this push; one non-blocking doc gap noted above (ZMQ.md not updated for the new rejection reason).
sent back to
no
rig verification required
Unchanged in substance from all prior passes: run plot_ir at the documented ceilings (60.0s duration, 60.0s tail, 32 harmonics, a 1,048,576-sample window, a 10,000-point sweep) and record peak memory, peak CPU, and stop-to-silence latency. This delta doesn't touch or resolve that gap. requires-rig stays; only a human clears it.
label note
claude-approved was absent going into this push (correctly voided when cf491623 landed after the ec63245f approval — in-review and requires-rig were left in place by the pusher, consistent with the approval-voiding convention). Re-applying claude-approved now for this pass's fresh approve verdict at cf491623.
codex qa — PR #437 at cf49162verdict: fail findings[severity: major] [confidence: high]
[severity: minor] [confidence: high]
gateClaude QA workspace gate: inherited at current tip unaddressed open questionsThe architect-assumed numeric ceilings still need the recorded rig measurements of peak memory, CPU, and stop-to-silence latency; the existing scopenone |
codex-qa found the stop-cancels-during-stimulus/tail regression tests only assert a prompt stop reply and busy:false, both of which also hold when plot_ir simply finishes on its own before stop is sent (the worker handle stays in the map until stop removes it). Drain PUB frames after stop and assert the request never published its impulse_response, report, or done frame — reachable against a revert to the non-cancellable play_and_capture (verified by hand: with that revert restored, plot_ir_stop_cancels_during_stimulus fails on the new impulse_response assertion and _during_tail fails because the worker already vacated the map before stop was sent). Also document plot's derived per-point duration ceiling (max(duration, 3/start_hz) <= 60s) in ZMQ.md, per the same review's minor finding. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Revision completed at design basisChecked issue #427 for an architect/UX comment newer than this branch's base commit ( the findings1. [major] Cancellation tests don't prove cancellation, only a prompt reply + Agreed and reproduced before fixing: with Fix: after 2. [minor] Agreed, fixed. Added a paragraph to verify gate at
|
|
Codex QA did not review the current tree: the |
|
Re-review. Commit range: mechanical gate (re-run at tip
|
| criterion | provenance | covered | notes |
|---|---|---|---|
| Stopping plot_ir terminates stimulus and capture promptly on every supported backend | measured | ✓ | Unchanged by this delta, but the delta strengthens how this is proven — see delta review above. |
| Duration, tail, point density, step count, harmonic count, and window length are rejected before worker spawn when outside explicit finite budgets | assumed (architect, #427) |
✓ (mechanism), ceiling values still open | Unchanged from prior pass — this delta is docs/tests only, doesn't touch the ceiling values. |
| Rejected requests emit no audio and return an observable error | measured | ✓ | Unchanged by this delta. |
| Regression coverage includes cancellation during stimulus, cancellation during tail, each budget boundary, non-finite input, and integer-conversion overflow | measured | ✓ | Strengthened — cancellation coverage now proves the worker was actually interrupted (no completion frames), not just that stop replied promptly and status read idle. |
standards conformance
standards check: not applicable — scope-none (issue #427's own label; reconfirmed on the issue directly this pass). Checked the delta against docs/architecture/standards.md's document map (/home/mui/src/ac/docs/architecture/standards.md:13-22): neither ac-daemon/src/handlers/audio/plot.rs nor ZMQ.md nor the it_protocol tests are listed modules, and this delta touches only a protocol-doc addition and a test — no measurement formula, unit, or displayed value changes.
correctness issues
none found. The one thing worth a maintainer's attention is non-blocking and noted above (test comment misdescribes the reap mechanism, though the test itself is reachable and correct).
test coverage gaps
none in the delta. The assumed-ceiling rig-evidence gap noted in every prior pass is unchanged — that remains a requires-rig matter, not a missing-test matter.
scope issues
none.
verdict
approve
Delta is docs + a strengthened regression test, both verified against the actual code paths rather than taken on the commit message. Full workspace gate (fmt, clippy -D warnings, test --workspace, check --features cpal-audio) is clean at tip 942c0e27. All open items from prior passes (assumed numeric ceilings, requires-rig) are unchanged by this push; the one previously-open non-blocking doc gap is now closed.
sent back to
no
rig verification required
Unchanged from all prior passes: run plot_ir at the documented ceilings (60.0s duration, 60.0s tail, 32 harmonics, a 1,048,576-sample window, a 10,000-point sweep) and record peak memory, peak CPU, and stop-to-silence latency. This delta doesn't touch or resolve that gap. requires-rig stays; only a human clears it.
label note
claude-approved predates 942c0e27 (codex-qa already flagged this on the PR and left labels alone). This pass re-validates the gate and the diff at the current tip with a fresh approve — claude-approved, in-review, and requires-rig all stay as currently set; no label change needed since they already match this review's outcome.
codex qa — PR #437 at 942c0e2verdict: fail findings[severity: major] [confidence: high]
gateClaude QA workspace gate: inherited at current tip unaddressed open questionsNone from the QA or UX comments. scopenone |
Codex QA at 942c0e2: the fixed RING_CAPACITY (120 s at 192 kHz) only covered the plot_ir budget up to 192 kHz, but JackEngine::start accepts whatever rate the JACK server reports. At 384 kHz a within-budget duration 60 + tail_s 60 request needs 46,080,000 samples against a 23,040,000-sample ring: the stimulus plays in full and the capture times out with no IR, the same failure the 96 kHz rig run found. meas_ring_capacity(sample_rate) now computes 2 x MAX_STIMULUS_DURATION_S x the live rate, imported from handlers (not duplicated), and start() allocates the measurement ring from self.sample_rate after JACK reports it. Resident cost at 96 kHz drops from 88 MiB to 44 MiB; at 384 kHz it is 176 MiB. Written by the developer session for this revise, which stopped while waiting on a backgrounded cargo test before committing; committed here after cargo fmt --check, cargo clippy -- -D warnings and cargo test --workspace passed on it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FuCG3RuLHArnC8snRZVDYG
Response to codex-qa at 942c0e2: capture ring sized from the live sample rateChange ( Memory: 120 s × 4 B/sample means 44 MiB per engine at 96 kHz (was 88 MiB, see the rig record's ring-wrap soak) and 176 MiB at 384 kHz. The rig record's resident-cost readout scales with that. How this was committed: the developer session for this revise wrote the change, then stopped while waiting on a backgrounded Known weakness, for review: |
|
Re-review. Commit range: mechanical gate (re-run at tip
|
| criterion | provenance | covered | notes |
|---|---|---|---|
| Stopping plot_ir terminates stimulus and capture promptly on every supported backend | measured | ✓ | Unchanged by this delta. |
| Duration, tail, point density, step count, harmonic count, and window length are rejected before worker spawn when outside explicit finite budgets | assumed (architect, #427) |
✓ (mechanism), ceiling values still open | This delta closes a real hole in the mechanism: the ring backing that budget now fits it at any live JACK rate, not just up to 192 kHz. Ceiling values remain rig-unverified, unchanged from every prior pass. |
| Rejected requests emit no audio and return an observable error | measured | ✓ | Unchanged by this delta. |
| Regression coverage includes cancellation during stimulus, cancellation during tail, each budget boundary, non-finite input, and integer-conversion overflow | measured | ✓ | Strengthened at the formula level (five rates including 384 kHz vs. four before); see the wiring-level gap noted above, which this criterion doesn't fully close for the reason given. |
standards conformance
standards check: not applicable — scope-none (issue #427's own label, reconfirmed directly on the issue this pass: bug, ready-to-implement, agent:triage, scope-none). Checked the delta against docs/architecture/standards.md's document map directly (grep -n "jack_backend\|audio/" /home/mui/src/ac/docs/architecture/standards.md — no match for this file or path); this delta sizes an internal SPSC capture-ring buffer from the live sample rate, it does not touch a measurement formula, unit, or displayed value.
correctness issues
none found in the delta.
test coverage gaps
- The new/renamed formula test doesn't exercise
start()'s actual wiring ofmeas_ring_capacity(self.sample_rate)— see the gap discussed above. Non-blocking: unfixable without a real JACK server in this environment, matches the pattern of two pre-existing#[ignore]d real-JACK tests already in this file, and the developer's own commit message flagged the same gap rather than concealing it. Suggested#[ignore]d addition given above.
scope issues
none.
verdict
approve
The delta correctly fixes the codex-qa-identified defect (fixed 192 kHz-sized ring silently failing above that rate) by deriving capacity from the live JACK rate at start(), verified independently by reading the actual ordering and formula rather than trusting the commit message. Full workspace gate (fmt, clippy -D warnings, test --workspace, check --features cpal-audio) is clean at tip c71b6995. One self-reported test-wiring gap is real but non-blocking (unclosable without real JACK hardware, matches existing #[ignore] precedent in this file). All open items from prior passes (assumed numeric ceilings, requires-rig, and the still-unaddressed non-blocking plot_ir.rs comment note) are unchanged by this push.
sent back to
no
rig verification required
Unchanged in substance from all prior passes: run plot_ir at the documented ceilings (60.0 s duration, 60.0 s tail, 32 harmonics, a 1,048,576-sample window, a 10,000-point sweep) and record peak memory, peak CPU, and stop-to-silence latency. This delta generalizes the ring-sizing fix to any live rate but doesn't change what needs measuring at the documented ceiling — requires-rig stays; only a human clears it. Separately, note the 384 kHz path this delta specifically targets is not reachable on the project's currently-documented dedicated rig hardware (FF400, which tops out at 192 kHz) — the fix is verified here at the formula level for that rate, but no rig run on existing hardware can exercise it; not requesting a new rig-verify-queue block for it on that basis.
label note
claude-approved predates c71b6995 (per the standing approval-voiding rule, any commit after an approval reverts the PR to needs-work until re-reviewed). This review re-validates the gate and the diff at the current tip with a fresh approve — re-applying claude-approved. in-review and requires-rig were already present and stay as-is.
…d revise from a declined one Three pipeline rounds on PR #437 were lost on 2026-09-15 the same way: a headless role (qa twice, developer once) started its cargo gate as a background command, ended its turn "waiting for the notification", and the claude -p process exited with nothing posted. The developer's fix sat uncommitted in the worktree. .agents/AGENTS.md gains an every-role "headless sessions" section: no later turn exists, so never background a command whose result you need, run gate steps in the foreground one call each, and have the deliverable (comment, push, labels) in place before the turn ends. The three session excerpts are quoted as the concrete bad example. qa.md, developer.md and codex-qa.md point to it where each role runs commands. bin/master.sh: "revise pushed nothing" always told the operator the developer had declined ("the block is one only you can clear"). It now counts PR comments around revise.sh. A comment keeps that message. No comment reports that the session did not finish, not a decline, and names any uncommitted tracked files left in the branch worktree plus the session log. needs-work and STATE=needs-human stay in both cases. Checked with a throwaway harness sourcing master.sh with gh_retry and revise.sh stubbed: commented, stalled with a dirty worktree, unreadable comment count and moved tip each take their own path, and the three unchanged-tip cases end in STATE=needs-human. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FuCG3RuLHArnC8snRZVDYG
rig-2026-09-15-pr437-c71b6995 — rig record (re-run on the current tip)Date (UTC): 2026-09-15 14:21–14:35 · Rig: pupu · Operator: Markus Kovero · Run by: Claude Code session Build under testrev c71b699 (dirty 0, Pre-flight, wiring, clock
Emission consentOperator, 2026-09-15, choosing "Rig re-run, then I clear" on the question naming the scope: loopback AN2→IN2 only, −40 dBFS, Runs — c71b699 vs a5b7d76 (same driver, same requests)
IN2 peak −37.1 dBFS on R1c/R7c, −36.9 on R3c. That is consistent with −40 nominal + 2.5 dB cable. Result — PASS for the ceilings on c71b699 at 96 kHzEvery documented Readouts, not gates
Confound
Rig state left behindDaemon stopped (no What should happen next
|
codex qa — PR #437 at c71b699verdict: pass gateClaude QA workspace gate: inherited at current tip All four issue #427 acceptance criteria are covered by the diff and changed tests. The explicitly assumed numeric ceilings are enforced before port resolution or worker spawn. Current-tip rig evidence confirms the combined unaddressed open questionsnone scopenone |
Conflict in ac-daemon/tests/it_protocol/out_of_range.rs: this branch's named-stop and plot-family budget tests, and main's #428 test plot_duration_zero_fails_atomically_instead_of_archiving_partial_sweep, landed at the same place. Kept both. The two collide on behaviour, not text: this branch's request budget rejects `duration: 0` for plot/plot_level/plot_ir before spawn, as ZMQ.md already documents ("greater than 0"), while the #428 test sent `plot` with `duration: 0.0` expecting `ok: true` so every point above 562.5 Hz falls under analyze's 256-sample minimum. Operator decision: keep the > 0 rule and move the test to `duration: 0.001`, renamed plot_tiny_duration_fails_atomically_instead_of_archiving_partial_sweep. max(0.001, 3.0 / freq) equals 3.0 / freq at every point in that sweep, so the partial-sweep failure it pins is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FuCG3RuLHArnC8snRZVDYG
|
Merged |
|
Re-review. Commit range reviewed: what the delta actually is
the one substantive thing to check: the conflict resolutionBoth branches added a test at the same spot in Verified the arithmetic claim independently, not just the commit message:
No trace of the old mechanical gate, re-run at 41b18bb (workspace, not per-crate)
points from my
|
| criterion | provenance | covered | notes |
|---|---|---|---|
| Stopping plot_ir terminates stimulus and capture promptly on every supported backend | measured | ✓ | Unchanged by this delta. |
| Duration, tail, point density, step count, harmonic count, and window length are rejected before worker spawn when outside explicit finite budgets | assumed (architect, #427) | ✓ (mechanism); ceiling values rig-verified this pass | Rig record rig-2026-09-15-pr437-c71b6995 measured all documented ceilings on hardware at the code now present in 41b18bb0 (files unchanged since); operator cleared requires-rig on that basis. |
| Rejected requests emit no audio and return an observable error | measured | ✓ | Unchanged by this delta. |
| Regression coverage includes cancellation during stimulus, cancellation during tail, each budget boundary, non-finite input, and integer-conversion overflow | measured | ✓ | Unchanged by this delta; the merge-resolution test is main's #428 coverage relocated, not new #427 coverage. |
standards conformance
standards check: not applicable — issue #427 is still labelled scope-none (reconfirmed directly on the issue this pass), and this delta touches none of PR #437's own files, so there's nothing new to raise the label against. The delta does carry other PRs' output-format changes (#428's error frame fields, #369's tau_state values) into this branch, but those are main's already-merged, already-gated content under their own issues — not this PR's diff to answer for.
correctness issues
none found in the delta.
test coverage gaps
coverage is adequate for this delta. (Standing, non-blocking note: plot_ir.rs's test comment misdescribing the reap mechanism — item 3 above — remains open and untouched.)
scope issues
none — the merge touches no file outside main's own already-merged history; nothing in PR #437's own manifest changed.
verdict
approve
Mechanical gate is clean at 41b18bb0 (fmt, clippy -D warnings, cpal-audio check, full cargo test --workspace, no flakes this run), the only PR-relevant content in the delta (the out_of_range.rs merge conflict resolution) is independently verified correct and its test is reachable and passing, and every open item from the prior pass is either still valid (assumed ceilings, now rig-verified and human-cleared; the non-blocking plot_ir.rs comment note) or confirmed unaffected (all three backend files, handlers/mod.rs, stop.rs — zero lines touched).
sent back to
no
rig verification required
no — rig-2026-09-15-pr437-c71b6995 already measured all documented plot_ir ceilings against this exact code (unchanged since), and the operator cleared requires-rig on that record. This delta doesn't touch any measured file, so that clearance carries forward to 41b18bb0 unchanged. (Confound noted in that record stands: 384 kHz remains formula-tested only, since the dedicated rig's FF400 tops out at 192 kHz — not grounds for a new queue entry, per the prior pass's same conclusion.)
label note
Both claude-approved and codex-approved currently on the PR predate 41b18bb0 (last applied 09:14 and 15:06 respectively, before the 15:32 merge push) — stale per the approval-voiding rule. Re-applying claude-approved fresh against this tip. Not touching codex-approved (human/Codex-only); it will need its own re-run.
closes #427
what changed
files touched
test output
ZMQ schema changed
yes — stop reply adds
stimulus: "silent"; plot-family ranges now reject out-of-budget requests.new dependencies
none
related
none
open questions for reviewer
The numeric resource ceilings are architect-approved assumed values; rig evidence may later refine them.