# 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/<name>`, 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/<name>`.
- ✅ `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 `<ul className="docs-session-files">` body list. Replaced with a session-overview card (title, transcript count, "Select one from the navigation" hint). Empty-state / not-found / error paths preserved. Updated the file's header comment to record the v0.20.0 change.

3. **`DocsLayout.jsx`**: rewrote the nav to a three-section shape (Docs / Specs / Sessions). The Specs section is driven by a new `getSpecsManifest()` fetch with loading skeleton + error state mirroring the existing sessions pattern. The Sessions section now renders each session row's transcripts nested under it as `<ul className="docs-nav-list--children">`. The transcript ordinals (`0014.0`, `0014.1`, …) are extracted from the filename via a small `transcriptOrdinal()` helper that pulls the `NNNN.N(.N)*` segment.

   Implementation choice: **always-expanded** (per the dispatch prompt's "probably always-expanded is fine"). On manifest load, `Promise.all(sessionKeys.map(nnnn => getSessionIndex(nnnn)))` fans out one cheap request per session; the backend's 5-min content TTL makes the repeat cost negligible. No collapse toggle.

4. **`App.css`**: added rules for `.docs-nav-list--children` (indented + softer color + monospace ordinals), `.docs-session-overview` (replacing the old `.docs-session-files` styling — old class kept in case some other surface references it), and `.docs-article-header` + `.docs-source-link` for the DocsSpec's "View source" link affordance.

5. **`VERSION` + `frontend/package.json`**: bumped to `0.20.0`. Also fixed the `frontend/package-lock.json` version drift (§19.2 candidate a from Session 0017.0: lockfile read `0.15.0` while package.json was several versions ahead). Synced both top-level `version` and `packages."".version` to `0.20.0`. No dependency changes; no `npm install` needed.

6. **`CHANGELOG.md`**: added the v0.20.0 entry above v0.19.0. Two `MAY:` upgrade steps (`OHM_DOCS_SPECS` override, content TTL). Called out the package-lock.json drift fix.

Ran the backend test suite: `332 passed in 61.38s` (was 313 in v0.19.0; +19 from the new specs vertical). Ran `npm run build`: clean. The pre-existing 500kB chunk-size warning is unchanged from v0.19.0.

Committed everything on the feature branch:

```
e0d9ed7 Release v0.20.0: /docs/specs surface + nested flyout nav + session body-list removal
```

Switched to main, `git merge --no-ff feature/v0.20.0-docs-specs-nav-hierarchy`:

```
cbc9949 Merge feature/v0.20.0-docs-specs-nav-hierarchy
```

Tagged `v0.20.0`, pushed origin main + tag + benstull main + tag. Deleted the merged feature branch locally.

### Arc 9 — Operator correction at close-out: handoff prompt before publish

Wrote and published the transcript first (commit `edca38d` on
`wiggleverse/ohm-session-history`), then sent the operator the session
summary. Operator replied: **"i need the prompt"** — they wanted the
paste-ready next-session handoff prompt delivered *before* publish, not
after. Verbatim follow-up: **"Always give me the next prompt before
cutting the transcript moving forward."**

Captured this as binding:

1. New feedback memory at
   `~/.claude/projects/.../memory/feedback_handoff_prompt_before_publish.md`
   so future sessions read it on open.
2. New bullet in `SESSION-PROTOCOL.md` §3 (Discipline notes):
   "Handoff prompt before transcript cut." Sequence at session close:
   finish substantive work → deliver handoff prompt to operator →
   finalize transcript → publish.
3. Re-finalized this transcript with Arc 9 + the cut-state row noting
   the protocol amendment, then re-published. Re-publish is the
   idempotent "update SESSION-…md" path; the original
   `edca38d` commit is preserved in the audit trail and the new
   commit names what changed.

Convention applies from Session 0019.0 onward. Session 0018.0 itself
is the meta-example — the operator wouldn't have had to ask for the
prompt if I'd surfaced it in the closing message before running
`publish-transcript.sh`.

### Arc 8 — Pin bump + deploy + verify

Bumped `ohm-rfc/.rfc-app-version` from `0.19.0` to `0.20.0`, committed (`c9a4755`), pushed.

Ran `flotilla deploy ohm-rfc-app`:

```
error: deploy already in flight for 'ohm-rfc-app' (deploys.id=27); `flotilla deploy abort` to release the lock
```

deploys.id=27 was Session 0017.0's stuck row (SSE-keepalive SIGTERM watchdog timeout — the 4th occurrence of the §19.2 pattern). The service IS healthy at v0.19.0; the row just never closed cleanly. Ran `flotilla deploy abort ohm-rfc-app`:

```
aborted deploys.id=27 for ohm-rfc-app (target was v0.19.0)
```

Then ran the deploy:

```
opened deploys row id=28; target v0.20.0 (snapshot 64171a4c8091…)
[1/9] validate: ok
[2/9] preflight: ok
[3/9] fetch+checkout: ok
[4/9] backend deps: ok
[5/9] frontend build: ok
[6/9] write .env: ok
[7/9] restart: ok
[8/9] verify /api/health: ok
[9/9] finalize: ok
ohm: deployed v0.20.0 (deploys.id=28)
ohm: deployed v0.20.0 (verify took 4.6s)
```

**Clean run — no §19.2-keepalive timeout this time.** First time in 5 consecutive OHM deploys (v0.16, v0.17, v0.18, v0.19, v0.20) the watchdog hasn't fired. Worth noting but not enough data to call the pattern resolved; v0.20.0's restart may have happened to land inside the watchdog's grace window. flotilla v1.2.0's SSE pre-drain is still on the docket.

Verification:
- `curl https://ohm.wiggleverse.org/api/health` → `{"version":"0.20.0","status":"ok"}`.
- `curl https://ohm.wiggleverse.org/api/docs/specs/manifest` → both specs configured + their gitea raw URLs.
- `curl /api/docs/specs/rfc-app` → HTTP 200, 255606 bytes (matches `SPEC.md` 4771-line size).
- `curl /api/docs/specs/flotilla` → HTTP 200, 76185 bytes (matches `SPEC.md` 1563-line size).

