Slice 2 hardens the presumptive agent-tap shape from ARCHITECTURE.md §"Agent tap"
(PORT_PLAN §10 open decision) against a working implementation:
- Replace slice-1's in-process EchoAudioPipe with a real out-of-process brain
reached over WSS; core-as-client, no inbound tap port (ADR-0006 posture).
- Versioned JSON event protocol (v1) over WS text frames with base64 PCM.
Event-named + JSON-over-text-WS so the step-3 OpenAI-Realtime adapter is a
translation shim, not a gRPC-bridge project.
- Decoupled TapEngine (cold-path tokio task) owns the WS connection; TapAudioPipe
is a thin sync wrapper the AudioSource/AudioSink seam holds. RtcSession's media
loop is byte-identical to slice-1 — the seam-test payoff.
- Core-authoritative playout buffer (5-frame/100ms ring; drop-oldest on overflow,
silence on underflow) — the place where "brain proposes, core disposes" lives.
- Bounded-backoff reconnect (250ms→5s cap, infinite retries); Channel stays
Connected; stateless-brain reconnect contract.
- Both a Python reference echo brain (examples/echo_brain/, not in CI) and a
Rust echo brain crate (crates/rutster-tap-echo, the in-process test server
+ standalone dev binary).
- ws:// loopback-only enforced; wss:// URL accepted at schema, 501 at connect
(cert/mTLS impl deferred to step 6).
Out-of-scope table (§1.2) locks the spearhead sequencing: real brain (3),
barge-in/VAD-driven playout kill (4), PSTN trunk (5), spend cap (6), wss:// TLS
posture (6), binary PCM mode (future-rung), byte-endian negotiation (tracked
open decision §9).