diff --git a/ohm/0074/SESSION-0074.0-TRANSCRIPT-2026-06-05T07-35--INPROGRESS.md b/ohm/0074/SESSION-0074.0-TRANSCRIPT-2026-06-05T07-35--INPROGRESS.md index b2f70a4..e3ab8da 100644 --- a/ohm/0074/SESSION-0074.0-TRANSCRIPT-2026-06-05T07-35--INPROGRESS.md +++ b/ohm/0074/SESSION-0074.0-TRANSCRIPT-2026-06-05T07-35--INPROGRESS.md @@ -2,19 +2,129 @@ > App: ohm > Start: 2026-06-05T07-35 (PST) +> End: 2026-06-05T08-35 (PST) > Type: coding -> Status: **PLACEHOLDER — claimed at session start; finalized at session end.** -> -> This file reserves session ID 0074 for ohm. The driver replaces this -> body with the full transcript and renames the file to its final -> SESSION-0074.0-TRANSCRIPT-2026-06-05T07-35--.md form at session end. +> Status: **FINALIZED.** +> Branch: `feat/s1-collection-grain` → PR #19 (merged to `main`). Released **v0.40.0**. ## Launch prompt -_(launch prompt not captured at claim time)_ +> `/goal` Write + execute the S1 plan for the §22 three-tier refactor: migration 029 +> (add `collections` table, move per-corpus fields down from `projects`, one default +> collection per project, re-key entry-scoped tables (project_id,slug)→(collection_id, +> slug) via the 028 rebuild pattern, project_members→memberships) + thread collection_id +> through app/auth.py·projects.py·cache.py·api_* + 308 /p//e/→ +> /p//c//e/. Acceptance: @S1 scenarios green; N=1 unchanged. +> Read docs/design/2026-06-05-three-tier-projects-collections.md (Part E / §A.6) first. +> Review/merge PR #18 first if approved. + +## Plan + +Coding session executing slice **S1** of the §22 three-tier refactor (design doc +spec'd in session 0072). Write a written implementation plan, then execute it via +TDD against the full backend suite as the "N=1 unchanged" regression net. Gate: +review/merge the spec PR #18 first. + +## Pre-state + +- Clean, pushed `main` @ **v0.39.0** (two-tier deployment→project model shipped). +- The three-tier design doc was on branch `spec/three-tier-projects-collections`, + open as **PR #18 (unmerged)** on `git.wiggleverse.org/ben.stull/rfc-app`. +- Memory flagged PR #18 as open and "NEXT = write+execute the S1 plan." + +## The arc (turn-by-turn) + +1. **Session gate / init.** Classified as a **coding** session; claimed ID **0074** + (`--type coding`), no concurrent sessions, clean `main` baseline. +2. **PR #18 triage.** The memory's "PR #18" wasn't on the `benstull` remote + (`git.benstull.org`) — found it on the canonical `origin` + (`git.wiggleverse.org/ben.stull/rfc-app`, PR #18 open + mergeable). Reviewed the + 637-line design doc in full: internally consistent, stale-memory premise corrected + (two-tier shipped @ v0.39.0), migration-029 strategy decided, slices `@S1`-tagged. + **Verdict: approved** → merged PR #18 to `main` (the design doc is now on main; the + SPEC.md merge itself rides S6). +3. **Codebase exploration.** Read migration 028 (the rebuild pattern to replicate), + 026/027 (current `projects`/`project_members` schema; `type`/`initial_state` live on + `projects`), `projects.py`/`auth.py`/`cache.py`/`api_deployment.py`/`App.jsx`. Three + parallel Explore agents mapped the `project_id` blast radius, the routing/308 + surface, and the test/migration tooling (key finding: **no Gherkin runner** — `@S1` + is realised as pytest verticals; the full suite is the N=1 net). +4. **Decision: default collection id = literal `'default'`.** Established that a stable + literal (not the project id) keeps the collection id identical across fresh-vs- + upgraded deploy histories, matches the spec's `/c/default/` URLs, and lets the + existing `restamp` keep renaming only the *project* grain. The re-key maps each + entry to its project's default collection via a JOIN (robust to project_id values). +5. **Wrote the S1 plan** (`docs/superpowers/plans/2026-06-05-s1-three-tier-collection-grain.md`) + via the writing-plans skill — phased: migration 029 → backend threading → API surface + → redirects → `@S1` acceptance → release. +6. **Executed (TDD, branch `feat/s1-collection-grain`).** + - **Migration 029** (`029_collections.sql`): `collections` table; `type`/ + `initial_state` moved down off `projects`; one default collection per project + (`id='default'`, repo root); the 13 entry-corpus tables re-keyed + `(project_id,slug)`→`(collection_id,slug)` via the 028 rebuild pattern; + `project_members`→`memberships(scope_type∈{project,collection},…)`, role enum + collapsed to `{owner,contributor}`. Shape test green first. + - **Threading.** Renaming the column broke the whole suite (the intended TDD signal). + Fixed module-by-module against the regression net: `collections.py` helpers; the + registry mirror (writes project group-fields + collection corpus-fields, type + immutability on the collection); `auth.project_of_rfc` (collections join); + `auth.project_member_role` (reads memberships, maps back to legacy role strings); + `cache`/`api.py`/`api_prs`/`api_branches`/`api_notifications`/`api_contributions`/ + `api_invitations`/`api_graduation`/`api_discussion`/`funder` (13-table reads/writes + → `collection_id`; `cached_prs` + denormalised `project_id` tags left unchanged); + `projects.py` restamp + initial_state; `api_deployment` reads type/initial_state + from the default collection. A missed `project_of_rfc` edit (500 on every entry + read) was the single biggest fix — caught by the suite. + - **Redirects.** Backend `/rfc/`+`/proposals/` 308s now target `/c/default/`. Frontend: + `/c/:collectionId/` route layer; `DefaultCollectionRedirect` (C3.7); `LegacyCorpusRedirect` + (v0.35.0 `/p/