The browser-side verification of the nav hierarchy + body-list removal + DocsSpec rendering is on the operator's plate (it was on the operator's plate for v0.19.0 too, but the Wave 9 brief pivoted past that step before they ran the gesture).

---

## Cut state (end of session)

| | |
| --- | --- |
| rfc-app | `cbc9949` on `main`, tag `v0.20.0` pushed to origin + benstull mirror |
| ohm-rfc | `c9a4755` on `main`; `.rfc-app-version=0.20.0` |
| ohm-rfc-app-flotilla | `417b6c5` on `main` (unchanged this session) |
| wiggleverse/ohm-session-history | `d512519` on `main` (21 transcripts rewritten + README amended) |
| OHM live | v0.20.0 healthy at `/api/health`; deploys.id=28 closed clean (9/9 phases) |
| ohm-infra (local) | `SESSION-PROTOCOL.md` §1 amended (no commit; not a git repo); 18 local transcript bodies rewritten |
| Subsession 0018.1 | stalled mid-flight; no transcript written; driver folded the report-back into this transcript per §5's "stub written by driver" fallback |

| Wave 9 ledger | Status |
| --- | --- |
| A — `/docs/specs/<name>` surface (rfc-app v0.20.0) | ✅ shipped |
| B — README scoping section (vibe-coded prototypes) | ✅ shipped |
| C — Nested flyout nav hierarchy (rfc-app v0.20.0) | ✅ shipped |
| D — `/docs/sessions/<NNNN>` body-list removal (rfc-app v0.20.0) | ✅ shipped |
| E — Legacy `Session L` → `Session 0012.0` body rewrite (502 reps / 39 files) | ✅ shipped |
| Bonus: ROADMAP #30 strikethrough with Phase 1+Phase 2 attribution | ✅ shipped |
| Bonus: SESSION-PROTOCOL.md §1 amendment (`N → 0014.0` + body-rewrite paragraph) | ✅ shipped |
| Bonus: `frontend/package-lock.json` version drift fix (Session 0017.0 §19.2 candidate a) | ✅ shipped |
| Bonus: SESSION-PROTOCOL.md §3 "Handoff prompt before transcript cut" amendment (operator correction at close-out) | ✅ shipped |

---

## §19.2 candidates surfaced

