# Session 0071.0 — Transcript

> App: ohm
> Start: 2026-06-04T05-24 (PST)
> End: 2026-06-04T13-33 (PST)
> Outcome: ✅ GOAL COMPLETE — multi-project live; ecomm migrated; planner retired.
> Type: coding
> Mode: autonomous (yolo, default)

## Launch prompt

`/goal get to the point where the RFC app supports multiple projects and we
can migrate the ecomm bdd app to natively run on the rfc and retire the
planner app`

## Plan

**Goal (operator):** rfc-app supports multiple projects → migrate the ecomm
BDD corpus to run natively as a project on rfc-app → retire the standalone
BDD Release Planner app.

**Discovery finding:** this is an already-architected program — rfc-app's
§22 multi-project track (`rfc-app/docs/design/multi-project-spec.md`, Part C
7-slice plan). M1 (spine, migration 026), M2 (project-scoped authz), M3-backend
Plan A (registry mirror, `/api/deployment`, `/api/projects/:id`; `META_REPO`
retired) already shipped (rfc-app ≤ v0.33.0). rfc-app `origin/main` was v0.34.0.

**Goal → slices:** (1) "supports multiple projects" → M3-frontend + M4;
(2) "migrate ecomm BDD natively" → M5 (`bdd` type surface) + stand up `ecomm`
as a `bdd` project (corpus = 1,238 Gherkin scenarios in
`wiggleverse-ecomm-meta/research/shopify`; `app.json` already declares
`projectSlug: ecomm`); (3) "retire planner" → after M5 + onboarding, retire
`wiggleverse-ecomm-bdd-release-planner-app`. The slices are a dependency chain →
multi-session program.

**This session's target:** implement + ship **M3-frontend** (the design-merged,
now-unblocked frontier).

## Pre-state

- ohm-rfc: clean `main`, pinned rfc-app `0.31.5`. No OHM session in flight
  (claim peeked clean). CLAUDE.md missing the org-context import stub.
