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.
84 lines
4.7 KiB
Markdown
84 lines
4.7 KiB
Markdown
# ADR-0001 — SIP strategy: native Rust core behind a Kamailio + rtpengine edge
|
|
|
|
- **Status:** ~~Accepted~~ **Superseded** (2026-06)
|
|
- **Date:** 2026-06
|
|
- **Supersedes:** the `🔌 Edge/FFI (pjproject)` disposition in PORT_PLAN.md §1 (historical)
|
|
- **Superseded by:** [ADR-0003](0003-sip-rust-native-trunk.md) — Rust-native trunk SIP, no SBC shield
|
|
|
|
> **Superseded.** Kept as the historical record of the layered "own the Rust parser, front with
|
|
> Kamailio + rtpengine" plan. Reversed under the AI-era contact-center scope (the device interop
|
|
> tail collapses to a few documented trunk providers). See [ADR-0003](0003-sip-rust-native-trunk.md).
|
|
|
|
## Context
|
|
|
|
SIP is rutster's highest-risk subsystem. Three forces pull against each other:
|
|
|
|
1. **The security thesis.** rutster's headline is "memory-safe by construction, fuzzed
|
|
parsers, no buffer-overflow/RCE class." The SIP parser is the *first* thing hostile
|
|
internet packets touch — the most exposed surface in the whole system.
|
|
2. **The interop tail.** The hard, *unbounded* part of SIP isn't RFC 3261 — it's 20 years
|
|
of device/carrier/NAT quirks. Owning that tail forever is what killed `chan_sip` and
|
|
drove Asterisk to retreat to pjproject. It is a permanent tax, not a one-time cost.
|
|
3. **Time-to-first-call.** We want interoperable SIP trunking early, without blocking on
|
|
a young stack maturing.
|
|
|
|
These don't resolve as a single build-vs-buy call, because they live at *different
|
|
layers* of SIP:
|
|
|
|
| Layer | CVE-class risk | Interop-tail cost | Verdict |
|
|
|---|---|---|---|
|
|
| Parser (bytes off the wire) | **Highest** | Low | **Own in Rust** — cheap, and the thesis depends on it |
|
|
| Transaction / dialog / timers | Medium | Medium (bounded by RFCs) | Own over time; sans-IO Rust fits |
|
|
| Interop tail (UA quirks, NAT, carrier glare) | Low | **Unbounded, forever** | **Rent** — this is what a mature edge is for |
|
|
|
|
Pure FFI to pjproject was rejected: it pays the interop cost *and* puts C at the most
|
|
exposed seam, gutting the memory-safety headline at the one place it matters most. It is
|
|
the right default for a generic PBX and the wrong one for a security-first platform.
|
|
|
|
## Decision
|
|
|
|
A **layered** strategy:
|
|
|
|
1. **Own the SIP parser in Rust, from day one.** Build on `rsip` (message types/parsing)
|
|
and the `ezk-sip` family (sans-IO transaction/dialog core). No hostile bytes ever hit
|
|
a C parser. This is non-negotiable — the security story requires it.
|
|
2. **Front the public SIP edge with Kamailio + rtpengine.** Kamailio handles signaling
|
|
(proxy, registrar, TLS termination, topology hiding, rate-limiting, anti-scan);
|
|
**rtpengine** handles the media leg (kernel-forwarded RTP relay, SRTP/DTLS-SRTP
|
|
bridging, ICE, NAT). This is the most-proven, most-scaled FOSS SIP edge — carrier-grade
|
|
on the open internet. It absorbs the interop tail and gives us a hardened edge in weeks.
|
|
3. **Grow the native Rust transaction/dialog core *behind* that shield.** It matures in
|
|
production where its early bugs aren't customer-facing outages. As it hardens,
|
|
Kamailio's role shrinks from "does all the SIP" → "just the public edge" → optionally
|
|
nothing.
|
|
|
|
**Chosen edge: Kamailio + rtpengine** (over OpenSIPS and drachtio). Rationale: largest
|
|
proven deployment pedigree and max-scale proxy track record; rtpengine is the canonical
|
|
media companion. OpenSIPS and drachtio remain valid alternatives (drachtio noted for a
|
|
future *programmable* edge once rutster's API model is solid).
|
|
|
|
## Topology
|
|
|
|
```
|
|
hostile internet trusted core
|
|
───────────────► Kamailio ──signaling──► rutster control plane
|
|
(SIP trunks, + rtpengine ──media─────► rutster media plane
|
|
far-end UAs) (edge SBC) (native Rust SIP core
|
|
grows here, behind the shield)
|
|
```
|
|
|
|
WebRTC ingress is unaffected and ships *first* (WebRTC signaling is app-defined, not SIP),
|
|
so first-call does not block on any of this.
|
|
|
|
## Consequences
|
|
|
|
- **Positive:** security headline holds (Rust parser at the edge of *our* trust boundary);
|
|
interoperable SIP trunking available early; native stack de-risked by maturing behind a
|
|
proven shield; no pjproject license/threading/`unsafe` entanglement.
|
|
- **Negative / costs:** an operational dependency on Kamailio + rtpengine (config,
|
|
deployment, expertise) for the foreseeable future; two media-handling points during the
|
|
shield phase (rtpengine at the edge, rutster media plane inside) to reason about.
|
|
- **Open follow-ups:** Kamailio↔rutster control-plane integration (KEMI vs. dispatcher vs.
|
|
a custom control channel); how far inward rtpengine relays vs. rutster terminating media
|
|
directly; the graduation criteria for retiring the shield.
|