Files
rutster/docs/adr/0003-sip-rust-native-trunk.md
adlee-was-taken 075e984fb5 docs: ratify vision revision across README/ARCHITECTURE/PORT_PLAN + ADRs 0002-0006
Folds the 2026-06-26 vision-revision pressure-test into the canonical
docs. The spec moves from Proposed to Ratified; the decisions it produced
land in the docs it said it would amend, with ADRs recording each
load-bearing reversal.

- README.md: reframe north star (AI-era contact-center engine, not
  Asterisk successor); persona; revised pillars (add data-ownership,
  demote WASM, promote spend-control); update 'what it is/isn't'.
- ARCHITECTURE.md: replace three-plane framing with fused per-call
  vertical + composable horizontal platform; remove control<->media
  hot-path gRPC hop; make the agent tap the central interface; add
  DX spine + GUI-as-API-client + k8s declarative/operational model.
  Also: 'too slow to police' -> 'too slow to enforce' (terminology).
- PORT_PLAN.md: recharacterize as capability checklist (not template);
  graduate contact-center capabilities to first-class domain; Rust-native
  trunk SIP rows; WASM demoted; thin-slice + capability ladder phasing.
- ADR-0001: marked Superseded by ADR-0003.
- ADR-0002 (new): north star + fused per-call core.
- ADR-0003 (new): Rust-native trunk SIP, no SBC shield.
- ADR-0004 (new): GPL-3.0-or-later license.
- ADR-0005 (new): Valkey as event bus + state store.
- ADR-0006 (new): WebRTC-first ingress; SIP endpoint deferred.
- vision-revision spec: status -> Ratified 2026-06-26.
2026-06-28 09:33:29 -04:00

77 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0003 — SIP strategy: Rust-native trunk SIP, no SBC shield
- **Status:** Accepted
- **Date:** 2026-06
- **Supersedes:** [ADR-0001](0001-sip-strategy.md)
- **Origin:** [vision-revision](../superpowers/specs/2026-06-26-vision-revision-design.md) §5
## 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 14 (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