Round 10 review, findings 1, 4 and 6. Finding 1 (P1, phase 6) — key 4 was `node.or_else(client)`, so a node's client-controlled application.process.id REPLACED its Client's protected pipewire.sec.pid. One process using two Clients could therefore split its identity: the tainted reader reports a bogus node pid, the output leg omits the node pid and falls back to the Client's real one, the legs are bounded by different values, and they neither bridge nor trip the unbounded sweep — the output stays eligible while re-emitting the call. Now a union of both values, deduplicated, with exception 1 applied to each independently so the pipewire-pulse pid still cannot fuse unrelated Clients. Mutation-verified: reverting to or_else fails ONLY the new split-Client test (so the union changes nothing else), dropping exception 1 fails 32 rows, and using the Client pid alone fails 16. Not reachable today — evaluate() is reached only by the dry-run audit, which creates no links. It becomes live when phase 6 consumes these decisions. Finding 4 — R10-4's test called peerspeak_owned() directly, so reverting node_observation_from_props to truthy() left it green; the only case it shared with production, exact "1", passes under both. A new test builds a real pw_properties dict and drives the production wiring, and the mutation now fails exactly that test while the helper test still passes. Finding 6 — the cross-repo fixture still documented carrier 1 as "any value other than false/0", which R10-4 made exact-"1". A producer following it could emit "true" and silently lose the carrier. Fixture updated in both repos (byte-identical, verified), along with the stale prose in taint/tests and snapshot.rs, and the contract is now also exercised through the production adapter rather than only against the constants. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
43 lines
2.3 KiB
Plaintext
43 lines
2.3 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, matched EXACTLY: `prop_value` below is the
|
|
# ONLY spelling the consumer reads as owned. A producer emitting "true", "yes"
|
|
# or "" is NOT owned on this carrier, and only carrier 2 would still catch it.
|
|
#
|
|
# ⚠️ This wording is load-bearing and it CHANGED in round 10. The consumer
|
|
# used to accept any value other than "false"/"0", on the theory that leniency
|
|
# over-excludes and is therefore safe. It is not: leniency buys false-positive
|
|
# exclusion, and it let any process suppress a rival application's audio from
|
|
# the share with a property it did not even have to spell right. Fail-closed
|
|
# on this feature is about ANCESTRY — an unresolvable graph is not eligible —
|
|
# not about parsing.
|
|
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
|