11 · Whole-system test
The whole system, tested for real
A working proof on real clusters: new platform = just a repo, new service = just a repo, failovers, Logto across regions. Results land here when the test ends.
- Owner ruling: build a whole working proof, keep cost low. DECIDED · owner D37
- It may use ProtoDurian and up to USD 100. DECIDED · owner D38
- Cloudflare only under
dpoc.; free Vercel is fine. DECIDED · owner D39specpenguin. dev
Already proven: a live move under heavy traffic
- Three machines in Singapore: an old Postgres, a new Postgres, and 8 app processes with the library. TESTED · spike L
- A no-error move works up to 100,000 writes a second, plus 300,000 reads a second. Every rate: 0 failed, 0 lost, 0 doubled. TESTED · spike L
- Writes wait a moment once; reads never pause. TESTED · spike L
Bar length is on a log scale (each step is 10× longer). Every rate: 0 failed, 0 lost. Reads never paused.
The numbers as a table
| Writes / s | Verdict | Failed / lost | Hold |
|---|---|---|---|
| 1,000 | PROVEN | 0 / 0 | 76 ms |
| 5,000 | PROVEN | 0 / 0 | 54 ms |
| 20,000 | PROVEN | 0 / 0 | 75 ms |
| 50,000 | PROVEN | 0 / 0 | 509 ms |
| 100,000, 2 subscriptions | PROVEN | 0 / 0 | 3.2 s |
| 100,000, 1 subscription | PROVEN | 0 / 0 | 6.1 s |
| 100,000, 8 subscriptions | PROVEN | 0 / 0 | 8.1 s and 18.1 s |
| 100,000, 4 subs, small batches | NOT REACHED | – | replication never caught up |
- While writes wait, they sit in a queue in the app's memory: 2.58 million writes waited 46 s across 8 apps, then went through in under 7 s with 0 errors. TESTED · spike L
- So memory is not what breaks first; the caller's own time limit is. TESTED · spike L
The whole-system test
How it works
Copied from poc/HOW-IT-WORKS.md as it stood at 2026-11-12 07:02 UTC. Its layout here is plain for now.
Answer first: a team makes a GitHub repo and pushes a version tag. Everything after that is automatic: the platform and service are found by their repo names, Kargo walks the version through the landscapes, Argo CD deploys it, and T3 (our operator) builds the databases, writes the secrets, keeps DNS pointed at healthy clusters, and publishes the address books that let apps survive a dead cluster or a dead DNS host.
Status tags used below: BUILT+TESTED (ran in the PoC, numbers in REPORT.md / drills.json) · BUILT (running, drill pending) · DESIGN ONLY (from the corpus, not built here) · CHANGED (the design had to change to work; see CHALLENGES.md).
1. The pieces (what exists)
| Piece | Where | Who changes it |
|---|---|---|
dpoc-fleet repo | GitHub ProtoDurian | 👤 people: registry/ (landscapes, clusters, accounts) · 🧱 rare: machinery/ |
dpoc-fleet-state repo | GitHub (mirror of the bot git server) | 🤖 machines only: T3 writes stubs, Kargo writes versions |
dpoc-<platform>. | one repo per platform | 👤 platform team: platform. (landscapes, release order, maturity) |
dpoc-<platform>. | one repo per service | 👤 service team: code + 2 charts |
| Primordial cluster | dpoc-prim | runs Argo CD, Kargo, T3. Not in the request path. |
| Workload clusters | pichu-opal, raichu-opal, raichu-ruby, ampharos-opal | run the apps, one Logto per landscape |
| T3 operator | on Primordial | cluster, materializer, dependency, logto, traffic, edge controllers |
Repos in the PoC: dpoc-fleet, dpoc-fleet-state, dpoc-nitroso., dpoc-nitroso. (bun API), dpoc-nitroso. (frontend), dpoc-aldehyde., dpoc-aldehyde. (Logto), and – created during the run – dpoc-argon., dpoc-argon..
Picture: see the diagram above.
2. Who writes what (every folder has ONE kind of writer)
| File | Writer | When | Depth from a human act |
|---|---|---|---|
dpoc-fleet/ | 👤 person, by PR | a new cluster | 0 |
dpoc-fleet/ | 🧱 person, rare | the system itself changes | 0 |
dpoc-fleet-state/ pin: | 🤖 Kargo | every release, per stage | 2 (tag → CI → Kargo) |
| same file, first creation (empty pins) | 🤖 T3 materializer | a repo dpoc-nitroso. appears | 1 |
same file, values: | 👤 person, emergency only | rare | 0 |
dpoc-nitroso. | 👤 platform team | new landscape for the platform | 0 |
dpoc-nitroso. (Database, KeyValue...) | 👤 service team | needs a dependency | 0 |
Secret tin-database-main in every cluster | 🤖 T3 dependency controller | record Ready / rotation / move | 1 |
DNS records under c. and cf. | 🤖 T3 traffic controller | every 5 s, only on change | 1 |
Edge docs fleet., selector/, catalog/ | 🤖 T3 edge controller | on change | 1 |
Row file (contract), e.g. platforms/:
platform: nitroso
service: tin
landscape: pichu
pin: {primordial: "1.0.0", chart: "1.0.0", image: "1.0.0"} # Kargo; "" = not deployed
values: {} # human emergency override, Kargo never touches it
CHANGED: the machine rows live in their own repo (pick 4b) and are written to a bot git server first, then mirrored to GitHub (the org blocks deploy keys; CHALLENGES 1).
3. Deploy order (empty system → first user), as run
- L0 seed (by hand, once): clusters exist; Argo CD + Kargo + cert-manager on Primordial; Secrets for vendor tokens, the CA, one credential per cluster;
kubectl apply -f machinery/.fleet-root. yaml - fleet-root syncs the CRDs, T3, the
platformsAppSet, thebaselineAppSet andregistry/(Landscapes, ClusterRegistrations). - T3 cluster controller: each ClusterRegistration → Argo CD cluster Secret with labels
landscape,mark+ a gateway certificate in that cluster. - baseline AppSet: every labelled cluster gets the gateway health responder + default TLS store (seen: all 4 clusters in < 1 min, no human step).
- platforms AppSet finds
dpoc-*.repos → onecarbon platform-<p>app → Kargo Project + the platform's AppSets. - T3 materializer finds
dpoc-<p>.repos → stub rows for every landscape in<svc> platform..yaml - Per service: a pipeline app renders the Kargo Warehouse + Stages from
stages: [pichu, [raichu, ampharos]]. - Logto first (platform
aldehyde, servicelithium): its Database record → T3 makes a Neon database in that landscape's region → Logto starts (2 replicas per cluster) → T3 boot-seeds its own admin app. - Services (tin, web): Database/KeyValue/Store/Email + LogtoApp records → T3 builds them → app pods start (they cannot start without the database secret) → Argo CD reports Healthy only when the records are Ready.
- Traffic: T3 probes every cluster every 5 s and writes the A-sets; edge docs are published to two hosts.
Picture: see the diagram above.
4. Release flow (v1 → v2, a broken v3)
- One version = image + app chart + primordial chart at the same semver; a half-published release makes no Freight.
- Kargo writes the pin into the first stage's row; the Stage is Healthy only when every Application of that row (Primordial + every cluster) is Healthy at that version; then the next stages get it.
- A broken version stops at the first stage (pichu); raichu and ampharos stay on the old one. BUILT (drill 3 numbers in drills.json).
5. The controllers (T3, one process on Primordial)
| Controller | Input | Output | Notes |
|---|---|---|---|
| cluster | ClusterRegistration | Argo CD cluster Secret (+labels), gateway cert (SAN *. per platform) | CHANGED: cert re-issued when a platform appears |
| materializer | GitHub repo names dpoc-<p>. | stub rows in fleet-state | never edits/deletes a row; unauthenticated GitHub = 60 calls/h → 2-min poll (CHALLENGES 3) |
| dependency | Database, KeyValue, Store, Email (dictionary-keyed modules) | Neon / PlanetScale / Upstash / Tigris resources + Secret <svc>-<class>-<module> in every cluster of the landscape | ledger in Tigris (intent → create → confirm), two-generation rotation, one live vendor move |
| logto | Logto per landscape + LogtoApp records | boot-seed admin app, API resources, apps, client ids as Secrets | create-once (the Secret is the commit point) |
| traffic | ClusterRegistration + 5 s probes | A-sets on Route 53 + DigitalOcean (main root) and Cloudflare (spare root) | brakes: never remove the last address, freeze when > half look down, lease so only one writer |
| edge | platforms × landscapes × services | Doc A/B/C on Tigris + S3/CloudFront | monotonic versions, 60 s cache |
6. Names and DNS roots
- App name =
<service>.(LPSM reversed), e.g.<platform>. <landscape>. <root> tin..nitroso. raichu. c. dpoc. specpenguin. dev - Logto issuer per landscape:
https:/– baked into apps, never read from a doc./ lithium. aldehyde. <landscape>. c. dpoc. specpenguin. dev/ oidc - Roots (PROPOSAL-DNS option 4, with the hosts we have):
| Root | Served by | Role |
|---|---|---|
c. | Route 53 and DigitalOcean DNS (one zone, two hosts; Cloudflare's delegation lists both) | main name |
cf. | Cloudflare | spare name (stand-in for a spare domain on another TLD) |
- Records per root R and landscape L:
L.A = healthy cluster IPs (TTL 60) ·R *.CNAME →L. R L.·R <mark>.A = one cluster (dark-verify).L. R
Picture: see the diagram above.
7. Edge documents (the address books)
| Doc | Path | Holds | When the client reads it |
|---|---|---|---|
| A fleet | fleet. | where the other docs live (Tigris + CloudFront) | refreshed in the background |
| B selector | selector/ | which landscapes the platform runs in (names, regions) | sign-up, to pick a home |
| C catalog | catalog/ | per landscape × service: ordered full addresses (main root first, spare after) | only when the rescue router trips |
Hosts: Tigris public bucket dpoc-edge and AWS S3 + CloudFront. No signing: the client only accepts addresses ending in ..
8. Sign-in per region (Logto)
- One Logto issuer per landscape (pichu, raichu, ampharos), each with its own database in its own region (Neon Singapore / Oregon), at least 2 replicas per cluster; raichu runs on 2 clusters = 4 replicas sharing one database.
- A user's home landscape is a claim; the client always talks to its home's issuer and API. A dead home region = restore event, not a routing event (home-sharding).
- Access token 10 min, refresh token 14 days rotating. If the issuer's DNS name dies, signed-in users keep working until the pass ends; nobody new signs in (G5 position).
9. Failover paths (what saves the user)
| What breaks | What saves the user | Time |
|---|---|---|
| one pod | Kubernetes + readiness | 0 errors |
| one node | the cloud LB's own health checks | 0 errors |
| one cluster of a landscape | client tries the next address (multi-A) + retry once; T3 removes it from DNS after 3 failed 5 s checks | user errors ≈ 0 with retry; DNS clean in ~13–19 s + TTL |
| Route 53 down | DigitalOcean answers the same zone | 0 errors (two hosts) |
| the whole main root dead | rescue router: Doc C → spare root cf. | first failing request + one doc fetch |
| Primordial down | nothing reactive depends on it: apps keep serving, DNS frozen at last good state | 0 errors; deploys pause |
| frontend host down | CNAME flip to the standby (stand-in) | DNS TTL |
10. Mercury (webhooks) — DESIGN ONLY in this PoC unless REPORT.md says otherwise
Mercury is the fleet's shared webhook service: an ordinary bun service on its own platform, one intake per serving landscape, behind the same gray DNS. It accepts a vendor's webhook, stores the event in that landscape's Upstash KV, then probes every candidate subscriber at delivery time: exactly one 200 (the owner) and every other 421 ("not mine") completes the delivery; anything else refuses loudly and retries the whole set later (72 h obligation, then dead letter). If every intake is down, the vendors' own retries cover the gap.
11. Every place the design had to change (details in CHALLENGES.md)
- Bot writes to GitHub: no deploy keys in the org → bot git server + mirror (corpus: name a GitHub App).
- Images: ghcr refused org CI → own registry.
- GitHub discovery without a token: 60 calls/h → slow polls (corpus: GitHub App + webhooks).
- Carbon chart names must follow
dpoc-<p>-carbon. - Spare DNS name cannot be independent without a second domain.
- TLS certs need one wildcard per platform (re-issued by T3).
- Logto's own app records cannot live in Logto's chart (Argo sync would wait on itself).
Result pending
Drill by drill
A timeline per drill: what happened at t = 0, and what the user saw.
Fills in by itself from poc/drills.json when it lands.
Result pending
What broke, what the design must change, cost
The test report.
Fills in by itself from poc/REPORT.md when it lands.
Challenges
Copied from poc/CHALLENGES.md as it stood at 2026-11-12 07:15 UTC. Its layout here is plain for now.
Each row: what broke or was unclear · what the PoC did · does the corpus need a change. Status words: FIXED IN POC (worked around and the fix is proven) · OPEN (owner must choose) · NOTE (small).
1. Machines cannot write to GitHub without a broad credential — FIXED IN POC (workaround) · corpus MUST change
- What happened: Kargo and T3 must push version pins and stub rows to
dpoc-fleet-state. The ProtoDurian org disables deploy keys ("Deploy keys are disabled for this repository"). The only token on hand is the owner'sghlogin token (admin:org,repoon every repo). - Example: putting that token on a droplet would let anything on it rewrite any repo of the owner.
- PoC fix: bots push to a small git server on the build machine (
git., Gitea); a relay on the lead's box mirrors it to GitHub every 3 s. The GitHub copy is what Argo CD reads, so GitHub stays the source of truth people see.dpoc. specpenguin. dev - Corpus change: name the credential: one GitHub App on the org with
contents: writeonfleet-stateonly (Kargo + T3) andmetadata: readon the org (discovery). The design says "the fleet-write credential lives here" but never says what it is.
2. Container images cannot be published to ghcr.io from org CI — FIXED IN POC (workaround) · corpus should change
- What happened: a workflow with
packages: writepushingghcr.gotio/ protodurian/ dpoc-probe denied(org package policy; no API to change it). - PoC fix: a registry on the build machine,
reg.(Let's Encrypt TLS, anyone can pull, push needs a password kept as a GitHub repo secret).dpoc. specpenguin. dev - Corpus change: the release CI section should say which registry and which org setting it needs ("allow GitHub Actions to create packages"), and that new ghcr packages start private, so clusters need a pull credential or a visibility step.
3. Unauthenticated GitHub discovery runs out of calls — FIXED IN POC (slower) · corpus should change
- What happened: the platforms AppSet (SCM generator) and the T3 materializer both list the org's repos. Without a token GitHub allows 60 calls an hour per IP; at 90 s + 60 s polling we were at 32 left after 10 minutes.
- PoC fix: SCM generator every 180 s, materializer every 120 s, ETag caching. Result: a new repo is noticed in up to 3 minutes.
- Corpus change: same GitHub App as item 1 (5,000 calls/h) + a GitHub webhook to the AppSet controller, so "new repo → pipeline" is seconds, not minutes.
4. Carbon is a "service" too, so its charts must follow the service name rule — FIXED IN POC · corpus NOTE
- What happened: the compiler expects charts
dpoc-<p>-<svc>and-primordial. The carbon repo first publisheddpoc-nitroso(no-carbon), so its pipeline waited forever with no error. - PoC fix: carbon charts are
dpoc-<p>-carbon/dpoc-<p>-carbon-primordial; carbon's Warehouse has no image subscription (spike A hole 12). - Corpus change: state the carbon chart names and the image-less Warehouse in fleet.md.
5. The spare DNS name is not independent here — OPEN (needs a second domain)
- What happened: everything lives under
specpenguin., a Cloudflare zone. The proposal (PROPOSAL-DNS.md option 4) wants the spare base on another domain, TLD and registrar.dev - PoC fix: main root
c.is one zone on two hosts (Route 53 + DigitalOcean, the proposal's two-host shape with DigitalOcean standing in for Google). Spare stand-indpoc. specpenguin. dev cf.lives on Cloudflare.dpoc. specpenguin. dev - What this cannot show: "Cloudflare (the parent) is dead" – both names die with it. A truly independent spare needs a second domain on another host.
6. One-label TLS wildcards vs dotted LPSM names — FIXED IN POC · corpus NOTE
- What happened:
tin.is two labels under the landscape;nitroso. pichu. c. dpoc… *.does not cover it.pichu. c. dpoc… - PoC fix: each cluster's certificate carries
*.for every platform; T3 re-issues it when a new platform appears (seen live: 9 → 12 → 15 names as nitroso and aldehyde arrived). DNS needs only<platform>. <landscape>. <root> *.(DNS wildcards match any depth).<landscape>. <root> - Corpus change: say the cert SAN set grows per platform, and who re-issues it.
7. Workload cluster API addresses must be reachable from Primordial pods — NOTE
- What happened: the provisioning credential used the docker container name; Primordial pods could not resolve it (
Was there a typo in the url or port?). Also the CA field was stored base64 twice. Both fixed in minutes. - Corpus change: none; the cluster controller DoD should include "Primordial can reach every cluster API" as a status condition.
8. Logto needs a database login that can create roles — FIXED IN POC · corpus MUST change
- What happened:
logto db seedfailed on Neon:permission denied to create role(42501, "Only roles with the CREATEROLE attribute may create roles"). T3's two-generation logins (app_a/app_b) are plain app logins. - PoC fix: generation logins get
CREATEROLE. - Corpus change: the Database record needs a privilege field (e.g.
privileges: app | admin), and the rotation section must say what happens to roles the app itself created (Logto createslogto_tenant_*roles owned by whichever generation ran the seed).
9. A T3 restart rotates every database password — FIXED IN POC by not restarting during drills · corpus note
- What happened: the PoC keeps credentials only in T3's memory (no Infisical). After a restart T3 cannot read them back, so it issues a new generation for every module (seen: generation 1 → 4 after three image updates). Apps survive (they re-read the file and retry), but every restart is a fleet-wide rotation.
- Corpus: this is exactly why the design makes Infisical "the commit point". The PoC skipped Infisical; a real build must not.
10. Logto's own app records cannot sit in Logto's chart — FIXED IN POC (H4) · corpus note
- What happened: if
dpoc-aldehyde.'s primordial chart held alithium LogtoApp, its Argo CD app could only be Healthy after Logto runs, and Logto cannot run before its Database (same app) is Ready → the stage waits on itself. - PoC fix: Logto's chart has only its Database; the T3 logto controller boot-seeds its own admin app straight into Logto's database.
11. A broken release holds its stage until the health wait times out, which blocks the fix — FIXED IN POC by hand · corpus should change
- What happened: Logto 1.0.0 could not start (item 8). Its Kargo promotion kept waiting for health (our
argocd-updateretry window is 15 min, needed for spike A hole 4). Logto 1.0.1 (the fix) was published 2 minutes later but could not promote until the first one ended. - PoC fix: aborted the stuck promotion (
kargo.); 1.0.1 promoted at once.akuity. io/ abort - Corpus change: say what aborts a waiting promotion when newer Freight arrives (T3 could do it: "newer Freight for the same stage + current promotion unhealthy > N min → abort"), or keep the health wait short and do the "apps not created yet" retry differently.