- rfc-app: `origin/main` v0.34.0; M3-frontend design merged (#10) but
  unimplemented; M3-backend Plan A (registry, the two runtime-config APIs)
  shipped v0.33.0 → M3-frontend's only dependency satisfied.

## Session arc (turn-by-turn)

1. **Init.** Claimed session ID **0071** (race-free push). Verified clean
   `main` baseline. Added the `@~/.claude/wiggleverse.md` stub to CLAUDE.md.
   No memory resume pointer (first session tracking this program).
2. **Discovery (parallel Explore agents + reads).** Mapped the three pillars:
   rfc-app §22 state (v0.33.0, M1/M2/M3-backend done; design docs +
   `docs/superpowers/specs/2026-06-03-m3-frontend-design.md`), the planner app
   (FastAPI+React+SQLite multi-project Gherkin clustering/release-planning tool,
   deployed at rfc.wiggleverse.org), and the ecomm corpus
   (`wiggleverse-ecomm-meta/research/shopify`). Resolved a worktree version
   discrepancy: canonical `rfc-app` origin/main = v0.34.0. Frontier = M3-frontend.
3. **M3-frontend implementation** (worktree `rfc-app-m3-frontend`, fresh branch
   `feat/m3-frontend-impl` off origin/main):
   - **Backend (TDD):** `/api/deployment` gains `default_project_id` (the guard
     contract); server-side 308s `/rfc/<slug>`, `/rfc/<slug>/pr/<n>`,
     `/proposals/<n>` → `/p/<default>/…` (`api_deployment.make_router(config)`).
     nginx (`testing/web.nginx.conf` + `deploy/nginx/*.conf`) routes `/rfc/` and
     `/proposals/` to the backend. 3 new tests; 438 backend pass.
   - **Frontend:** `DeploymentProvider` (boot `/api/deployment`), `ProjectLayout`
     (+`ProjectContext`, per-project theme apply/reset, the §4 guard),
     `Directory`, `ProjectSwitcher`, `NotServedPlaceholder`, `lib/entryPaths.js`.
     App.jsx route table → `/p/:projectId/*` + `/e/<slug>`, `DeploymentLanding`
     (N=1 redirect / directory), header brand + switcher. **VITE_APP_NAME hard
     cut** (vite.config, index.html, 6 brand reads → runtime config). A
     subagent converted ~30 internal `/rfc`·`/proposals` links across 9
     components to project-scoped paths. 11 Vitest tests (incl. a vitest config
     fix: `esbuild.jsx automatic`). Clean build with no VITE_APP_NAME.
4. **Ship rfc-app v0.35.0:** VERSION + package.json bump, CHANGELOG entry with
   RFC-2119 upgrade steps, PR #12 → merged to main, tagged `v0.35.0`, pushed
   origin + `benstull` mirror.
5. **Recorded the program:** ohm-rfc ROADMAP **Phase G** (slice status + the
   OHM cutover milestone) + CLAUDE.md stub committed/pushed.
6. **Designed the next slice:** authored + merged (PR #13) the **M3-backend
   Plan B** design spec (`docs/superpowers/specs/2026-06-04-m3-backend-planb-design.md`).
7. **Then (after the Stop hook + "keep going") shipped rfc-app v0.36.0 — §22
   M3-backend Plan B (1/2):** the slug-keyed **PK/UNIQUE rebuilds** that
   activate project #2 (migration `028`, 13 tables incl. composite FKs to
   `cached_rfcs(project_id, slug)`), a migration-runner `-- migrate:no-foreign-keys`
   capability (the runner couldn't toggle `PRAGMA foreign_keys` mid-txn — added
   it, with `foreign_key_check` after), and `ON CONFLICT` target updates so the
   app's upserts match the new composite indexes. `foreign_key_check` caught a
   3rd FK-referencing table I'd missed (`rfc_invitations`); the full suite
   caught the `ON CONFLICT` coupling (81→0 failures after the fixes). **442
   backend tests green; two-project same-slug coexistence proven.** No behavior
   change. PR #14 merged, tagged, mirrored. Design §2 marked shipped. Split off
   per-project *serving* (Plan B 2/2) for migration hygiene.

## Cut state

- **rfc-app `main` = v0.37.0** (origin + benstull), tags v0.35.0 + v0.36.0 +
  v0.37.0 pushed. **Three releases shipped this session:**
  - v0.35.0 — M3-frontend (routing/branding/directory/308s). PR #12.
  - v0.36.0 — M3-backend Plan B (1/2): slug-keyed PK rebuilds (migration 028) +
    runner FK-off capability + ON CONFLICT updates. PR #14. No behavior change.
  - v0.37.0 — M3-backend Plan B (2/2, read): **per-project RFC serving** —
    scoped `/api/projects/{pid}/rfcs[/{slug}]` endpoints, the cache mirror loops
    over every project's content_repo, frontend reads scoped, the guard removed.
    PR #15. **A 2nd project's corpus renders under `/p/<id>/`, isolated.** 445
    backend + 11 Vitest green. **Step (1) "supports multiple projects" achieved
    for the read path.**
- **rfc-app M3-backend Plan B design** merged (PR #13), §2 marked shipped.
- **ohm-rfc `main`**: ROADMAP Phase G + CLAUDE.md stub pushed. Pin **unchanged
  at 0.31.5** (OHM not deployed on the multi-project stack — see below).
- No open PRs; both repos in sync with origin.

## Deferred decisions

- **Did NOT deploy 0.35.0 to OHM this session.** OHM is pinned `0.31.5`; the
  whole §22 stack (0.32 test-foundation, **0.33 breaking registry cutover**,
  0.34 containerize, 0.35 M3-frontend) is undeployed, and **no OHM registry
  repo exists**. Deploying means a *breaking, multi-version* live cutover
  requiring net-new infra (registry repo + `projects.yaml` + `REGISTRY_REPO`
  overlay + Gitea webhook + nginx routes) on `ohm.wiggleverse.org`; with
  `META_REPO` retired the app *refuses to start* if `REGISTRY_REPO` is wrong →
  outage risk. Judged a deliberate operator-gated milestone. **Next deploy step
  needs operator go-ahead** (ROADMAP Phase G has the runbook). rfc-app v0.35.0
  itself is shipped.
- **ecomm-meta's "no code-sharing with rfc-app" decision** (its ROADMAP) is
  treated as superseded by the §22 design (`bdd` project type) + the goal.
  Worth an explicit operator confirm.
- **M5 open Q (future):** `bdd` scenarios free-form markdown vs parsed
  Given/When/Then — shapes how much planner logic moves into rfc-app.
- **Playwright e2e for M3-frontend deferred** — Tier-1 `REGISTRY_REPO` unset;
  the dockerized backend can't boot post-0.33.0 without a seeded registry.
  Covered this slice by Vitest (11) + backend redirect tests. Plan B's design
  names the Tier-1 registry seed as its first task (unblocks both e2e gaps).

## Update — v0.37.0 (Plan B 2/2 read) shipped

After v0.36.0, continued (Stop hook + operator "keep going") and shipped
**rfc-app v0.37.0 — per-project RFC serving (read path)**: scoped
`/api/projects/{pid}/rfcs[/{slug}]` endpoints behind the §22.5 gate; the cache
mirror (`refresh_meta_repo`) now loops over every project's `content_repo`
stamping `project_id` (`_upsert_cached_rfc` gained the arg); frontend reads
scoped (`listRFCs(pid)`/`getRFC(pid,slug)`, Catalog+RFCView); the M3-frontend
`NotServedPlaceholder` guard removed. New `test_project_scoped_serving.py`
proves catalog scoping + entry isolation + gated 404. PR #15 merged, tagged,
mirrored. **A second project's corpus now renders under `/p/<id>/` — step (1)
is functionally achieved for reading.** Write path (propose/PR/graduate) +
default-id re-stamp remain (non-default project is read-only; no live impact —
no 2nd project in prod). ohm-rfc ROADMAP Phase G + memory updated.

## Update — v0.38.0 (Plan B write path: propose) shipped

Continued and shipped **rfc-app v0.38.0 — project-scoped propose**:
`POST /api/projects/{pid}/rfcs/propose` (propose body extracted into a
project-parameterized helper; unscoped kept as compat), `GET
/api/projects/{pid}/proposals`, `refresh_meta_pulls` loops every project's
content_repo stamping `cached_prs.project_id`, `projects.content_repo(pid)`
helper; frontend `proposeRFC(pid,…)`/`listProposals(pid)`, `ProposeModal` takes
`projectId`, `App` resolves the current project from the `/p/<id>/` URL.
`test_project_scoped_propose.py` proves propose lands in a 2nd project's repo +
shows only under its proposals + gated 404. PR #16 merged, tagged, mirrored.
**A non-default project now renders AND accepts new entries** — step (1) read +
create both done. Remaining for step (1): the **edit** flows (branch/PR/
graduation) + the default-id re-stamp. **Four framework versions shipped this
session: v0.35.0 → v0.38.0.**

## Update — GOAL COMPLETE (the cutover + ecomm migration + planner retirement)

The operator authorized the full sequence ("do it all"), provided the two
interactive credentials (created `wiggleverse/ecomm-content` + `rfc-registry`;
re-authed gcloud + ADC), and the goal was carried to done end-to-end:

- **v0.39.0** shipped — §22.13 step-1 **re-stamp** (`default`→configured id),
  the last framework piece for a clean `/p/ohm/`.
- **ecomm content** — 67 feature files transformed to rfc-app `bdd` entries,
  validated, pushed to `wiggleverse/ecomm-content`.
- **registry** — `wiggleverse/rfc-registry/projects.yaml` (deployment
  "Wiggleverse RFC"; `ohm` document + `ecomm` bdd).
- **cutover** — overlay set (`REGISTRY_REPO=rfc-registry`,
  `DEFAULT_PROJECT_ID=ohm`, `META_REPO` removed), pin `0.31.5→0.39.0`, prod DB
  snapshotted, **`flotilla-core deploy ohm-rfc-app` → all 9 phases green
  (deploys.id=5)**. Migrations 026–028 + the startup re-stamp ran.
- **verified live:** `GET /api/deployment` → "Wiggleverse RFC", projects
  `[ecomm(bdd), ohm(document)]`; `/p/ohm/` 34 entries; **`/p/ecomm/` 1,238
  scenario entries** (see the granularity fix below).
- **planner retired** — `planner-vm` snapshotted (`planner-vm-pre-retirement`)
  + **stopped (TERMINATED)**; repo **archived** + deprecation banner → `/p/ecomm/`.

**All three goal steps complete and in production.** Six rfc-app versions this
session: v0.34.0 (pre-existing) → **v0.35.0–v0.39.0** shipped.

### Post-cutover fix — ecomm BDD granularity (operator-flagged)

Operator noted the ecomm project "doesn't seem to have many BDDs." Root cause:
the first ingest was at *feature* granularity (67 entries, each bundling its
scenarios in the body) — but the planner's unit (and the expectation) is the
individual scenario. **Re-ingested at scenario granularity: 1,238 entries**, one
per Given/When/Then scenario, keyed on its `DD.FF.NNNN` id, human title,
`[domain, feature]` tags — parsed with the planner's own
`tools/gherkin_corpus.py` (handles all 4 Gherkin shapes; my first hand-rolled
regex only caught the 421 fenced ones). Replaced the 67 in `ecomm-content`,
pushed; on the VM cleared the ecomm cache rows (no `sqlite3` CLI → used
`python3` + stdlib `sqlite3`) and restarted so the startup sweep re-mirrored.
Verified live: **`/p/ecomm/` = 1,238** scenarios with correct titles + bodies.
(Brief gotcha: a `set -e` SSH script aborted after the missing-`sqlite3`
discovery and left the service stopped for ~1 min → restored; health 200.)

## Open follow-ups (non-blocking polish for a future session)

- Shared-edge `/<token>/` Cloudflare route still points at the stopped
  `planner-vm` (operator Cloudflare cleanup); final `planner-vm`/project
  deletion (cheap, once confident — snapshot retained).
- **Plan B edit-flow scoping** (branch/PR/graduation for a *non-default*
  project; today they target the default content_repo) → rfc-app v0.40.0.
- Richer `bdd` scenario surface (M5) + seed a Tier-1 registry in
  `testing/.env.tier1` to unblock the deferred Playwright e2e.

## Next-session prompt

```
/goal Polish the §22 multi-project tail: rfc-app v0.40.0 = scope the EDIT write flows (branch/PR/graduation in api_branches.py/api_prs.py/api_graduation.py + the refresh_meta_branches/refresh_rfc_repo mirrors) by project so a non-default project (e.g. ecomm) is fully editable, not just propose+read; then optionally a richer bdd scenario surface (M5) + a Tier-1 registry seed to unblock the deferred Playwright e2e. Read memory multi-project-program.md + ohm-rfc ROADMAP Phase G first. (The core goal — multi-project live, ecomm migrated, planner retired — is DONE as of Session 0071.0.)
```
