diff --git a/0033/SESSION-0033.0-TRANSCRIPT-2026-05-28T19-44--2026-05-28T20-14.md b/0033/SESSION-0033.0-TRANSCRIPT-2026-05-28T19-44--2026-05-28T20-14.md new file mode 100644 index 0000000..e2fa970 --- /dev/null +++ b/0033/SESSION-0033.0-TRANSCRIPT-2026-05-28T19-44--2026-05-28T20-14.md @@ -0,0 +1,202 @@ +# Session 0033.0 — Transcript + +> Date: 2026-05-28 +> Start: 2026-05-28T19-44 (PST implied) · End: 2026-05-28T20-14 +> Goal: Advance the OHM roadmap by one disjoint item, parallel-safe. +> Picked the recommended item: **#28 Parts 2 + 3** — offer-to-create-an-RFC +> for strong-candidate terms, and offer-to-contribute-to-a-pending-RFC. +> +> Outcome: **rfc-app v0.29.0 shipped + deployed + verified live on +> ohm.wiggleverse.org (deploys.id=40).** All three #28 parts are now live. +> One additive migration (024, `contribution_requests`); no config / +> overlay / secret / nginx / systemd change. 374 backend tests green (9 +> new); frontend builds clean. Merged as PR #3 (`8a94e26`), tagged +> `v0.29.0`, pushed origin + benstull mirror; ohm-rfc pin 0.28.0 → 0.29.0; +> ROADMAP #28 row struck through (all three parts shipped). + +--- + +## Launch prompt + +OHM roadmap driver session, parallel-safe. Claim ID first; read +SESSION-PROTOCOL §7 + ohm-rfc/ROADMAP.md. State at hand-off (end of 0031): +OHM at v0.27.0; flotilla v1.2.0 merged+tagged. Recommended item: **#28 +Parts 2 + 3** → target v0.28.0 (possibly split). Avoid conflicting with +session 0032 (then running) and v0.27.0's fresh security surfaces. Hard +rules: never ask for secret bytes; fresh worktree+venv for rfc-app builds; +coordinate the serialized deploy lock + version slot; FF-merge via gitea +API; finalize+publish transcript LAST, handoff prompt before publish. + +--- + +## Plan / TODO + +- [x] Claim session ID (→ 0033), read SESSION-PROTOCOL §7 + ROADMAP. +- [x] Reconcile stale brief state vs reality (0032 finished; v0.28.0 shipped). +- [x] Explore the #28 surfaces (scanner, propose flow, inbox, invite, roles, Haiku). +- [x] Isolated rfc-app worktree + venv off main; baseline tests green. +- [x] Part 2 — create-RFC offers (scanner candidate bucket + propose pre-fill + gating). +- [x] Part 3 — contribute-to-pending (scanner pending bucket + request flow + inbox actions + accept→invite + decline). +- [x] Tests (9 new), full backend suite, frontend build. +- [x] CHANGELOG + VERSION + frontend mirror. +- [x] Commit → PR #3 → FF-merge → tag v0.29.0 → push origin + benstull. +- [x] ohm-rfc pin bump → deploy → verify live. +- [x] ROADMAP #28 row struck through; worktree cleaned up. +- [x] Finalize + publish transcript (this file). + +--- + +## Pre-session state vs. reality (the brief was stale) + +The launch brief said OHM was live at **v0.27.0** and that session 0032 +was *actively running*; it also implied v0.28.0 was un-tagged/un-deployed. +By session start the picture had moved: + +- **0032 had finished** (transcript `…18-52--19-13`). Its work: IAP-only + SSH hardening, flotilla v1.2.0 re-verify, orphaned-db cleanup, and + rfc-app **v0.28.0** (audit I3 HTML-email guard + I4 async Turnstile) + opened as PR #2. The only `--INPROGRESS` placeholders left were stale + **0026 / 0027** (their security work already shipped as v0.27.0 — the + brief said to ignore them). +- The operator had since **merged, tagged, AND deployed v0.28.0**: live + `/api/health` returned `version=0.28.0`, the ohm-rfc pin was `0.28.0`, + and tag `v0.28.0` existed on main. This removed the version-slot + ambiguity the brief worried about — there was no un-tagged predecessor + to reconcile, so this session simply took the next slot, **v0.29.0**. + +Claimed session **0033** via `claim-session-id.sh --start +2026-05-28T19-44` (push to ohm-session-history is the atomic claim). + +--- + +## Scope decisions (documented in code, CHANGELOG, and ROADMAP) + +Two interpretive calls shaped the build; both were made to match Part 1's +conservative, false-positive-averse philosophy and were written into the +code docstrings so they aren't re-litigated later: + +1. **"Pending RFC" = a super-draft** (`cached_rfcs.state='super-draft'`), + not a pre-merge idea PR. A super-draft is in `cached_rfcs` (so the #12 + `rfc_invitations` FK the accept path reuses resolves), is owned + (`owners_json` — routes the request, names the owner), and has a + contribution surface to open. Pre-merge idea PRs satisfy none of those + cleanly, so they're deliberately out of scope — a documented future + extension. +2. **Part 2 candidate heuristic = multi-word #27-taxonomy tags with no + defining RFC.** Multi-word is the same guard Part 1 uses for titles; a + single common tag word (`identity`) would turn every prose occurrence + into an affordance. The roadmap sanctions "a heuristic OR the Haiku + path"; the cheap deterministic tag heuristic was chosen, with + capitalized-phrase mining / repeated-term detection / the #27 Haiku + (`ANTHROPIC_API_KEY`) pathway noted as sanctioned-but-deferred + extensions (mirroring how Part 1 deferred the curated canonical-terms + list). + +--- + +## Turn-by-turn arc + +### Arc 1 — Claim + orient +Claimed 0033. Read SESSION-PROTOCOL §7, ROADMAP (#28 detail + operating +instructions), and 0032's transcript. Confirmed live OHM = v0.28.0, pin = +0.28.0, deploy lock free, no competing active sessions. + +### Arc 2 — Explore (two parallel Explore agents) +Mapped the surfaces #28 Parts 2+3 touch: the role model (`require_contributor` +gates propose; `permission_state='granted'` is "has create rights"); the +RFC lifecycle (idea-PR-open → super-draft → active); the notification / +§15 inbox system (`_emit_one` chokepoint, `render_summary`, kinds, the +recipient-scoped inbox); and the #12 owner-invite flow (`rfc_invitations` ++ `rfc_collaborators`, accept writes the membership row). Verified +migrations top out at 023 → **024 free**. + +### Arc 3 — Backend build (isolated worktree + venv) +Took a git worktree off main on branch +`feature/v0.29.0-pr-rfc-create-contribute` with its own `.venv`; baseline +63 tests green. Then: +- **`rfc_links.py`** rewritten to a three-bucket scanner (`Term` namedtuple + + `kind` ∈ active/pending/candidate; precedence active > pending > + candidate then longest-match-first). Kept backward-compat with the legacy + `(key, slug, title)` 3-tuple so all Part 1 unit tests pass untouched. + `build_index` now also gathers super-draft terms (with resolved owner + display) and candidate tags. +- **`notify.py`** — `fan_out_contribution_request` (one actionable + notification per owner) + `notify_contribution_decided`; three new + `render_summary` branches; the inbox list item now carries `extras` + (recipient-scoped, so safe) for inline who/why/use-case. +- **`api_invitations.py`** — extracted the invite issue path into one + reusable `issue_invitation(...)` chokepoint shared by the manual + endpoint and Part 3's accept. +- **`api_contributions.py`** (new) — the GET target + request + accept + + decline endpoints; accept fires `issue_invitation` (role contributor), + reusing an existing pending invite if one exists. +- **migration 024** — additive `contribution_requests` table (partial + unique index = one open request per (RFC, user)). +- Registered the new router in `api.py`. + +### Arc 4 — Frontend build +`LinkedText.jsx` renders the two new segment kinds as query-param-routed +affordances (no prop-threading from deep in comment lists): `rfc-candidate` +→ `?propose=` (gated on create rights), `rfc-pending` → `?contribute= +&term=` (gated on signed-in). `App.jsx` reads the params and +opens `ProposeModal` (new `initialTitle`) / the new `ContributeRequestForm` +(3-field). `Inbox.jsx` gained a `ContributionRequestRow` — the first +actionable inbox kind — showing who/why/use-case with Accept/Decline. +`api.js` + CSS additions. `viewer`/`canCreate` threaded into the three +LinkedText call sites (PRView ×2, RFCDiscussionPanel). Frontend builds +clean. + +### Arc 5 — Tests +3 scanner-bucket unit tests + 6 end-to-end (PR-view segment surfacing; +request→accept→invite→notify; decline; owner-cannot-self-request; +active-RFC-rejected; eligibility). **Full backend suite 374 passing.** + +### Arc 6 — Release + deploy +VERSION + frontend mirror → 0.29.0; CHANGELOG entry with RFC-2119 upgrade +steps. Committed; pushed branch; opened **PR #3** via gitea API; FF-merged +(`8a94e26`); tagged `v0.29.0`; pushed tag + main to **origin and the +benstull mirror** (the VM fetches rfc-app from the mirror — tag must be +there before deploy). Bumped ohm-rfc pin 0.28.0 → 0.29.0, pushed. Ran +`flotilla deploy ohm-rfc-app` — all 9 steps OK, **deploys.id=40**, verify +4.6s. Live checks: `/api/health` = `0.29.0`; the new +`/api/rfcs/{slug}/contribution-target` route returns the handler's +`{"detail":"RFC not found"}` (route wired); `GET /api/rfcs` still 200. + +### Arc 7 — Record + cleanup +ROADMAP #28 row struck through (all three parts shipped, with the +deploys.id=40 + v0.29.0 link + the scope decisions); committed + pushed to +ohm-rfc. Worktree removed; shared `/Users/benstull/git/rfc-app` checkout +fast-forwarded to the merge. + +--- + +## Friction / notes + +- The brief's pre-state was stale (OHM was already on 0.28.0, 0032 done). + Verifying live state + tags first — rather than trusting the brief — + avoided a phantom version-slot reconciliation. +- No secret bytes were needed or requested (this release adds no secret/ + config). Hard rule held trivially. +- `issue_invitation` extraction is a small §19.2-style consolidation: the + manual invite endpoint and the new accept path now share one chokepoint, + so the dup-guard / token / email stay identical. + +--- + +## Cut state (end of session) + +- **OHM live:** `https://ohm.wiggleverse.org/api/health` → `version=0.29.0`, + `status=ok`. Deploy lock free. +- **rfc-app:** `main` = `8a94e26` (PR #3 merge); tag `v0.29.0` on origin + + benstull. 374 backend tests green. +- **ohm-rfc:** pin `.rfc-app-version` = `0.29.0`; ROADMAP #28 struck + through. `main` pushed (`62929b2`). +- **deploys.id=40** records the v0.29.0 deploy. + +--- + +## Operator-plate (manual gestures, if any) + +**None.** v0.29.0 needed no secret/config/overlay/nginx/systemd change; +the additive migration 024 ran automatically during the deploy. Nothing is +waiting on the operator. diff --git a/0033/SESSION-0033.0-TRANSCRIPT-2026-05-28T19-44--INPROGRESS.md b/0033/SESSION-0033.0-TRANSCRIPT-2026-05-28T19-44--INPROGRESS.md deleted file mode 100644 index 977cb0a..0000000 --- a/0033/SESSION-0033.0-TRANSCRIPT-2026-05-28T19-44--INPROGRESS.md +++ /dev/null @@ -1,15 +0,0 @@ -# Session 0033.0 — Transcript - -> Date: 2026-05-28 -> Start: 2026-05-28T19-44 (PST implied) -> Status: **PLACEHOLDER — claimed at session start; finalized at session end.** -> -> This file reserves session ID 0033. The driver replaces this body -> with the full transcript before publishing, and renames the file to -> its final SESSION-0033.0-TRANSCRIPT-2026-05-28T19-44--.md form. - ---- - -## Launch prompt - -_(launch prompt not captured at claim time)_