carlos / platform Public

spec: canary minting is static-only; durable account ids gate the rollout

Merge review found that a minted canary host for an instance app would
proxy to the stable process while advertising the canary channel — a URL
that lies. Instance canaries need per-host instance spawning, not routing
aliases. Also records two prerequisites the review surfaced: durable
account identity (sqids currently ride reassignable row ids) and
wake-through aliasing for hibernating apps.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 02da01297033789442fa09d85432347524660f2a parent 80d6811
1 file changed, +32 −4
  • docs/superpowers/specs/2026-08-02-custom-domains-design.md +32 −4
diff --git a/docs/superpowers/specs/2026-08-02-custom-domains-design.md b/docs/superpowers/specs/2026-08-02-custom-domains-design.md
index 58c906a36..023f1a233 100644
--- a/docs/superpowers/specs/2026-08-02-custom-domains-design.md
+++ b/docs/superpowers/specs/2026-08-02-custom-domains-design.md
@@ -58,10 +58,20 @@ each step is idempotent and additive:
(Socket/Addr/backing) as the app's first ready route (ordered by host,
deterministic), `platform=1`.
Existing apps are backfilled on the first pass after rollout.
-3. **Canary hosts**: any `canary/<name>` channel pointer in the bucket
- whose app has no route following it gets
- `<name>.<app>.<sqid>.<apps-domain>` minted on that channel — closing
- console slice 3's hostless-canary gap with no console write authority.
+3. **Canary hosts — static apps only** (corrected 2026-08-02 after merge
+ review): any `canary/<name>` channel pointer whose app has no route
+ following it gets `<name>.<app>.<sqid>.<apps-domain>` minted on that
+ channel **when the app's source route is `Kind=static`** — there the
+ copied channel genuinely IS the backend (the static handler resolves
+ the pointer to a tar), so the URL serves what it claims.
+ **Instance/service apps are skipped**: a minted route can only copy an
+ existing upstream, so a canary URL would proxy to the app's *stable*
+ process while advertising the canary channel — a URL that lies about
+ what it serves, and an operator could validate a build that isn't
+ running. Closing that gap needs per-host canary *instance spawning*
+ (the unbuilt `carlos canary` verb), not a routing alias. Console slice
+ 3's hostless-canary gap therefore remains open for instance apps, by
+ design, until that lands.
Retiring the channel (console or CLI) removes the minted route on a
later pass (only routes with `platform=1` are ever auto-removed;
custom domains are never touched by reconciliation).
@@ -143,6 +153,24 @@ Per app page, replacing the raw routes framing:
deliberately excluded here).
- **Multi-region DNS checks** (per-region edge IP sets once the mesh
ports land).
+- **Durable account identity** (raised by merge review, 2026-08-02):
+ sqids currently encode the account's AUTOINCREMENT registry row id,
+ assigned in bucket-listing order at first reconcile. A registry rebuild
+ — or a second box materializing accounts in a different order —
+ reassigns ids and silently re-homes every platform domain. The frozen
+ goldens freeze the *encoding*, not the *assignment*. Before these URLs
+ are shared anywhere that matters, account identity must become durable:
+ either the account's assigned id is written back into its bucket
+ manifest (the bucket is the control plane, so it should hold the
+ identity) or the sqid derives deterministically from the account name.
+ **This is a prerequisite for enabling the feature on the flagship**,
+ and belongs in the multi-account spec that supersedes §2.
+- **Wake-through aliasing**: a hibernating app's platform domain 502s
+ while the app sleeps — the activator arms on the canonical route only,
+ and a minted route deliberately does not copy `Hibernate` (copying it
+ would spawn a duplicate process against an empty DBPath). The edge
+ needs to resolve an alias to its source route before the activator
+ gate for "every app is born addressable" to hold for sleepers.
- **Path routing** — one host fanning out to several upstreams by path
prefix: `/blog` to a static site while the rest of the domain serves
the dynamic app, or an app's satellites behind one origin (Woodstar's