diff --git a/CHANGELOG.md b/CHANGELOG.md index b6ff32c..5151836 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,76 @@ skip versions are the composition of each intervening adjacent release's steps in order — no A-to-B path is pre-computed beyond that. +## 0.24.0 — 2026-05-28 + +**Minor — one new secret required before this version serves tag +suggestions; no schema migration; no behavior change for deployments +that do not bind the key.** Roadmap item #27: as a contributor fills in +the propose-RFC form, the backend asks Claude Haiku to recommend tags +drawn from the collection's existing tag set, surfaced as clickable +suggestion chips. Shipped from driver session 0025.0. This is the §9.1 +"Slice 2" AI-suggested chips that the propose modal has carried a +deferred placeholder for since Slice 1. + +- **`POST /api/rfcs/suggest-tags`** (contributor-gated, per-user + rate-limited). Takes the partial draft (`title`, `pitch`, + `use_case`) and returns `{ "suggestions": [{ "tag", "confidence" }, + …] }`. The model is constrained to the corpus's existing tags — v1 + tags are free-form chip input, so "the taxonomy" is the de-facto set + of distinct tags the existing RFCs carry. The model MUST NOT invent + tags; taxonomy extension is a deliberate out-of-scope follow-up. +- **Always Claude Haiku, for cost.** Tag suggestion uses Haiku + regardless of the `ENABLED_MODELS` chat-picker universe, via the new + `providers.construct_haiku()` factory. There is no RFC slug at propose + time, so the §6.7 per-RFC funder credential path does not apply — the + surface runs on the operator's own `ANTHROPIC_API_KEY`. +- **Degrades to silence, never error.** No key bound, an empty corpus, + an empty draft, a rate-limited caller, or an unparseable model reply + all yield an empty list; the propose modal hides its suggestion row, + and the rest of the app is unaffected. So a deployment that does not + set the key sees no change at all. +- **Privacy disclosure.** The modal carries an inline note that the + draft text is sent to Anthropic to generate the suggestions. This is + required for honesty (the text leaves the deployment before the RFC + is submitted); cookie-consent does not gate it because the user has + actively typed into a draft surface. The exact wording wants a + counsel pass before OHM's deploy, per the #22 drafting discipline. +- **Frontend.** `ProposeModal` debounce-posts the draft (700 ms, with a + stale-response guard); suggestion chips are clickable and add to the + tag list (nothing auto-applies). `api.suggestTags()` is forgiving — + any non-OK response resolves to `[]`. + +Tests: 11 new (`test_tag_suggest_vertical.py`) — contributor-gating, +universe-constrained filtering, no-key / empty-corpus / rate-limit +paths, plus units for the universe gather, the tolerant reply parser, +the max cap, the empty-draft short-circuit, and provider-failure +fallback. Full suite 351 green. + +Upgrade steps: + +1. You **MUST** bind `ANTHROPIC_API_KEY` for the suggestion surface to + work. On OHM this is an operator gesture — the key never touches the + conversation. Set it from your own terminal via stdin (so the bytes + never land in shell history): + + ```bash + printf '%s' "$(pbpaste)" | .venv/bin/ohm-rfc-app-flotilla \ + secret set ohm-rfc-app ANTHROPIC_API_KEY + ``` + + (The §18 chat stack already reads this same key, so a deployment + that has chat configured **MAY** already have it bound — confirm with + `flotilla secret list ohm-rfc-app`.) If the key is absent the app + still boots and serves normally; tag suggestions are simply + unavailable until it is set. +2. You **MAY** tune the per-user rate limit via `TAG_SUGGEST_RATE_MAX` + (default 30) and `TAG_SUGGEST_RATE_WINDOW_SECONDS` (default 60). The + defaults apply when unset. +3. You **SHOULD** have counsel review the modal's disclosure wording + before exposing the surface to users, per the #22 drafting + discipline — the copy is honest as written, but the legal review is + the right call for any "your text is sent to a third party" notice. + ## 0.23.0 — 2026-05-28 Roadmap item #29: signing in lands the user on their most recently diff --git a/VERSION b/VERSION index ca222b7..2094a10 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.23.0 +0.24.0 diff --git a/frontend/package.json b/frontend/package.json index 1820c84..b0116e9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "rfc-app-frontend", "private": true, - "version": "0.23.0", + "version": "0.24.0", "type": "module", "scripts": { "dev": "vite",