Trust
What Switchyard proves, and what it does not claim.
Every statement on this page is backed by the implementation, the test suite, or a recorded test run in the repository. Where a number appears, the hardware, software, topology, and duration it was measured under appear with it.
Guarantees
What Switchyard guarantees
Only guarantees supported by the implementation and its tests. Nothing here is aspirational.
PostgreSQL is the durable source of truth. PubSub carries notifications, not state.
Events are persisted before Switchyard returns acceptance.
Delivery is at least once; duplicates remain possible and are recorded as duplicate hints.
Important work does not live only in memory. Delivery and maintenance work runs on Oban durable jobs.
Private-network delivery uses the authenticated relay.
Receipts and evidence bundles are sanitized and versioned; raw bodies, header, cookie, and signature values, tokens, and secret material are structurally absent from exports.
Non-claims
What Switchyard does not claim
Stated plainly, because these are the claims that usually get webhook tooling in trouble.
Exactly-once delivery. Delivery is at least once; duplicates remain possible.
A Kafka replacement.
A general message broker.
An ETL platform.
A workflow automation platform.
A payment-grade delivery service.
A full API gateway.
An arbitrary code-execution environment.
System model
The durable system model
How the pieces fit together to make the guarantees above hold.
- PostgreSQL source of truth
- Events, deliveries, and operational history are rows in PostgreSQL. If it is not committed, Switchyard does not claim it happened.
- Persist before accept
- The ingest path commits the event before the sender receives an acceptance response.
- Oban durable work
- Delivery and maintenance jobs live in the database-backed Oban queues, so a restart does not strand work that exists only in process memory.
- At-least-once semantics
- A delivery can be attempted more than once. Duplicates remain possible and are surfaced as duplicate hints, never hidden.
- Local relay boundary
- The relay runs next to your services, authenticated, so the Switchyard server never dials your private network directly.
- Remote destination restrictions
- Outbound delivery is constrained to configured destinations; the delivery path does not fetch arbitrary addresses.
- Audit history
- Decisions, attempts, and operator actions are recorded so you can reconstruct what happened after the fact.
- Redaction and evidence boundaries
- Receipts and bundles are sanitized and versioned. Masked fields carry a masked marker with null values; secret material is structurally absent.
Tested limits
The v0.9 two-hour soak, with its full context
In a 2-hour loopback soak on an Apple M1 Pro (16 GiB), Switchyard accepted 142,120 of 142,120 offered events and sustained 19.74 events/s. Those numbers mean nothing without the scenario they were measured in, so here is the scenario.
Scenario and configuration
- Hardware
- Apple M1 Pro, 10 schedulers, 16 GiB RAM
- Software
- Elixir 1.19.5 / OTP 28 / PostgreSQL 17 (Docker) / released CLI 0.8.0 / released relay
- Topology
- Single loopback HTTP server, disposable database, default Oban queues (
deliveries: 10,maintenance: 1), PostgreSQL pool 10 - Concurrency
- 25
- Duration
- 7,200 seconds (2 hours)
- Seed
- 90045, run 2026-07-23
Results
- Offered / accepted
- 142,120 / 142,120
- Completed
- 142,110 (10 non-success terminal deliveries in one batch)
- Sustained throughput
- 19.74 events/s
- Capture latency p50 / p95 / p99 / max
- 130.3 / 254.5 / 348.0 / 2,445.8 ms
- Delivery latency p50 / p95 / p99 / max
- 64 / 170 / 224 / 2,340 ms
- Errors / timeouts / duplicates
- 2 / 1 / 0
- Hard invariants
- 0 before the run, 0 after
- Retention under load
- 120 cleanup runs deleted 137,019 events at 19.03 events/s, matching ingest
- First bottleneck
- The same-host load generator exceeded its 1-second batch budget 11 times across the 2 hours. Network and IO were not the bottleneck.
Classification
The strict harness rule classifies this run as Invalid: it requires zero errors and accepted equal to completed, and this run ended 10 rows apart. A human reviewed the failure pattern and accepted the numbers on 2026-07-23, because the system remained healthy throughout: hard invariants at 0 before and after, 0 duplicates, and a 0.0070% non-success rate across 142,120 events. The strict rule, not the system, was the problem. Both error batches are recorded in full in the receipt.
The soak ran against a loopback HTTP server. It excludes Internet and TLS behavior entirely. A tested limit is a conservative passed boundary under the recorded scenario — not a universal capacity claim, and never a product maximum.
The complete record, including raw receipts and per-table database growth, lives in the repository: docs/v0.9/TESTED_LIMITS.md.
Separately, a short-mode smoke run (seed 90045, 2026-07-23) passed all six harness scenarios as Valid with 0 hard invariant violations. That is harness smoke — a verification practice, not a performance result, and not publishable as one.
Release verification
The gates every release passes
These are the commands that run before a release ships. Each one is in the repository and safe to run yourself.
mix setup # deps, database, migrations, assets
mix test # the full test suite
mix quality # format check, warnings-as-errors, Credo --strict
mix security # deps.audit, hex.audit, Sobelow
mix check # fast gate: format, compile, Credo, security, tests
mix check.all # everything in check, plus Dialyzer
bin/verify-v0.9 # the v0.9 operator exit gate
bin/verify-quickstart # the five-minute walkthrough, end to end mix setup- Proves a fresh checkout can be brought to a working development state.
mix test- Proves the test suite passes against the real persistence layer.
mix quality- Proves the code is formatted, compiles with warnings as errors, and passes Credo in strict mode.
mix security- Proves dependencies and Hex packages audit clean and Sobelow finds no flagged issues.
mix check- Proves the fast gate passes: format, compile, Credo, security, and tests in one run.
mix check.all- Adds Dialyzer static analysis on top of the fast gate.
bin/verify-v0.9- Proves the v0.9 operator exit gate passes against the released artifacts.
bin/verify-quickstart- Proves the documented five-minute walkthrough actually works, end to end.
These gates verify code and operator behavior. They do not prove marketing-page visual quality, and this site does not pretend they do.
See the loop, then read the code.
Walk the diagnostic loop on sample data, or go straight to the repository and run the verification gates yourself.