reshape: move OHM transcripts under ohm/ for org-wide multi-app layout; add org-wide root README

This commit is contained in:
2026-06-03 06:54:38 -07:00
parent bd21825bc2
commit 3713299f08
73 changed files with 200 additions and 181 deletions
@@ -0,0 +1,316 @@
# Session 0029.0 — Transcript
> Date: 2026-05-28
> Goal: Advance the OHM roadmap autonomously as a parallel driver session;
> pick one disjoint item that needs no operator input and doesn't collide
> with the two in-flight sessions.
>
> Outcome: **rfc-app v0.26.0 SHIPPED + DEPLOYED — roadmap #28 Part 1
> (auto-link accepted RFCs inside PR descriptions + PR/discussion
> comments). 363 backend tests green, frontend builds clean. Merged to
> main `698821f`, tagged v0.26.0 (origin + benstull), deployed to OHM as
> deploys.id=34 — live at ohm.wiggleverse.org/api/health = 0.26.0. The
> operator authorized merge + deploy mid-session.**
>
> Highlights:
> - Discovered the only buildable rfc-app feature (#28) and scoped it to
> its clean, non-colliding slice (Part 1).
> - Deliberate, documented spec deviation: read-time enrichment, not
> submit-time (§19.3-rule-2 note).
> - Zero migration (a concurrent session already holds migration 023);
> XSS-safe structured segments (no `dangerouslySetInnerHTML`).
---
## Pre-session state
- **OHM live**: rfc-app **v0.24.0** on the renamed VM `ohm-rfc-app`
(deploys.id stack from Session 0028: v0.22.0→v0.23.0→v0.24.0 landed
after the #1 VM-rename blocker cleared). Deploys unblocked, lock free.
- **ohm-rfc pin** (`.rfc-app-version`): `0.24.0`.
- **flotilla**: v1.2.0 built + pushed as a PR by Session 0028, NOT merged
(operator to open/merge/tag).
- **Active parallel sessions** at claim time (from `claim-session-id.sh`):
**0026** and **0027**, both claimed 2026-05-28T13-46, both `--INPROGRESS`.
- **rfc-app working dir** (`/Users/benstull/git/rfc-app`): a **shared**
checkout, mid-edit on branch `feature/v0.25.0-security-hardening`
(created 14:06 today off main/v0.24.0). Uncommitted, unpushed: OTC
verify-lockout, in-process rate limiting (`backend/app/ratelimit.py`),
HTML/XSS sanitization (`frontend/src/lib/sanitizeHtml.js` +
`MarkdownPreview.jsx` / `ProposalView.jsx` / `Editor.jsx`), and
**migration 023** (`023_otc_verify_lockout.sql`). This is one of the
0026/0027 sessions' rfc-app side — the v0.25.0 slot is claimed.
---
## Turn-by-turn arc
### Arc 1 — Claim, survey, and the parallel-session hazard
Claimed session ID **0029** via `claim-session-id.sh --start
2026-05-28T15-47` (placeholder pushed at `286e75f`). Read SESSION-PROTOCOL
§7; pulled ohm-rfc/ROADMAP.md and read it end to end.
Surveyed the candidate set from the launch prompt against "what can an
autonomous session actually ship tonight without operator input and
without colliding with 0026/0027":
- #21 Part A (Amplitude audit) — time-gated to ~2026-06-04 (needs a week
of real data). Not now.
- #22 (pro-consent copy) — blocked on operator-drafted + counsel-reviewed
text. Not now.
- #20 DMARC Phase B — time-gated to ~2026-06-04. #18/#20 ops remainder
(stale `wiggleverse/meta` webhook, bounce wiring) is operator/gitea-
admin work.
- #31b / #25-redesign — blocked on operator screenshots.
- #33 / #34 (name alignment) — operator-led, URL-breaking moves.
- **#28 (PR cross-references)** — Track B rfc-app feature, deps #3/#7/#12
all shipped. The one item buildable with no operator input. Picked.
Then the hazard surfaced: the real rfc-app checkout
(`/Users/benstull/git/rfc-app`) was a **shared working dir mid-edit** on
`feature/v0.25.0-security-hardening`. Per the launch prompt's explicit
warning ("branches alone do NOT isolate concurrent sessions sharing one
working dir — take a manual git worktree with its own venv"), I created
an isolated worktree:
```
git worktree add /Users/benstull/git/rfc-app-s0029 \
-b feature/v0.26.0-pr-rfc-links main
```
…and never touched the shared checkout again. The v0.25.0 slot being
claimed → I target **v0.26.0**.
### Arc 2 — Scoping #28 to its clean, non-colliding slice
#28 is explicitly "large, its own session" with three parts. I dispatched
one **read-only Explore agent** to map the PR/comment/RFC surfaces (folded
into this transcript per §5's driver-fold for read-only helpers — it did
no commits and warranted no separate `.1` transcript). Key findings:
- **PR descriptions and comments render as plain text** (`PRView.jsx:221`
description, `:443` PR conversation; `RFCDiscussionPanel.jsx:282`
discussion) — **not** through the `MarkdownPreview` surface the
security branch is hardening. **Zero frontend file overlap.**
- The security branch already created **migration 023**. Decisive signal
to make my slice **migration-free** — achievable by enriching at
read-time against the live `cached_rfcs` active set rather than
persisting links at submit time. That also avoids `main.py` (no new
endpoint) and any migration collision.
- RFC corpus: `SELECT slug, title, rfc_id FROM cached_rfcs WHERE
state='active'`. RFC view route is `/rfc/:slug`. Codebase convention
for internal nav inside these components is plain `<a href>` (e.g.
`PRView.jsx:190`), not react-router `<Link>`.
Scoped to **Part 1 only** (auto-link existing accepted RFCs), the
roadmap's recommended "easy win first". Parts 2 + 3 deferred.
### Arc 3 — Implementation (v0.26.0)
Read-time enrichment, migration-free, XSS-safe structured segments:
- **`backend/app/rfc_links.py`** (new): `build_index(conn, exclude_slug=)`
→ `LinkIndex.segment(text)` → list of `{type:"text"}` /
`{type:"rfc", slug, label, title}` segments. Conservative matching to
avoid false positives: links only **rfc_id** tokens (`RFC-0001`),
**multi-word** titles (whitespace present, e.g. `Open Human Model`), and
**hyphenated** slugs (e.g. `open-human-model`). A single common-word
title/slug (a hypothetical RFC titled "Human") is **not** linked — that
would turn every prose "human" into a link; the roadmap's "curated
canonical-terms list" stays an explicit future opt-in. Case-insensitive,
word-boundary-anchored, longest-match-wins, self-reference suppressed
via `exclude_slug`.
- **`api_prs.py`** `get_pr()`: builds the index once (exclude current
slug), adds `description_segments` and per-comment `text_segments`.
- **`api_discussion.py`** `get_discussion_thread_messages()`: per-comment
`text_segments`.
- **`frontend/src/components/LinkedText.jsx`** (new): maps segments onto
React text nodes + `<a class="rfc-autolink">`. No
`dangerouslySetInnerHTML` → XSS-safe by construction, independent of the
security branch's `sanitizeHtml.js`. Falls back to raw `text` when
segments are absent (older cached responses).
- Wired into `PRView.jsx` (description + PR conversation bodies) and
`RFCDiscussionPanel.jsx` (discussion bodies). `App.css`: a tokenized
`.rfc-autolink` rule (accent + dotted underline).
- `VERSION` → `0.26.0`; `frontend/package.json` → `0.26.0` (the
package-lock version field is stale at 0.21.0 across recent releases —
left as-is to match convention).
**Deliberate spec deviation** (recorded per §19.3-rule-2): the roadmap row
says the scan happens "at submit/post time"; I shipped **read-time**
enrichment. The intent the row actually names — "not as live compose
preview" — holds (drafts are never scanned). Read-time was chosen for
correctness (links track the live active set: newly-accepted RFCs start
linking, withdrawn ones stop), zero migration, and cheapness (the corpus
is small + cache-resident).
### Arc 4 — Tests, build, ship
- New `backend/tests/test_rfc_links_vertical.py`: 12 tests (9 scanner
units covering the gating rules, word boundaries, longest-match,
case-insensitivity, casing preservation; 3 end-to-end that PR
description + review comment + discussion comment all surface
`*_segments`, plus self-reference suppression). Two integration-test
fixes mid-flight: the change `original` text must exist verbatim in
`SEED_BODY` (else "stale"), and the PR description carries an appended
§6.5 `On-behalf-of:` trailer (so assert containment, not equality).
- **Full backend suite: 363 passed** (351 baseline + 12 new).
- **Frontend builds clean** (`npm ci` + `npm run build` with a throwaway
`.env` providing `VITE_APP_NAME`; the chunk-size warning is pre-existing).
- Committed `e794523`; pushed `feature/v0.26.0-pr-rfc-links` to **origin**
(git.wiggleverse.org) + **benstull** (mirror).
- ohm-rfc ROADMAP #28 row updated with a "Part 1 built + PR-pushed"
status note (commit `0f09403`, pushed to ohm-rfc main) so a future
driver doesn't re-pick Part 1.
I left the branch PR-ready and recorded a "built + PR-pushed" status note
on the ohm-rfc ROADMAP #28 row — initially deferring the merge/deploy to
the operator per the launch prompt's "coordinate the deploy lock + slot"
rule.
### Arc 5 — Operator authorized merge + deploy
Mid-session the operator replied: **"go ahead and merge the PR and
deploy."** So I carried it through, with two safety detours forced by the
parallel-session environment:
- **Merge.** `main` was not checked out in any worktree (the shared rfc-app
checkout holds the security branch with uncommitted work — untouchable).
Created a fresh detached worktree on `main`, `git merge --no-ff` the
feature branch (merge `698821f`), tagged `v0.26.0` (lightweight, house
style), pushed `main` + tag to origin + benstull. Version-slot note:
merging v0.26.0 makes the parallel v0.25.0 security session "last to
merge" — it renumbers/rebases per the roadmap rule; flagged for the
operator.
- **Deploy.** The canonical flotilla checkout had **uncommitted
`deploy.py` changes** — the 0026/0027 secret-redaction WIP on
`_PhaseRunner` — and its editable `.venv` runs the working tree. Rather
than actuate a production deploy with another session's unmerged code,
I deployed from a **clean detached worktree on flotilla `main`
(c26f251 = v1.1.0)** with its own venv. The state DB
(`~/.ohm-rfc-app-flotilla/`) is a fixed user path, so the worktree saw
the registered deployment + deploy log + §8.3 lock.
- **A scare, resolved.** A `deploy log | tail -12` appeared to show the
last *success* as v0.17.0 with three aborted v0.18.0 rows — seemingly
contradicting "live at v0.24.0." I stopped and probed ground truth:
`deploy status` + a direct curl both returned **0.24.0**. The "missing"
rows were a `tail` artifact (the log prints newest-first; `tail` hid
ids 2634). No real discrepancy. (Lesson: probe live health before
trusting a truncated log view.)
- **Deploy.** Dry-run confirmed the plan (target v0.26.0, 7 secret refs
resolve incl. the already-bound `ANTHROPIC_API_KEY`, renamed VM
`/opt/ohm-rfc-app`, no migration step). Real deploy: all 9 phases ok,
**deploys.id=34**, health verify in 7.3s — no SSE-keepalive abort
despite deploying with pre-v1.2.0 flotilla (the intermittent failure
didn't trigger). Live `/api/health` = `0.26.0`; `pin check` matches.
- Updated the ohm-rfc ROADMAP #28 row to **Part 1 ✅ SHIPPED + DEPLOYED**
(commit `b4d39a8`). Removed all three temporary worktrees.
---
## Cut state (end of session)
| Repo / surface | State |
| --- | --- |
| rfc-app | `main` @ `698821f` (merge), tag **v0.26.0** pushed to origin + benstull. 363 tests green, FE builds. Feature commit `e794523`. |
| ohm-rfc | `main` @ `b4d39a8` — pin bumped to **0.26.0**, ROADMAP #28 Part 1 struck SHIPPED + DEPLOYED. |
| OHM live | **v0.26.0** on `ohm-rfc-app`, healthy (`/api/health`=0.26.0). **deploys.id=34** succeeded (9/9 phases, verify 7.3s). |
| Worktrees | All three temporary worktrees (rfc-app feature, rfc-app main-merge, flotilla deploy) removed. |
| #28 ledger | Status |
| --- | --- |
| #28 Part 1 (auto-link accepted RFCs) → v0.26.0 | ✅ shipped + deployed (deploys.id=34) |
| #28 Part 2 (offer-to-create-RFC) | ⏸ not started |
| #28 Part 3 (offer-to-contribute-to-pending) | ⏸ not started |
---
## §19.2 / process candidates surfaced
1. **Branch-chat auto-linking.** Part 1 enriches PR descriptions, PR
review comments, and PR-less discussion comments — but not branch-chat
messages (the AI-collaboration surface, `ChatPanel.jsx` +
`api_branches.py`). Extending `rfc_links` there is a small follow-up if
branch chat warrants it.
2. **Curated canonical-terms / per-RFC alias list.** The conservative
matcher deliberately skips single common-word titles/slugs. The roadmap
names a "curated canonical-terms list" for exactly these; it's left as
an explicit opt-in (config/content), not guessed at in framework code.
3. **rfc-app test deps aren't in `requirements.txt`.** `pytest` /
`httpx` / `pytest-asyncio` had to be pip-installed into the fresh
worktree venv by hand (the shared checkout's venv had them). A
`requirements-dev.txt` (or an extras group) would make a clean worktree
test-ready in one step. Minor ergonomic gap, like the `PYTHONPATH=.`
one CONTRIBUTING already notes.
---
## What lands on the operator's plate
1. **v0.26.0 is shipped + deployed (deploys.id=34) — nothing left here.**
Worth a real-world eyeball: open a PR or post a comment on OHM that
mentions an accepted RFC (RFC-0001 / "Open Human Model") and confirm
the inline auto-link renders to `/rfc/<slug>`.
2. **The parallel v0.25.0 security-hardening session (0026/0027) is now
"last to merge."** Because v0.26.0 landed first, that session must
rebase onto a `main` that's already at v0.26.0 and **renumber to
v0.27.0** (its target slot is taken). Expect a trivial top-of-file
CHANGELOG/VERSION resolution; the code regions are disjoint from
v0.26.0's (their MarkdownPreview/otc/ratelimit vs. my rfc_links/PRView/
discussion).
3. **The local flotilla `deploy.py` working tree still has the 0026/0027
secret-redaction WIP uncommitted** — I deployed from clean `main`
(v1.1.0) and left their WIP untouched. Nothing for you unless you want
to land it.
4. (Carried from 0028) flotilla v1.2.0 PR still open + unmerged — the
phase-7 SSE pre-drain it carries would have de-risked this deploy's
restart phase (which happened to succeed without it).
5. **Parts 2 + 3 of #28** remain unbuilt — the larger follow-up.
---
## Prompt the operator can paste into the next Claude Code session
```
OHM roadmap driver session, parallel-safe. Claim your ID first:
~/git/ohm-infra/scripts/claim-session-id.sh --start <now PST, YYYY-MM-DDTHH-MM>
It prints active --INPROGRESS sessions — coordinate. Read SESSION-PROTOCOL §7
+ pull ohm-rfc/ROADMAP.md.
STATE (end of 0029, 2026-05-28): OHM live at rfc-app **v0.26.0** on
ohm-rfc-app (deploys.id=34, healthy), pin=0.26.0, deploy lock free.
Session 0029 shipped + DEPLOYED #28 Part 1 (auto-link accepted RFCs in PR
text + comments). Still built-but-unmerged / in-flight:
- flotilla v1.2.0 (Session 0028) — PR open, not merged (its phase-7 SSE
pre-drain de-risks deploy restarts; the v0.26.0 deploy succeeded
without it).
- rfc-app v0.25.0 security-hardening (Sessions 0026/0027) — uncommitted
in the shared /Users/benstull/git/rfc-app checkout (+ uncommitted
deploy.py redaction WIP in the flotilla checkout). Because v0.26.0
merged first, this session is now "last to merge" → it must rebase
onto main@v0.26.0 and **renumber to v0.27.0** (slot 0.25.0 superseded).
Code regions are disjoint from v0.26.0's.
PICK ONE disjoint item. Open candidates: #28 Parts 2+3 (offer-to-create-RFC;
offer-to-contribute-to-pending — the larger follow-up, its own session, and
it will rebase on whatever v0.25.0's MarkdownPreview/sanitize work settled);
#21 Part A Amplitude audit (real data ~2026-06-04); #22 pro-consent copy
(operator-drafted + counsel text); #20/#18 ops (DMARC Phase B ~2026-06-04;
stale wiggleverse/meta webhook still pointing at deprovisioned
rfc.wiggleverse.org; bounce wiring); #31b/#25-redesign (operator
screenshots); #33/#34 repo + GCP name alignment (operator-led).
AVOID shipped/in-flight surfaces: #26/#27/#29/v0.21.0; the v0.25.0 security
files (otc.py, ratelimit.py, MarkdownPreview/ProposalView/Editor.jsx,
sanitizeHtml.js, migration 023); and v0.26.0's surfaces (rfc_links.py,
LinkedText.jsx, get_pr/discussion enrichment).
Hard rules: never ask for secret bytes (give the
`printf '%s' "$(pbpaste)" | .venv/bin/ohm-rfc-app-flotilla secret set
ohm-rfc-app <KEY>` gesture); coordinate the serialized deploy lock + version
slot with the operator; if you build in rfc-app, take a manual git worktree
with its own venv (the shared /Users/benstull/git/rfc-app checkout may be
mid-edit by another session); subagents write their own §5 subsession
transcripts; finalize + publish your transcript LAST (deliver the handoff
prompt before publish). Use branches + PRs. Claim your ID, then go.
```