1. **Agent `isolation: worktree` contract may not be enforced.** Subagent 0018.1 was dispatched with `isolation: worktree` but worked directly in the main rfc-app repo (`/Users/benstull/git/rfc-app/`), on a freshly-created branch on the main checkout — no separate worktree directory was created. The watchdog-stall recovery would have been cleaner with an actually-isolated worktree (driver could have cleaned up the worktree and re-dispatched without disturbing the main repo's state). Investigate before next subagent dispatch — possibly a tool-level issue that needs reporting upstream, possibly a CLI flag mismatch on my side.

2. **Subagent stream watchdog stalls on long subagent runs.** The 600s no-progress timeout caught 0018.1 partway through Item D (frontend file edits). Whether the subagent was actually idle or just slow at producing output isn't visible from my side — the result text was a single line. Mitigations: shorter subagent dispatches; or accept the failure mode + driver-recovery pattern as the working contract.

3. **§19.2 SSE-keepalive watchdog timeout may be intermittent rather than chronic.** v0.20.0's deploys.id=28 ran 9/9 phases clean, ending the 4-deploy streak of SSE-watchdog-killed exit codes. One clean run isn't enough data, but it's worth tracking whether the pattern recurs in subsequent deploys before committing flotilla v1.2.0 SSE pre-drain work.

4. **`flotilla deploy abort` is a foot-gun when chained with the §19.2 watchdog pattern.** Today the deploy lock can be held by a row whose target version is already healthy on the service (the watchdog killed the *deploy* runner without the *service* having failed). `flotilla deploy` errors with "already in flight" and points at `abort` — but the operator has to interpret the `deploys.id=N` log to confirm the service is healthy *despite* the lock before aborting. A `flotilla deploy reconcile` gesture that checks `/api/health` against the pending row's target and auto-closes the row when they match would remove a manual step. Filed against flotilla v1.2.0 alongside the SSE pre-drain work.

5. **The `sessions.json` titles still carry "Session B —", "Session E —", etc. prefixes** — they weren't part of the body-rewrite scope (the operator's instruction was scoped to transcript bodies). Worth refining (drop "Session N —" prefix since the NNNN key already names the session, OR rewrite to "Session 0002.0 — first OHM deployment…" form) but that's operator-prerogative per the prompt — not a §19.2 thing, just a follow-up item.

---

## What lands on the operator's plate

1. **Visual verification of v0.20.0 in browser.** The nav hierarchy, `/docs/specs/<name>` rendering, and `/docs/sessions/<NNNN>` body-overview shape are all confirmed at the backend / build level but haven't been operator-eyeballed yet. Five-minute pass when you have it.

2. **README placeholder review.** The three `<!-- operator: rewrite this section in your voice -->` markers are still in place. The "Where the record begins" section I added (the vibe-coded prototype context) is on top of those — feel free to edit it too; it's a draft from your instruction, not an authoritative voice match.

3. **`sessions.json` title refinement.** See §19.2 candidate 5. The current titles read "Session B — first OHM deployment…" — likely you want to drop the legacy-letter prefix in favor of the numeric form (or just the topic). Pure operator-prerogative.

4. **Decide on the §19.2 candidates** — particularly #1 (the agent worktree-isolation gap, which has implications for safety on future subagent dispatches) and #4 (flotilla deploy reconcile gesture).

5. **Two M-session docs PRs still awaiting merge** — `rfc-app feature/contributing-and-spec-analytics @ 213f686` and `ohm-rfc feature/contributing-roadmap-guide @ f26fae4`. Carried forward from Session 0017.0's brief; no change this session.

6. **DMARC Phase A → Phase B.** Watch the `rua=` mailbox for ≥1 week of clean reports (around 2026-06-04) before flipping to `p=quarantine`. Unchanged from Session 0014.0.

