diff --git a/0025/SESSION-0025.0-TRANSCRIPT-2026-05-28T13-06--2026-05-28T13-30.md b/0025/SESSION-0025.0-TRANSCRIPT-2026-05-28T13-06--2026-05-28T13-30.md new file mode 100644 index 0000000..756f680 --- /dev/null +++ b/0025/SESSION-0025.0-TRANSCRIPT-2026-05-28T13-06--2026-05-28T13-30.md @@ -0,0 +1,302 @@ +# Session 0025.0 — Transcript + +> Date: 2026-05-28 +> Goal: Pick one roadmap item disjoint from v0.21.0's polished surfaces +> and from #26/#29, build it on a manual worktree while deploys are +> frozen. Recommended fits from the 0022 handoff: #19 (CONTRIBUTING +> docs) or #27 (Haiku tag suggestions). +> +> Outcome: **#19 turned out to be already shipped (Session 0013.1) but +> never struck in the ROADMAP — which is exactly what misdirected this +> session to it. Pivoted to #27. Built Claude Haiku tag suggestions on +> the propose-RFC modal, tagged rfc-app [v0.24.0](https://git.wiggleverse.org/ben.stull/rfc-app/src/tag/v0.24.0), +> pushed to origin + benstull. 351 backend tests green, frontend builds +> clean. NOT deployed — deploys frozen behind the #1 VM-rename blocker +> (Session 0022); pin held at 0.22.0. ROADMAP bookkeeping corrected +> (#19 struck, #21 Part B noted shipped, #27 recorded as built+staged).** +> +> Highlights: +> - The §9.1 "Slice 2" AI-suggested tag chips, deferred since the +> propose modal first landed, are now wired. +> - Reused the existing §18 provider abstraction (`AnthropicProvider`, +> `_CLAUDE_VARIANTS["claude-haiku"]`) — added one small factory +> `providers.construct_haiku()`. `ANTHROPIC_API_KEY` was already a +> config var (the chat stack reads it), so #27's "new secret" may +> already be bound on OHM — flagged for the operator to check. +> - Held the pin and staged the deploy, consistent with how v0.23.0's +> pin is being held during the freeze. + +--- + +## Pre-session state + +| repo | sha | state | +| --- | --- | --- | +| rfc-app | `daebb54` | `main`; last tag v0.23.0 (#29). Backend 340 tests green. | +| ohm-rfc | `9f0c4e7` | `main` clean; pin `.rfc-app-version` = 0.22.0 | +| ohm-rfc-app-flotilla | `85f01f8` | session anchored here; `main` clean except untracked `.claude/` | +| OHM live | running v0.21.0 (per the 0019.0 / 0024.0 ledger), healthy | — | + +**Deploy freeze in force.** The 0022 handoff: flotilla deploy of +v0.22.0 failed preflight (install dir `/opt/ohm-app` missing on the VM; +clean failure, no lock held, no partial deploy). Session 0022 is +investigating whether the #1 VM rename (`ohm-app` → `ohm-rfc-app`) was +started on the VM, leaving the §13 deployment record pointing at the +old path. Deploys blocked until 0022 clears it; OHM still healthy at +v0.21.0. Deploy order when it unblocks: v0.22.0 → v0.23.0 → mine. + +Sessions 0022 (deploy-blocker, INPROGRESS), 0023, 0024 (roadmap-capture +#33/#34, done) preceded this. None were building #27. + +--- + +## Turn-by-turn arc + +### Arc 1 — Claim, orient, pick an item + +Claimed session ID **0025** via `claim-session-id.sh --start +2026-05-28T13-06` (pushed the placeholder; the push is the atomic +claim). Read SESSION-PROTOCOL.md §7 + the session-start gesture, and +the full ROADMAP (PULL'd ohm-rfc first — already up to date). + +Reasoned to **#19** over #27 initially: deploy-free (ships as PRs the +operator merges), zero code-surface collision with the avoid-list, +fully completable this session. #27 by contrast needs a new secret, a +counsel pass, and a deploy — none closeable during the freeze. + +### Arc 2 — #19 is already done (the ledger lied) + +Before touching anything, checked the repos for existing artifacts. +**Both `CONTRIBUTING.md` files already existed and were committed:** + +- rfc-app `CONTRIBUTING.md` + SPEC §21 analytics chapter landed on + `main` via `213f686` (merge `ac3513a`, *"Session 0013.1"*) — the + commit message literally reads *"Lands roadmap item #19 ... and #21 + Part B ... as a single docs commit."* Verified `213f686` is an + ancestor of `origin/main` and the file is in the `main` tree. +- ohm-rfc `CONTRIBUTING.md` committed (`90965d4` + later edits). + +So **#19 + #21 Part B shipped back in Session 0013.1** and were simply +never struck in the ROADMAP version-target table. The 0022 handoff +recommended #19 not realizing it was done — the un-struck row is what +misdirected this session. This is the session's main friction finding +(see §19.2 candidates). + +Pivoted to the other named fit, **#27**. Confirmed via local +transcripts + rfc-app tags/branches that no live session was building +it (0024 only *lists* #27 as a future candidate; no `v0.24.0` tag, no +`#27` branch). + +### Arc 3 — Map the surfaces + +Mapped before building (all reads, no subagents — #27 is one cohesive +feature, so the driver built it directly; no §5 subsession transcripts +warranted): + +- **Existing LLM infra (§18 chat stack).** `backend/app/providers.py` + already has a multi-provider abstraction with `AnthropicProvider` and + `_CLAUDE_VARIANTS["claude-haiku"] = ("claude-haiku-4-5-20251001", + "Claude Haiku")`. `ANTHROPIC_API_KEY` is already a config var + (`config.py:44/91`) and `anthropic>=0.39` is already a dep. The + `models_resolver` docstring even anticipates *"the §9.1 tag + suggestions"*. So #27's "new secret" is the same key the chat stack + uses — it may already be bound on OHM. +- **Tags are free-form chip input** ("free-form for slice 1; the + AI-suggested chips of §9.1 are deferred to Slice 2"). No curated + taxonomy. So "the existing tag taxonomy" #27 references = the + de-facto set of distinct tags across `cached_rfcs` (`tags_json`). +- **Propose endpoint** is in `api.py`'s `make_router(config, gitea, + bot, providers)` closure, gated by `auth.require_contributor`. +- **Provider-call convention** (`api_prs._draft_with_provider`): async + endpoints call `provider.send()` directly (no threadpool), wrapped in + try/except → graceful stub fallback. Matched it. +- **Test harness**: no shared conftest; tests self-bootstrap via + `app_with_fake_gitea` / `sign_in_as` / `provision_user_row` from + `test_propose_vertical.py`. Runner `./.venv/bin/python -m pytest` + from `backend/` (340 tests pre-change). + +### Arc 4 — Build #27 (worktree) + +Manual worktree per the handoff (Agent worktree isolation is broken): +`git worktree add -b feature/v0.24.0-haiku-tags +/Users/benstull/git/rfc-app-v0.24.0-haiku-tags main`, then symlinked +`frontend/node_modules` + `backend/.venv` in. (`.gitignore` ignores +`.venv/`/`node_modules/` as directories; the symlinks showed as +untracked, so every commit staged explicit files — never `-A`.) + +Backend: +- **`backend/app/tag_suggest.py`** (new) — `gather_tag_universe()` + (distinct corpus tags, most-common first, capped 200); `Draft` + dataclass; `haiku_provider(config)` seam (monkeypatchable; `None` + when no key); `build_messages` + tolerant `parse_reply` (drops + invented tags, dedupes case-insensitively to canonical spelling, + clamps confidence, caps); `suggest()` orchestration; in-process + per-user sliding-window rate limit (`TAG_SUGGEST_RATE_MAX` / + `_WINDOW_SECONDS`, defaults 30/60). +- **`providers.construct_haiku(api_key)`** — dedicated Haiku provider, + model id sourced from `_CLAUDE_VARIANTS`. Independent of + `ENABLED_MODELS`; no RFC slug at propose time so the §6.7 funder path + doesn't apply. +- **`POST /api/rfcs/suggest-tags`** in `api.py` — `require_contributor`, + rate-limit → 429, `SuggestTagsBody {title, pitch, use_case}`. Returns + `{suggestions:[{tag,confidence}]}`. Degrades to `[]` (200, never an + error) for no key / empty corpus / empty draft / parse failure. +- `backend/.env.example` — documented that `ANTHROPIC_API_KEY` also + powers tag suggestions + the two optional rate-limit vars. + +Frontend: +- `ProposeModal.jsx` — debounced (700 ms, stale-response-guarded) + suggestion fetch on `[title, pitch, useCase]`; clickable suggestion + chips that add to the tag list (nothing auto-applies); the required + inline disclosure ("Suggestions are generated by Claude (Anthropic). + The text you've entered above is sent to Anthropic to produce them."). +- `api.suggestTags()` — forgiving; any non-OK → `[]`. + +Tests: **`test_tag_suggest_vertical.py`** (11) — anon→401, contributor +gets universe-filtered suggestions (invented tag dropped), no-key→[], +empty-corpus→[] (model never called), rate-limit→429, plus units for +gather/parser-tolerance/max-cap/empty-draft-short-circuit/provider- +failure. One initial failure (the gather unit test needed the db +initialized, which happens in the TestClient lifespan) — fixed by +wrapping in a `TestClient(app)` context. Full suite **351 green**; +frontend `npm run build` clean (needed the deployment `.env` copied in +from the main checkout — gitignored, not committed). + +### Arc 5 — Release (tag), staged deploy, bookkeeping + +Followed the established release shape: feature commit on the branch +(`fb9b4fa`) → `--no-ff` merge to `main` (`376a6da`) → release commit +bumping `VERSION` + `frontend/package.json` + `CHANGELOG.md` (`28015ed`) +→ tag **`v0.24.0`** → pushed `main` + branch + tag to **origin** and +**benstull**. Re-ran the full suite on `main` post-merge: 351 green. + +CHANGELOG `Upgrade steps:` (RFC 2119) names the **MUST** +`flotilla secret set ohm-rfc-app ANTHROPIC_API_KEY` gesture (stdin +pbpaste form; never paste bytes), notes the chat stack may already have +it bound, the optional rate-limit knobs, and a **SHOULD** counsel pass +on the disclosure wording (per #22). + +**Pin deliberately NOT bumped** — held at 0.22.0, consistent with how +v0.23.0's pin is being held during the freeze. Bumping to 0.24.0 would +have jumped ahead of un-deployed 0.22.0/0.23.0 and scheduled a frozen +deploy. The deploy + pin bump are staged for the operator. + +ROADMAP corrected + pushed (`f62cb90`): struck **#19** (with the +"misdirected 0025" note), annotated **#21 Part B** as shipped in +0013.1, recorded **#27** as built+tagged v0.24.0 with the full +operator-pending-gesture list. Did **not** touch #26/#29 rows — those +are tagged-but-not-struck pending deploy and belong to the still-open +Session 0022. + +Removed the build worktree (branch preserved on both remotes). + +--- + +## Cut state (end of session) + +| | | +| --- | --- | +| rfc-app | `28015ed` `main`, tag **v0.24.0** (#27) — pushed origin + benstull. 351 tests green, frontend builds clean. | +| ohm-rfc | `f62cb90` `main` — ROADMAP corrected; **pin held at 0.22.0** | +| OHM live | unchanged — v0.21.0, healthy. **No deploy** (frozen). | +| flotilla | untouched | + +| Roadmap ledger | Status | +| --- | --- | +| #19 CONTRIBUTING + onboarding | ✅ was already shipped (0013.1); struck this session | +| #21 Part B analytics discipline | ✅ was already shipped (0013.1) with #19; noted | +| #27 Haiku tag suggestions (v0.24.0) | 🟡 built + tagged + pushed; ⏸ deploy staged (freeze) | + +--- + +## §19.2 candidates surfaced + +1. **The ROADMAP version-target ledger lags reality and it cost a + session's worth of misdirection.** #19 + #21 Part B shipped in + 0013.1 but were never struck; #26 (v0.22.0) and #29 (v0.23.0) are + tagged-but-not-struck pending deploy. A future session reading the + table can't tell "available" from "shipped-but-unbooked." Worth a + convention call: either (a) strike on *tag* (not deploy) with a + separate "deployed?" column, or (b) a fast `git tag` vs. table + reconciliation pass at session start. The first gesture of an + implementer session should be "is this already done?" — this session + only avoided wasted work by checking the tree before building. +2. **`ANTHROPIC_API_KEY` is overloaded across two surfaces** (the §18 + chat stack and now #27 tag suggestions). Fine today (same provider), + but if a deployment wants a *cheaper/separate* key for the + high-volume suggestion path vs. interactive chat, that's a future + `TAG_SUGGEST_ANTHROPIC_KEY`-style split. Noted, not built. +3. **Tag suggestion quality is bounded by corpus size.** Constrained to + existing tags (per #27's explicit scope), a near-empty corpus yields + near-empty suggestions. The roadmap already names taxonomy-extension + (letting the model propose genuinely new tags) as the deferred + follow-up; this is the data point that it'll matter early for OHM. + +--- + +## What lands on the operator's plate + +1. **Clear the deploy freeze** (Session 0022's `/opt/ohm-app` blocker), + then deploy in order: v0.22.0 → v0.23.0 → **v0.24.0**, bumping the + ohm-rfc pin at each step and verifying. +2. **Before/at the v0.24.0 deploy:** set `ANTHROPIC_API_KEY` — + `printf '%s' "$(pbpaste)" | .venv/bin/ohm-rfc-app-flotilla secret set + ohm-rfc-app ANTHROPIC_API_KEY` (never paste the bytes). **Check + first** whether it's already bound for the §18 chat stack: + `flotilla secret list ohm-rfc-app`. Without it the app still serves; + suggestions are just unavailable. +3. **Counsel pass** on the propose-modal disclosure wording before + exposing the surface, per #22 discipline. The copy is honest as + written. +4. End-to-end verification of the suggestion surface happens + post-deploy (couldn't be done this session — no deploy, and no key + should ever touch the model). + +--- + +## Prompt the operator can paste into the next Claude Code session + +``` +You are an OHM roadmap driver session. Claim your session ID first +(~/git/ohm-infra/scripts/claim-session-id.sh --start ); your +number is not assigned here. Read SESSION-PROTOCOL.md §7 + ohm-rfc/ +ROADMAP.md (PULL ohm-rfc first). + +State at handoff (from session 0025): +- rfc-app main @ 28015ed: v0.24.0 tagged + pushed (origin + benstull) — + roadmap #27, Claude Haiku tag suggestions on the propose-RFC modal. + 351 backend tests green, frontend builds clean. NOT deployed. +- THREE rfc-app releases now sit un-deployed behind the freeze: + v0.22.0 (#26), v0.23.0 (#29), v0.24.0 (#27). ohm-rfc pin still 0.22.0 + (all three pin-bumps held for deploy). +- ⛔ DEPLOYS STILL BLOCKED pending Session 0022's /opt/ohm-app VM-rename + investigation. Do NOT run flotilla deploy until that clears — + coordinate with the operator. Deploy order: v0.22.0 → v0.23.0 → + v0.24.0, bump pin + verify at each. +- #19 + #21 Part B were already shipped (Session 0013.1) — struck/noted + in the ROADMAP this session. The ledger had lagged; check the rfc-app + git tags against the version-target table before assuming a row is + available (#26/#29 are tagged-but-not-struck pending deploy). + +Operator gestures pending for v0.24.0 (#27), at deploy time: +- Set ANTHROPIC_API_KEY (operator-run pbpaste|flotilla secret set; never + paste bytes). It may already be bound for the §18 chat stack — check + `flotilla secret list ohm-rfc-app` first. +- Counsel pass on the propose-modal disclosure copy (per #22). + +Your job: pick one roadmap item that's shippable and disjoint from the +un-deployed surfaces (#26 ProposeModal/PRModal/RFCView/PRView, +#29 App.jsx sign-in region, #27 ProposeModal suggestion row + +tag_suggest.py + the suggest-tags endpoint) and from v0.21.0's polished +CSS. Build on a manual git worktree (git worktree add -b + main; symlink frontend/node_modules + backend/.venv). Good +deploy-free fits while frozen: #21 Part A (Amplitude audit — but it +wants real-world data) or another Track-A surface that can build + tag + +stage. Avoid touching the three un-deployed features' code regions. + +Hard rules: never ask for secret bytes; subagents write their own §5 +subsession transcripts; finalize + publish your transcript last, +delivering the next handoff prompt to the operator before publish. + +Claim your ID, then go. +``` diff --git a/0025/SESSION-0025.0-TRANSCRIPT-2026-05-28T13-06--INPROGRESS.md b/0025/SESSION-0025.0-TRANSCRIPT-2026-05-28T13-06--INPROGRESS.md deleted file mode 100644 index 96efbd9..0000000 --- a/0025/SESSION-0025.0-TRANSCRIPT-2026-05-28T13-06--INPROGRESS.md +++ /dev/null @@ -1,15 +0,0 @@ -# Session 0025.0 — Transcript - -> Date: 2026-05-28 -> Start: 2026-05-28T13-06 (PST implied) -> Status: **PLACEHOLDER — claimed at session start; finalized at session end.** -> -> This file reserves session ID 0025. The driver replaces this body -> with the full transcript before publishing, and renames the file to -> its final SESSION-0025.0-TRANSCRIPT-2026-05-28T13-06--.md form. - ---- - -## Launch prompt - -_(launch prompt not captured at claim time)_