Service tiers¶
Status: Current | Last reviewed: 2026-09-01
36 services live under apps/. They do not all matter equally, and
pretending otherwise is expensive in both directions: it lets a service on the payment
path ship with no tests because "nothing has tests", and it lets a demo bridge block a
release because "everything needs tests".
This page assigns each service a tier and states the quality bar that tier owes. A tier is a commitment, not a description — Tier 1 means a regression there is a customer incident, so the gate exists whether or not anyone feels like writing the test today.
What the tiers mean¶
| Tier | Meaning | Bar it owes |
|---|---|---|
| 1 | On the path of a real customer conversation, or holds money, credentials, or the authoring source of truth. A regression is an incident. | Unit tests gated in CI + E2E coverage of its golden path + docs current |
| 2 | Per-vendor connectors and build-time services. A regression breaks one integration or one publish, loudly, and usually for one customer. | Unit tests for its core logic gated in CI + a service page under 03-services/ |
| 3 | Demos, optional/legacy services, single-purpose lambdas, and flag-off features. | Builds in CI + its README states what it is and whether it is live |
Tier is about blast radius, not code size. code-executor is one small FastAPI app and
is Tier 1 because it runs tenant-authored Python in the same cluster as
MASTER_ENCRYPTION_KEY. crm-dashboard is a whole Next.js app and is Tier 3 because it is
a restored demo.
Tier 1 — ten services¶
Every one of these is gated in test.yml as of
2026-08-12.
| Service | Language | Why Tier 1 | CI job | Unit test files |
|---|---|---|---|---|
| ai-manager | Node (Next.js) | Agent Studio: the authoring surface and the API in front of every table | unit (ai-manager) |
78 |
| ai-orchestrator | Python (Pipecat) | The live call. Every voice conversation runs here | unit (ai-orchestrator) |
99 |
| conversation-api | Python (FastAPI) | The conversation store, and the sole authority for customer-auth assurance and payment outcomes | unit (conversation-api) |
16 |
| surface-app | Node (Next.js) | The one embed UI every CRM surface wraps | unit (surface-app) |
15 |
| ari-controller-node | Node | Call control, and the CCaaS default-deny allow-list gate | unit (ari-controller-node) |
5 |
| payment-vault | Python (FastAPI) | The PCI boundary — the only component that ever sees a PAN | unit (payment-vault) |
9 |
| collab-gateway | Node (TypeScript) | Owns the Y.Doc → Postgres flush; a dropped key deletes authored config | unit (collab-gateway) |
2 |
| async-agent | Python (LangGraph) | The workflow runtime: email, SMS, and every scheduled agent action | unit (async-agent) |
32 |
| agent-host | Python (FastAPI/MCP) | Hosts the MCP tools every agent calls, including A2UI and warm transfer | unit (agent-host) |
4 |
| code-executor | Python (FastAPI) | Executes tenant-authored Python; its sandbox is a security boundary | unit (code-executor) |
1 |
async-agent, agent-host, and code-executor are Tier 1 by an explicit maintainer
decision (2026-08-11): the async path is a product surface in its own right, and those two
are what it runs on.
Golden-path E2E coverage is the Playwright suite,
gated by the browser E2E (authoring half) job. It covers the ai-manager authoring half
end to end. The live-call half needs provider credentials and skips by capability gate
rather than by timeout — which means the Tier-1 E2E bar is met for the authoring path and
open for the voice path. See that page for what is and isn't covered.
Tier 2 — five services¶
| Service | Language | Why Tier 2 | Unit test files |
|---|---|---|---|
| genesys-connector-go | Go | AudioHook BYOC terminator — the busiest CCaaS integration | 2 |
| connect-scv-translator | Node | Salesforce SCV BYOT bridge; browser-side live translation | 0 |
| media-proxy | Go | RTP/WebRTC media plane | 7 |
| catalog-builder | Node | Compiles and publishes A2UI catalogs | 4 |
| event-publisher | Go | Postgres NOTIFY fan-out across clouds | 0 |
None of these is gated in CI yet. connect-scv-translator and event-publisher have
no test files at all. That is the Tier-2 gap, and it is the next test-floor task after
Tier 1.
Tier 3 — everything else¶
The remaining 19 services: the per-vendor connectors not listed above
(webex-connector-go, webex-app-manager, genesys-agent-go,
five9-voicestream-connector-go, connect-kvs-connector, chime-sip-attrs), the
lambdas (email-ingest, notification-ingest, salesforce-forward,
scv-transcript-gate, connect-session-start, authentik-connect-sync), the sandboxed
runners (antigravity-runner, workspace-agent-runner), multimodal-service, status-page,
code-server, janus-gateway, and teams-agent-gateway.
Tier 3 owes a build and an honest README. It does not owe a test suite, and adding one is not a priority call anyone needs to justify avoiding.
One placement is worth revisiting:
multimodal-servicerenders A2UI, which is on the live conversation path when an agent draws a surface. It is Tier 3 becausesurface-appand the shared@trueserve/a2ui-reactpackage carry the rendering that customers actually see.
What was true before this page¶
The tiering exercise was worth doing for what it found, and the findings are the argument for keeping the gates:
- Five of the ten Tier-1 services were not gated in CI at all —
ari-controller-node,payment-vault,agent-host,code-executor,collab-gateway. Four of them had real suites that simply never ran. code-executor's suite was 13-of-25 red and had been for an unknown length of time. A symlinked interpreter in itsconftest.pymeant the sandbox subprocess could not importtsf_runtime. Nobody noticed, because nothing ran it.payment-vault's documented way to install its test runner had never worked.pip install -e ".[dev]"fails outright — it is a flat-layout application with two top-level packages, so setuptools refuses to auto-discover. The pins moved torequirements-test.txt.collab-gatewayhad zero tests, while owning the flush that decides whether authored agent config reaches Postgres.agent-host's suite depended on an ambientARI_CONTROLLER_INTERNAL_TOKEN— eight tests passed on a developer shell that had sourced the dev env and failed on a bare checkout, which is what CI is.
Writing the missing tests also turned up two live product bugs, both silent:
- Fail-open: the
?tools=andmultimodal_clients.tool_scopetool filter was installed only when an unrelated feature flag was on, so both narrowings were ignored in every environment (agent-host). - Fail-closed: collab-gateway's copy of ai-manager's permission map was never updated for the five-permission consolidation, so catalog presence and catalog writes were broken for every non-platform-admin (collab-gateway). That one surfaced from a doc task, not a test task — the doc had been right and the code wrong, and rewriting the doc to match the code tripped an unrelated audit test.
A gate that has never run is not a passing gate, and a doc that agrees with the code is not necessarily a correct doc.
Adding a service¶
Assign a tier in the same PR that adds the service, and wire the bar it owes:
- Add a row to the services catalog and a service page.
- Add it to the tier table here.
- Tier 1 or 2 → add its suite to
test.yml. Tier 1 also means a golden-path E2E spec. - State the tier in the service's own
README.md, in the first section, so someone working in the directory sees it without reading this page.
If it is not obvious which tier a service belongs to, the question to ask is what happens to a customer conversation when this breaks — not how complicated the service is.
See also¶
- Services catalog — every service, grouped by role
- Browser E2E tests — the Tier-1 golden-path suite
test.yml— the gates themselves- SaaS hardening plan — where this tiering came from