Appearance
Operator tooling
Operator tooling builds a release, deploys it, and holds the credentials a live grafted-wars deployment needs. It is written for a solo operator running staging and production alone, who is not a Cloudflare expert and is reading this while deploying.
From a green gate to a live deployment
- Start from a green gate (
npm run check) on the branch being deployed. - If no owner token exists yet on this machine, mint one:
node scripts/owner-claim.mjs mint. - Deploy to true staging:
npm run deploy:staging. This needsCLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_ID, from the environment or the repository's gitignored.env. - The first time the staging worker
grafted-wars-true-stagingis deployed, give it itsADMIN_EMAILsecret — the worker refuses every request without one:npx wrangler secret put ADMIN_EMAIL --name grafted-wars-true-staging. - Build the claim-link page and claim owner on staging:
node scripts/owner-claim.mjs page <staging base url>, then open~/rocket-showroom/grafted-wars-enter.htmland follow the staging link once. - Optionally, mint test accounts for a walkthrough:
node tools/mint-accounts.mjs --base-url <staging base url>. - When staging looks right, deploy to production:
GW_FLIP_ACK=grafted-wars.com npm run deploy:prod -- --flip. - The first time the production worker
grafted-wars-stagingis deployed, give it its ownADMIN_EMAILsecret too — it is a separate worker with a separate secret:npx wrangler secret put ADMIN_EMAIL --name grafted-wars-staging. - Build a claim-link page for production (or reuse the one from step 5, adding the production URL) and claim owner there the same way.
- Verify the deploy — see "After a deploy" below.
What differs between staging and production
| Aspect | Staging | Production |
|---|---|---|
| Command | npm run deploy:staging | npm run deploy:prod |
| Worker name | grafted-wars-true-staging | grafted-wars-staging — the two names are confusable at a glance |
| Arming | None — runs on any invocation | Double-armed: needs both --flip and GW_FLIP_ACK=grafted-wars.com |
| Domain | workers.dev only | grafted-wars.com and www.grafted-wars.com, bound through the Cloudflare API |
| Public signup | On (GW_PUBLIC_SIGNUP=1) | On (GW_PUBLIC_SIGNUP=1), narrowed to the addresses named in the GW_SIGNUP_ALLOW secret |
| Admin surface | Reachable (ADMIN_ROUTES=1) | Off (not set) |
| Starting seed | Packed to capacity (GW_DENSE_SEED=1) | Empty, fills as accounts join |
| Clock | 25x (GW_CLOCK_RATE=25) | Real time (GW_CLOCK_RATE=1) |
| Reset | GW_STAGING_RESET=<new value> wipes all user state on the next boot | No such switch |
After a deploy
Both deploy scripts print a RED:-prefixed line and exit with a nonzero code on failure. A successful run ends with a one-line summary naming the worker, and for production, the domain bindings.
After a production deploy, run the curl command the script prints, or hit /api/health directly on the live hostname. The script names that command but does not run it, since local DNS can still answer the old address for a while.
A freshly deployed worker that has never had its ADMIN_EMAIL secret set answers every request with a refusal rather than a working page. Check for that before suspecting the deploy itself went wrong.
Units in this area
Every unit in operator tooling, with the page that documents it.
| Unit | What it does |
|---|---|
deploy-prod.mjs | Builds the site, deploys the production Cloudflare Worker, and binds grafted-wars.com and its www alias to it. |
deploy-staging.mjs | Deploys the true staging Cloudflare Worker with the spectator-testing environment: public signup on, the admin surface reachable, the home system packed at boot, and a 25x clock. |
owner-claim.mjs | Mints, hashes and reads the local owner admin token, and builds a one-click claim-link page for entering owner on a deployment. |
mint-accounts.mjs | Mints throwaway grafted-wars accounts against a running deployment, one real signup-login-session cycle per account. |