Files
rutster/docs/adr/0005-event-bus.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

63 lines
3.3 KiB
Markdown

# ADR-0005 — Event bus & state store: Valkey
- **Status:** Accepted
- **Date:** 2026-06
- **Closes:** the event-bus open-decision carried in the founding docs (NATS vs. Kafka vs. Redis Streams)
## Context
The fused per-call core ([ADR-0002](0002-north-star-and-fused-core.md)) needs:
- a **bus** for cross-service control events (replacing Asterisk's internal Stasis bus for
anything crossing the boundary),
- a **KV state store** replacing `astdb` + sorcery / realtime config state,
- **presence sets** for MWI/BLF signaling aggregation.
The founding docs listed the choice as NATS vs. Kafka vs. Redis Streams.
## Decision
**Valkey** — the Linux-Foundation BSD-3-Clause fork of Redis 7.2.4 (wire-protocol-compatible drop-in).
### Why not "Redis"
Redis relicensed in March 2024 to **RSALv2 + SSPLv2****not OSI-open-source**, and license-incompatible with this project's posture (FOSS-clean + GPL-3.0-or-later per [ADR-0004](0004-license.md)).
Recommending "Redis" undercuts the data-ownership pillar ([ADR-0002](0002-north-star-and-fused-core.md)) and the clean-license story. Valkey is *Redis-the-thing* with a compatible license, maintained by the community (AWS, Google, Oracle, et al.).
### Why Valkey fits the wedge specifically
- **Collapses bus + state store + presence into one dependency.** A solo operator runs one process
with `compose up`. NATS is a cleaner pure-bus but doesn't also replace `astdb`/sorcery; Kafka is
structural overkill at self-hosting scale and violates the one-binary / operational-simplicity
pillar.
- One tool, three roles:
- **streams + consumer groups** → CDR/CEL/analytics pipeline fanout and replay,
- **pub/sub** → presence / MWI / BLF signaling,
- **KV** → state store (config + runtime state replacing `astdb`/sorcery).
### Alternatives
- **Kafka — rejected.** Structural overkill at self-hosting scale; operational weight violates
the operational-simplicity pillar.
- **NATS — retained as a config-pluggable alternative.** An operator outgrowing Valkey (notably
needing NATS JetStream's durable streaming model at larger scale) can swap it in. The bus
backend seam stays **pluggable** at the config boundary, not architecture-load-bearing.
## Constraints (load-bearing, not preferences)
1. **The 20ms media loop never rides the bus.** Media timing stays in-core on dedicated timing
threads ([ADR-0002](0002-north-star-and-fused-core.md) §7; vision-revision §7). The bus carries
control / cross-service events only — not latency-pinned media — so Valkey's sub-ms local
latency is plenty.
2. **The bus is NOT the source of truth for billing- or call-loss-critical state.** Valkey
persistence (RDB/AOF) is async-ish — fine for transport / replay / fleeting retention, **wrong**
for "the CDR that proves what we billed." CDR and recordings emit **durably to object storage**
in their own services; the bus only *flows* events into that pipeline and lets services *react*.
## Consequences
- **Positive:** one OSS dep for bus + state + presence; self-hostable and license-clean; pluggable
to NATS later without architecture changes; aligns with operational-simplicity.
- **Negative:** Valkey is "good enough" at each role, not best-of-breed for each — accepted
deliberately for the ops-simplicity pillar.