add 0063/SESSION-0063.0-TRANSCRIPT-2026-06-02T06-18--2026-06-02T08-34.md + replace placeholder/variant SESSION-0063.0-TRANSCRIPT-2026-06-02T06-18--INPROGRESS.md

This commit is contained in:
2026-06-02 08:36:39 -07:00
parent 511eec0074
commit e6e38debaa
2 changed files with 194 additions and 15 deletions
@@ -0,0 +1,194 @@
# Session 0063.0 — Transcript
> Date: 2026-06-02
> Start: 2026-06-02T06-18 (PST implied) • End: 2026-06-02T08-34
> Goal: OHM **wildcard-TLS cutover** — move the origin off its per-host certbot
> Let's Encrypt cert onto a shared `*.wiggleverse.org` cert. Decide cross-project
> secret access; operator loads the cert bytes; assistant deploys; operator flips
> Cloudflare to Full(strict)+orange-cloud; finish with `certbot delete`.
>
> Outcome: **Done — but it grew into a full `ohm`→`rfc` hostname migration.**
> Mid-session the operator decided `rfc.wiggleverse.org` (not `ohm.wiggleverse.org`)
> is the canonical host going forward, with OHM as a project/collection within the
> rfc-app. Origin now serves a shared `*.wiggleverse.org` **Cloudflare Origin**
> cert over **Full(strict)** (scoped per-host), at `https://rfc.wiggleverse.org`;
> `ohm.wiggleverse.org` retired (DNS + certbot cert deleted). Gitea login,
> Turnstile, email OTC, and the webhook all verified working. **No secret byte
> entered the session.** No flotilla code change (operational).
>
> Highlights:
> - **Secret-access decision:** ONE shared wildcard secret, homed in the
> `wiggleverse` org project's Secret Manager, read at deploy time by the
> **operator ADC** — NOT per-VM-SA grants (the brief's framing). flotilla never
> reads secrets via the VM service account (SPEC §7.3; no impersonation).
> - **Two brief-vs-reality discrepancies caught before damage:** (1) the live
> vhost still pointed at the certbot cert, not the wildcard paths as briefed;
> (2) `ohm.wiggleverse.org` DNS had already been deleted (site was down). The
> second triggered the operator's pivot to `rfc` as canonical.
> - **Zone-wide Full(strict) incident:** setting it at the zone level took down
> `git.wiggleverse.org` (521) and `wiggle-snip-ppe` (526) — origins not
> strict-ready. Fixed by reverting the zone to Flexible + a per-hostname
> **Configuration Rule** scoping Full(strict) to `rfc` only.
> - **Wrong-webhook detour:** operator twice edited a "BDD Planner Webhook" (a
> different repo's hook) before we pinned the real one (hook #2 on
> `wiggleverse/ohm-content`) by its exact id via the Gitea API.
---
## Pre-session state
- OHM rfc-app live at `ohm.wiggleverse.org`, served by nginx on the VM
`ohm-rfc-app` (`136.116.40.66`, project `wiggleverse-ohm`, gcloud config
`wiggleverse`). (Note: the VM had been renamed `ohm-app``ohm-rfc-app` since
the old deployment-host memory was written; install `/opt/ohm-rfc-app`, unit
`ohm-rfc-app.service`.)
- `flotilla` is now a thin shim over `flotilla-core` (v1.8.0+); the `secret-file`
verb group (bind/set/list/unbind) exists in flotilla-core and writes a secret
to a VM path with a deduped fail-stop reload.
- No secret files bound; all 8 app secrets lived in `wiggleverse-ohm`. No
wildcard secret existed anywhere.
- Working tree had uncommitted `CHANGELOG.md`/`operator-guide.md` from the
2026-06-01 gitea-rotation doc work (a prior session's) — left untouched.
## Decision — cross-project secret access
Grounded in SPEC §7.3 + `flotilla_core/deploy.py` + `secrets.py`: flotilla
resolves secret-file bytes on the operator's machine via **ADC**, then pushes
them to the VM over SSH. The **VM runtime SA is not in the read path**. So the
brief's "secretAccessor grants to each VM's SA" doesn't apply. Chose (via
AskUserQuestion) **one shared secret homed in the `wiggleverse` org project**:
`wiggleverse/wiggleverse-wildcard-fullchain` + `…-privkey`, read cross-project
by the operator ADC (owner on `wiggleverse`). Rejected per-project copies (N×
renewal toil). The cert turned out to be a **Cloudflare Origin Certificate**
(SAN `*.wiggleverse.org` + `wiggleverse.org`, ~15-yr) — ideal for orange-cloud
+ Full(strict).
## Turn-by-turn arc
### Arc 1 — Recon + the two discrepancies
Read-only VM preflight showed the live/effective nginx config still pointed at
`/etc/letsencrypt/live/ohm.wiggleverse.org/…` (NOT the wildcard paths the brief
said were "already" wired), and the wildcard files didn't exist. Separately,
`ohm.wiggleverse.org` returned **NOERROR/0-answers** in public DNS — the A
record had been deleted (it resolved for yesterday's deploy id=52). Surfaced
both to the operator rather than proceeding.
### Arc 2 — Origin cert cutover (TLS)
1. Enabled Secret Manager API on `wiggleverse` (was off).
2. **Operator** loaded both cert secrets via `flotilla secret-file set
--project wiggleverse --secret-id …` (bytes via stdin; never in the
transcript). Bindings + SM entries verified (refs only).
3. Dry-run confirmed the operator ADC reads both cross-project. **Deploy
id=53** landed both files (crt 0644, key 0600, root) + ran the nginx reload;
phases 17 green. Phase 8 (health verify) **false-failed** on a local DNS
lookup of the now-deleted `ohm.wiggleverse.org` — actuation had succeeded.
Verified on-VM: cert↔key moduli match, issuer = Cloudflare Origin CA, SAN
`*.wiggleverse.org`, app healthy on localhost.
4. Repointed vhost `ssl_certificate`/`_key` (lines 8081) → wildcard paths,
keeping the certbot global includes (`options-ssl-nginx.conf`,
`ssl-dhparams.pem`) which survive `certbot delete`. nginx-t-gated, reloaded.
Verified origin serves the wildcard cert via direct IP+SNI.
### Arc 3 — The `ohm`→`rfc` pivot (host migration)
Operator clarified: **don't restore `ohm`; make `rfc.wiggleverse.org` canonical**,
OHM as a project within it — reversing the 2026-05-27 settlement. Recon found
`rfc.wiggleverse.org` was a **stale mapping** to `34.59.1.73` (the bdd.ecomm
box — 404 on rfc paths, ecomm `/api/health` "scenarios" shape, its own LE cert).
Confirmed safe to repoint to the OHM VM `136.116.40.66`. Mapped the full surface
(more than DNS): `APP_URL` overlay, vhost `server_name` + redirect, `health_url`,
OAuth redirect URI, Turnstile domains, Gitea webhook target.
My parts: `overlay set APP_URL=https://rfc.wiggleverse.org`; vhost
`server_name` + `if ($host = …)` redirect repointed `ohm`→`rfc` (nginx-t-gated);
`deployment update --health-url …rfc…`. Verified origin answers as `rfc` via
direct IP+SNI.
### Arc 4 — Cloudflare + the zone-wide Full(strict) incident
Operator created `rfc` A → `136.116.40.66` proxied. First hit a **301 redirect
loop** (Flexible SSL → CF reaches origin over HTTP:80 → nginx 80→443 redirect).
Operator set **Full(strict) at the zone level** → fixed `rfc` but **broke**
`git.wiggleverse.org` (521) and `wiggle-snip-ppe` (526), whose origins aren't
strict-ready. Diagnosed the blast radius; operator **reverted the zone to
Flexible** (restoring git/wiggle-snip) and added a **Configuration Rule**
(Rules → Configuration Rules, top-level menu — not under SSL/TLS) scoping
**Full(strict)** to `rfc.wiggleverse.org` only. `rfc` → 200, loop gone.
### Arc 5 — Redeploy + certbot delete
With `git` reachable again, **deploy id=54** ran clean end-to-end (phase 8
verified health at `rfc` through Cloudflare) — applied `APP_URL` to the VM
`.env`, superseding the id=53 false-failure. Then **`certbot delete
--cert-name ohm.wiggleverse.org`** (it was the only cert); the global certbot
includes survived, `nginx -t` stayed green, reloaded.
### Arc 6 — External deps B/C/D + the wrong-hook detour
- **OAuth (B):** app emits `redirect_uri=https://rfc.wiggleverse.org/auth/callback`.
The OAuth app ("OHM App", client_id `3e85cebb…`) is registered at the Gitea
**site-admin** OAuth2 level — editable in the admin panel, NOT the owner's
user settings (a Gitea gotcha that cost some hunting). ("RFC Contributor",
`9ec2dd9c…`, is a different, unused app.) Operator updated it; Gitea login
round-trips.
- **Turnstile (C):** operator added `rfc.wiggleverse.org` to the site-key
allowed domains. Verified via the login captcha + email OTC.
- **Webhook (D):** operator twice edited a **"BDD Planner Webhook"** (Push-only,
singular `/api/webhook/` path) — a *different* repo's hook — before we found
the real one. Pinned it via the Gitea API: hook **id=2** on
`wiggleverse/ohm-content` (the only hook there). Operator edited just its URL
→ `https://rfc.wiggleverse.org/api/webhooks/gitea`. Updated the flotilla
**expected** webhook set to match; `flotilla webhook check` → green.
## Cut state (end of session)
| Layer | State |
|---|---|
| Canonical host | **`https://rfc.wiggleverse.org`** (200; OHM content within rfc-app) |
| `ohm.wiggleverse.org` | **retired** — CF DNS deleted, certbot cert deleted, vhost repointed |
| Origin TLS | shared `*.wiggleverse.org` Cloudflare Origin cert (SM: `wiggleverse/wiggleverse-wildcard-{fullchain,privkey}`) |
| Cloudflare | `rfc` A→`136.116.40.66` proxied; zone=Flexible, **Full(strict) via per-host Configuration Rule** |
| App config | `APP_URL`, `health_url`, OAuth redirect, Turnstile, webhook all on `rfc` |
| Deploys | id=53 (verify false-failed, actuation OK), **id=54 clean success** v0.31.4 |
No flotilla code change. No pin bump. No release tag. No secret bytes in
transcript (cert key via operator stdin; Gitea read-token used via env var,
never printed).
## §19.2 / candidates surfaced
- `flotilla secret-file` has no lightweight "apply files only" path — landing
cert files requires a full deploy (build + restart). Fine here, but a
cert-only refresh gesture is a future nicety.
- `flotilla webhook` is read-only against Gitea (no edit) — retargeting the hook
was a manual UI step. Editing hooks remains a §19.2 candidate.
- Zone-wide Full(strict) is a footgun across a multi-origin zone; per-host
Configuration Rules are the right tool. (Recorded to memory.)
## What lands on the operator's plate
1. **Revert the "BDD Planner Webhook"** you edited mid-session — it belongs to
the BDD/ecomm app and is now likely pointing at the rfc-app endpoint, which
breaks the ecomm app's own git-sync. Set its Target URL back to the BDD app's
endpoint.
2. **Ecomm-box cleanup (spawned as a separate task):** the stale
`rfc.wiggleverse.org` vhost + LE cert on `34.59.1.73`
(`wiggleverse-ecomm-bdd-app`) will start failing HTTP-01 renewals now that
`rfc` DNS moved — remove the vhost + `certbot delete` there.
3. **Long-term:** if you ever want zone-wide Full(strict), give `git` and
`wiggle-snip` origins valid certs + 443 listeners first.
4. The uncommitted `CHANGELOG.md`/`operator-guide.md` (2026-06-01 gitea-rotation
docs) are still uncommitted — separate from this session.
## Prompt the operator can paste into the next Claude Code session
```
OHM is now served at https://rfc.wiggleverse.org (canonical as of 2026-06-02,
session 0063); ohm.wiggleverse.org is RETIRED (DNS + certbot cert deleted). The
origin uses a shared *.wiggleverse.org Cloudflare Origin cert (SM:
wiggleverse/wiggleverse-wildcard-{fullchain,privkey}, read by operator ADC at
deploy), with Full(strict) scoped to rfc via a Cloudflare Configuration Rule
(zone default is Flexible — do NOT set the zone to Full(strict), it 521s
git.wiggleverse.org and wiggle-snip). Two loose ends: (1) revert the "BDD
Planner Webhook" (a non-OHM repo hook) that got mis-pointed at the rfc-app
during the cutover; (2) clean up the stale rfc.wiggleverse.org vhost + LE cert
on the bdd.ecomm box (34.59.1.73, project wiggleverse-ecomm-bdd-app) — its
HTTP-01 renewals will now fail. This is an OHM driver session if it touches the
live deployment — claim a session ID at start.
```
@@ -1,15 +0,0 @@
# Session 0063.0 — Transcript
> Date: 2026-06-02
> Start: 2026-06-02T06-18 (PST implied)
> Status: **PLACEHOLDER — claimed at session start; finalized at session end.**
>
> This file reserves session ID 0063. The driver replaces this body
> with the full transcript before publishing, and renames the file to
> its final SESSION-0063.0-TRANSCRIPT-2026-06-02T06-18--<end>.md form.
---
## Launch prompt
_(launch prompt not captured at claim time)_