carlos / platform Public

woodstar runbook: D0/D2.1-3 done, account bdm, sha 1aa534e, Bluesky-native #77 ruling

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 21d1b7d90abcbd32c21ca2abd77639885681ffe1 parent dec1900
1 file changed, +58 −26
  • docs/superpowers/plans/2026-08-16-woodstar-cutover-runbook.md +58 −26
diff --git a/docs/superpowers/plans/2026-08-16-woodstar-cutover-runbook.md b/docs/superpowers/plans/2026-08-16-woodstar-cutover-runbook.md
index 88478728a..154d00a31 100644
--- a/docs/superpowers/plans/2026-08-16-woodstar-cutover-runbook.md
+++ b/docs/superpowers/plans/2026-08-16-woodstar-cutover-runbook.md
@@ -22,7 +22,10 @@ per spec `docs/superpowers/specs/2026-08-12-woodstar-carloku-migration-design.md
| Delegation zone | `acme.oncarlos.com` (oncarlos.com zone `Z04313755ASMHAWD536L`, Route53, keymail account — edge publishes TXT here via `CARLOS_DNS_PROVIDER=route53` suffix-walk) |
| Delegation CNAME | `_acme-challenge.woodstar.app` → `_acme-challenge.woodstar.app.acme.oncarlos.com` — **DONE 2026-08-16** (stale Caddy TXT leftovers deleted in the same change batch) |
| Old-box cert headroom | apex + wildcard both expire **2026-10-21**; old-box renewal is blocked by the delegation CNAME from its ~Sept 21 renewal window — cutover must land before then, rollback keeps existing certs |
-| W0 build sha | woodstar `origin/main` (`0bdcb07` at runbook time; re-read at D2 — always build ALL SIX binaries from ONE sha, `GOOS=linux GOARCH=arm64`, from a CLEAN checkout: `git status --porcelain` empty, never the stale local tree) |
+| W0 build sha | woodstar `origin/main` `1aa534e` — **BUILT + SHIPPED + PROMOTED 2026-08-17** (all six binaries + status, one sha, `GOOS=linux GOARCH=arm64`, clean worktree; channel `canary/woodstar`). A later re-ship repeats D2.3 verbatim at the newer sha |
+| Account | `woodstar` = sqid **`bdm`** on console.carloku.com (Paul owner) — settled 2026-08-17 |
+| Channel | `canary/woodstar` (the canary/keymail pattern; all seven apps ride it) |
+| Old-box SSH | `ssh -i ~/.ssh/woodstar-canary.pem ec2-user@52.30.232.124` (key per woodstar `scripts/status-publish.sh`) |
| Ports (loopback only) | relay 8451, media 8452, indexer 8453, notify 8454, unfurl 8455, apbridge 8456 |
| Data | `/data/woodstar` 0700 owner `woodstar` (`/data` stays 0711) |
| App env file | `/etc/carlos/apps/woodstar.env` 0600 root: `WOODSTAR_APPLE_APP_ID=J5NDF5PCD8.app.woodstar.ios` — in place BEFORE the flip or iOS passkeys break |
@@ -30,6 +33,29 @@ per spec `docs/superpowers/specs/2026-08-12-woodstar-carloku-migration-design.md
| Replicated DBs | relay.db, indexer.db, apbridge.db — **unfurl.db deliberately excluded** (cache, repo rule); `apbridge.seed` = federation identity flat FILE, copied not litestreamed |
| Apps (7) | `woodstar-relay/-media/-indexer/-notify/-unfurl/-apbridge` (kind binary, linux-arm64) + `woodstar-status` (kind static) |
+## Bluesky-native (#77) ruling — 2026-08-17
+
+woodstar #77 (merged the morning of 2026-08-17) added `atbridge`,
+Woodstar's own AT Proto PDS, replacing Bridgy: a seventh service
+(:7077), its own `atbridge.db` + `atbridge.seed`, a `pds.woodstar.app`
+exact host, an apex `/at/*` leg, and wildcard
+`/.well-known/atproto-did` moving apbridge→atbridge — **on the
+devbox/canary only**. Probed live 2026-08-17:
+`pds.woodstar.app/xrpc/_health` 302s to `woodstar.app/pds` (the
+wildcard profile redirect), i.e. prod has NO pds host and NO atbridge;
+prod's atproto-did still answers from apbridge (Bridgy-era did:plc).
+
+**Ruling (spec §11 applied — parity with live behavior, no new
+features ride the migration):** the cutover moves the SIX-service
+topology exactly as prod runs it today. The W0 fan-out's
+atproto-did→apbridge routing is therefore CORRECT parity, and no
+`-atbridge-upstream` leg is needed for the migration. The PDS prod
+rollout is woodstar's own post-migration work, done ON CARLOS through
+the product surface (new app `woodstar-atbridge`, `pds.woodstar.app`
+exact route, fan-out `-atbridge-upstream` + atproto-did repoint as a
+woodstar PR, `atbridge.db` litestream + `atbridge.seed` backup) — see
+D5. D1.1 verifies the six-unit assumption on the box.
+
## Standing constraints (spec §7, restated)
- No DNS A-record changes and no touching running woodstar services
@@ -49,12 +75,10 @@ per spec `docs/superpowers/specs/2026-08-12-woodstar-carloku-migration-design.md
## D0 — Platform preconditions (no prod impact beyond two unit restarts)
State at runbook time: track live (box binary `c42ec0c`, console
-`3f28e9f`, both contain Plans B+C); delegation CNAME done. One item
-open:
+`3f28e9f`, both contain Plans B+C); delegation CNAME done.
-- [ ] **D0.1 — set the delegation zone on the flagship** (this exact
- command was permission-blocked for the authoring session; run it or
- approve its retry):
+- [x] **D0.1 — set the delegation zone on the flagship** — DONE
+ 2026-08-17 (Paul ran it; both units restarted `active`):
```bash
cd ~/github.com/carlosframework/platform-infrastructure && \
@@ -70,9 +94,11 @@ aws --profile keymail ssm send-command --instance-ids i-092c0c1eea75723cb \
`/etc/carlos/host.env` (verified 2026-08-16), so the one line covers
door and issuance. Inert until a claim opts in.
-- [ ] **D0.2 — verify:** `curl -sI https://console.carloku.com/ | grep
- -i x-carlos-version` still answers (post-restart); box journal shows
- NO `CARLOS_ACME_DELEGATION_ZONE … invalid` line from either unit.
+- [x] **D0.2 — verify:** DONE 2026-08-17 — console 200
+ (`x-carlos-version: 5bef643`), edge boot line reads
+ `wildcard certs on (static [], apps domain "oncarlos.com",
+ delegation zone "acme.oncarlos.com")`, no invalid-zone line, all six
+ existing `*.oncarlos.com` wildcards reloaded from cache.
## D1 — Old-box pre-flight (SSH, read-only, any time)
@@ -81,10 +107,12 @@ record it in the session and in this file's margin notes.
- [ ] **D1.1 — units:** `systemctl cat woodstar-*.service` (expect
six). Capture EVERY ExecStart flag and Environment line verbatim —
- especially apbridge's `-domain`/`-seed`/`-bridgy`/`-bsky-api` and
- any relay `-passkey-rp`/`-media`/`-imports` values. Six units are
- the target; a seventh unit or a flag the spec never mentioned is a
- FINDING — stop and record it before D2.
+ especially apbridge's `-domain`/`-seed` + Bridgy-era flags and any
+ relay `-passkey-rp`/`-media`/`-imports` values. Six units are the
+ target (the #77 ruling above: NO `woodstar-atbridge.service` on
+ prod — if one appears, the ruling's premise is stale; stop and
+ re-probe). Any other seventh unit or unspec'd flag is a FINDING —
+ stop and record it before D2.4.
- [ ] **D1.2 — sizes:** per-service RSS (`systemctl status`), total
`du -sh /opt/woodstar/data` — re-confirm the t4g.nano-scale verdict.
- [ ] **D1.3 — data dir:** `ls -la /opt/woodstar/data` — expect
@@ -106,16 +134,13 @@ record it in the session and in this file's margin notes.
## D2 — Flagship tenant build-out (pre-flip, real hostnames NOT routed yet)
-- [ ] **D2.1 — account decision (Paul, one line):** which console
- account owns the seven apps. Recommendation: a dedicated `woodstar`
- account (own statements, own tokens), same pattern as tito=bae on
- the tito console. Needed before any `carlos apps create`.
-- [ ] **D2.2 — apps:** `carlos apps create` × 7 under that account
+- [x] **D2.1 — account:** `woodstar` (`bdm`) on console.carloku.com,
+ Paul owner — existed already, confirmed 2026-08-17.
+- [x] **D2.2 — apps:** all seven created 2026-08-17 under `bdm`
(six binary + `woodstar-status` static).
-- [ ] **D2.3 — build + ship:** from a clean woodstar checkout at
- origin/main: six `CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build`
- binaries, `carlos ship` + promote each on its app's canary channel.
- Status site: `carlos ship -kind static` of the status content.
+- [x] **D2.3 — build + ship:** DONE 2026-08-17 — six binaries + the
+ repo's `status/` site, all at `1aa534e`, shipped and promoted to
+ `canary/woodstar`.
- [ ] **D2.4 — box-side (SSM, root):** system user `woodstar`
(sysusers), `/data/woodstar` 0700, `/etc/carlos/apps/woodstar.env`
(0600, the AASA line), six hardened units
@@ -134,9 +159,10 @@ record it in the session and in this file's margin notes.
**`-media` AND `-media-upstream` are BOTH required** (importer vs
fan-out — final-review catch). apbridge keeps
- `-domain woodstar.app -seed /data/woodstar/apbridge.seed` + D1's
- `-bridgy`/`-bsky-api` values. Units installed but **NOT started**
- (founder trap) — except as D3 rehearses on copies.
+ `-domain woodstar.app -seed /data/woodstar/apbridge.seed` plus
+ whatever Bridgy-era flags D1.1 captured, verbatim. Units installed
+ but **NOT started** (founder trap) — except as D3 rehearses on
+ copies.
- [ ] **D2.5 — routes via product surface:** relay's primary route as
a declared route record (#137 vocabulary) on the flagship;
`status.woodstar.app` attach for `woodstar-status` (first-route
@@ -213,9 +239,15 @@ keep the window short. Old box afterwards: units stopped, disk intact,
frozen 30 days. (Old-box certs stay valid to 2026-10-21 regardless of
the delegation CNAME.)
-## D5 — Post-cutover (spec §9)
+## D5 — Post-cutover (spec §9 + the #77 ruling)
- [ ] Promote the W0 sha to stable after the 72 h supply-chain bake.
+- [ ] **PDS prod rollout (woodstar's own project, on CARLOS):** app
+ `woodstar-atbridge` + `pds.woodstar.app` exact route via the door;
+ a woodstar PR adding the relay fan-out `-atbridge-upstream` (`/at/*`
+ leg) and moving wildcard atproto-did apbridge→atbridge;
+ `atbridge.db` into litestream + `atbridge.seed` into the backup set.
+ Wildcard DNS already covers the pds hostname.
- [ ] Repoint status publishing: `carlos ship -kind static` + promote
replaces `scripts/status-publish.sh`.
- [ ] Note woodstar `infra/` tofu drift; retire the old prod instance