7. **Stale `wiggleverse/meta` hook on deprovisioned `rfc.wiggleverse.org`** — still needs operator deletion (#20 ops side).

---

## Prompt the operator can paste into the next Claude Code session

```
You are the OHM roadmap driver, Session 0019.0. Read this whole prompt
before doing anything.

# What Session 0018.0 shipped (Wave 9)

Five items bundled — three landed as rfc-app v0.20.0 (shipped clean,
deploys.id=28, /api/health returns 0.20.0), the other two as direct
edits to wiggleverse/ohm-session-history + a SESSION-PROTOCOL.md
amendment:

A. **/docs/specs/<name> surface** — new on-site framework-spec
   surface. Backend `docs_specs.py` mirrors `docs_sessions.py`
   shape: manifest endpoint (env-configurable list, framework
   default OHM-flavored: rfc-app SPEC + flotilla SPEC); per-spec
   content endpoint with 5-min TTL cache + negative caching;
   strict slug guard. Frontend `DocsSpec.jsx` renders via the
   existing MarkdownPreview; `DocsSpecsIndex.jsx` redirects bare
   /docs/specs to first configured spec. 19 new pytest cases
   (332 backend total green).

B. **README scoping section** — "Where the record begins" on
   wiggleverse/ohm-session-history's README. Explains the two
   vibe-coded prototypes that preceded spec-driven development and
   that the transcript record begins at the spec-driven phase.
   The three existing operator-review placeholders are still
   pending operator rewrite — Session 0018.0 only added the new
   prefix section.

C. **Nested flyout nav hierarchy** — DocsLayout.jsx rewritten to
   render sessions as a tree (transcripts nested under each
   session row, labeled by .N ordinal). Always-expanded; fan-out
   fetch via Promise.all of getSessionIndex(nnnn). New "Specs"
   section between User Guide and Sessions, populated from
   /api/docs/specs/manifest.

D. **/docs/sessions/<NNNN> body-list removal** — DocsSessionIndex.jsx
   no longer renders the transcript-link <ul>. Body is now a
   session-overview card with the count + "select from the
   navigation" hint. Nav-only navigation per operator preference.

E. **Legacy-letter body rewrite** — 502 replacements across 39
   transcripts in two repos. "Session L" → "Session 0012.0",
   "Session M.1" → "Session 0013.1", "SESSION-L-TRANSCRIPT" →
   "SESSION-0012.0-TRANSCRIPT", etc. Scoped to canonical-filename
   transcripts only; SESSION-PROTOCOL.md, README, runbooks, and
   proposals deliberately left intact (they reference the legacy
   form as part of explanatory mapping tables). The §1 legacy
   subsection of SESSION-PROTOCOL.md was amended to document the
   reversal and add `N → 0014` to the mapping table.

Bonus:
- `frontend/package-lock.json` version drift fix (was 0.15.0;
  now 0.20.0 — Session 0017.0 §19.2 candidate a).
- ROADMAP #30 strikethrough with Phase 1 (v0.19.0) + Phase 2
  (v0.20.0) attribution.

# Subagent stall caveat

Subagent 0018.1 was dispatched in the background (isolation:
worktree, run_in_background: true) and **stalled on the 600s
stream watchdog** after shipping the backend + spec components
but before applying the nav hierarchy + body-list removal +
version bump + CHANGELOG + commit/tag/push. The driver picked up
the remaining frontend wiring inline. No subsession transcript
was written by 0018.1; the parent transcript folded the
report-back into Arc 6 per §5's "stub written by driver because
subagent did not produce one" fallback.

The subagent also worked directly in /Users/benstull/git/rfc-app
(the main checkout, on a freshly-created branch) rather than in
an isolated worktree, despite `isolation: worktree`. New §19.2
candidate — investigate before next subagent dispatch.

# Cut state at handoff

- rfc-app `main`: `cbc9949` → tag `v0.20.0` pushed to origin +
  benstull mirror.
- ohm-rfc `main`: `c9a4755` — `.rfc-app-version=0.20.0`.
- ohm-rfc-app-flotilla `main`: `417b6c5` (no flotilla code change
  this session).
- wiggleverse/ohm-session-history `main`: `d512519` — 21
  transcripts body-rewritten + README amended with vibe-coded
  prototypes scoping section.
- OHM live: **v0.20.0 healthy** (`/api/health` returns
  `{"version":"0.20.0","status":"ok"}`).
- deploys.id row for v0.20.0: deploys.id=28, **closed clean** —
  9/9 phases passed, no §19.2-keepalive timeout (first clean
  deploy in 5 — worth tracking whether the pattern was
  intermittent or whether v1.2.0 SSE-drain is still needed).
- ohm-infra: SESSION-PROTOCOL.md §1 amended (NOT in a git repo
  locally, so no commit; the file IS what it is on disk).
- DMARC Phase A unchanged from Session 0014.0 — watch `rua=`
  mailbox for ≥1 week of clean reports (around 2026-06-04)
  before flipping to `p=quarantine`.
- Two Session-M docs feature branches still awaiting operator merge:
  - rfc-app `feature/contributing-and-spec-analytics` @ `213f686`
  - ohm-rfc `feature/contributing-roadmap-guide` @ `f26fae4`

# What is and isn't proven working

- ✅ v0.20.0 service health (`/api/health` returns 0.20.0).
- ✅ /api/docs/specs/manifest returns both configured specs +
  their gitea raw URLs.
- ✅ /api/docs/specs/rfc-app returns HTTP 200 + 255606 bytes
  (matches rfc-app SPEC.md size).
- ✅ /api/docs/specs/flotilla returns HTTP 200 + 76185 bytes
  (matches flotilla SPEC.md size).
- ⏸ End-to-end /docs/* surfaces in a real browser **still not
  operator-confirmed** (was the load-bearing first ask for
  Session 0018.0; the operator's brief pivoted before the test
  ran). First gesture this session: have the operator load:
  - `https://ohm.wiggleverse.org/docs/specs/rfc-app` → renders
    rfc-app SPEC.md in-browser via react-markdown.
  - `https://ohm.wiggleverse.org/docs/specs/flotilla` → renders
    flotilla SPEC.md.
  - `https://ohm.wiggleverse.org/docs/sessions/0014` → session-
    overview body (NO inline transcript-link list).
  - Flyout nav (any /docs/* route) shows the Specs section + the
    Sessions section with transcripts nested under each session.

# Wave 10 candidates (priority is operator's call)

1. **Visual verification of v0.20.0 in browser** (above) — load-
   bearing first gesture.
2. **Operator rewrites the 3 README.md placeholder sections** on
   `wiggleverse/ohm-session-history`. Operator-only gesture;
   commit directly to main. (Carried from Session 0017.0.)
3. **Operator refines sessions.json titles** — currently still
   "Session B — first OHM deployment…", "Session E — flotilla
   Slices 1 & 2 …" with the legacy letter as a prefix.
4. **Operator merges the two M docs PRs**.
5. **Investigate §19.2 candidate 1**: the worktree-isolation gap
   on subagent dispatch.
6. **#1 VM rename + flotilla v1.2.0 SSE-keepalive drain +
   `flotilla deploy reconcile`** (§19.2 candidate 4) — bundled.
7. **DMARC Phase A → Phase B (`p=quarantine`)** — ≥1 week of
   clean rua data; ETA 2026-06-04.
8. **#20 ops side**: delete stale `wiggleverse/meta` hook on
   deprovisioned `rfc.wiggleverse.org`.
9. **#18 ops side**: bounce-source wiring (Path A or B in the
   runbook).
10. **#21 Part A Amplitude audit** — defer to ~2026-06-04 for a
    week of post-fix dashboard data.
11. **#22 pro-consent copy** — operator-drafted + counsel-reviewed;
    subagent wires once approved.
12. **#26-29** — four operator-added items from Session 0014.0
    (propose-RFC fields, Haiku tags, PR cross-references, sign-in
    resume). Each is a clean rfc-app minor.
13. **#17 repo naming alignment** — operator decides Q1 first.

# Hard rules carried forward (binding)

- **Never EVER ask the operator to paste secret bytes into the
  conversation.** Always give the operator-run gesture
  (`pbpaste | flotilla secret set ohm-rfc-app <KEY>`). Public
  bundle-embedded values (VITE_*) are fine in-conversation via
  `flotilla overlay set`.
- **§5 subsession-transcript convention**: forked subagents write
  their own transcripts BEFORE returning their report. Driver
  re-verifies deliverables on disk rather than depending on the
  report-back text. **When a subagent stalls, driver folds the
  report-back into the parent transcript per §5's "stub written
  by driver" fallback.**
- **§3 "Handoff prompt before transcript cut"** (new, Session 0018.0):
  the driver MUST deliver the paste-ready handoff prompt to the
  operator in a chat message BEFORE invoking
  `scripts/publish-transcript.sh`. Sequence at close: finish work →
  deliver prompt → finalize transcript → publish. Re-publishing
  is idempotent if the operator's review surfaces more work.
- **Protocol amendments must land with the code change.**
- **Naming**: this is Session 0019.0. Driver transcript:
  `SESSION-0019.0-TRANSCRIPT-<start>--<end>.md`. Subagent
  transcripts: `SESSION-0019.1-…`, etc.
- **Numeric session ID**: if other sessions are running
  concurrently, ask the operator which IDs are taken before
  claiming yours.

# First actions for Session 0019.0

1. Read `~/git/ohm-infra/SESSION-PROTOCOL.md` (the §1 amendment
   from Session 0018.0 is the relevant new content: `N → 0014.0`
   row + body-rewrite paragraph).
2. Read `/Users/benstull/projects/wiggleverse/ohm-rfc/ROADMAP.md`
   end-to-end. #30 is now struck through with Phase 1 + Phase 2
   attribution.
3. Read the Session 0018.0 transcript at
   `~/git/ohm-infra/SESSION-0018.0-TRANSCRIPT-2026-05-28T09-23--<end>.md`
   for the full triage detail (this prompt is the summary).
4. Have the operator load `/docs/specs/rfc-app` and
   `/docs/sessions/0014` (with the new nested-nav flyout open)
   in a fresh browser tab. That's the load-bearing first test
   that Session 0018.0 punted on.
5. Pick Wave 10's shippable scope. Note that the operator's
   pattern from Session 0017→0018 was "load-bearing first test
   gets supplanted by operator's substantive brief" — be
   prepared for the same.

Note that the next session ID is **0020** — include it in the
handoff prompt you generate at end of session. The operator
likes to start the next session as soon as it doesn't interfere
with the current work.
```

