# ADR-0008 — The FOB and the green zone: the build-vs-reuse doctrine - **Status:** Accepted - **Date:** 2026-06 - **Origin:** 2026-06 strategic-relevance review — names the boundary doctrine implicit across ADRs 0002–0007 and makes it a mechanical rule every contributor (human or agent) applies the same way. - **Amends:** `docs/ARCHITECTURE.md` (adds the organizing metaphor), `AGENTS.md` (adds it to "key decisions") - **Related:** [ADR-0002](0002-north-star-and-fused-core.md) (the boundary this rule governs), [ADR-0007](0007-trunk-rented-transport.md) (a green-zone call), [ADR-0005](0005-event-bus.md) (a green-zone call), [ADR-0006](0006-ingress-posture.md) (arm's-length out-of-tree adapters) ## Context Across ADRs 0002–0007 one criterion kept deciding calls without ever being named: **what does rutster build and own, and what does it reuse?** Fused vertical (0002), rent the trunk (0007), bundle Valkey (0005), the out-of-tree SBC (0006) — all the same judgment, applied case by case. A solo build cannot re-derive that judgment per decision, and multiple coding agents now work this repo and need one explicit, mechanical rule so they classify consistently. The failure mode this prevents is **not-invented-here**: rebuilding mature, actively-maintained OSS inside the core and drowning the scarce solo-years in undifferentiated plumbing. The from-scratch Rust trunk-SIP stack (superseded by [ADR-0007](0007-trunk-rented-transport.md)) was exactly that mistake. Stated as one image: **stop building a fortress; build a secure base of operations.** Harden and own the core — the **FOB** (forward operating base). Operate through a trusted, actively-maintained OSS perimeter — the **green zone**. Leverage, not autarky. ## Decision Every capability is classified **FOB** or **green zone**. ### FOB — build it, own it, in Rust Memory-safe Rust, owned, fuzzed, **inside the trust boundary** — the surface you would certify (PCI / HIPAA / TCPA). A capability is admitted to the FOB **only if it passes at least one** of three tests: 1. **Hot path** — it runs on the per-call real-time loop, where a GC pause / jitter / an extra network hop would degrade call quality. *(media termination, jitter buffer, pacing, the reflexes.)* 2. **Security-constitutive** — it *is* the auditable boundary: the spend/abuse gate, the trust-domain edge, the audit surface. A 3-vendor chain structurally cannot enforce it. *(spend gate, the boundary itself.)* 3. **Differentiating** — it is the thing no competitor ships and a reason rutster exists. *(the reflex loop, the agent tap, the contact-center domain logic.)* The FOB **may link mature OSS for internals** — libopus (codec), `str0m` (sans-IO WebRTC), speexdsp (DSP) — as **trusted vendored dependencies**. Linking a maintained library to *implement* an FOB capability is not a violation: you don't rewrite a codec. What makes the capability FOB is that rutster owns it, it passes an FOB test, and the wire-facing parser is memory-safe Rust. Any vendored dep that parses hostile bytes is fuzzed. **Current FOB:** media termination (`rutster-media`, on `str0m`) · real-time reflexes (VAD/barge-in, jitter, pacing) · call model (`rutster-call-model`) · the agent tap (`rutster-tap`) · the spend/abuse gate (`rutster-spend`) · the control API + the state/bus **trait** (`rutster`). ### Green zone — reuse it, at arm's length Trusted, **actively-maintained** OSS or an external managed service, **reused at arm's length** — its own process, container, or trust domain, **never in the FOB's address space**, so its failures cannot corrupt the core. A capability belongs here if it **fails all three FOB tests** and a trusted, maintained project already does it well. **Current green zone:** Valkey (state store + bus, [ADR-0005](0005-event-bus.md) — bundled in the all-in-one image, external in the modular layout) · the carrier trunk (CPaaS raw-media fork / out-of-tree SBC, [ADR-0007](0007-trunk-rented-transport.md)) · the agent brain (OpenAI Realtime or a self-hosted STT/LLM/TTS) · the reference GUI (admin portal + call-flow builder — a pure API client) · object storage (recording/CDR durability) · KMS/Vault (secrets) · the OTel collector · the container supervisor (tini/s6). ### The "actively maintained" gate is load-bearing A green-zone dependency the FOB relies on **must** be healthy: maintained, released, production-grade, not bus-factor-1. This single gate is what: - **excludes** a first-party Rust SIP stack (`ezk`, bus-factor-1 / pre-1.0 — [ADR-0007](0007-trunk-rented-transport.md)) and `webrtc-rs` (perpetual re-architecture); - **admits** Valkey (healthy), and `str0m` **for WebRTC** (its maintained sweet spot) — while rejecting `str0m` for SIP (out of scope there, "not for production"). Re-audit periodically — a project can go cold (e.g. FreeSWITCH's OSS line). A green-zone dep that stops being maintained is a defect to resolve, not a fixture. ## How to apply (every contributor, human or agent) Before building a subsystem or adding a dependency, run the test: 1. **Does it pass an FOB test?** (hot-path **or** security-constitutive **or** differentiating) - **No** → green zone. Find the trusted, actively-maintained OSS/service and integrate it **at arm's length** (separate process / container / trust domain). **Do not rebuild it in-core.** - **Yes** → build it in the FOB, in Rust. For *internals* a mature library already solves (codecs, DSP), link that library as a trusted vendored dep — don't rewrite it. Fuzz any vendored parser that touches hostile bytes. 2. **Is the OSS you're about to depend on actively maintained / production-grade?** If not, it is not eligible for anything the FOB depends on — find another, or scope the need away. When in doubt, default to **green zone**. The FOB earns its members; it does not collect them. ## Consequences - **Positive:** one mechanical rule, applied identically by every human and agent; the solo-years concentrate on the FOB (the only part that differentiates); the memory-safety claim becomes *precise* rather than an over-claim; retroactively consistent with ADRs 0002–0007. - **Negative:** the green zone is a dependency-trust surface that must be re-audited ("actively maintained" can decay); arm's-length integration costs some glue versus pulling things in-process. - **Restated pillar:** **memory-safe = the FOB** (100% Rust at the boundary that holds the call), with mature OSS trusted at arm's length around it — *not* a claim that every byte in the deployment is Rust (libopus, Valkey, the SBC are not). ## Worked example — deployment packaging The all-in-one container is the doctrine made physical: the **FOB binary** + bundled `valkey-server` (green zone) + the reference GUI (green zone), supervised in one container; point it at a brain + CPaaS, `docker run`, taking calls. The modular/compose layout splits the same green-zone services out to scale. Same FOB binary underneath; only the state/bus backend seam differs (bundled vs external). *(The deployment topology itself may get its own ADR once that design closes.)* ## References - [ADR-0002](0002-north-star-and-fused-core.md) — fused per-call vertical + composable platform (the boundary this rule governs) - [ADR-0007](0007-trunk-rented-transport.md) — rent the trunk (a green-zone classification) - [ADR-0005](0005-event-bus.md) — Valkey (a green-zone classification) - [ADR-0006](0006-ingress-posture.md) — out-of-tree adapters (arm's-length integration)