add 0047/SESSION-0047.0-TRANSCRIPT-2026-05-30T11-02--2026-05-30T12-47.md + replace placeholder/variant SESSION-0047.0-TRANSCRIPT-2026-05-30T11-02--INPROGRESS.md
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
# Session 0047.0 — Transcript
|
||||
|
||||
> Date: 2026-05-30
|
||||
> Started: 2026-05-30T11-02 · Ended: 2026-05-30T12-47 (PST implied)
|
||||
> Goal: Advance ROADMAP **#38** (Track Δ) — turn the session-0046 e2e
|
||||
> scaffold (rfc-app PR #4) into a working, green Tier-1 local-Docker suite.
|
||||
> No VM work (Track Δ's VM pieces stay gated/deferred to their own session).
|
||||
>
|
||||
> Outcome: **#38 Tier 1 is live and green.** `docker compose up --build`
|
||||
> stands up the full stack (frontend+backend+SQLite+Mailpit+real disposable
|
||||
> Gitea) and the Playwright suite passes 4/4, deterministically across
|
||||
> repeated runs: health, landing render, and the OTC sign-in vertical
|
||||
> (API round-trip + full browser UI). Pushed to **rfc-app PR #4**
|
||||
> (`session-0046/e2e-tier1-scaffold`, fast-forward `a3f48ba..15af891`).
|
||||
> One default-secure framework change rode along (`ratelimit.py` test
|
||||
> bypass). Not a release; no deploy; PR #4 left for the operator to merge.
|
||||
|
||||
---
|
||||
|
||||
## Pre-session state
|
||||
|
||||
- **flotilla**: `main` @ `5f1689f` (v1.4.0). **v1 has shipped** — relevant
|
||||
below.
|
||||
- **rfc-app**: `main` @ `0c972c8` (v0.31.0). PR #4 open from session 0046:
|
||||
branch `session-0046/e2e-tier1-scaffold` @ `a3f48ba`, an `e2e/` scaffold
|
||||
(compose topology + helpers + `test.fixme` specs) — **not yet brought up
|
||||
or validated**; Dockerfiles + the Gitea bootstrap were the explicit TODO.
|
||||
- **OHM live**: v0.31.0 (deploys.id=46). Untouched this session.
|
||||
- **Other sessions in flight at claim time**: 0045 (`--INPROGRESS`, UX pass
|
||||
on the admin Users page — rfc-app *frontend*, disjoint from `e2e/`), plus
|
||||
stale `--INPROGRESS` placeholders 0026/0027.
|
||||
|
||||
---
|
||||
|
||||
## Turn-by-turn arc
|
||||
|
||||
### Arc 1 — Orient + the v1-gate question
|
||||
|
||||
Read SESSION-PROTOCOL.md + the ROADMAP Track-Δ section (#37–#42). Claimed
|
||||
**session 0047** via `claim-session-id.sh` (placeholder pushed at `e76b1d3`).
|
||||
|
||||
The launch prompt insisted on confirming **flotilla v1 timing** before any
|
||||
VM-side work. Asked the operator (Tier-1-only vs PPE-in-scope). The operator
|
||||
turned it back to me: *"can we do #2 this session or stick to #1?"*
|
||||
|
||||
**My call: stick to Tier-1 (#1) this session.** Surfaced a factual
|
||||
correction — **flotilla v1 has already shipped (v1.4.0)**, so the
|
||||
"gated on v1" condition on Track Δ is *already satisfied*; #37 (PPE) isn't
|
||||
blocked by v1 timing, it's just a large, separate live-infra effort (new GCP
|
||||
project + micro VM + colocated `ppe.git` Gitea + DNS + a real flotilla
|
||||
multi-deployment code change). #38 Tier-1 is prerequisite-free, operator-
|
||||
gesture-free, and de-risks PPE (Tier 2 reuses the same suite). House
|
||||
discipline is one feature per session.
|
||||
|
||||
### Arc 2 — Map the backend (Explore subagent)
|
||||
|
||||
Dispatched an Explore agent to produce a concrete reference: `config.py`
|
||||
required vars, boot/migration path (`app.main:app`, `db.run_migrations`),
|
||||
OTC endpoints (`POST /auth/otc/request` → 202; `POST /auth/otc/verify` →
|
||||
session cookie `rfc_session`), the Turnstile knob (`TURNSTILE_REQUIRED`),
|
||||
the `gitea.py` client surface, the seed scripts, the frontend build
|
||||
(`VITE_APP_NAME` required), `/api/health`, and the `deploy/nginx` proxy
|
||||
shape. Verified the load-bearing details directly afterward.
|
||||
|
||||
**Key catch:** the `rfc_session` cookie is `Secure` by default → browsers
|
||||
drop it on `http://localhost` → sign-in wouldn't stick in Tier 1. Confirmed
|
||||
the opt-out is `SESSION_COOKIE_SECURE=false` (`main.py:152`).
|
||||
|
||||
### Arc 3 — Build the Tier-1 stack (in an isolated worktree)
|
||||
|
||||
Per the parallel-session rule (0045 in flight, same repo), worked in a
|
||||
dedicated git worktree on `session-0047/e2e-tier1` (off the scaffold tip),
|
||||
never the shared checkout. Wrote:
|
||||
|
||||
- `e2e/docker/backend.Dockerfile` (+ `backend-entrypoint.sh`) — repo-mirror
|
||||
layout so `parents[2]/VERSION` and the seed scripts' `parent.parent`
|
||||
resolve as in prod; entrypoint reads the minted bot token into
|
||||
`GITEA_BOT_TOKEN`. Same image runs the `gitea-seed` one-shot.
|
||||
- `e2e/docker/frontend.Dockerfile` + `nginx.conf` — Vite build → nginx
|
||||
serving the SPA + proxying `/api`,`/auth` to `backend:8000`.
|
||||
- `scripts/bootstrap_e2e_gitea.py` — create the org, then reuse
|
||||
`seed_meta_repo.py` to create + seed `META_REPO` (`ohm-content`).
|
||||
- Rewrote `docker-compose.yml`: `gitea` (real `gitea/gitea:1.22`),
|
||||
`gitea-init` (mint bot user+token via CLI → shared volume), `gitea-seed`
|
||||
(org + seed), `backend`, `frontend`, `mailpit`, chained by `depends_on`.
|
||||
- `.env.example`: added `SESSION_COOKIE_SECURE=false`, `GITEA_ADMIN_PASSWORD`,
|
||||
annotated the runtime-overridden `GITEA_BOT_TOKEN`; root `.dockerignore`.
|
||||
|
||||
### Arc 4 — Bring it up; three real obstacles, fixed
|
||||
|
||||
Iterated against a live `docker compose up`:
|
||||
|
||||
1. **Gitea refuses to run as root** → every `gitea admin user create`
|
||||
FATAL'd. Fix: container is root only to `chown` the fresh token volume;
|
||||
the `gitea` commands drop to the `git` user via `su-exec`.
|
||||
2. **gitea-init not idempotent** on an `up` over a persisted volume (user +
|
||||
token-name `e2e` already existed → exit 1). Fix: short-circuit if the
|
||||
token file exists; tolerate an existing user; unique token name.
|
||||
3. **Per-IP OTC rate limiter** (`5 sends / 5 min`, `ratelimit.py`) — the
|
||||
suite drives all auth from one IP, so a normal run + CI retries trip it.
|
||||
This is a *real* determinism issue, not just test churn. Fix: a
|
||||
default-secure, env-gated `RFC_APP_RATELIMIT_DISABLED` bypass in
|
||||
`allow()` (mirrors `RFC_APP_INSECURE_WEBHOOKS`; durable per-email
|
||||
lockouts unaffected) + `tests/test_ratelimit_bypass.py` (incl. the
|
||||
default-still-enforces case, run green via a throwaway venv).
|
||||
|
||||
After fixes: clean `down -v && up --build` → all services healthy,
|
||||
`/api/health` → `{"version":"0.31.0","status":"ok"}`, gitea seeded.
|
||||
|
||||
### Arc 5 — Green the suite
|
||||
|
||||
Finalized the `test.fixme` specs against the live DOM:
|
||||
- `smoke.spec.js`: health shape + landing `<h1>`/title.
|
||||
- `otc-login.spec.js`: API round-trip (request→Mailpit→verify→`/me`,
|
||||
asserts `pending`/`needs_profile`) **and** a browser sign-in.
|
||||
|
||||
Two real DOM obstacles in the browser test: the **v0.13.0 cookie-consent
|
||||
banner** intercepts clicks (added a reusable `helpers/app.js`
|
||||
`dismissCookieConsent`), and a fresh OTC user redirects to the pending
|
||||
"request is in review" page rather than staying on the capture-profile copy
|
||||
(asserted the "Sign out" link + the review *heading*, dodging a strict-mode
|
||||
double-match). **4/4 green, twice, ~1.7s.**
|
||||
|
||||
### Arc 6 — Ship + clean up
|
||||
|
||||
Committed `15af891`, verified fast-forward safety against the unchanged
|
||||
remote tip (`a3f48ba`), pushed to **PR #4**. Tore down Docker (`down -v`),
|
||||
removed the worktree + throwaway venv. Shared rfc-app checkout never touched.
|
||||
|
||||
---
|
||||
|
||||
## Cut state (end of session)
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| rfc-app PR #4 | `session-0046/e2e-tier1-scaffold` @ `15af891` (fast-forward over scaffold `a3f48ba`). **Open, not merged.** Tier-1 suite green. |
|
||||
| rfc-app `main` | unchanged @ `0c972c8` (v0.31.0) |
|
||||
| OHM live | unchanged — deploys.id=46, v0.31.0, healthy |
|
||||
| ohm-rfc pin | unchanged (v0.31.0) |
|
||||
| flotilla | unchanged @ `5f1689f` (v1.4.0) |
|
||||
|
||||
| Track Δ ledger | Status |
|
||||
| --- | --- |
|
||||
| #37 PPE pre-prod env | ⏸ deferred — own session (live infra; v1 gate already satisfied) |
|
||||
| #38 e2e suite + gate | 🟡 **Tier 1 shipped to PR #4 (green); Tier 2 gated on #37** |
|
||||
| #39 blue/green slots | ⏸ depends on #37 |
|
||||
| #40 compat gate | ⏸ Tier-1 harness is the next #38-adjacent piece |
|
||||
| #41 canary routing | ⏸ depends on #39/#40 |
|
||||
| #42 auto-rollback | ⏸ depends on #41 |
|
||||
|
||||
---
|
||||
|
||||
## §19.2 / process candidates surfaced
|
||||
|
||||
1. **The e2e suite needs a stable test-posture profile.** Three env knobs
|
||||
(`SESSION_COOKIE_SECURE=false`, `RFC_APP_RATELIMIT_DISABLED=1`,
|
||||
`RFC_APP_INSECURE_WEBHOOKS=1`) + `TURNSTILE_REQUIRED=0` are all
|
||||
"deterministic-test" toggles. PPE (#37) will want the same posture
|
||||
*except* `SESSION_COOKIE_SECURE` (https). Worth codifying as a named
|
||||
profile rather than scattered env when Tier 2 lands.
|
||||
2. **The (B) Gitea stub vs (A) real-Gitea split is now half-built.** (A) is
|
||||
the default everywhere today; (B) (the fast-inner-loop optimization)
|
||||
remains a TODO behind `gitea.py`. Decide whether (B) earns its keep once
|
||||
the suite has enough non-Gitea scenarios to make inner-loop speed bite.
|
||||
3. **flotilla multi-deployment audit (#37 dependency).** The §8 deploy
|
||||
phases assume one host/project; driving a second deployment (PPE) on its
|
||||
own VM/gcloud-config is the real flotilla code change behind #37 — audit
|
||||
before standing up PPE.
|
||||
|
||||
---
|
||||
|
||||
## What lands on the operator's plate
|
||||
|
||||
1. **Merge rfc-app PR #4** — the Tier-1 suite is green and one fast-forward
|
||||
commit (`15af891`) over the scaffold. Left unmerged because it's your PR
|
||||
from 0046 and the 0046 heads-up flagged a wedged Gitea merge-queue;
|
||||
merging is a clean operator gesture (additive `e2e/` + a default-secure
|
||||
`ratelimit.py` gate; no version, no deploy). When it merges, the ohm-rfc
|
||||
ROADMAP #38 row can be updated to "Tier 1 shipped."
|
||||
2. **Decide #37 PPE timing** — it's unblocked (v1 shipped); it's a full
|
||||
live-infra session (new GCP project + micro VM + `ppe.git` Gitea + DNS +
|
||||
flotilla multi-deployment support). Confirm before any VM stand-up.
|
||||
|
||||
---
|
||||
|
||||
## Prompt the operator can paste into the next Claude Code session
|
||||
|
||||
```
|
||||
OHM driver session. Read ~/git/ohm-infra/SESSION-PROTOCOL.md and
|
||||
~/projects/wiggleverse/ohm-rfc/ROADMAP.md (Phase F / Track Δ, #37–#42).
|
||||
Claim your session id via claim-session-id.sh --start <now>.
|
||||
|
||||
State: flotilla v1 has shipped (v1.4.0) — the "gated on v1" condition on
|
||||
Track Δ is ALREADY SATISFIED. Session 0047 shipped #38 **Tier 1**: a
|
||||
working, green local-Docker e2e suite on rfc-app PR #4
|
||||
(branch session-0046/e2e-tier1-scaffold, tip 15af891). `cd e2e && cp
|
||||
.env.example .env && docker compose up -d --build && npx playwright test`
|
||||
→ 4/4 green (health, landing, OTC API round-trip, OTC browser sign-in)
|
||||
against a real disposable Gitea + Mailpit + fresh SQLite. A default-secure
|
||||
RFC_APP_RATELIMIT_DISABLED gate was added to backend/app/ratelimit.py
|
||||
(test-posture only; unit-tested). PR #4 is OPEN, not merged.
|
||||
|
||||
Pick one:
|
||||
(a) Merge rfc-app PR #4 (operator gesture; additive, no deploy), then
|
||||
update the ohm-rfc ROADMAP #38 row to "Tier 1 shipped."
|
||||
(b) #38 follow-ons that need no VM: the (B) in-memory gitea.py stub
|
||||
(fast inner loop), broader scenarios (propose-RFC / contribute-PR /
|
||||
invites / notifications — reuse helpers/mailpit.js + helpers/app.js),
|
||||
or the #40 Tier-1 compat-gate harness (N-1 image → migrate → N).
|
||||
(c) #37 PPE — the big one. Unblocked but live-infra: a SEPARATE GCP
|
||||
project + micro VM + colocated ppe.git Gitea + DNS + a real flotilla
|
||||
multi-deployment code change (audit the §8 deploy phases first).
|
||||
CONFIRM with the operator before standing up anything on a VM.
|
||||
|
||||
Heads-up (still relevant): a wedged Gitea merge-queue was seen in 0046
|
||||
(persistent 405); verify git state against origin (git ls-remote) before
|
||||
assuming a push/merge landed; put --max-time on curls; do hands-on git in
|
||||
an isolated worktree (other sessions share the checkout).
|
||||
```
|
||||
@@ -1,50 +0,0 @@
|
||||
# Session 0047.0 — Transcript
|
||||
|
||||
> Date: 2026-05-30
|
||||
> Start: 2026-05-30T11-02 (PST implied)
|
||||
> Status: **PLACEHOLDER — claimed at session start; finalized at session end.**
|
||||
>
|
||||
> This file reserves session ID 0047. The driver replaces this body
|
||||
> with the full transcript before publishing, and renames the file to
|
||||
> its final SESSION-0047.0-TRANSCRIPT-2026-05-30T11-02--<end>.md form.
|
||||
|
||||
---
|
||||
|
||||
## Launch prompt
|
||||
|
||||
```
|
||||
OHM driver session. Read ~/git/ohm-infra/SESSION-PROTOCOL.md and
|
||||
~/projects/wiggleverse/ohm-rfc/ROADMAP.md (Phase F / Track Δ, #37–#42)
|
||||
first. Claim your session id via claim-session-id.sh --start <now>.
|
||||
|
||||
Session 0046 recorded the operator's Track-Δ design decisions into the
|
||||
docs (engineering handbook §10 + ohm-rfc ROADMAP). Nothing was built —
|
||||
all of Track Δ is GATED ON flotilla v1. The decided shape:
|
||||
|
||||
- Two-tier testing (handbook §10.3 / ROADMAP #38, #40): env-agnostic
|
||||
suite (one BASE_URL + mail-sink API URL). Tier 1 = local Docker per-PR
|
||||
(no VM); Tier 2 = PPE as the deploy gate. The #40 N−1/N compat gate
|
||||
runs first in Tier-1 Docker, PPE as prod-like confirmation.
|
||||
- #37 PPE = COMPLETELY SEPARATE infra (handbook §10.1 / ROADMAP #37):
|
||||
own GCP micro instance + separate gcloud stack (own project/config) +
|
||||
own Gitea at ppe.git.wiggleverse.org colocated on the PPE VM. NOT
|
||||
colocated on prod; only flotilla's code-deploy gesture crosses over.
|
||||
Auth in tests = OTC (OAuth caveat resolved, #5 shipped).
|
||||
- #38 Tier-1 Gitea = stub for the fast inner loop, real Gitea for the
|
||||
gate (Tier 2 uses PPE's own Gitea). Scaffold OPEN at rfc-app PR #4
|
||||
(branch session-0046/e2e-tier1-scaffold, e2e/ dir, NOT a release).
|
||||
- #42 auto-rollback = always-on VM-side watcher (systemd daemon, DB-free
|
||||
rollback only; bounded carve-out from flotilla laptop-only).
|
||||
- Open follow-on (not decided): self-host PROD Gitea on the prod VM too.
|
||||
|
||||
CONFIRM flotilla v1 timing with the operator before standing up ANYTHING
|
||||
on a VM (PPE micro instance, the PPE/prod Gitea, DNS). Work that does NOT
|
||||
need the VM and can proceed now: flesh out rfc-app PR #4 toward a passing
|
||||
Tier-1 suite (Dockerfiles + the (B) gitea stub + the (A) gitea bootstrap
|
||||
+ real selectors) — that's #38.
|
||||
|
||||
Heads-up: 0046 hit a wedged Gitea merge-queue (persistent 405); harness
|
||||
Bash/Read corruption; verify git state against committed blobs; --max-time
|
||||
on every curl; check git branch -r --contains before assuming PR merge path.
|
||||
|
||||
```
|
||||
Reference in New Issue
Block a user