# Session 0018.0 — Transcript > Date: 2026-05-28 > Goal: Wave 9 — operator follow-ups on the v0.19.0 docs surface. Ship a follow-on rfc-app minor (v0.20.0) that adds `/docs/specs/`, fixes the flat-flyout nav hierarchy, removes body links from session index pages; amend the `wiggleverse/ohm-session-history` README with a scoping section about the vibe-coded prototypes that preceded spec-driven development; rewrite legacy `Session L`/`Session M.1`-style refs inside transcript bodies to the numeric `Session 0012.0`/`Session 0013.1` form across both `~/git/ohm-infra/` and the published repo. > > Outcome: **All five items shipped. rfc-app v0.20.0 live on OHM (deploys.id=28, clean — no §19.2-keepalive timeout this time). 502 body-ref replacements across 39 transcripts in two repos. README scoping section added. ROADMAP #30 struck through with Phase 1 / Phase 2 attribution. Subagent 0018.1 stalled mid-flight and the driver picked up the remaining frontend wiring inline.** > > Wave 9 ledger (this session): A specs surface ✅, B README amendment ✅, C nav hierarchy ✅, D body-link removal ✅, E body rewrite ✅. Five new §19.2 candidates surfaced (see end). --- ## Pre-session state Session 0017.0 had shipped v0.19.0 (the first cut of the on-site sessions browser) and the wiggleverse/ohm-session-history repo restructure (one folder per session + README + sessions.json) maybe ~30 minutes before Session 0018.0 opened. Cut state at handoff was: | repo | state | | --- | --- | | rfc-app | `69a166a` on `main`, tag `v0.19.0` pushed to origin + benstull mirror | | ohm-rfc | `de17e79` on `main`; `.rfc-app-version=0.19.0` | | ohm-rfc-app-flotilla | `417b6c5` on `main` (unchanged this session) | | wiggleverse/ohm-session-history | `412b6ab` on `main` (Session 0017.0's published transcript) | | OHM live | v0.19.0 healthy at `/api/health`; deploys.id=27 stuck `in_progress` from Session 0017.0's §19.2-keepalive SIGTERM SSH watchdog timeout | | ohm-infra working repo | not a git repo; `SESSION-PROTOCOL.md` already carried Session 0017.0's §1 + §5 amendments | The operator opened with a substantive Wave 9 brief. After my clarifying questions ("which specs", "what does 'no body links' mean specifically", "do you want me to draft the vibe-coded prose", "is Session 0017 still writing on ohm-session-history?") the operator's reply was "this all sounds great. Just do it and I'll review and we can adjust based on what I see." Session 0017's SESSION-0017.0 transcript landed locally at `2026-05-28T08-50--2026-05-28T09-22.md` and published to the repo (commit `412b6ab`) about a minute before this session started — so 0017 was wrapping, not actively still touching the repo. No coordination conflict. --- ## Turn-by-turn arc ### Arc 1 — Pre-state read + Wave 9 plan Read `~/git/ohm-infra/SESSION-PROTOCOL.md` end-to-end (the §1 + §5 amendments from Session 0017.0 were the relevant new content), `/Users/benstull/projects/wiggleverse/ohm-rfc/ROADMAP.md` end-to-end (#30 still marked `**NEXT**` — Session 0017.0 hadn't struck it through), and grep'd the repos for the file paths I'd need to touch. Engaged the operator with the load-bearing first test (load `/docs/sessions/about` + a sample transcript page in a fresh incognito tab; confirm the v0.19.0 flyout nav works at all before stacking more on top). The operator's reply pivoted past the verification and went straight into the Wave 9 substantive brief, which signaled both "the basic surface works" and "here's what's wrong with it that we should fix in this session." Distilled the Wave 9 brief into five items and confirmed scope with four clarifying questions. Operator: "Just do it and I'll review." Set up seven TaskCreate tasks tracking the work, marked #1 in_progress. ### Arc 2 — Dispatch subagent 0018.1 + driver inline B+E in parallel Cloned `wiggleverse/ohm-session-history` to `/tmp/ohm-session-history-0018/` (the publish script does this to a tempdir per invocation, but for a multi-file commit I needed a working clone). Read `DocsLayout.jsx`, `DocsSessionIndex.jsx`, `docs_sessions.py`, the existing v0.19.0 route shape in `App.jsx`, the README's current operator-review placeholders, and the SESSION-PROTOCOL.md §1 legacy-form subsection. Dispatched subsession **0018.1** with `isolation: worktree`, `run_in_background: true`, briefing it on the three rfc-app items (A specs surface, C nav hierarchy, D body-link removal). The dispatch prompt named the subsession ID, the exact transcript filename to write, the §5 binding, the version target (v0.20.0), the deploy gesture boundary (`subagent stops at "pushed to origin + benstull"; driver bumps pin + deploys`), and a paste-ready success sentence. While the subagent worked, the driver ran items B + E inline. ### Arc 3 — Item E: legacy-letter body rewrite (driver inline) Built `/tmp/rewrite-session-refs.py` — a small Python script applying two named regexes: 1. `\b[Ss]ession ([A-N])(\.\d+)?(?![A-Za-z0-9])` → letter mapped to zero-padded NNNN, default `.0` ordinal if no `.N` (case-preserving). 2. `\bSESSION-([A-N])(\.\d+)?-TRANSCRIPT` → numeric-form filename ref. Scoped to **canonical transcript filenames only** (`SESSION-NNNN.M-TRANSCRIPT-…md`); the script's `_TRANSCRIPT_FILENAME_RE` skip-filter passes over `SESSION-PROTOCOL.md`, README, runbooks, and proposals — those legitimately cite the legacy form as part of explanatory tables. Dry-ran on four sample folders first; spot-checked the diff on `SESSION-0005.0` (formerly Session E) and reverted to verify reversibility. Then applied to both `/tmp/ohm-session-history-0018/` and `~/git/ohm-infra/`: ``` Total: 502 replacements across 39 files ``` Breakdown: 21 files in the published repo (`0001/` through `0017/`), 18 files in the local working dir. Skipped: `SESSION-PROTOCOL.md` (explanatory) and `SESSION-L-TRANSCRIPT-…-INPROGRESS.md` (legacy stub). One adjustment caught at grep time: the mapping needed to extend to `N → 0014` because Session 0014.0's body still referred to itself as "Session N" mid-flight (Session N was the rename session itself; the file shipped under the numeric form but the body wasn't rewritten in Session 0014.0's own §23 work). Two `Session N` occurrences and one `Session N.1` in the published bodies, all caught. ### Arc 4 — Item B: README amendment (driver inline) Two edits on `/tmp/ohm-session-history-0018/README.md`: 1. New "Where the record begins" section, before "How OHM gets built". Explains that OHM started with two vibe-coded prototypes (no transcripts; the discipline didn't exist yet), the first draft of `rfc-app/SPEC.md` was written off what those prototypes taught, and from that draft onward the build switched to spec-driven development — which is where this transcript record begins. The two vibe-coded prototypes are not represented here; the spec is the primary text for understanding OHM's thinking. 2. Updated the existing "Sessions 0001 through 0013 originally shipped under a letter-form naming…" paragraph to reflect that body refs are *now* also in numeric form (Session 0018.0's gesture; "the rename was initially filename-level only; Session 0018.0 reversed that call"). ### Arc 5 — Item: SESSION-PROTOCOL.md §1 amendment + ROADMAP #30 strikethrough Amended `~/git/ohm-infra/SESSION-PROTOCOL.md` §1's "Legacy form (Sessions B through M)" subsection: - Added `N → 0014.0 (+ N.1 → 0014.1)` row to the mapping table. - Replaced the "bodies were NOT rewritten" paragraph with one documenting the reversal (Session 0018.0; mechanical sed via the small Python script; 502 replacements across 39 transcripts). Struck through ROADMAP #30 with a Phase 1 (v0.19.0 — Session 0017.0) + Phase 2 (v0.20.0 — Session 0018.0) attribution. Final answers to the open questions captured: gitea-only (no GitHub mirror); runtime fetch with TTL cache. Committed and pushed: - `wiggleverse/ohm-session-history`: `412b6ab..d512519` — 21 transcripts + README, one commit. - `ohm-rfc`: `5c69982` — ROADMAP strikethrough. - ohm-infra (local working): no commit (not a git repo); files are on disk. ### Arc 6 — Subagent 0018.1 stalled mid-flight About 10 minutes in, the subagent failed with `Agent stalled: no progress for 600s (stream watchdog did not recover)`. The result field said `"Now update DocsSessionIndex.jsx to drop the body list (Item D)"` — so it had reached Item D in its plan but lost the watchdog before making the edit. Checked the worktree state. Surprise: the subagent had worked **directly in `/Users/benstull/git/rfc-app/`** (the main repo, on a freshly-created branch `feature/v0.20.0-docs-specs-nav-hierarchy`), not in an isolated worktree as the `isolation: worktree` parameter would have promised. The other worktrees from prior sessions (v0.15.0 / v0.16.0 / v0.17.0 sibling paths) still exist; this one didn't. New §19.2 candidate: the worktree-isolation contract didn't take effect here, and the failure mode left changes in the main repo's tree rather than in a sandbox. Investigate before next subagent dispatch. What the subagent had shipped on the branch: - ✅ `backend/app/docs_specs.py` (327 lines, mirroring docs_sessions.py — manifest validator, env override, slug guard, in-process TTL cache, fetcher). - ✅ `backend/tests/test_docs_specs_vertical.py` (469 lines, 19 tests). - ✅ `backend/app/api.py` route mount for `/api/docs/specs/manifest` and `/api/docs/specs/`. - ✅ `frontend/src/api.js` `getSpecsManifest()` + `getSpec()` helpers using the existing `_textOrThrow` / `jsonOrThrow` machinery. - ✅ `frontend/src/components/DocsSpec.jsx` + `frontend/src/components/DocsSpecsIndex.jsx`. - ❌ `DocsLayout.jsx` nav hierarchy (no diff applied). - ❌ `DocsSessionIndex.jsx` body-link removal (no diff applied). - ❌ `App.jsx` route additions for `/docs/specs`. - ❌ VERSION + package.json bump. - ❌ CHANGELOG entry. - ❌ pytest run, frontend build. - ❌ Commit / merge / tag / push. Decision: **pick this up inline rather than re-dispatching**. The remaining work was mechanical (the architectural pieces were in place), and re-dispatching risked another stall. Updated task #2's subject + description to record the recovery. ### Arc 7 — Driver picks up the rest of v0.20.0 inline Read the subagent's `docs_specs.py`, `DocsSpec.jsx`, `DocsSpecsIndex.jsx`, and the api.py / api.js diffs. Verified `_textOrThrow` exists at api.js:745 (the subagent's `getSpec` reference resolved correctly). Verified the route layer's status-to-HTTP mapping mirrors docs_sessions. Edits I applied to finish: 1. **`App.jsx`**: added the `DocsSpec` + `DocsSpecsIndex` imports and the two new routes inside the `DocsLayout`-shelled route group (`specs` index + `specs/:name`). 2. **`DocsSessionIndex.jsx`**: dropped the `