carlos / platform Public

woodstar runbook: D2.5/D2.6 done — routes live, *.woodstar.app issued via delegation; D2.4 script staged

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 68d85dfa32f8d6b2e6923541041b864e0c4ebd25 parent 4581c04
1 file changed, +56 −24
  • docs/superpowers/plans/2026-08-16-woodstar-cutover-runbook.md +56 −24
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 c4dc67498..d7d80f69f 100644
--- a/docs/superpowers/plans/2026-08-16-woodstar-cutover-runbook.md
+++ b/docs/superpowers/plans/2026-08-16-woodstar-cutover-runbook.md
@@ -168,12 +168,33 @@ Original checklist (for a re-run; all over
- [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
- `woodstar-{relay,media,indexer,notify,unfurl,apbridge}.service`
- patterned on `keymail-relay.service` + `scripts/harden-host.sh`
- drop-ins. ExecStart flags = D1.1 verbatim, transposed: paths to
+- [ ] **D2.4 — box-side (SSM, root): SCRIPT STAGED, needs Paul's run**
+ (classifier blocks remote mutations for the session — the D0.1
+ pattern). The complete idempotent script is at
+ `s3://carlos-flagship-271376211898/ops/woodstar/d24-setup.sh`:
+ user + `/data/woodstar` 0700 + env file + six hardened units
+ (keymail-relay pattern), installed but NOT enabled/started, with
+ **ExecStartPre founder-trap guards** — relay refuses to start
+ without `relay.db`, indexer without `indexer.db`, apbridge without
+ `apbridge.seed` + `apbridge.db` — so no adoption restart or stray
+ start can ever boot an empty registration-open relay. ExecStart
+ binaries are the ADOPTED paths
+ (`/opt/carlos/live/woodstar-<svc>.bdm.oncarlos.com` — symlinks
+ already on the box, placed by adoption at `1aa534e`). Run:
+
+ ```bash
+ aws --profile keymail ssm send-command --instance-ids i-092c0c1eea75723cb \
+ --document-name AWS-RunShellScript --parameters "$(jq -n '{commands: [
+ "aws s3 cp s3://carlos-flagship-271376211898/ops/woodstar/d24-setup.sh /root/d24-setup.sh && bash /root/d24-setup.sh"
+ ]}')"
+ ```
+
+ Unit stamping (`carlos route … -unit woodstar-<svc>.service`, run as
+ carlos on the box, all six routes) moves to **D4.2** with the start
+ sequence — stamping is safe earlier thanks to the guards, but it
+ buys nothing before restore. Original spec text for reference:
+
+ ExecStart flags = D1.1 verbatim, transposed: paths to
`/data/woodstar`, ports to the 845x map, PLUS relay fan-out flags:
```
@@ -190,24 +211,35 @@ Original checklist (for a re-run; all over
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
- static attach or alias — whichever the live #82 door supports for
- the shape). **`status.woodstar.app`'s exact-host route MUST exist
- before the wildcard alias serves** — with the alias live and the
- status route missing, status 302s into the SPA and the status page
- silently becomes the app. Then attach `woodstar.app` as alias to the
- relay's route.
-- [ ] **D2.6 — wildcard, pre-flip cert proof:** `carlos domains attach
- woodstar.app -wildcard -catchall` (door refuses until D0.1 is done —
- that refusal text is itself a check). Watch the edge obtain
- `*.woodstar.app` via the delegation CNAME; then handshake-verify
- against the flagship IP without DNS:
- `curl -sv --resolve paul.woodstar.app:443:99.81.104.219
- https://paul.woodstar.app/ -o /dev/null 2>&1 | grep -E
- "subject:|expire"` → subject `CN=*.woodstar.app`. Issuance does not
- depend on the A records: this is the whole point of §4.
+- [x] **D2.5 — routes via product surface: DONE 2026-08-17**, and the
+ shape turned out fully member-facing — no bucket hand-writes at all:
+ - Six `kind:service` records via `carlos instances enable` (domain
+ pinned `bdm.oncarlos.com`, channel `canary/woodstar`) +
+ `carlos instances create -host woodstar-<svc>.bdm.oncarlos.com
+ -addr 127.0.0.1:845x`. Routes materialized in seconds; edge
+ already terminates TLS for them (502 until units run); **adoption
+ delivered all six binaries to
+ `/opt/carlos/live/woodstar-<svc>.bdm.oncarlos.com` at `1aa534e`
+ with zero hand-copying.**
+ - `status.woodstar.app`: first-route static attach via the door
+ (API POST `{"host":…,"kind":"static","channel":"canary/woodstar"}`
+ — CLI attach has no `-kind` by design). Materialized AND
+ **already Serving** the shipped status site. Precedence invariant
+ (exact-host route before any wildcard alias) satisfied.
+ - `woodstar.app` attached as alias →
+ `woodstar-relay.bdm.oncarlos.com`; DNS honestly `elsewhere`
+ (points at old box until D4).
+- [x] **D2.6 — wildcard, pre-flip cert proof: DONE 2026-08-17.**
+ Capabilities enabled through the attach door
+ (`wildcard:true, catchall:true`); CNAME gate passed; list shows
+ `WILDCARD yes / CATCHALL yes / DELEGATION delegated`; edge published
+ the TXT at `_acme-challenge.woodstar.app.acme.oncarlos.com` and
+ **`*.woodstar.app` ISSUED ~30 s after enable** — handshake-verified
+ against 99.81.104.219: subject `CN=*.woodstar.app`, expires
+ 2026-11-15. Per-host certs for `woodstar.app`/`status.woodstar.app`
+ correctly wait for post-flip HTTP-01 — do NOT TLS-probe those two
+ hosts via `--resolve` pre-flip (each probe burns a doomed ACME
+ order against the box-wide budget).
## D3 — Rehearsal (copies only, tear down after)