diff --git a/docs/screenshare-audio-exclusion-impl-plan.md b/docs/screenshare-audio-exclusion-impl-plan.md index d34ff98..745b5c9 100644 --- a/docs/screenshare-audio-exclusion-impl-plan.md +++ b/docs/screenshare-audio-exclusion-impl-plan.md @@ -16,7 +16,9 @@ are built, validated and committed locally in PixelPass (`5a65f50`). Capture-sin and successful exact-channel relinking are built, validated and committed locally in PixelPass (`d09ee9b`). **The Row 1 mutation-edge identity gate and the Row 8d/8e fail-closed construction gates are built, validated and committed locally in PixelPass (`6be07ef`).** -The remaining Phase 6 refusal/matrix rows, plus phases 7–9, are not built — nothing +**The independent Row 6a/6b/6c refusal gates are built, validated and committed locally in +PixelPass (`956534f`).** The remaining Phase 6 matrix/qualification work, plus phases 7–9, +is not built — nothing released to date changes the feature's user-visible behaviour. **Phase 6 remains the current front.** **Date:** 2026-07-21 (v4); status line refreshed 2026-08-21 @@ -738,6 +740,33 @@ ancestry becoming unsafe. > system Rust 1.97.1. The disposable 1.0 GiB release cache was removed afterward, leaving 12 GiB > free. Next is the independent Row 6a/6b/6c refusal/reason slice; Phase 6 is not complete. +> **Row 6a/6b/6c slice — built, validated and committed locally as PixelPass `956534f` on +> 2026-08-21.** +> The bound Node observer now subscribes to the configured `SPA_PARAM_Format` only for +> `Stream/Output/Audio` nodes that advertise it as readable, and classifies the native libspa +> format as raw, encoded or IEC958. Missing/unparseable format evidence is a per-stream +> fail-closed `format-unknown`, not permission to link. `node.passthrough` stays a separate +> predicate, so it cannot be masked by the format classifier. +> +> Three independent controller fixtures prove Row 6a `port.exclusive`, Row 6b encoded and Row +> 6c IEC958 each make **zero** link-creation attempts and emit exactly their own +> `stream_unsupported` reason (`port-exclusive`, `encoded`, `iec958-passthrough`) once. A fourth +> gate independently exercises explicit `node.passthrough`; another proves the ordinary +> Node-info-before-Format ordering stays fail-closed without emitting a transient false warning, +> then captures once raw PCM arrives. Row 6a remains the accepted injected-graph gate: v1 still +> does not bind Ports, so a live exclusive port reaches the already-gated clean link-failure path. +> +> The first read-only live audit exposed and prevented two observer defects before completion: +> generic Pod deserialization rejected the real Format object, and enumerating Format on every +> driver Node produced expected ENOENT/EIO core errors. The corrected path uses libspa's native +> format parser and the Node's advertised readable-param list. A second live audit observed +> Strawberry, FFXIV and Chromium settle from `format-unknown` to eligible raw PCM within the +> initial callback burst, with no parse or core errors. Full PixelPass validation is 342 passed, +> 0 failed and 12 ignored; all three Row 6 gates pass in an optimized one-job release build; +> strict all-target Clippy, formatting, `git diff --check` and `pixelpass --doctor` pass. The +> 966 MiB disposable release cache was removed and disk space returned. Next is the revised Row +> 9 positive/negative partition; Phase 6 is not complete. + Failure ⇒ report the stream unsupported. **Never** fall back to the default monitor — and after 0d that fallback is unconstructible in this mode, by either path. diff --git a/docs/screenshare-audio-exclusion-plan.md b/docs/screenshare-audio-exclusion-plan.md index 8f54b55..f326df7 100644 --- a/docs/screenshare-audio-exclusion-plan.md +++ b/docs/screenshare-audio-exclusion-plan.md @@ -1401,13 +1401,29 @@ zero unsafe creates. Two optimized-release fault-injection gates prove capture-s failure and readiness timeout both fail `DesktopExcluding` closed without resolving the legacy default monitor or constructing legacy routing. Full validation reports 335 passed and 12 ignored; strict Clippy, all three serialized live Phase 6 gates, diagnostics and residue checks -pass. The next bounded slice is the three independent Row 6a/6b/6c refusal/reason fixtures. +pass. -1. **Continue Phase 6:** add independent refusal/reason fixtures for Row 6a `port.exclusive`, - Row 6b encoded streams and Row 6c IEC958 passthrough. -2. Carry the revised row-9 partition forward: music-only and a different-device microphone +PixelPass commit `956534f` closes the three independent Row 6a/6b/6c refusal/reason fixtures. +`Stream/Output/Audio` Nodes advertising a readable configured Format +param are subscribed and parsed through libspa into raw, encoded or IEC958; unknown format is +per-stream fail-closed, while the existing `node.passthrough` property remains an independent +predicate. Separate controller gates prove `port.exclusive`, encoded and IEC958 each make zero +link-create calls and emit only `port-exclusive`, `encoded` and `iec958-passthrough` +respectively. An additional gate proves an explicit passthrough property cannot be masked by a +raw Format, and the initial Node-info-before-Format ordering does not emit a false warning. + +A read-only live audit initially caught generic Pod parsing failures and harmful Format queries +against Nodes that did not advertise the param. After switching to libspa's native parser and +gating queries on readable Format support, Strawberry, FFXIV and Chromium all settled to raw +eligible streams with no parse/core errors. Full validation is 342 passed and 12 ignored; the +three Row 6 cases also pass optimized release, strict Clippy and `pixelpass --doctor` are clean. +The `port.exclusive` case remains an injected-graph gate under v1's accepted no-Port-binding +limitation; a live exclusive port still degrades through the separately tested link-failure path. + +1. **Continue Phase 6:** carry the revised Row 9 partition forward: music-only and a + different-device microphone stay eligible; same-device capture and a tainted-monitor capture are excluded. -3. Preserve the new live mutation slice's ownership, serial-revalidation, fail-closed, +2. Preserve the new live mutation slice's ownership, serial-revalidation, fail-closed, exact-channel, all-links-active and crash-cleanup gates while finishing the phase. Still owed beyond that, unchanged: the §9.2 rig upgrade before any exclusion claim is