Files
pixelpass/src/host/audit
molluskandClaude Opus 5 bbf6744444 host/audit: phase 5 — dry-run audit mode (read-only)
Runs phases 2-4 against the live PipeWire graph on every registry event and
reports the complete eligible/excluded candidate partition with stable reason
codes. Creates no links, loads no modules, changes no routing.

Impl plan §5. Two entry points behind the hidden PIXELPASS_AUDIO_AUDIT=1
trigger: inside a real `pixelpass host` run (the plan-literal reading, proves
the path phase 6 will mutate), and a hidden `--audit-audio` standalone mode
with no iroh endpoint or capture pipeline, which is what drives the §5.1
matrix.

The recompute runs inline on the observer thread via a new ProjectionSink
hook, once per applied event. Polling `latest()` was rejected: it coalesces,
and phase 4 detects a module unload by observing the empty gap before the next
module appears — with indices reused verbatim (v3.4 §5.2 correction 3), a
missed gap aliases a fresh module onto a dead identity. Running inline is what
makes phase 4's "one observe per graph event" contract true, and it puts the
cost where O5 can measure it.

Split as usual: the auditor and the metrics are pure and unit-tested; the
clock, the writer and the env parsing are the thin edge in `sink`/`run`.

- audit/mod.rs   Auditor: AEC validator + taint engine + record building.
                 The AEC gate and the engine's own reasons stay
                 distinguishable — a shut gate must not erase the reason codes
                 the §5.1 rows assert.
- audit/metrics.rs  O5: event rate, bucketed recompute distribution + exact
                 max, busy fraction, and a documented lower-bound queueing
                 proxy (libpipewire exposes no queue depth).
- audit/sink.rs  JSON Lines to stderr, or PIXELPASS_AUDIO_AUDIT_FILE. Never
                 stdout — peerspeak parses that stream.
- audit/run.rs   Env parsing; a malformed AEC value is fatal, matching phase
                 4's rule that it must not silently become "no AEC".

Observer gains `EventKind` (derived from RegEvent, so a consumer's view of
"was this a real graph change?" cannot disagree with the model's) and
`Projection::readiness`, which distinguishes the three ways graph_ready can be
false. taint::fixture is now pub(crate) so audit tests share one graph
vocabulary with the taint tests.

33 new tests, 178 green, clippy -D warnings and fmt clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-25 15:43:10 -04:00
..