# ADR-0003 — SIP strategy: Rust-native trunk SIP, no SBC shield - **Status:** ~~Accepted~~ **Superseded** (2026-06) - **Date:** 2026-06 - **Supersedes:** [ADR-0001](0001-sip-strategy.md) - **Superseded by:** [ADR-0007](0007-trunk-rented-transport.md) — rent the trunk transport; no first-party SIP stack - **Origin:** [vision-revision](../superpowers/specs/2026-06-26-vision-revision-design.md) §5 > **Superseded.** Kept as the historical record of the "own trunk SIP + media termination in Rust, > no SBC shield" plan. Reversed under the 2026-06 strategic-relevance review: a from-scratch Rust > trunk-SIP stack is the highest-cost / lowest-differentiation part of a solo build, and there is no > production-hardened pure-Rust SIP stack to stand on. The trunk is **rented, not built** — see > [ADR-0007](0007-trunk-rented-transport.md). ## Context ADR-0001 layered the SIP strategy: own the Rust parser, but front the public edge with a proven **Kamailio + rtpengine** SBC to rent the "20-year device/carrier interop tail." That tail is real for a generic PBX — thousands of desk-phone quirks, NAT behaviors, carrier glare. Reconsidered under the AI-era contact-center scope ([ADR-0002](0002-north-star-and-fused-core.md)), the tail **collapses**: rutster talks to a few **documented, cooperative SIP-trunk providers (Telnyx, Bandwidth, Twilio SIP)**, IP-allowlisted, not thousands of far-end desk-phone UAs. An inbound/outbound SIP-trunk client against cooperative carriers is tractable in `rsip` / `ezk`, bounded by carrier documentation, not device quirks. The C SBC shield, meanwhile, directly contradicts the wedge: - It puts **C at the most-exposed seam** (the public internet) — gutting the memory-safety headline *at the one place it matters most*. - It **terminates media twice** — rtpengine at the edge, rutster's media plane inside — breaking "terminate media once" / "one auditable boundary." ## Decision Own trunk SIP **and** media termination directly in the Rust core; IP-allowlist the handful of trunk providers. **No Kamailio + rtpengine shield. No pjproject FFI.** - Parser: `rsip` (message types/parsing). Sans-IO transaction/dialog/core: the `ezk` family. No hostile bytes ever hit a C parser. **Fuzzed.** - The memory-safety thesis becomes **literally true at the wire**: hostile bytes hit a fuzzed Rust parser first, at the edge of *our* trust boundary. - Interop surface is **bounded by carrier docs** (a finite, knowable set), not the unbounded device tail ADR-0001 rented the shield for. ### Scope boundary — this ADR is about *trunk* SIP, not *endpoint* SIP Inbound SIP **endpoint** registration (desk/soft phones: `REGISTER`, BLF/MWI, DTMF variants, per-device NAT/provisioning) is a **different axis** and is **deferred** — it re-imports the unbounded device-interop tail this ADR deliberately closes. Human-participant ingress is **WebRTC**. See [ADR-0006](0006-ingress-posture.md). ## Topology ``` hostile internet trusted core ───────────────► (carrier trunk) ──► rutster control + media plane (SIP trunks, (native Rust SIP parser + far-end UAs) transaction/dialog core, owned end-to-end here) ``` WebRTC ingress ships **first** and is unaffected (WebRTC signaling is app-defined, not SIP), so first-call never blocks on SIP. ## Consequences - **Positive:** memory-safety headline *literally true* at the wire; one media-termination point; no C operational dependency (no Kamailio/rtpengine config/deploy/expertise); no pjproject license/threading/`unsafe` entanglement; the trunk client is bounded by carrier docs, not device quirks. - **Negative / cost:** we own a (bounded) SIP-trunk client early; carrier-specific interop must be maintained as trunks are added. - **Mitigation:** WebRTC-first ordering means first-call doesn't block on SIP; the thin-slice steps 1–4 (media core → tap → brain → barge-in) all land before step 5 (real PSTN trunk). - **Graduation:** unlike ADR-0001, there is no shield to retire — the question is only how the trunk client matures in production. ## References - [ADR-0001](0001-sip-strategy.md) — superseded (the layered Kamailio+rtpengine + Rust-core plan) - [ADR-0002](0002-north-star-and-fused-core.md) — the fused-vertical reframe this SIP decision enables - [ADR-0006](0006-ingress-posture.md) — WebRTC-first ingress; SIP endpoint deferred