Zero behaviour change. This is what makes the screenshare exclusion engine able to see us at all (plan §5.1, impl plan §3): pixelpass must refuse to fan out our own playback, and until now it had no way to recognise it. Two carriers, matched by pixelpass as a union — `peerspeak.owned=1` and a `node.name` prefix `peerspeak_owned_<role>_<pid>`. Round 8 added the second after the phase-5 audit found a node property is invisible to the PipeWire registry `global` event and recoverable only by binding the node; the prefix is announced directly. A union is also the fail-closed direction: a missed tag leaks call audio into a share, a spurious one only over-excludes. Three tagging sites, all three verified live on this host: - native call playback → props on the stream dict - screenshare mpv/VLC → PULSE_PROP + PIPEWIRE_PROPS on the child - notification chimes → same, on pw-play/paplay The literals are a cross-repo wire contract, so they appear once here as named constants and are pinned in a fixture committed byte-identical in both repos (tests/fixtures/ownership-tag-contract.txt). The contract test is black-box: it builds a real child `Command` and reads back the environment it would carry, rather than testing our own formatter. Three live `#[ignore]`d exit-gate tests drive the real call sites and poll `pw-dump` for the resulting node — the plan requires the tag be shown landing on a live node, not just in the env. All three mutation-verified (drop either carrier, or the role, and the matching gate fails). Measured while verifying: mpv, VLC, pw-play and paplay all honour `node.name` from those env vars. The native stream set neither `application.name` nor a description, so a mixer fell back to `node.name` — which the tag turns into an internal identifier. Added an explicit `node.description = "PeerSpeak"` there, which keeps the plan's rule (the prefix must not reach `node.description`) while preserving its intent: mixers stay readable. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
35 lines
1.7 KiB
Plaintext
35 lines
1.7 KiB
Plaintext
# Screenshare audio exclusion — ownership tagging wire contract.
|
|
#
|
|
# peerspeak PRODUCES these carriers on every audio node it owns; pixelpass
|
|
# CONSUMES them as the primary taint root of the exclusion engine. Neither
|
|
# repo depends on the other, so this file is the contract: it is committed
|
|
# byte-identical in both, and each repo has a test that asserts its own named
|
|
# constants (and, on the producer side, the environment a real child Command
|
|
# would carry) match these values exactly.
|
|
#
|
|
# peerspeak/tests/fixtures/ownership-tag-contract.txt
|
|
# pixelpass/tests/fixtures/ownership-tag-contract.txt
|
|
#
|
|
# Pinned by peerspeak docs/screenshare-audio-exclusion-impl-plan.md §3 and
|
|
# docs/screenshare-audio-exclusion-plan.md §5.1 (v3.5). Changing a value here
|
|
# is a cross-repo breaking change: both repos must land in the same session,
|
|
# and the phase 5 matrix must be re-run.
|
|
#
|
|
# Two carriers, matched as a UNION — a node is peerspeak-owned if EITHER
|
|
# matches. Round 8 added the second because a property is invisible to the
|
|
# PipeWire registry `global` event and readable only via a node bind, so the
|
|
# primary taint root must not rest on one observation mechanism alone.
|
|
|
|
# Carrier 1 — a node property. The consumer treats any value other than
|
|
# "false"/"0" as truthy, which is the fail-closed direction; the producer
|
|
# always emits exactly this value.
|
|
prop_key=peerspeak.owned
|
|
prop_value=1
|
|
|
|
# Carrier 2 — a `node.name` prefix, announced by the registry without a bind.
|
|
# `node.description` is deliberately NOT touched, so mixers still show "mpv".
|
|
# Only the prefix is matched; the rest of the name is for diagnostics.
|
|
node_name_prefix=peerspeak_owned_
|
|
node_name_format=peerspeak_owned_<role>_<pid>
|
|
node_name_example=peerspeak_owned_mpv_31284
|