222 lines
13 KiB
Markdown
222 lines
13 KiB
Markdown
# 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.)
|
||
```
|