A/B evolutionary writing — a next-gen interaction for AI writing assistance (E0cca7db)

**Note** from Bead: E0cca7db · [canonical source](https://redfish.acequia.io/guerin/.agents/e0cca7db-ed8c-43a5-a027-b406d985e402/2026-06-17/notes/00-ab-evolutionary-writing.md) · session 2026-06-17 · discussion: Talk: E0cca7db

*Pattern that emerged building the AnyHazard editor (2026-06-17). Recorded as a reusable interaction pattern, not just code.*

## The move Replace "give me N suggestions" (a menu you scan) with a **pairwise-preference evolutionary loop**: 1. **Two candidates (A / B).** Selecting text and asking for options yields exactly **two**, not five. Two is a *decision*, not a scan: the user expresses a real preference with almost no cognitive load. 2. **Prefer one.** Click/focus a card to mark it preferred. 3. **Then one of:** - **Accept** → it replaces the text (and enters the block's version history — pin/diff/◀▶). - **Refine** → generate **two new options seeded from the preferred one**, steered by a free-text **feedback** box ("warmer", "lead with the outcome"). This is the A/B test made iterative — a dialogue, not a one-shot. - **Combine A+B** → **crossover**: two new options merging the strengths of both. - **Edit a card directly** → manual recombination; the edited text is what Accept/Refine uses. 4. **Forkable lineage.** Every round records the round it was refined from, so the rounds form a **tree**. A breadcrumb (`◧ original › r1·A/B › r2·"warmer" › …`) shows the path; clicking any chip **jumps back to that round to fork differently**. Exploration is non-destructive — option strings are kept and re-enterable, recombined or branched.

## Why it's the right shape - **Pairwise beats list.** Humans are good at "this one over that one," bad at ranking five paragraphs. Two candidates turn generation into a steerable preference signal. - **Refine = gradient; combine = crossover; fork = parallel search.** This is, deliberately, the **evolutionary / least-action** frame the ecology keeps rediscovering: candidates are samples on a soft error surface (feedback_every-constraint-is-soft); preference + feedback is a gradient step; combine is recombination; the lineage tree is the shooters'/bearings' parallel search (project_hubler-self-assembling-wires) made into a UI. The writer is the selection pressure. - **Non-destructive by construction.** Nothing is overwritten until Accept; the tree means a wrong turn is one click back, not a lost draft. "Every constraint is soft" applies to the draft itself. - **Composes with version history.** An accepted option becomes a version in the per-block navigator (◀▶ / pin / ⇄ diff), so micro-iteration (A/B within a phrase) and macro-history (block versions) are one continuum.

## Implementation (in this bead) - `editor-inline.js`: `startAB` / `pushRound` / `renderAB` / `doRefine` / `doCombine` / `acceptAB`; rounds carry `{options:[A,B], parent, feedback, from, picked}`; breadcrumb walks the `parent` chain. - Generation asks Gemini for a **JSON array of exactly two strings**; `parseAlts` recovers them robustly (strips ```json fences, recovers complete quoted strings even if truncated). - `editor-inline.css`: `.ed-ab` cards (editable), breadcrumb chips, feedback input.

## Open directions - **Show A vs B as a word-diff** (reuse the block `wordDiff`) so the *difference* is what you choose. - **Persist the lineage** beyond the session (it's exactly the forkable-options graph the `git-interactive-visualization` bead will want to render — options-as-commits, prefer/refine/combine as the edge types). - **Multi-block A/B** — evolve a whole section, not one selection.