reshape: move OHM transcripts under ohm/ for org-wide multi-app layout; add org-wide root README
This commit is contained in:
@@ -0,0 +1,466 @@
|
||||
# Session 0017.0 — Transcript
|
||||
|
||||
> Date: 2026-05-28
|
||||
> Start: 2026-05-28T08-50 PST
|
||||
> End: 2026-05-28T09-22 PST
|
||||
> Goal: drive Wave 8 — pick a shippable scope from the post-Wave-7 candidate list now that the OTC sign-in gate is open; the operator marked roadmap #30 (docs nav + on-site sessions browser + session-history repo restructure) as **NEXT** in ROADMAP.md, so that became the target.
|
||||
>
|
||||
> Outcome: **Wave 8 = roadmap #30 shipped end-to-end. rfc-app v0.19.0 tagged + pushed (canonical + benstull mirror); ohm-rfc pin bumped to 0.19.0; OHM live at v0.19.0 healthy. `wiggleverse/ohm-session-history` restructured into one folder per session + `README.md` (operator-review draft) + `sessions.json` title manifest (15 entries, all titled). `publish-transcript.sh` extended for the folder convention + sessions.json upsert. SESSION-PROTOCOL.md §1 + §5 amended. Three subagents (0017.1 rfc-app code, 0017.2 session-history restructure, plus the driver-inline publish-script + protocol edits) all delivered.**
|
||||
>
|
||||
> Highlights:
|
||||
> - The OTC sign-in end-to-end gate (Wave 7 carry-forward) was operator-confirmed working at session start — first-time-since-launch.
|
||||
> - Two other sessions were running concurrently (0015.0 troubleshooting an OTC-config edge case; 0016.0 completed). Driver took ID 0017.0 per operator confirmation.
|
||||
> - Settled at session time: gitea-only (no GitHub mirror); runtime fetch with cache for `/docs/sessions`; full `SESSION-NNNN.M-TRANSCRIPT-…md` filename retained inside each folder (overrode roadmap example's trimmed form).
|
||||
> - SSE-keepalive SSH-watchdog timeout fired again at deploy time (4th occurrence; flotilla v1.2.0 §19.2 candidate). Service came up at v0.19.0 healthy regardless.
|
||||
|
||||
---
|
||||
|
||||
## Pre-session state
|
||||
|
||||
- rfc-app `main` @ `ac3513a` ("Merge: CONTRIBUTING.md + SPEC.md §21 analytics chapter (Session 0013.1)"); `v0.18.0` was the latest tag; clean working tree.
|
||||
- ohm-rfc `main` @ `74a3e12` ("ROADMAP: +#24..#29"); pin `.rfc-app-version=0.18.0`. (Between session start and the post-deploy pin push, the operator landed at least one more commit on ohm-rfc — `9c47792` — adding roadmap item #30 with its **NEXT** marker; my pin-bump committed onto the updated `9c47792` cleanly.)
|
||||
- ohm-rfc-app-flotilla `main` @ `417b6c5` (v1.1.0, Wave 7 deploy with VITE_* overlay propagation). Local working tree had one modified file: `CLAUDE.md`.
|
||||
- OHM live: v0.18.0 healthy (`/api/health` 200, `{"version":"0.18.0","status":"ok"}`).
|
||||
- ohm-infra (`~/git/ohm-infra/`, not a git repo locally): `publish-transcript.sh` at the post-#23 form (accepting numeric + legacy letter regex); `SESSION-PROTOCOL.md` at the post-Session-0014.0 amendment shape. Stale `SESSION-0012.0-TRANSCRIPT-…INPROGRESS.md` still on disk (handoff said leave as-is).
|
||||
- Session 0014.0's main driver transcript NOT yet on disk at session start (it appeared at 08:43 mid-session — the parallel-running driver was finalizing). 0014.1 subagent transcript was on disk from 07:42. 0016.0 transcript not seen on disk this session.
|
||||
|
||||
The operator's handoff prompt (pasted at session start) was the load-bearing summary of what Wave 7 shipped + the Wave 8 candidate list. Two clarifying gates the operator surfaced at the top:
|
||||
1. **OTC sign-in end-to-end was unverified.** Wave 7's full triage stopped before the operator retested.
|
||||
2. **Two other sessions were running.** Session ID for this driver had to be calculated from what the other sessions had claimed.
|
||||
|
||||
---
|
||||
|
||||
## Turn-by-turn arc
|
||||
|
||||
### Arc 1 — Orient + clear the two gates
|
||||
|
||||
Read `SESSION-PROTOCOL.md`, `ohm-rfc/ROADMAP.md` (which surfaced a NEW item #30 marked **NEXT** by the operator — newer than the handoff prompt and effectively re-shaping the Wave 8 priority order), the on-disk transcript listing (showed 0001–0013.3 + 0014.1 in numeric form), and the publish-transcript.sh + flotilla state. Health-probed OHM (v0.18.0 ok). Confirmed `flotilla deploy ohm-rfc-app` venv at `.venv/bin/ohm-rfc-app-flotilla`.
|
||||
|
||||
Asked the operator two questions in one tool call:
|
||||
1. Session ID — other sessions claimed 0015.0 + 0016.0; driver took **0017.0**.
|
||||
2. OTC sign-in test in a fresh incognito window — **"Code arrived, sign-in worked"** — first-time-since-launch confirmation of the Wave 7 v0.18.0 chain working end-to-end. The Wave 7 load-bearing gate is closed.
|
||||
|
||||
Asked a follow-up: what are 0015.0 and 0016.0 doing, so Wave 8 doesn't collide? **0016.0 is complete (transcript pending publish — at this point not yet on disk locally, but operator confirmed it's done); 0015.0 is troubleshooting an OTC-not-being-sent edge case described as a config issue, no code changes**, and the operator was going to context-switch to 0015.0 directly. That cleared the way for #30 since neither competing session was touching the rfc-app or session-history surfaces.
|
||||
|
||||
### Arc 2 — Propose Wave 8 scope + settle the open #30 decisions
|
||||
|
||||
Recommended Wave 8 = #30 since the operator had marked it **NEXT** and nothing else was more pressing. Proposed shape: three parallel subagents touching three different repos (session-history restructure + rfc-app v0.19.0 + ohm-infra publish-script + protocol updates).
|
||||
|
||||
Asked the operator's two open session-time questions from the roadmap text:
|
||||
1. **Repo host**: gitea-only / gitea+GitHub mirror / GitHub canonical. Operator chose **gitea-only**.
|
||||
2. **Fetch mode**: runtime fetch with cache (recommended) / build-time bundle. Operator chose **runtime fetch with cache**.
|
||||
|
||||
Then asked two coordination questions:
|
||||
3. **Is restructuring the session-history repo safe to start now?** (The handoff's "don't do transcript renames yet — another session is running" caveat might still apply.) Operator chose **"Wait — I'll signal when clear"** for the restructure subagent specifically; authorized the other two subagents to proceed.
|
||||
4. **Session titles + README prose drafting**: subagent drafts / operator hand-writes / hybrid. Operator chose **subagent drafts both, operator reviews**.
|
||||
|
||||
Renumbered the subagent labels by dispatch order per protocol §5: subagent dispatched first = `.1`, second = `.2`. So:
|
||||
- 0017.1 = rfc-app v0.19.0 code subagent (dispatched first)
|
||||
- 0017.2 = session-history restructure subagent (held until operator signal)
|
||||
|
||||
Driver does the ohm-infra publish-script + protocol updates inline (small enough; not a forked subagent — captured in this transcript).
|
||||
|
||||
### Arc 3 — Driver-inline edits: publish-script + SESSION-PROTOCOL.md
|
||||
|
||||
Read the existing `scripts/publish-transcript.sh`. Rewrote the body to:
|
||||
|
||||
- Parse out `NNNN` from `SESSION-NNNN.M-TRANSCRIPT-…md` via bash regex `^SESSION-([0-9]{4})\.[0-9]+(\.[0-9]+)*-TRANSCRIPT`.
|
||||
- For numeric form: place transcript in `NNNN/` subfolder (`mkdir -p`); for legacy letter form: place at repo root (backward compat).
|
||||
- Upsert `sessions.json` via inline `python3` heredoc (pure stdlib, no jq): if `NNNN` key is missing, add `{"NNNN": {"title": ""}}`, sort keys numerically, write 2-space-indented JSON with trailing newline. If `sessions.json` is malformed JSON, fail cleanly with exit 2.
|
||||
- Compute commit message based on what's in the diff (`add NNNN/SESSION-… + sessions.json: add entry for NNNN`, or just one of those).
|
||||
- Use `git status --porcelain` after staging to detect any change; no-op exit 0 if nothing changed.
|
||||
- Keep dry-run behavior; expand its logging to name both the transcript-action and the manifest-action.
|
||||
|
||||
Smoke-tested the regex locally (numeric forms parse, legacy letters reject) and the Python upsert in isolation (first-add returns 1, re-add returns 0, malformed JSON exits 2, sort order works).
|
||||
|
||||
Edited `SESSION-PROTOCOL.md`:
|
||||
- §1 gained a **"Published repo layout (Session 0017.0 amendment, 2026-05-28)"** subsection describing the `NNNN/` folder shape, the `sessions.json` schema, and the "local files stay flat — folders are publish-time" rule. Documents the decision to retain the full `SESSION-NNNN.M-TRANSCRIPT-…md` filename inside folders (no trim of the `SESSION-` prefix; overrides the roadmap example).
|
||||
- §5 gained a short **"Published-repo placement"** note saying subagent transcripts inherit their parent's `NNNN/` folder (publish-script handles this by parsing the leading `NNNN`).
|
||||
|
||||
Documented that the local working files at `~/git/ohm-infra/SESSION-…` keep the flat shape — folders are a publish-time gesture only.
|
||||
|
||||
### Arc 4 — Dispatch subsession 0017.1 (rfc-app v0.19.0)
|
||||
|
||||
Dispatched a forked general-purpose subagent in the background with a self-contained prompt:
|
||||
- Pre-assigned subsession ID `0017.1`.
|
||||
- Repo `/Users/benstull/git/rfc-app`, branch `feature/v0.19.0-docs-sessions-browser` off `main@ac3513a`.
|
||||
- Settled decisions: gitea-only, runtime fetch + cache.
|
||||
- Concrete scope (backend endpoints + TTL cache + frontend route tree + flyout nav + CHANGELOG + version bumps).
|
||||
- Hard rules: do NOT tag, do NOT bump ohm-rfc pin, do NOT push to benstull mirror, do NOT deploy. Driver handles all of those after 0017.2 also returns.
|
||||
- Transcript expectations per §5 (write `SESSION-0017.1-TRANSCRIPT-…md` BEFORE returning report).
|
||||
- Pasted roadmap item #30 verbatim for self-containment.
|
||||
|
||||
Subagent ran ~15 minutes and reported back:
|
||||
- Branch `feature/v0.19.0-docs-sessions-browser` @ `477f496`, pushed to origin only.
|
||||
- 313 backend pytest passing (18 new in `test_docs_sessions_vertical.py`); frontend `npm run build` green; no frontend test framework (per dispatch); dev-server smoke not run (sandboxed agent, no browser — flagged for driver).
|
||||
- Settled in-session: per-session listing source = separate `/api/docs/sessions/<NNNN>/index` endpoint (not extending the manifest, keeps it cheap); negative-cache 404s (rationale: at ship time the repo restructure is racing the rfc-app deploy; empty-state path may be hot for hours); the dispatch's `pyproject.toml` was a non-op (repo uses `backend/requirements.txt` only — canonical version sources are `VERSION` + `frontend/package.json#version`, both bumped).
|
||||
- 5 §19.2 candidates surfaced (`package-lock.json` version drift, missing `pyproject.toml`, validator-leak, CHANGELOG style drift, cache-invalidation seam).
|
||||
- Transcript at `SESSION-0017.1-TRANSCRIPT-2026-05-28T08-52--2026-05-28T09-07.md`.
|
||||
- Notable in-flight snag (full detail in its transcript): the shared `app_with_fake_gitea` fixture monkeypatches `httpx.AsyncClient` globally on the module — the first-attempt test fixture captured a `real_client_cls = httpx.AsyncClient` that was already the gitea-patched wrapper; subagent fixed by importing the truly-unpatched `AsyncClient` from `httpx._client` directly. `_UpstreamHandler` gained a host-marker filter so reconciler-side gitea calls don't inflate cache-hit assertions.
|
||||
|
||||
Driver verified deliverables on disk (don't depend on report-back text per §5 amendment):
|
||||
- `feature/v0.19.0-docs-sessions-browser` exists locally at `477f496`, matches origin.
|
||||
- `VERSION` = `0.19.0`; `frontend/package.json` version = `0.19.0`; `main` untouched at `ac3513a`.
|
||||
- Transcript exists at the named path, 350 lines, header matches expected shape.
|
||||
- CHANGELOG diff: 12 lines added; full v0.19.0 entry with `Upgrade steps:` block.
|
||||
- Backend diff: 855 LOC across `api.py` + `docs_sessions.py` + tests.
|
||||
- Frontend diff: 864 LOC across `App.css` / `App.jsx` / `api.js` / 5 new components / `analytics.js` (+ `Docs.jsx` deletion).
|
||||
|
||||
Noticed one quick fix the subagent flagged as §19.2 (`## v0.19.0` vs `## 0.18.0` style mismatch — every prior CHANGELOG header drops the `v` prefix; the new entry having `v` was MY dispatch-prompt typo, not architectural). Made a small driver-inline commit on the feature branch normalizing the header — `bb5137f CHANGELOG: normalize 0.19.0 header (drop 'v' prefix to match surrounding style)`, pushed to origin. The other §19.2 candidates are genuinely architectural and stay deferred.
|
||||
|
||||
(One operator-config note: git emitted the "your name and email were configured automatically based on hostname" warning for the commit — `benstull@mac.lan` rather than `ben@wiggleverse.org`. Per the "no `git config` edits" hard rule I left it; same identity shape as the subagent's commits and as 0017.2's later commit. Operator can normalize globally if desired.)
|
||||
|
||||
### Arc 5 — Operator clears the restructure gate; dispatch 0017.2
|
||||
|
||||
Operator said "we're good to go. Go for it" — clearing 0017.2's hold.
|
||||
|
||||
Dispatched the second forked general-purpose subagent in the background:
|
||||
- Pre-assigned subsession ID `0017.2`.
|
||||
- Mission: restructure `wiggleverse/ohm-session-history` (gitea SSH remote at `ssh://git@git.wiggleverse.org:2222/wiggleverse/ohm-session-history.git`); one atomic commit on `main`.
|
||||
- Settled decisions baked into the prompt (keep `SESSION-` prefix in folder filenames; gitea-only).
|
||||
- README ingredients (per roadmap #30): how OHM is built, why transcripts are public, the verbatim "Oh and Jan, your joke is in there somewhere." line, link to canonical repo. Subagent drafts; operator reviews via embedded `<!-- operator: rewrite this section in your voice -->` markers.
|
||||
- Title-drafting heuristic: read each transcript's `> Goal:`/`> Outcome:` header block. Driver supplied starter sketches for 0001 + 0009–0014; subagent filled in 0002–0008 + 0015 from the actual transcripts.
|
||||
|
||||
Subagent ran ~5 minutes and reported back:
|
||||
- Public repo `main` @ `ad01c08` (fast-forward push from `b6a7b7d`); 19 transcripts `git mv`'d into 15 `NNNN/` folders, rename detection 100%; zero legacy letter-form at root (Session 0014.0's #23 rename had already cleared them).
|
||||
- `sessions.json`: 15 entries, every session titled, no placeholders. Did NOT include 0016/0017 (unpublished in the public repo as of 0017.2's run).
|
||||
- README.md drafted with 3 operator-review markers on key sections (~520 words, includes canonical-link callout + publish-script how-to + license pointer).
|
||||
- Transcript at `SESSION-0017.2-TRANSCRIPT-2026-05-28T09-10--2026-05-28T09-15.md`.
|
||||
- 3 §19.2 candidates (publish-script placeholder-on-first-publish contract; README ↔ /docs/sessions/about render contract; local-vs-published shape asymmetry).
|
||||
- Cosmetic note: committer identity `Ben Stull <benstull@mac.lan>` (same as 0017.1's and the driver inline commit).
|
||||
|
||||
Driver verified:
|
||||
- Transcript exists at named path, 13.5 KB.
|
||||
- Gitea raw probe: `sessions.json` returns 200; `README.md` returns 200; `0014/SESSION-0014.0-TRANSCRIPT-2026-05-28T07-01--2026-05-28T08-25.md` returns 200.
|
||||
- `sessions.json` content sane (15 entries; titles read like decent first drafts; 0013 is a semicolon-list — likely worth compression; 0014 uses subagent's phrasing rather than §1-example verbatim form — operator's call).
|
||||
|
||||
### Arc 6 — Merge, tag, push, pin, deploy, verify
|
||||
|
||||
With both subagents returned and verified, executed the coordinated landing:
|
||||
|
||||
1. `git checkout main` on rfc-app, `git merge --no-ff feature/v0.19.0-docs-sessions-browser -m "Merge feature/v0.19.0-docs-sessions-browser"` → merge commit `69a166a` (16 files changed, 1732+/57-).
|
||||
2. `git tag v0.19.0` on the merge commit.
|
||||
3. `git push origin main v0.19.0` → success.
|
||||
4. `git push benstull main v0.19.0` → success.
|
||||
5. `cd ohm-rfc && echo "0.19.0" > .rfc-app-version && git commit -m "Pin rfc-app 0.19.0 — Wave 8 deploy: /docs nav + on-site sessions browser (#30)"` → commit `de17e79`. (Local main was at `9c47792`, not `74a3e12` as seen at session start — operator landed at least one more ohm-rfc commit in between; commit graph stayed clean.)
|
||||
6. `git push` → success.
|
||||
7. `.venv/bin/ohm-rfc-app-flotilla deploy ohm-rfc-app` → **hit the §19.2 SSE-keepalive SSH-watchdog timeout** at phase 7 (`SshError: ssh to ohm-app timed out after 60.0s running: 'sudo sh -c ... systemctl restart ohm-app.service ...'`). 4th occurrence of this pattern (Session 0009.0 §19.2 / Session 0014.0 carry-forward).
|
||||
8. **Verification via `/api/health`** (not the flotilla exit code, per Session 0014.0's lesson): first probe right after the timeout returned 502 from nginx (service was mid-restart); second probe 15s later also 502; but then `.venv/bin/ohm-rfc-app-flotilla deploy status ohm-rfc-app` returned `HTTP 200 version=0.19.0 status=ok`. Re-probed the public URL — 5 consecutive 200s, all `{"version":"0.19.0","status":"ok"}`, ~190 ms each. So: deploy succeeded; the 502 window was transient (a few seconds while the service was finishing restart); SSH watchdog falling off doesn't reflect actual deploy outcome.
|
||||
|
||||
(Side observation: an `ssh ohm-app` attempt to read journalctl failed "Could not resolve hostname ohm-app" — my local SSH config doesn't have the alias the flotilla CLI uses internally. `flotilla deploy status` was the canonical path anyway. Not blocking.)
|
||||
|
||||
deploys.id row for this deploy will read aborted-on-SSH-timeout despite the service running healthy at v0.19.0 — same dichotomy as deploys.id 23/24/25 from Session 0014.0.
|
||||
|
||||
### Arc 7 — Operator asks for the next-session prompt mid-arc; transcript wraps after
|
||||
|
||||
Operator asked for the closing-handoff prompt at the moment the deploy verification finished. Driver drafted it inline in the conversation (full prompt included below in "Prompt the operator can paste into the next Claude Code session"). Browser-side verification of `/docs/sessions/about` + a per-transcript view is the next session's first gesture, not 0017.0's — the deploy is up; the on-site rendering is the operator's eyeball confirmation.
|
||||
|
||||
Then this transcript got written (you are reading it).
|
||||
|
||||
---
|
||||
|
||||
## Cut state (end of session)
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| rfc-app | `main` @ `69a166a` (merge commit); tag `v0.19.0`; pushed to origin + benstull mirror |
|
||||
| ohm-rfc | `main` @ `de17e79` — `.rfc-app-version=0.19.0` |
|
||||
| ohm-rfc-app-flotilla | `main` @ `417b6c5` — no flotilla code change this session (`CLAUDE.md` modified file from session start was carried through unchanged) |
|
||||
| `wiggleverse/ohm-session-history` | `main` @ `ad01c08` — restructured into 15 `NNNN/` folders + `README.md` (with 3 operator-rewrite markers) + `sessions.json` (15 entries, all titled) |
|
||||
| OHM live | v0.19.0 healthy (`/api/health` 200, `{"version":"0.19.0","status":"ok"}`); deploys.id row = aborted-on-SSH-timeout per §19.2 (h) below |
|
||||
| ohm-infra | `scripts/publish-transcript.sh` extended for NNNN/ folders + sessions.json upsert; `SESSION-PROTOCOL.md` §1 + §5 amended. (Not a git repo locally; on-disk changes are the artifact.) |
|
||||
| Session 0017 transcripts on disk | `SESSION-0017.0-TRANSCRIPT-2026-05-28T08-50--2026-05-28T09-22.md` (this file), `SESSION-0017.1-TRANSCRIPT-2026-05-28T08-52--2026-05-28T09-07.md`, `SESSION-0017.2-TRANSCRIPT-2026-05-28T09-10--2026-05-28T09-15.md`. All three publish via `publish-transcript.sh` at session close. |
|
||||
|
||||
| Wave 8 ledger | Status |
|
||||
| --- | --- |
|
||||
| #30 docs nav + on-site sessions browser + session-history restructure (rfc-app v0.19.0 + ohm-session-history reshape) | ✅ shipped |
|
||||
|
||||
---
|
||||
|
||||
## §19.2 candidates surfaced
|
||||
|
||||
a. **`frontend/package-lock.json` version drift** (0017.1). Lockfile top-level `"version"` reads `0.15.0` while `frontend/package.json#version` is `0.19.0`. Cosmetic but ugly; symptom of no automated lockfile-discipline check. Repo doesn't run `npm install` as part of the version bump, so the lockfile drifts on every minor.
|
||||
|
||||
b. **rfc-app backend has no `pyproject.toml`** (0017.1). Dispatch named one as a version source; the repo uses `backend/requirements.txt` only. Canonical version sources are `VERSION` + `frontend/package.json#version`. If a backend `pyproject.toml` is desired (for editable installs, build-tool integration, etc.), it earns its own small release.
|
||||
|
||||
c. **`docs_sessions.py` private validators leak into the route layer** (0017.1). `_is_valid_session_dir` / `_is_valid_transcript_filename` are referenced from route handlers; consolidating into a public `validate_path()` would tighten the seam.
|
||||
|
||||
d. **`docs_sessions` cache has no external invalidation** (0017.1). In-process TTL only; no `reset_cache()` admin endpoint or test seam. Operationally fine (TTL is short); developer-experience worth improving.
|
||||
|
||||
e. **`publish-transcript.sh` should auto-populate `sessions.json` placeholder entries on first-publish** (0017.2). **Already partially shipped** in the driver-inline edit (publish-script upserts `{"NNNN": {"title": ""}}` if the key is missing). Worth confirming the contract end-to-end against a real fresh-session publish; surfaced as a §19.2 mostly to track the testing follow-up.
|
||||
|
||||
f. **Contract between README and rfc-app `/docs/sessions/about` renderer** (0017.2). Operator-review HTML comments (`<!-- ... -->`) should render as nothing on-site (markdown stripping). Worth confirming in the next session's first browser-verification gesture; if they show up as raw text the renderer needs a small fix.
|
||||
|
||||
g. **Local-vs-published shape asymmetry** (0017.2). Local working dir `~/git/ohm-infra/` stays flat; published repo is nested in `NNNN/` folders. Already documented in `SESSION-PROTOCOL.md` §1, but worth a one-line callout if future drivers get confused.
|
||||
|
||||
h. **SSE-keepalive SSH-watchdog timeout — 4th occurrence** (driver). Hit at phase 7 of every recent deploy: SIGTERM doesn't drain SSE connections in under 60 s, the SSH watchdog falls off, flotilla reports aborted, the service actually restarts and comes up healthy. flotilla v1.2.0 candidate: pre-drain SSE connections (or raise the watchdog to e.g. 180 s) before `systemctl restart`. Driver verification now leans entirely on `/api/health` + `flotilla deploy status` post-deploy rather than the flotilla exit code.
|
||||
|
||||
i. **Driver-inline commit identity drift** (driver). Three commits this session (one driver-inline CHANGELOG fix + two subagent merges + the pin bump) carried `Ben Stull <benstull@mac.lan>` as the committer rather than the operator's preferred identity. Per the hard rule, no `git config` edit; operator can rewrite if desired. Worth surfacing as an operator-tooling §19.2: a one-line "ensure git identity is set on this machine" gesture would prevent it.
|
||||
|
||||
j. **`publish-transcript.sh` `sessions.json` formatting churn** (driver, noticed at publish-time after 0017.2's restructure had already shipped). The script's inline-Python upsert uses `json.dump`'s default `indent=2` (expands every entry to multi-line) AND default `ensure_ascii=True` (escapes em-dashes / `§` / en-dashes as `—` / `§` / `–`). 0017.2's subagent had hand-written `sessions.json` with compact one-line entries per session + raw UTF-8. The first publish-time upsert (0017.0's transcript publish, which added the `0017` placeholder) rewrote the file in the expanded ASCII-escaped form, so the operator's next edit starts from that shape rather than the subagent's. Fix is one-line in `publish-transcript.sh`: `json.dump(out, f, indent=2, ensure_ascii=False)` plus a small custom emitter to keep each session's `{ "title": "…" }` on one line. Cosmetic; no functional impact.
|
||||
|
||||
---
|
||||
|
||||
## What lands on the operator's plate
|
||||
|
||||
1. **Browser-verify `/docs/*` surfaces** (next-session first gesture). Concrete URLs in the next-session prompt below. ~5 minutes.
|
||||
2. **Rewrite the 3 README.md placeholder sections** on `wiggleverse/ohm-session-history` (sections marked with `<!-- operator: rewrite this section in your voice -->`). Direct commit to main; no PR ceremony needed.
|
||||
3. **Refine `sessions.json` titles** if desired. 0013's title is a semicolon-list of three subagent workstreams (may want compression); 0014's title is the subagent's phrasing rather than the §1-example verbatim form. Add a title for **0017** (currently absent from the manifest — it'll be added as `{"title": ""}` when this transcript publishes; operator fills in something like `"Wave 8 driver — docs nav + on-site sessions browser (#30)"`).
|
||||
4. **Merge the two Session-M docs PRs** still awaiting operator merge:
|
||||
- rfc-app `feature/contributing-and-spec-analytics` @ `213f686`
|
||||
- ohm-rfc `feature/contributing-roadmap-guide` @ `f26fae4`
|
||||
5. **DMARC Phase A → Phase B**: ≥1 week of clean `rua` reports at `ben.stull@wiggleverse.org` since Session 0014.0; ETA 2026-06-04 to flip `p=quarantine`.
|
||||
6. **#1 VM rename + flotilla v1.2.0 SSE-keepalive drain** (combined session) — the watchdog pattern is now 4× confirmed; worth fixing alongside the rename when the maintenance window opens.
|
||||
7. **Update ohm-rfc/ROADMAP.md**: strikethrough #30 row in the version-target table; link to v0.19.0 + the deploys.id row (when one materializes — currently aborted-on-timeout).
|
||||
|
||||
---
|
||||
|
||||
## Prompt the operator can paste into the next Claude Code session
|
||||
|
||||
```
|
||||
You are the OHM roadmap driver, Session 0018.0. Read this whole prompt
|
||||
before doing anything.
|
||||
|
||||
# What Session 0017.0 shipped
|
||||
|
||||
Wave 8 was roadmap item #30 — the docs nav + on-site sessions browser
|
||||
+ session-history repo restructure — picked because the operator
|
||||
marked #30 **NEXT** in ROADMAP.md and the load-bearing OTC sign-in
|
||||
gate (the Wave 7 / v0.18.0 carry-forward) was confirmed working
|
||||
end-to-end at session start. Three parallel subagents:
|
||||
|
||||
1. **flotilla / ohm-infra** (driver inline) — `publish-transcript.sh`
|
||||
extended to place new transcripts into their `NNNN/` subfolder and
|
||||
upsert `sessions.json` (a top-level title manifest, keyed by
|
||||
4-digit `NNNN`, value `{"title": ""}`). Backward-compat: legacy
|
||||
letter-form transcripts still land at repo root. JSON upsert is
|
||||
pure stdlib via inline `python3` heredoc, no jq dep.
|
||||
SESSION-PROTOCOL.md §1 gained a "Published repo layout" amendment
|
||||
documenting the new folder shape, the `sessions.json` schema, and
|
||||
the "local files stay flat — folders are publish-time" rule. §5
|
||||
gained a short "Published-repo placement" note saying subsession
|
||||
transcripts inherit their parent's `NNNN/`.
|
||||
|
||||
2. **subsession 0017.1 — rfc-app v0.19.0** (merged + tagged + pushed).
|
||||
Backend: `/api/docs/sessions/{manifest,about,<NNNN>/index,<NNNN>/<file>}`
|
||||
with in-process TTL cache (60s manifest, 5min content; both
|
||||
env-tunable via `OHM_DOCS_SESSIONS_MANIFEST_TTL_SEC` /
|
||||
`OHM_DOCS_SESSIONS_CONTENT_TTL_SEC`). Negative caching for 404s
|
||||
(rationale: at ship time the repo restructure is racing the rfc-app
|
||||
deploy; empty-state path may be hot for hours). Gitea raw base
|
||||
configurable via `OHM_SESSION_HISTORY_RAW_BASE`. 18 new pytest
|
||||
cases (`test_docs_sessions_vertical.py`, 313 backend total green).
|
||||
Frontend: `/docs` → redirect to `/docs/user-guide`; `/docs/sessions`
|
||||
→ redirect to `/docs/sessions/about`; `/docs/sessions/<NNNN>` and
|
||||
`/docs/sessions/<NNNN>/<filename>` for index + transcript view;
|
||||
`DocsLayout.jsx` with left-side flyout nav driven by the manifest;
|
||||
reuses the v0.14.0 react-markdown renderer; Amplitude `Doc Viewed`
|
||||
events + `data-amp-track-*` decoration. Branch
|
||||
`feature/v0.19.0-docs-sessions-browser` merged to main at `69a166a`,
|
||||
tag v0.19.0, pushed to origin + benstull mirror.
|
||||
|
||||
3. **subsession 0017.2 — wiggleverse/ohm-session-history restructure**
|
||||
(one atomic commit `ad01c08` on `main`, fast-forward push). 19
|
||||
transcripts `git mv`'d into 15 `NNNN/` folders (rename detection
|
||||
100%); `0013/` holds 4 transcripts (driver + 3 subagents from
|
||||
Session 0013.0); `0014/` holds 2 (driver + 1 subagent). Top-level
|
||||
`README.md` rewritten with 3 `<!-- operator: rewrite this section
|
||||
in your voice -->` markers (sections: "How OHM gets built", "Why
|
||||
transcripts are public" — which includes the verbatim
|
||||
"Oh and Jan, your joke is in there somewhere." line — and
|
||||
"What's in the repo"). Top-level `sessions.json` drafted with 15
|
||||
entries, every session titled (no placeholders); titles read off
|
||||
each transcript's `Goal:`/`Outcome:` header block. Operator-review
|
||||
notes: 0013's title is a semicolon-list of three subagent
|
||||
workstreams (may want compression); 0014's title is the
|
||||
subagent's phrasing rather than the §1-example verbatim form.
|
||||
Filename convention inside each folder: full
|
||||
`SESSION-NNNN.M-TRANSCRIPT-…md` form retained (no trim of the
|
||||
`SESSION-` prefix). The roadmap example showed trimmed form;
|
||||
Session 0017.0 settled on retained-prefix for file-self-
|
||||
identification. Document in SPEC.md if operator wants to flip.
|
||||
|
||||
# Cut state at handoff
|
||||
|
||||
- rfc-app `main`: `69a166a` (merge) → tag `v0.19.0` published; pushed
|
||||
to origin + benstull mirror.
|
||||
- ohm-rfc `main`: `de17e79` — `.rfc-app-version=0.19.0`.
|
||||
- ohm-rfc-app-flotilla `main`: `417b6c5` (no flotilla code change
|
||||
this session).
|
||||
- wiggleverse/ohm-session-history `main`: `ad01c08` — restructured
|
||||
into `NNNN/` folders + README.md + sessions.json at root.
|
||||
- OHM live: **v0.19.0 healthy** (`/api/health` returns
|
||||
`{"version":"0.19.0","status":"ok"}`).
|
||||
- deploys.id row for v0.19.0: aborted-due-to-SSH-timeout (the
|
||||
§19.2 SSE-keepalive pattern fired again; service IS healthy at
|
||||
v0.19.0; the aborted row reflects the SSH watchdog falling off,
|
||||
not the deploy itself — 4th occurrence; flotilla v1.2.0
|
||||
candidate).
|
||||
- ohm-infra: `scripts/publish-transcript.sh` extended;
|
||||
`SESSION-PROTOCOL.md` §1 + §5 amended (NOT in a git repo locally,
|
||||
so no commit; the files ARE what they are on disk).
|
||||
- DMARC Phase A unchanged from Session 0014.0 (`p=none`, `pct=100`,
|
||||
TTL=3600s, `rua=mailto:ben.stull@wiggleverse.org`). 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
|
||||
|
||||
- ✅ OTC sign-in end-to-end (Session 0017.0 operator-confirmed at
|
||||
session start — the Wave 7 / v0.18.0 carry-forward gate).
|
||||
- ✅ v0.19.0 service health (`/api/health` returns 0.19.0).
|
||||
- ✅ wiggleverse/ohm-session-history restructure (gitea raw probes
|
||||
on `sessions.json`, `README.md`, and a sample 0014/ transcript
|
||||
all return 200).
|
||||
- ⏸ End-to-end `/docs/*` surfaces in a real browser **not yet
|
||||
operator-confirmed**. Session 0017.0 ended before the operator
|
||||
loaded the site. First gesture this session: have the operator
|
||||
load these URLs in a fresh browser tab:
|
||||
- `https://ohm.wiggleverse.org/docs` → should redirect to
|
||||
`/docs/user-guide` (existing v0.14.0 content, no behavior change
|
||||
beyond the URL move).
|
||||
- `https://ohm.wiggleverse.org/docs/sessions/about` → renders the
|
||||
README.md from `wiggleverse/ohm-session-history`. Expect the
|
||||
3 operator-review HTML comments to render as nothing on-site
|
||||
(one of the §19.2 candidates is to verify this; if they're
|
||||
visible as raw text, that's a markdown-renderer bug to fix).
|
||||
- `https://ohm.wiggleverse.org/docs/sessions/0009` → session index
|
||||
page for Session 0009.0 (the multi-wave driver). Should show
|
||||
"Session 0009.0 — multi-wave driver (rfc-app v0.4–v0.13, skipping
|
||||
vacants)" as the title from sessions.json.
|
||||
- `https://ohm.wiggleverse.org/docs/sessions/0013` → should show
|
||||
4 transcripts (driver + 3 subagents) and resolve the right list
|
||||
via the per-session `/index` endpoint.
|
||||
- `https://ohm.wiggleverse.org/docs/sessions/0014/SESSION-0014.0-TRANSCRIPT-2026-05-28T07-01--2026-05-28T08-25.md`
|
||||
→ renders Wave 7 driver transcript in-browser.
|
||||
- Flyout nav: open from any /docs/* route; on mobile, confirm the
|
||||
drawer toggles.
|
||||
- ⏸ Operator hasn't reviewed the README draft prose or sessions.json
|
||||
titles — they're shipped as drafted; refinement is a follow-up.
|
||||
|
||||
# Wave 9 candidates (priority is operator's call)
|
||||
|
||||
1. **Verify /docs/* surfaces in browser** (above). Five minutes if
|
||||
they work; longer if not.
|
||||
2. **Operator rewrites the 3 README.md placeholder sections** on
|
||||
`wiggleverse/ohm-session-history`. Operator-only gesture; commit
|
||||
directly to main.
|
||||
3. **Operator refines sessions.json titles** if desired (0013's
|
||||
semicolon-list, 0014's phrasing, or anywhere else); also fills in
|
||||
the empty title for 0017 (added as `{"title": ""}` when 0017.0's
|
||||
transcript published).
|
||||
4. **Operator merges the two M docs PRs**.
|
||||
5. **#1 VM rename + flotilla v1.2.0 SSE-keepalive drain** — the
|
||||
§19.2 SSE-keepalive timeout pattern was hit a 4th time this
|
||||
session; worth fixing alongside the rename. flotilla v1.2.0
|
||||
would pre-drain SSE connections before `systemctl restart` to
|
||||
close the watchdog gap.
|
||||
6. **DMARC Phase A → Phase B (`p=quarantine`)** — ≥1 week of clean
|
||||
rua data; ETA 2026-06-04.
|
||||
7. **#20 ops side**: delete stale `wiggleverse/meta` hook on
|
||||
deprovisioned `rfc.wiggleverse.org`.
|
||||
8. **#18 ops side**: bounce-source wiring (Path A or B in the
|
||||
runbook).
|
||||
9. **#21 Part A Amplitude audit** — defer to ~2026-06-04 for a week
|
||||
of post-fix dashboard data (Amplitude + OTC both now confirmed
|
||||
working).
|
||||
10. **#22 pro-consent copy** — operator-drafted + counsel-reviewed;
|
||||
subagent wires once approved.
|
||||
11. **#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.
|
||||
12. **#17 repo naming alignment** — operator decides Q1 first.
|
||||
|
||||
# §19.2 candidates surfaced in Session 0017.0
|
||||
|
||||
From subsession 0017.1 (rfc-app v0.19.0):
|
||||
a. `frontend/package-lock.json` top-level "version" field drifted
|
||||
(lockfile reads `0.15.0` while `package.json` is `0.19.0`).
|
||||
Cosmetic but ugly. Symptom of no automated lockfile-discipline
|
||||
check.
|
||||
b. rfc-app backend has no `pyproject.toml` — the dispatch assumed
|
||||
one. Repo uses `backend/requirements.txt` only. Canonical version
|
||||
sources are `VERSION` + `frontend/package.json#version`.
|
||||
c. `docs_sessions.py`'s private validators (`_is_valid_session_dir`,
|
||||
`_is_valid_transcript_filename`) leak into the route layer —
|
||||
consider consolidating into a public `validate_path()`.
|
||||
d. `docs_sessions` in-process cache cannot be invalidated externally
|
||||
without a process restart or a `reset_cache()` test seam.
|
||||
Operationally fine (TTL is short); developer-experience worth
|
||||
improving.
|
||||
|
||||
From subsession 0017.2 (session-history restructure):
|
||||
e. publish-transcript.sh should auto-add `sessions.json` placeholder
|
||||
entries on first-publish for a new NNNN. **Already partially
|
||||
shipped** in 0017.0's publish-script extension (the upsert logic
|
||||
adds `{"NNNN": {"title": ""}}` if the key is missing). Worth
|
||||
confirming the contract end-to-end.
|
||||
f. Contract between README and rfc-app `/docs/sessions/about`
|
||||
renderer — operator-review HTML comments (`<!-- ... -->`) should
|
||||
render as nothing on-site. Worth confirming in the first-test
|
||||
gesture.
|
||||
g. Local-vs-published shape asymmetry (local flat in
|
||||
`~/git/ohm-infra/`, published nested in `NNNN/` folders) is
|
||||
already documented in SESSION-PROTOCOL.md §1; worth surfacing as a
|
||||
one-line callout if it confuses future drivers.
|
||||
|
||||
From driver:
|
||||
h. The §19.2 SSE-keepalive SIGTERM holding past the 60s SSH watchdog
|
||||
— hit AGAIN this session (4th occurrence). flotilla v1.2.0 should
|
||||
pre-drain SSE connections before `systemctl restart`. Driver
|
||||
verification now leans entirely on `/api/health` post-deploy
|
||||
rather than the flotilla exit code.
|
||||
i. Driver-inline commit identity drift (`benstull@mac.lan` rather
|
||||
than `ben@wiggleverse.org`). Per hard rule no `git config` edit
|
||||
this session; surfaced for operator tooling.
|
||||
j. `publish-transcript.sh` `sessions.json` formatting churn. The
|
||||
script's inline-Python upsert uses `json.dump`'s default
|
||||
`indent=2` (every entry expands to multi-line) and default
|
||||
`ensure_ascii=True` (em-dashes / `§` / en-dashes escape to
|
||||
`\uXXXX`). 0017.2's subagent had hand-written compact one-line
|
||||
entries with raw UTF-8; the first publish-time upsert (0017.0's
|
||||
publish, adding the `0017` placeholder) rewrote the file in the
|
||||
expanded ASCII-escaped form. Operator's next edit starts from
|
||||
that shape. One-line fix: `json.dump(out, f, indent=2,
|
||||
ensure_ascii=False)` + a small custom emitter to keep each
|
||||
session on one line. Cosmetic only; no functional impact.
|
||||
|
||||
# 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** (binding from Session
|
||||
0013.0 onward): forked subagents write their own transcripts
|
||||
BEFORE returning their report. Driver re-verifies deliverables on
|
||||
disk rather than depending on the report-back text.
|
||||
- **Protocol amendments must land with the code change.**
|
||||
- **Naming**: this is Session 0018.0. Driver transcript:
|
||||
`SESSION-0018.0-TRANSCRIPT-<start>--<end>.md`. Subagent transcripts:
|
||||
`SESSION-0018.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 0018.0
|
||||
|
||||
1. Read `~/git/ohm-infra/SESSION-PROTOCOL.md` (the §1 + §5
|
||||
amendments from Session 0017.0 are the relevant new content).
|
||||
2. Read `/Users/benstull/projects/wiggleverse/ohm-rfc/ROADMAP.md`
|
||||
end-to-end. #30 is the most recent item shipped (strikethrough
|
||||
pending — operator may or may not have updated the version-target
|
||||
table; if not, do it on the next ohm-rfc edit you make).
|
||||
3. Read the Session 0017.0 transcript at
|
||||
`~/git/ohm-infra/SESSION-0017.0-TRANSCRIPT-2026-05-28T08-50--2026-05-28T09-22.md`
|
||||
for the full triage detail (this prompt is the summary).
|
||||
4. Have the operator load `/docs/sessions/about` and at least one
|
||||
`/docs/sessions/<NNNN>/<filename>` in a fresh browser tab. That's
|
||||
the load-bearing first test.
|
||||
5. Pick Wave 9's shippable scope. The roadmap doesn't have an
|
||||
explicit **NEXT** marker after #30 ships, so the picking is the
|
||||
operator's call.
|
||||
```
|
||||
@@ -0,0 +1,350 @@
|
||||
# Session 0017.1 — Subsession transcript
|
||||
|
||||
> Parent: SESSION-0017.0-TRANSCRIPT-…md (not yet written; driver writes
|
||||
> at end of session 0017.0)
|
||||
> Date: 2026-05-28
|
||||
> Goal: rfc-app v0.19.0 — /docs/sessions browser + flyout nav (roadmap
|
||||
> item #30)
|
||||
> Outcome: **Shipped on branch `feature/v0.19.0-docs-sessions-browser`
|
||||
> at `477f496`. Backend mediates `/api/docs/sessions/{manifest,about,
|
||||
> <NNNN>/index, <NNNN>/<file>}` with an in-process TTL cache (60s
|
||||
> manifest, 5min content; both env-tunable + negative-cached on 404).
|
||||
> Frontend reorganizes `/docs` into a left-flyout hub with the new
|
||||
> session browser sub-routes; existing DOCS.md content moves to
|
||||
> `/docs/user-guide`. 313/313 backend tests pass (18 new); frontend
|
||||
> builds clean. No tag, no pin bump, no benstull mirror push — driver
|
||||
> takes over after subsession 0017.2 lands.**
|
||||
|
||||
---
|
||||
|
||||
## Pre-session state
|
||||
|
||||
- `rfc-app` was at `main @ ac3513a`, VERSION `0.18.0`, working tree
|
||||
clean. Two remotes:
|
||||
- `origin` → `git.wiggleverse.org/ben.stull/rfc-app` (canonical)
|
||||
- `benstull` → `git.benstull.org/benstull/rfc-app` (mirror)
|
||||
- The most recent release on `main` was v0.18.0 (email + webhook
|
||||
hygiene, roadmap items #18 + #20).
|
||||
- Existing `/docs` surface was the v0.14.0 single-route DOCS.md
|
||||
shape: `components/Docs.jsx` rendering markdown via the shared
|
||||
`MarkdownPreview` (marked + lazy-loaded mermaid). Backend served
|
||||
the body at `/api/docs` from a disk-cached `DOCS.md` at the repo
|
||||
root.
|
||||
- Dispatch settled two design choices before this subsession opened:
|
||||
the transcript repo is gitea-only (canonical at
|
||||
`git.wiggleverse.org/wiggleverse/ohm-session-history`, no GitHub
|
||||
mirror) and the rendering shape is runtime fetch with cache (no
|
||||
build-time bundling of transcripts).
|
||||
|
||||
---
|
||||
|
||||
## Turn-by-turn arc
|
||||
|
||||
### Arc 1 — Orientation
|
||||
|
||||
Read `~/git/ohm-infra/SESSION-PROTOCOL.md` (full), `rfc-app/CLAUDE.md`,
|
||||
the SPEC §21 analytics chapter (DOM patterns + the autocapture
|
||||
attribute conventions), `backend/app/docs.py` and `backend/app/api.py`
|
||||
(to see how the existing v0.14.0 `/api/docs` was wired), and
|
||||
`backend/tests/test_propose_vertical.py` for the `app_with_fake_gitea`
|
||||
fixture shape that every existing test reuses.
|
||||
|
||||
Noted that `pyproject.toml` doesn't exist in rfc-app (the dispatch
|
||||
prompt's "bump pyproject.toml" instruction was a non-op — there's a
|
||||
`backend/requirements.txt` only, and the canonical version sources
|
||||
are `VERSION` + `frontend/package.json#version` per
|
||||
SPEC §20.1).
|
||||
|
||||
### Arc 2 — Design choice: per-session listing
|
||||
|
||||
The dispatch prompt named the open design question for the per-session
|
||||
index page (`/docs/sessions/:nnnn`). Two options:
|
||||
|
||||
1. Extend the manifest endpoint to also list per-session filenames
|
||||
via the gitea contents API.
|
||||
2. Add a separate per-session listing endpoint that hits gitea
|
||||
contents only when the session-index page is visited.
|
||||
|
||||
I went with **option 2** (separate `/api/docs/sessions/<NNNN>/index`
|
||||
endpoint). Reasoning: the manifest stays cheap and small (one fetch,
|
||||
one cache entry, 60s TTL); per-session listings are fetched on
|
||||
demand and cached at the content TTL (5min). This means a user who
|
||||
only browses the flyout's session list (via the manifest) doesn't
|
||||
pay for `N` extra gitea contents-API calls — only the user who
|
||||
clicks into a session pays. The endpoint filters the contents-API
|
||||
response to entries matching the `_TRANSCRIPT_FILENAME_RE` so any
|
||||
sibling files in a `NNNN/` folder (e.g. an attached `notes.md`)
|
||||
don't show up in the list.
|
||||
|
||||
### Arc 3 — Design choice: negative caching for 404s
|
||||
|
||||
The dispatch prompt left negative caching for 404s as optional.
|
||||
**Decided to implement it**: cache 404 results at the content TTL
|
||||
across the manifest, about, transcript, and session-index endpoints.
|
||||
|
||||
Reasoning: at v0.19.0 ship time, the parallel
|
||||
ohm-session-history repo restructure (subsession 0017.2) hasn't
|
||||
shipped yet — the repo is still flat, so the manifest, about,
|
||||
session-index, and per-transcript fetches will all 404 from gitea
|
||||
for the first few hours / days. Without negative caching, every
|
||||
page-view in that window would trigger a fresh gitea request even
|
||||
though we already know it's 404. With negative caching, repeated
|
||||
visits to a known-missing transcript only hit gitea once per
|
||||
5-minute window. Manifest 404 cache means the first OHM user
|
||||
loading `/docs/sessions/*` doesn't hammer the upstream while
|
||||
0017.2 is still mid-flight.
|
||||
|
||||
The behavior is exercised by `test_transcript_404_is_cached` in
|
||||
the new test file.
|
||||
|
||||
### Arc 4 — Backend slice
|
||||
|
||||
Wrote `backend/app/docs_sessions.py` (the fetcher + cache module)
|
||||
and added four routes to `backend/app/api.py`:
|
||||
|
||||
- `GET /api/docs/sessions/manifest` — returns `sessions.json` as a
|
||||
JSON object. 404 from gitea → `{}` at HTTP 200 (empty-state
|
||||
contract, lets the frontend short-circuit without an error
|
||||
banner). 5xx / timeout → HTTP 502 with
|
||||
`{detail: {error, detail}}`.
|
||||
- `GET /api/docs/sessions/about` — returns README.md as
|
||||
`text/markdown; charset=utf-8`. 404 → HTTP 404; 5xx → 502.
|
||||
- `GET /api/docs/sessions/{nnnn}/index` — returns
|
||||
`{"files": [...]}`. The path param `nnnn` must match
|
||||
`^\d{4}$`; otherwise 400 before any network call. 404 from
|
||||
gitea (no such folder) → HTTP 404.
|
||||
- `GET /api/docs/sessions/{nnnn}/{filename}` — returns the
|
||||
transcript body. Both path params are regex-validated before
|
||||
the network call (`^\d{4}$` for nnnn,
|
||||
`^SESSION-\d{4}\.\d+(\.\d+)*-TRANSCRIPT(-<start>--<end>)?\.md$`
|
||||
for filename — `<start>--<end>` is optional so legacy renamed-
|
||||
letter transcripts without timestamps remain reachable).
|
||||
Returns the body as `text/markdown; charset=utf-8`.
|
||||
|
||||
The fetcher uses `httpx.AsyncClient` with a 5s timeout and no auth
|
||||
header (the gitea repo is public). The cache is plain
|
||||
`dict` keyed by URL-path + `time.monotonic()` checks; the
|
||||
`_lock` is a `threading.Lock` so the cache is safe under
|
||||
FastAPI's worker thread pool.
|
||||
|
||||
Env knobs:
|
||||
- `OHM_SESSION_HISTORY_RAW_BASE` (default points at
|
||||
`wiggleverse/ohm-session-history` on git.wiggleverse.org)
|
||||
- `OHM_SESSION_HISTORY_CONTENTS_BASE` (default mirrors the raw base
|
||||
on the contents-API mount)
|
||||
- `OHM_DOCS_SESSIONS_MANIFEST_TTL_SEC` (default 60)
|
||||
- `OHM_DOCS_SESSIONS_CONTENT_TTL_SEC` (default 300)
|
||||
|
||||
### Arc 5 — Backend tests + the monkeypatch ordering snag
|
||||
|
||||
Wrote 18 new tests in
|
||||
`backend/tests/test_docs_sessions_vertical.py`. The tricky bit
|
||||
took a couple iterations to nail:
|
||||
|
||||
The shared `app_with_fake_gitea` fixture from
|
||||
`test_propose_vertical.py` monkeypatches `httpx.AsyncClient` via
|
||||
`monkeypatch.setattr("app.gitea.httpx.AsyncClient", patched)`.
|
||||
Since `app.gitea.httpx` IS the shared `httpx` module, that
|
||||
setattr mutates the global `httpx.AsyncClient` attribute. My
|
||||
docs-sessions test fixture then did the same for
|
||||
`"app.docs_sessions.httpx.AsyncClient"` — meant to override —
|
||||
but the first version captured
|
||||
`real_client_cls = httpx.AsyncClient` at fixture-setup time.
|
||||
At that point `httpx.AsyncClient` was already the gitea-patched
|
||||
wrapper, so my "patched" function ended up wrapping the
|
||||
gitea-patched wrapper, and gitea-bound requests still routed
|
||||
through the FakeGitea handler (and the FakeGitea returned
|
||||
404 for session-history URLs, making my test see "manifest
|
||||
empty").
|
||||
|
||||
Fix: import the truly-unpatched `AsyncClient` from
|
||||
`httpx._client` and use that as the base inside my install
|
||||
closure. The `_UpstreamHandler` also gained a host-marker
|
||||
filter so it only counts session-history URLs (not the
|
||||
reconciler's incidental Gitea calls that also hit our handler
|
||||
via the shared httpx module) in its `.calls` list — that lets
|
||||
the cache-hit assertions stay exact.
|
||||
|
||||
Test inventory after the fix lands:
|
||||
- Manifest happy-path / empty-state / 502
|
||||
- About happy-path / 404 / 502
|
||||
- Transcript happy-path / 404 / 502
|
||||
- Path-validation rejection: invalid nnnn, path-traversal,
|
||||
legacy flat-root filename — all rejected 400 before network
|
||||
- Session-index happy-path / 404 / invalid-nnnn rejection
|
||||
- Cache-hit-within-TTL for manifest + transcript
|
||||
- Negative cache for transcript 404s
|
||||
|
||||
All 18 pass; full backend suite is **313/313**.
|
||||
|
||||
### Arc 6 — Frontend slice
|
||||
|
||||
The dispatch prompt was specific about reusing the existing
|
||||
markdown renderer (`MarkdownPreview` — marked + mermaid lazy-load),
|
||||
so the four new sub-route components each render their body
|
||||
through that same component. No new markdown library.
|
||||
|
||||
Component layout:
|
||||
- `DocsLayout.jsx` — shell with the flyout nav + `<Outlet/>` for
|
||||
sub-routes. Owns the manifest fetch + the mobile-drawer toggle.
|
||||
- `DocsUserGuide.jsx` — DOCS.md content (the old `/docs` route).
|
||||
- `DocsSessionsAbout.jsx` — renders the session-history README.
|
||||
- `DocsSessionIndex.jsx` — per-session transcript list. Fetches
|
||||
the manifest (for the title) AND the per-session index
|
||||
endpoint (for the file list). Treats title-fetch failure as
|
||||
decorative (just renders the bare `Session NNNN` header) while
|
||||
the file-list fetch is the load-bearing one.
|
||||
- `DocsSessionTranscript.jsx` — renders a single transcript.
|
||||
|
||||
`App.jsx` route registration replaced the single
|
||||
`Route path="/docs"` with:
|
||||
|
||||
```
|
||||
/docs → Navigate to /docs/user-guide
|
||||
/docs/* → DocsWithSidebar (nested Routes inside)
|
||||
├── /user-guide
|
||||
├── /sessions → Navigate to /sessions/about
|
||||
├── /sessions/about
|
||||
├── /sessions/:nnnn
|
||||
└── /sessions/:nnnn/:filename
|
||||
```
|
||||
|
||||
Mobile drawer: at viewport ≤ 720px the sidebar is hidden by a
|
||||
`transform: translateX(-100%)` and revealed via a `☰` button in
|
||||
the header. A scrim overlay (`.docs-drawer-scrim`) intercepts
|
||||
outside clicks. The drawer auto-closes on every route change
|
||||
(via a `useEffect` keyed on `location.pathname`) so a click in
|
||||
the flyout doesn't strand the user on a drawer-open view.
|
||||
|
||||
Analytics (per SPEC §21):
|
||||
- Added `EVENTS.DOC_VIEWED` to `frontend/src/lib/analytics.js`
|
||||
(new constant, taxonomy entry per §21.1's "new events SHOULD
|
||||
land via a release"). Each sub-route component fires
|
||||
`track(EVENTS.DOC_VIEWED, { section: '...' })` on mount.
|
||||
- Every interactive nav element (links, buttons) carries
|
||||
`aria-label` + `data-amp-track-name` so autocapture rows are
|
||||
readable per §21.3. The per-row session links also carry
|
||||
`data-amp-track-session={nnnn}` so the dashboard can
|
||||
aggregate by session.
|
||||
|
||||
The old `Docs.jsx` is now dead code; deleted in the same commit.
|
||||
|
||||
### Arc 7 — Version bumps + CHANGELOG + push
|
||||
|
||||
Bumped `VERSION` (root) and `frontend/package.json#version` from
|
||||
`0.18.0` → `0.19.0`. The dispatch prompt named `pyproject.toml`
|
||||
but there isn't one in this repo (the backend uses a plain
|
||||
`requirements.txt`); noted in this transcript but no edit
|
||||
performed.
|
||||
|
||||
`frontend/package-lock.json` still reads `0.15.0` — it has been
|
||||
drifting since the v0.15.0 release (four minor versions). Not
|
||||
touched in this release (separate cleanup; see §19.2 candidates).
|
||||
|
||||
CHANGELOG entry was prepended above the v0.18.0 entry verbatim
|
||||
per the dispatch prompt (header date, body paragraph, upgrade-
|
||||
steps MAY block, degradation note about the parallel
|
||||
session-history restructure shipping in subsession 0017.2).
|
||||
|
||||
Three commits on the feature branch, pushed to origin only:
|
||||
- `39e5770` v0.19.0 backend: /api/docs/sessions/* endpoints + TTL cache
|
||||
- `822f426` v0.19.0 frontend: /docs/* route tree + flyout nav + sessions browser
|
||||
- `477f496` Release v0.19.0: /docs nav + on-site sessions browser
|
||||
|
||||
`benstull` mirror untouched per dispatch.
|
||||
|
||||
---
|
||||
|
||||
## Cut state
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| rfc-app | feature/v0.19.0-docs-sessions-browser @ `477f496`, pushed to `origin` only |
|
||||
| Tests | pytest backend: **313 passing** (18 new in test_docs_sessions_vertical.py); frontend has no test framework — `npm run build` is green |
|
||||
| Frontend dev-server smoke check | Skipped (subsession is a sandboxed agent, no browser to drive). The CHANGELOG-named degradation path is structurally exercised by the backend's 404 → frontend's empty-state contract; route-mount errors would have surfaced at `npm run build` |
|
||||
| What the driver does next | tag v0.19.0 after 0017.2 lands → merge to main → push to origin + benstull mirror → bump ohm-rfc pin → `flotilla deploy ohm-rfc-app` → verify /docs/user-guide + /docs/sessions/about surfaces in the deployed environment |
|
||||
|
||||
---
|
||||
|
||||
## §19.2 candidates surfaced
|
||||
|
||||
1. **`frontend/package-lock.json` version drift** — what / lock
|
||||
reads `0.15.0` while `package.json` is now `0.19.0` (the lock
|
||||
has been stale since the v0.15.0 release). why / it's an
|
||||
audit-log inconsistency in the npm metadata. when / one-shot
|
||||
cleanup, low-priority — the lock doesn't affect builds because
|
||||
the resolved versions are correct, just the top-level `name`
|
||||
stanza. Fix in the next session that touches frontend deps.
|
||||
|
||||
2. **rfc-app backend has no `pyproject.toml`** — what / the
|
||||
dispatch prompt assumed a `pyproject.toml` exists; the repo
|
||||
uses a plain `backend/requirements.txt`. why / standard
|
||||
Python tooling (uv, hatch, ruff config, mypy config) all
|
||||
prefer pyproject.toml; absence makes those tools less
|
||||
ergonomic. when / a session that brings in another tool that
|
||||
wants the file. Could pair with a §20.1-style canonical-source
|
||||
audit ("VERSION here, pyproject.toml there — which wins?").
|
||||
|
||||
3. **`docs_sessions.py`'s private symbols leak into `api.py`** —
|
||||
what / I called `docs_sessions._is_valid_session_dir` and
|
||||
`docs_sessions._is_valid_transcript_filename` from the route
|
||||
layer (underscore-prefixed names). why / the validation is
|
||||
load-bearing for path-traversal rejection and shouldn't be
|
||||
re-implemented in the route, but exporting two helpers vs.
|
||||
one consolidated `validate_path(nnnn, filename) -> bool` would
|
||||
keep the API cleaner. when / next docs-sessions touch.
|
||||
|
||||
4. **CHANGELOG entry header style drifted** — what / the v0.18.0
|
||||
entry header is `## 0.18.0 — 2026-05-28` (no `v` prefix); my
|
||||
new v0.19.0 entry is `## v0.19.0 — 2026-05-28` (with `v`
|
||||
prefix) — I followed the dispatch prompt's verbatim block.
|
||||
why / cosmetic inconsistency in the changelog history. when /
|
||||
a release that audits the file for consistency could rename
|
||||
one direction or the other.
|
||||
|
||||
5. **`docs_sessions` cache cannot be invalidated externally** —
|
||||
what / the in-process cache exposes `reset_cache()` but no
|
||||
"invalidate this URL" gesture. why / if the operator publishes
|
||||
a transcript correction and the cache has the old body, they
|
||||
wait up to 5 minutes for the next reader to see the fix. when /
|
||||
a session that wires the reconciler's existing periodic refresh
|
||||
gesture in `cache.py` to also tick this module — or that adds
|
||||
an admin POST `/api/docs/sessions/refresh` for an explicit
|
||||
bust. Low priority; the publish gesture is rare.
|
||||
|
||||
---
|
||||
|
||||
## Notes for the driver
|
||||
|
||||
- **Path-traversal corner**: FastAPI / Starlette normalizes `..`
|
||||
in the URL path before routing, so `/api/docs/sessions/0001/../etc/passwd`
|
||||
resolves to a path that doesn't match the
|
||||
`/api/docs/sessions/{nnnn}/{filename}` route. The defense-in-depth
|
||||
is still in place (regex validates `nnnn` AND `filename` before
|
||||
any network call), but the test for path traversal had to use
|
||||
`etc%2Fpasswd` (URL-encoded slash) to actually reach the
|
||||
handler — the bare `../etc/passwd` was 404'd by the router
|
||||
itself.
|
||||
|
||||
- **TestClient + lifespan**: the backend tests use
|
||||
`with TestClient(app) as client:` which triggers the FastAPI
|
||||
lifespan. That starts the reconciler, which makes Gitea calls
|
||||
that ALSO hit our patched `httpx.AsyncClient` (since httpx is a
|
||||
shared module — see Arc 5). The `_UpstreamHandler` filters its
|
||||
`.calls` list to session-history URLs to keep the cache-hit
|
||||
assertions exact. Reconciler hits return 404 (no matching key
|
||||
in the responses dict), which the reconciler logs as a warning
|
||||
and proceeds — harmless for our test surface.
|
||||
|
||||
- **Frontend dev-server check not run**: the dispatch prompt
|
||||
named this as optional. The subsession is a sandboxed agent
|
||||
without a browser to drive; the build's success and the route
|
||||
registration's symmetry with the existing `/philosophy` chrome
|
||||
is the closest analog I could verify. Recommend the driver run
|
||||
`npm run dev` against the feature branch before merging to
|
||||
spot-check the flyout's render + drawer toggle on a real
|
||||
viewport.
|
||||
|
||||
- **No tag, no pin, no mirror push** — per dispatch. Driver
|
||||
handles tag → ohm-rfc pin bump → flotilla deploy after 0017.2
|
||||
lands.
|
||||
@@ -0,0 +1,262 @@
|
||||
# Session 0017.2 — Subsession transcript
|
||||
|
||||
> Parent: SESSION-0017.0-TRANSCRIPT-…md (not yet written; driver writes at end of session 0017.0)
|
||||
> Date: 2026-05-28
|
||||
> Start: 2026-05-28T09-10 PST
|
||||
> End: 2026-05-28T09-15 PST
|
||||
> Goal: wiggleverse/ohm-session-history restructure — per-session folders + README + sessions.json (roadmap item #30, Track Ω half)
|
||||
> Outcome: **Single commit `ad01c08` on `main` (b6a7b7d..ad01c08, fast-forward push), 19 transcripts `git mv`'d into 15 `NNNN/` folders (rename detection 100% on every file), top-level `README.md` rewritten with operator-review markers on 3 sections, top-level `sessions.json` drafted with 15 entries — no placeholders, every session titled.**
|
||||
|
||||
## Pre-session state
|
||||
|
||||
Remote `wiggleverse/ohm-session-history` `main` was at `b6a7b7d` at
|
||||
clone time (commit subject: `update SESSION-0014.0-TRANSCRIPT-…md`).
|
||||
Repo was fully flat — root contents:
|
||||
|
||||
- `LICENSE` (CC BY 4.0, ~17 KB, untouched by this session)
|
||||
- `README.md` (~4.7 KB, pre-rewrite; documented the old letter-form
|
||||
layout and the legacy publish flow)
|
||||
- 19 transcripts in numeric form:
|
||||
- `SESSION-0001.0-…md` through `SESSION-0015.0-…md`
|
||||
- including 3 subagent transcripts in the `0013/` cohort
|
||||
(`0013.1`, `0013.2`, `0013.3`) and 1 in the `0014/` cohort
|
||||
(`0014.1`)
|
||||
|
||||
No legacy letter-form transcripts (`SESSION-0001.0-TRANSCRIPT-…`,
|
||||
`SESSION-0013.1-TRANSCRIPT-…`, etc.) at root — Session 0014.0 / roadmap
|
||||
#23 already renamed all of them in commit `1afa9f5`.
|
||||
|
||||
## Turn-by-turn arc
|
||||
|
||||
### Arc 1 — Clone + inventory
|
||||
|
||||
Read `~/git/ohm-infra/SESSION-PROTOCOL.md` first; the §1 amendment
|
||||
(Session 0017.0, 2026-05-28) names the binding shape — folder per
|
||||
session, full `SESSION-` prefix retained, `sessions.json` flat object
|
||||
keyed by 4-digit NNNN, subagent transcripts share the parent's folder.
|
||||
|
||||
Cloned the remote into `/tmp/0017.2-work/ohm-session-history`. Did
|
||||
NOT work in `~/git/ohm-infra/` (that's the local-transcripts working
|
||||
dir, not a git repo). Inventoried — 19 transcripts at root, all
|
||||
numeric-form, plus `LICENSE` and `README.md`. No surprises.
|
||||
|
||||
### Arc 2 — git mv into NNNN/ folders
|
||||
|
||||
Ran one loop that for each `SESSION-NNNN.M-TRANSCRIPT-…md` extracted
|
||||
the leading `NNNN` via `sed`, `mkdir -p NNNN`, and
|
||||
`git mv SESSION-… NNNN/SESSION-…`. All 19 renames worked first try.
|
||||
|
||||
`git status` after showed 19 renames (no `deleted+added` —
|
||||
`git mv` preserves rename detection cleanly), zero surprises. The 15
|
||||
folders created: `0001/`, `0002/`, `0003/`, `0004/`, `0005/`,
|
||||
`0006/`, `0007/`, `0008/`, `0009/`, `0010/`, `0011/`, `0012/`,
|
||||
`0013/` (4 files), `0014/` (2 files), `0015/`.
|
||||
|
||||
### Arc 3 — sessions.json draft titles
|
||||
|
||||
Method: read the `Goal:` and `Outcome:` lines from each transcript's
|
||||
header (the `> Date: … > Goal: … > Outcome:` block at the top), then
|
||||
distilled into a tight phrase. For sessions that already named
|
||||
themselves "Session X" in the header (because the rename was filename-
|
||||
only, not body), I kept that internal letter-name in parens or as a
|
||||
prefix so the rendered nav has a hook for the chronology the operator
|
||||
already references in conversation.
|
||||
|
||||
Drafted titles (operator review needed — these are starter sketches):
|
||||
|
||||
```
|
||||
0001: "Bootstrap — git.benstull.org personal Gitea on GCP"
|
||||
0002: "Session 0002.0 — first OHM deployment (ohm.wiggleverse.org from zero)"
|
||||
0003: "Session 0003.0 — rfc-app 0.3.0 release + OHM upgrade (allowlist + anon read)"
|
||||
0004: "Session 0004.0 — flotilla SPEC + rfc.wiggleverse.org deprovision"
|
||||
0005: "Session 0005.0 — flotilla Slices 1 & 2 (registry + overlay; secret refs)"
|
||||
0006: "Session 0006.0 — flotilla Slice 3 (pin reading + deploy --dry-run, v0.3.0)"
|
||||
0007: "Session 0007.0 — flotilla Slice 4 (full deploy gesture + health probe, v0.4.0)"
|
||||
0008: "Session 0008.0 — flotilla v1.0.0 + first real OHM upgrade via flotilla"
|
||||
0009: "Session 0009.0 — multi-wave driver (rfc-app v0.4–v0.13, skipping vacants)"
|
||||
0010: "Session 0010.0 — DOCS.md + /docs route (rfc-app v0.14.0)"
|
||||
0011: "Session 0011.0 — Wave 4 (admin /users, device trust, CloudFlare Turnstile)"
|
||||
0012: "Session 0012.0 — Wave 5 (Amplitude, owner-invite, admin-create)"
|
||||
0013: "Session 0013.0 — Wave 6 (CONTRIBUTING + SPEC §21 analytics; repo-naming; email/webhook runbook)"
|
||||
0014: "Session 0014.0 — Wave 7 driver (SMTP + webhook hardening, #23 transcript rename)"
|
||||
0015: "Roadmap-capture parallel session (items #24–#30 added to ROADMAP.md)"
|
||||
```
|
||||
|
||||
No placeholders — every published session has a drafted title. Did
|
||||
NOT include entries for 0016 or 0017 (those are unpublished as of
|
||||
this subsession; the publish script will add them when their
|
||||
transcripts land).
|
||||
|
||||
JSON shape: flat object, 4-digit zero-padded NNNN keys, two-space
|
||||
indent, trailing newline. Matches the §1-amendment example exactly.
|
||||
|
||||
Mid-arc reconsideration: I first wrote `sessions.json` with stub
|
||||
entries `0016` and `0017`. Then re-read the dispatch — "one entry
|
||||
per session number per reading each transcript's header" — and
|
||||
realized 0016/0017 don't have transcripts in the public repo yet,
|
||||
so including them would be drafting titles for sessions that haven't
|
||||
shipped. Stripped both. The driver Session 0017.0 will add its own
|
||||
entry when it publishes its transcript.
|
||||
|
||||
### Arc 4 — README draft
|
||||
|
||||
Rewrote `README.md` end-to-end. Kept the structure of the existing
|
||||
README (intro → how / why → layout → publish → not-this → related →
|
||||
license) but rewrote every section to match the new layout and the
|
||||
post-#23 / post-#30 reality. Ingredients per the dispatch:
|
||||
|
||||
- **How OHM gets built** section: paired-session discipline, one-
|
||||
feature-per-session, parallel-subagent fan-out, cross-repo
|
||||
coherence. Marked for operator rewrite (this is the highest-
|
||||
voice-stakes section).
|
||||
- **Why transcripts are public** section: the §19.3 lesson ("the
|
||||
build is the artifact; cleanup is dishonest"), the cross-session
|
||||
driver brief, the invitation to read. Marked for operator rewrite.
|
||||
Includes the verbatim shout: **"Oh and Jan, your joke is in there
|
||||
somewhere."** Placed at the end of this section because that's
|
||||
where the affectionate aside fits the tonal arc.
|
||||
- **What's in the repo** section: documents the new folder layout,
|
||||
subagent placement under parent folder, sessions.json's role,
|
||||
legacy-letter-form mapping (pointer to SESSION-PROTOCOL.md §1).
|
||||
Marked for operator rewrite.
|
||||
- **How transcripts get added** section: kept the publish-script
|
||||
example, updated the path to use a 0017.0-style filename. Not
|
||||
marked for rewrite — this is operational, not voice-stakes.
|
||||
- **What this repo is not** / **Related repos** / **License**:
|
||||
preserved with minor edits to reflect new layout and updated
|
||||
remote URLs. Not marked.
|
||||
- Canonical-link callout at the top: gitea-only, no GitHub mirror,
|
||||
on-site at `ohm.wiggleverse.org/docs/sessions`.
|
||||
|
||||
3 sections marked with `<!-- operator: rewrite this section in your
|
||||
voice -->`. Length: ~520 words (target was ~400–600).
|
||||
|
||||
### Arc 5 — Commit + push
|
||||
|
||||
Staged all (19 renames + README modified + sessions.json new). Verified
|
||||
`git status` showed exactly the expected 19 renames + 1 modify + 1 new
|
||||
file, no stragglers.
|
||||
|
||||
Single commit, message verbatim from the dispatch prompt:
|
||||
|
||||
```
|
||||
#30: per-session folder layout + README + sessions.json
|
||||
…
|
||||
Session 0017.0; see SESSION-PROTOCOL.md §1 amendment for the binding shape.
|
||||
```
|
||||
|
||||
Committed as `ad01c08`. Git emitted a "Committer: Ben Stull <benstull@mac.lan>"
|
||||
notice (default identity from the local hostname); did NOT touch
|
||||
`git config` to suppress it (per CLAUDE.md / safety: never update git
|
||||
config). The notice is informational; the committer is fine for a
|
||||
local-clone tempdir push.
|
||||
|
||||
Pushed to `origin main`: clean fast-forward, `b6a7b7d..ad01c08`. No
|
||||
non-fast-forward retry needed; nothing landed in the public repo
|
||||
between clone and push.
|
||||
|
||||
## Cut state
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| Public repo | `wiggleverse/ohm-session-history` `main` @ `ad01c08`; 19 transcripts now in 15 `NNNN/` folders + `README.md` + `sessions.json` at root; `LICENSE` unchanged. |
|
||||
| Files moved | 19 (all via `git mv`, rename detection 100%); legacy letter-form left at root: 0 (none existed post-#23) |
|
||||
| Titles drafted | 15; operator-empty placeholders: 0 |
|
||||
| README markers | 3 sections marked `<!-- operator: rewrite this section in your voice -->` (How / Why / Layout) |
|
||||
|
||||
## §19.2 candidates surfaced
|
||||
|
||||
1. **`sessions.json` update on every publish** — the publish-transcript.sh
|
||||
script needs to gain logic that adds/updates the `sessions.json` entry
|
||||
for the session it's publishing. Today it just copies the file in;
|
||||
it does not touch `sessions.json`. For the first publish of a session,
|
||||
the script should add `"NNNN": {"title": ""}` as a placeholder and
|
||||
leave a hint that the operator (or the session's own README/transcript
|
||||
pass) needs to fill it. Subsequent publishes (same NNNN, different .N,
|
||||
or `update SESSION-…`) should not touch an existing title. This is a
|
||||
§19.2 because the subsession 0017.1 (rfc-app side) and 0017.2 (this
|
||||
one) shipped under a manual-fill convention; a §19.2 candidate would
|
||||
automate it.
|
||||
|
||||
2. **README rendered into rfc-app /docs/sessions/about** — the dispatch
|
||||
says rfc-app v0.19.0+ renders this README at `/docs/sessions/about`.
|
||||
The README I wrote includes operator-only HTML comments
|
||||
(`<!-- operator: rewrite this section in your voice -->`) that should
|
||||
NOT render on the public site. Markdown renderers typically strip HTML
|
||||
comments, but if the rfc-app docs renderer happens to pass them through
|
||||
as raw HTML, the markers would still be invisible (HTML comments are
|
||||
not displayed). Worth confirming — if rfc-app's renderer is strict
|
||||
sanitization, the markers vanish; if it's loose, they pass through
|
||||
inert. Either way, a §19.2 candidate is "what's the contract between
|
||||
ohm-session-history/README.md and the on-site docs renderer? Are
|
||||
there sections of the README that should NOT render on-site (e.g.,
|
||||
the publish-script how-to is operator-only)?"
|
||||
|
||||
3. **Local-vs-published transcript shape divergence** — local working
|
||||
files at `~/git/ohm-infra/SESSION-NNNN.M-TRANSCRIPT-…md` keep the
|
||||
flat shape; publish-time gesture moves them into folders. This
|
||||
subsession's transcript (the file you're reading) is at
|
||||
`~/git/ohm-infra/SESSION-0017.2-TRANSCRIPT-…md` — flat. When the
|
||||
driver publishes it, it lands at `0017/SESSION-0017.2-…md`. The
|
||||
asymmetry is fine but worth a one-line acknowledgement in the
|
||||
protocol doc (§1 already covers it but the wording is buried).
|
||||
|
||||
## Notes for the driver
|
||||
|
||||
Operator-review checklist for sessions.json titles (paste into the
|
||||
next operator-attention session):
|
||||
|
||||
- **0001**: Currently "Bootstrap — git.benstull.org personal Gitea on
|
||||
GCP." The transcript subtitle is "_For Jan, with affection and
|
||||
discomfort_" — operator may prefer a title that gestures at Jan
|
||||
rather than the technical surface.
|
||||
- **0002–0008**: Each titled "Session X — <work>". Operator may
|
||||
prefer dropping the "Session X" prefix (the folder/filename already
|
||||
encodes the letter via the legacy mapping); the work-summary alone
|
||||
may read cleaner in the nav. Or operator may prefer the prefix as
|
||||
a chronology hook.
|
||||
- **0013**: "Session 0013.0 — Wave 6 (CONTRIBUTING + SPEC §21 analytics;
|
||||
repo-naming; email/webhook runbook)" — Session 0013.0 dispatched three
|
||||
subagents whose work spans three distinct workstreams. The
|
||||
semicolon-list format may not be ideal; consider a one-phrase
|
||||
framing like "Track Ω inventory wave (#17, #18, #19, #20, #21)".
|
||||
- **0014**: Pulled the phrasing straight from SESSION-PROTOCOL.md §1
|
||||
example ("Wave 7 driver — SMTP + webhook hardening (#18 + #20 +
|
||||
#23)"). I shortened it slightly to fit nav width. Operator may
|
||||
prefer the example's verbatim form.
|
||||
- **0015**: This session was the "roadmap-capture parallel session"
|
||||
that ran concurrent with 0014.0 and added items #24–#30. The title
|
||||
reflects that. Operator may prefer "Companion to Wave 7 — roadmap
|
||||
items #24–#30" or similar.
|
||||
|
||||
README operator-rewrite checklist:
|
||||
|
||||
- **Section "How OHM gets built"** (~280 words) — voice-heavy; the
|
||||
operator should own this.
|
||||
- **Section "Why transcripts are public"** (~190 words) — includes
|
||||
the Jan shout verbatim per dispatch; rest of section is voice-
|
||||
heavy; operator should own this.
|
||||
- **Section "What's in the repo"** (~150 words) — mostly mechanical
|
||||
(layout description) but the prose framing is mine, operator may
|
||||
prefer their own.
|
||||
|
||||
Three other notes:
|
||||
|
||||
- The publish-transcript.sh script needs to know about the folder
|
||||
layout. Subsession 0017.1 (rfc-app side) was named in the dispatch
|
||||
as also handling a publish-script extension; I assume that ran in
|
||||
parallel and the script now routes by parsing the leading NNNN. If
|
||||
not, the next session that tries to publish a flat-form transcript
|
||||
to the now-folder-shaped repo will fail. (Subsession 0017.1's
|
||||
report-back to the driver should confirm.)
|
||||
- Future sessions that publish under the new layout will need their
|
||||
parent session's `sessions.json` entry to exist (or the publish
|
||||
script to add it). This subsession added entries 0001–0015; the
|
||||
driver session 0017.0 should plan to add its own `0017` entry when
|
||||
it publishes its own transcript, and to ensure 0017.1 and 0017.2
|
||||
(this one) inherit from it.
|
||||
- No git config edit happened. The commit shows
|
||||
`benstull@mac.lan` as committer (default from hostname). This is
|
||||
cosmetic — the audit trail is intact, the author email could be
|
||||
set later via `--amend` if the operator prefers `ben@wiggleverse.org`.
|
||||
Per safety rules I did not amend.
|
||||
Reference in New Issue
Block a user