/e/` bookmarks → `/c/default/`, query preserved); path builders + carry the segment (serving stays project-scoped — collection=default; S2 owns + collection-aware serving). + - **Tests.** Added `test_migration_029_collections.py`, `test_s1_collection_grain_vertical.py` + (`@S1`), `entryPaths.test.js`. Updated the fixtures/assertions that seeded the dropped + columns (`test_api_deployment`, `test_registry`, `test_registry_wiring`, `test_migration_027`, + `test_initial_state_landing`, `test_restamp_default_project`, the multi-project + project-scoped + verticals). **Retired `test_migration_028`** (its keying is superseded by 029; invariants now + covered at the collection grain). +7. **Verification + release.** Backend **458 passed**, frontend **18 passed**, build green + (the N=1-unchanged gate + `@S1`). Bumped **VERSION/package.json → 0.40.0** (parity checked), + wrote the CHANGELOG entry with a breaking-URL upgrade-steps block. Pushed; opened **PR #19**; + self-reviewed (fully tested) and merged to `main`; deleted the branch. + +## Cut state + +- `main` @ **v0.40.0**, clean and pushed. Migration `029_collections.sql` on `main`. +- Slice **S1 shipped**: the collection grain exists as the invisible default; N=1 deployments + run unchanged with one extra `/c//` path segment. +- Full backend suite 458 green; frontend 18 green + build green. + +## Operator plate (what shipped) + +- The three-tier model (deployment → project → RFC collection) now has its collection grain + in code. A deployment upgrading 0.39.0 → 0.40.0 runs migration 029 automatically (no config + change); existing entries re-key into the default collection with no data loss; old + `/p//e/`, `/rfc/`, `/proposals/` links keep working. ## Deferred decisions -_Autonomous-mode low-confidence calls the driver made and would have -liked operator input on. Appended as the session runs; surfaced at -finalize. Empty if none._ +- **Default collection id = literal `'default'`** (not the project id): chosen for + cross-deploy-history stability + spec-URL fidelity; the multi-project-at-migration case + uses a `CASE` fallback to the project id to avoid a PK collision (non-standard pre-S5). + Worth a glance from the spec author, but it honors the spec's structural invariants. +- **`test_migration_028` retired** rather than rewritten — its `(project_id,slug)` keying is + overwritten by 029, so the test asserted a state the runner can no longer reach; the + collection-grain invariants live in `test_migration_029`. +- Denormalised `project_id` tags (`cached_prs`/`threads`/`changes`/`notifications`/`actions`/ + `pr_resolution_branches`) intentionally left as `project_id` (project grain) for S1. + +## Next-session prompt + +``` +/goal Execute slice S2 of the §22 three-tier refactor (create & navigate a second +collection): teach the registry mirror to read `.collection.yaml` manifests; add the +bot-commit-wrapped create-collection endpoint (authorized by existing deployment +owner/admin for now); the project collection-directory at /p//; and +collection-scoped propose/serve under /p//c//. Acceptance: @S2 +scenario (C3.6, anonymous reader of an empty collection catalog) green; N=1 unchanged. +Read docs/design/2026-06-05-three-tier-projects-collections.md (Part E "S2") first. +```