docs: advance audio exclusion plan into phase 6

This commit is contained in:
2026-08-21 15:40:12 -04:00
parent 9ba42c4cda
commit 9e52acf9d3
3 changed files with 242 additions and 56 deletions
@@ -17,6 +17,62 @@ was closed with this data on 2026-07-26 (see "What still blocks phase 6").
---
## Addendum — pre-Phase-6 hardware/readiness gate (2026-08-21)
This addendum does not rewrite the historical 2026-07-26 matrix. Design v3.8 §6.9 adds one
conservative edge the old engine did not have: tainted playback into a positively classified
hardware sink taints passive capture nodes carrying the same snapshot-local `device.id`. It
also closes the readiness-budget calibration that round 9 left open.
### Hardware path — targeted live exact partition
The audit started first and reached readiness. Controlled modules then created three named
candidates:
| candidate | expected | observed |
| --- | --- | --- |
| tagged playback into ALC897 | excluded root | `peerspeak-owned` |
| capture/re-emitter reading the ALC897 source | excluded through hidden same-device hop | `tainted-owner-bridge` |
| identical capture/re-emitter reading the Arctis source | eligible; different Device | eligible, no reason |
The settled record was `graph_ready=true`, epoch `complete`. This revises row 9 for every
future full matrix: music-only and a microphone on a **different Device** remain eligible;
a microphone on the **same Device receiving tainted playback** and a tainted-monitor capture
are excluded. This is deliberate fail-closed over-exclusion because a private hardware or
firmware loopback is not observable as a PipeWire Link.
The host's ALC897 had no `Stereo Mix` capture-source item: `Input Source` offered Rear Mic,
Front Mic and Line. Its separate `Loopback Mixing` control was disabled. Runtime safety does
not depend on either spelling; USB/vendor loopbacks need the same rule.
### Readiness calibration — retain the 2 s sticky deadline
Each measurement used a fresh observer process and its emitted monotonic `at_ms` readiness
timestamp:
| arm | runs | min | p50 | p95 | max | timed out |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| ambient live graph | 30 | 4 ms | 5 ms | 10 ms | 11 ms | 0 |
| 24 temporary null sinks + 24 loopbacks | 30 | 109 ms | 111 ms | 113 ms | 114 ms | 0 |
| 250 null-sink create/remove cycles concurrent with starts | 20 | 4 ms | 5 ms | 6 ms | 8 ms | 0 |
The inflated maximum is 17.5x below the 2 s deadline. All temporary modules were unloaded by
the exact ids returned from `pactl`; no test modules remained, and the configured default
sink/source were unchanged.
### Regression gates
- focused taint engine: 83 passed;
- observer: 65 pure passed, then all 3 serialized live PipeWire tests passed;
- complete non-GUI PixelPass suite: 313 passed, 0 failed, 9 ignored;
- disk before the first build: 20 GiB free; after tests and Clippy: 17 GiB free.
**Verdict:** both former pre-Phase-6 design blockers are closed. S4/S5/0d, round 11, and the
first pure Phase 6 channel-planning prerequisite are committed locally in PixelPass `781defc`;
the first fan-out mutation remains the current work.
---
## What changed since run 1
Run 1 failed on two defects, both fixed before this run:
@@ -276,10 +332,11 @@ orders of magnitude of remaining headroom, not one.
teardown in bursts, and a 32 µs recompute drains a burst faster than it forms.
`busy_fraction` is the number to trust.
⚠️ **The readiness budget still has no calibration argument.** 12 ms against
2000 ms is three orders of magnitude of slack on *this* host with 18 binds; it is
not an argument about a host with a large USB interface, many virtual devices, or
a cold cache. Carried forward as open, unchanged.
⚠️ **Historical run-2 finding, closed by the 2026-08-21 addendum above:** 12 ms
against 2000 ms was three orders of magnitude of slack on *this* host with 18
binds, but not an argument about enumeration volume or instability. The addendum
adds a 48-module graph and concurrent create/remove churn and retains the 2 s
budget from that evidence.
---