Spec · v1 draft · for red-pen, then the neuron lane
The Serving Plane
Retire per-site deploys: one router, one warehouse, sites as rows of data — no hosting cap at any scale, preview equals live, rollback is a pointer flip.
Draft for Robert’s annotation · not approved · no building yet · 2026-08-20
We hit Cloudflare’s ceiling: 100 hosting projects per account, on every plan, raise-by-request-form only. We have 500+ clients and a 425-site pilot cohort. The teammate write-up correctly names the current setup a dead end — but its proposed path (one Worker per site) re-hits an identical wall at 500, exactly our client count.
The cure: stop giving each site its own deployment. One small serving program (the receptionist) answers every request — it reads which domain was asked for, looks the site up in a table, and hands back that site’s exact files from storage we already use (the warehouse). Sites become rows of data, not deployments. Rows have no cap.
This is how Shopify, Webflow, and Squarespace host millions of customer sites — Shopify runs this exact shape on Cloudflare itself. We are adopting the boring industry answer, not inventing one.
↘ go deeper — tie to the three goals
Publish becomes a file upload plus a table row (seconds — directly serves the sub-30-minute pipeline goal). Rollback becomes a pointer flip (the proven undo the constitution demands before speed is allowed). The exam is untouched — make gate-cutover remains the sole arbiter of ship-ready, unchanged.
02
Decisions locked
Locked unless Robert reopens one.
Shape
One serving plane, not per-site deploys
Sites are rows in a lookup table. Onboarding site N+1 adds data, never code — and there is no ceiling at 500, 5,000, or beyond.
Storage
R2 is the warehouse
Already our artifact store; serving from it is free of egress fees. Every site version’s exact bytes stay addressable forever.
DNS
Client zones move to Cloudflare at cutover
Alie’s 8/20 ruling, ratified. The plane makes it the smooth default, not a hard requirement — a refusing client can point one record at us instead (the industry fallback).
Live sites
The 15 current sites stay put
Migrated opportunistically, no deadline. Nothing breaks while we build.
Parked
“Workers for Platforms” not needed
That product exists to run per-customer code. We serve static bytes. Revisit only if that ever changes.
03
How it works — follow one site, factory to live
Adamson’s site, walked through the whole plane.
The factory finishes the site.The publish step drops the certified bundle into the warehouse under a version fingerprint. The bytes the gate certified are the bytes stored — nothing transforms them afterward.↘ go deeper — what the builder stores
R2 layout sites/<siteId>/<version-hash>/… plus a per-version manifest: every file path, its sha256, its response headers, and the site’s redirect rules as data. The per-file hashes are what let any non-author recompute the byte-identity claim from disk.
The preview exists instantly.One wildcard address set up once — then every site automatically has adamson.preview.<our-domain> the moment its files land. No per-site setup, a branded stable link, and any historical version stays reachable at its own address.
The gate runs against the preview.Our cutover gate loads source and deploy in a real browser and diffs them — it does not care what serves the bytes. It stays the sole arbiter of ship-ready, unchanged.
The DNS move — the one step that can hurt a client outside the website.A clinic’s domain also routes its email. Before the nameserver flip, a fidelity gate must pass: export every record from the current DNS host, import, machine-diff, and flip only on a clean diff — receipt filed. A missed mail record silently kills a practice’s inbox; this gate is non-optional.↘ go deeper — the fidelity gate’s contract
Export the authoritative zone (MX, TXT/SPF/DKIM/DMARC, A/AAAA/CNAME/SRV, TTLs) → import to Cloudflare → machine-diff must be empty → post-flip probe confirms mail records answer identically from Cloudflare’s nameservers. The registrar-side flip needs client credentials and timing — an operational cost per cutover, named in the playbook, not hidden.
Go live = two rows.A route on the client’s zone pointing at the plane, and a table row: “this domain → adamson at this version.” The version is the one the preview served and the gate passed — what was approved is byte-for-byte what serves. There is no second deploy between approval and live.
Rollback = repoint the row.Seconds, fully reversible — every pointer move writes a receipt (who, what, when, from, to).
The ledger continues.Every serve decision stays legible: the per-site completeness ledger keeps being written, and an unknown domain fails closed — an explicit error page plus a ledger entry, never a guess, never another client’s site.
04
Invariants — the contract the lane builds to
I1Byte-identity at serve time
The plane serves exactly the certified bytes — never transforms. Per-file fingerprints let any non-author recompute the claim.
I2Preview equals live
Same store, same bytes, same version. Approval binds to a version fingerprint, not to a URL.
I3Fail closed
Unknown domain, ambiguous row, or a corrupt table read → explicit error, never a guess, never another site’s bytes.
I4Reversible with receipts
Versions retained per policy; every pointer flip receipted.
I5A new site is data, never code
Onboarding touches zero serving-program code. If a site class ever requires program changes, that is a frame question — surfaced to Robert.
I6The gate must be able to fail
The cutover gate runs unchanged against the plane AND the spike must show a red: mutate one stored byte, watch the gate fail. A gate that cannot fail proves nothing.
I7Headers & redirects ported as data, with tests
The old host handled these for free; we own them now. The worst deploy bug we ever shipped (silent catch-all redirects hiding 102 missing pages) lived in exactly this layer — redirect rules must never hide missing real pages.
The spike decides, not this doc. Phase 0 serves one already-certified site through the plane and runs the full cutover gate against it — pass and demonstrated fail (I6). If the spike fails structurally, this spec returns to Robert before any further build.
05
Phases
P0
The spike — the gate decides
One certified site through router + warehouse on a scratch address; full gate run; the demonstrated red. Watch the header-parity axis — the one most likely to differ from the old host. Exit: PASS + proven-able-to-FAIL.
P1
Productionize the plane
Table schema with atomic pointer flips; the header/redirect engine with tests (I7); preview wildcard + versioned preview addresses; rollback receipts; edge-cache strategy with purge-on-pointer-move; the serve ledger. Plane changes ship via gradual rollout, version-pinned.
P2
Factory seam swap
The publish step targets the plane (upload + row) instead of creating hosting projects. The completeness ledger keeps being written per site. The lane locates the exact seam — this spec stays capability-level on purpose.
P3
Cutover playbook + DNS-fidelity gate
The export→import→diff→flip gate as a real instrument with receipts; post-flip mail-record probe; registrar runbook; the one-record fallback for DNS-refusing clients documented.
P4
Drain and stop the bleed
Migrate the 15 old-host keepers opportunistically. Internal review pages and one-pagers consolidate into shared surfaces — no more one-project-per-doc (85 of our 100 slots today are internal docs).
Every phase: builder paired with an independent validator; the verifier is never the author; evidence on disk a non-author can recompute; nothing merges unfalsified.
06
Honest risks
Shared blast radius
One plane serves every client; a bad plane change touches all of them. Mitigations: the plane is tiny and rarely changes (I5 keeps it that way), gradual rollouts with version pinning, and every change goes through the courts. This is the price of the pattern; the industry pays it knowingly.
We own redirects & headers now
Real work, real regression surface (I7). Counter: our worst deploy bug lived in the old host’s free layer — owning it with tests beats renting it blind.
DNS moves touch client email
The fidelity gate (P3) is the cure and must exist before zone moves become a standard playbook step.
Cache staleness
A rollback that serves stale cached bytes breaks preview-equals-live. Purge-on-pointer-move is part of P1’s exit — verified, not assumed.
The table is a single point of truth
A corrupt or half-written table means a wrong answer. Atomic writes, versioned tables, and the fail-closed read posture (I3).
100 hosting projects per account on every plan; 500 Workers per account on paid — why per-site Workers merely relocates the wall. One Worker can be attached to 1,000 client zones — a single plane covers the whole fleet with room. Warehouse egress is free; expected total hosting cost at 500 sites is roughly $5–25/month, matching the write-up. Precedent: Shopify’s storefront gateway on Cloudflare, Webflow on Workers, Cloudflare’s own reference architecture for companies hosting customer sites.
08
Open questions — the red-pen targets
1 ★
Where the lookup table lives.
Three candidate stores, different trade-offs on atomic flips, edge read speed, and audit trail. The lane argues its pick in the P1 design — flag here if you want to weigh in early.
6 ★
The publish seam.
The lane names the exact factory step P2 swaps, before P2 is specced. This spec deliberately stays capability-level about the factory’s internals.
2
Preview domain.
Which domain hosts the previews — the main company domain or a dedicated one?
3
Version retention.
How many versions stay instantly serveable per site; archive policy for the rest.
4
Cache dial.
Aggressive edge caching with purge-on-flip, or short-lived caching that always re-checks? Must satisfy the staleness risk.
5
Fallback timing.
Build the one-record fallback for DNS-refusing clients in P3, or defer until the first such client appears?
09
Non-goals
“Workers for Platforms”; any change to the capture or compile stages; migrating the 15 live sites on a deadline; the legacy pipeline (untouched).