**Note** from Bead: Simtable Learnmore Anyhazard · [canonical source](https://redfish.acequia.io/guerin/.agents/3e978f25-63f0-4002-9501-83d3f79345f4/2026-06-18/notes/00-design.md) · session 2026-06-18 · discussion: Talk: Simtable Learnmore Anyhazard
Orientation note for bead `3e978f25-63f0-4002-9501-83d3f79345f4` (`simtable-learnmore-anyhazard`). Read `agent.md` first for the operating contract; this note is the architecture + the open questions.
## The user story (Stephen, 2026-06-18) > Active bead with `agent.md` that watches its `/request` folder for updates and then updates > `simtable.com/learnmore/anyhazard.html`. An HTML file shows the current versions and overlays > that show replacement text. When a replacement is shown, a `redfish-ai:` 4-line textarea below > it has a conversation with gemini-access-api (appended context = goal and strategy of Simtable > and AnyHazard) to respond to and change the language on that active paragraph. An Accept button > replaces the text and sends a CRDT change to this bead's `/request`. Register as the handler for > `/simtable-learnmore-anyhazard`. Keep the current page HTML in a local `.git`.
## Architecture ``` browser: editor.html GET /source ──────────► current page/anyhazard.html POST /redfish-ai ─────► Gemini (brief + paragraph + conversation) ─► proposed text POST /request ────────► mint CRDT op ─► request/<ts>-<opId>.json ─► (apply:true) runStep │ animator (handler.mjs runStep / dev-serve watch) │ drain request/ ─► crdt.apply(page,op,registers)─► page/anyhazard.html ─► git commit (one per op) ─► ctx.webdav.put → simtable.com/learnmore/anyhazard.html ─► response/<opId>.receipt.json + request/<file>.ack.json ``` Lanes (per bead-remote `792ebed9` request/response + bead-as-webdav-handler `fe7fbaf5`): **sync verbs** (`GET /`, `GET /source`, `POST /redfish-ai`) answer inline; the **async dock** (`request/` → `response/`) carries durable change ops. `uploads/` is the generic deposit dock.
## The CRDT model (`crdt.mjs`) A **map of LWW-Registers keyed by paragraph id**. Each editable `<p>` inside `<div class="intro">` is one register, addressed `intro-p0`, `intro-p1`, … in DOM order. A change op SETS a register: ```json { "opId":"op-…", "type":"lww-set", "paraId":"intro-p1", "baseHash":"sha256-…", "oldText":"…", "newText":"…", "author":"redfish-ai", "lamport":3, "ts":"2026-06-18T…Z", "sessionId":"…" } ``` - Edits to **different** paragraphs commute (independent registers). - Concurrent edits to the **same** paragraph resolve **last-writer-wins** by `(lamport, author)`. - `apply()` locates the paragraph by the register's tracked `currentText` (falls back to the op's `oldText`), so it is robust to whitespace/markup differences between the browser's innerHTML and the raw file. Registers persist in `state.json`; idempotent by `opId` (re-applying is a no-op). This is **paragraph-granularity**, not character-level RGA. Honest trade-off (see decentralized-cache-management `4456cd24` on write granularity): enough for owner-edits to a small marketing page; would need a real sequence CRDT (Yjs/Automerge) for concurrent character-level co-editing. Open question Q3 below.
## Cognition — the gemini-access-api `gemini-cognition.mjs` calls `https://generativelanguage.googleapis.com/v1beta` (model default `gemini-2.5-flash`). **BYOK**: key resolved per call from `GEMINI_API_KEY` or `.credentials/api-keys/gemini.json`, sent as `x-goog-api-key`, never echoed or written into the bead. The prompt = `context/simtable-anyhazard-brief.md` (goal + strategy + voice rules) + the active paragraph + the conversation + the user's textarea. The brief is the distillation of the marketing bead [`d119bda6`](https://redfish.acequia.io/guerin/.agents/d119bda6-7258-4f67-a742-7aa87cfafe72/about.md).
## Versioning — the local `.git` `page/anyhazard.html` is the working copy / source of truth, tracked in a `.git` **inside the bead** (`.gitignore` tracks only `page/`). The snapshot at open is commit `1c1cf40`. Each applied op is one commit (`crdt <opId> <paraId> by <author>`); `GET /history` returns the log. The remote page is downstream of this working copy.
## Handler registration (OFFERED, not self-wired) The route `/simtable-learnmore-anyhazard` is declared in `agent.json.handler`. It is **offered** to the runtime owner / bead-orchestrator [`4c6470f9`](https://redfish.acequia.io/guerin/.agents/4c6470f9-b74a-4aba-b436-5e998f469cce/about.md); this bead does **not** edit the live runtime (`C:\caddy\origins\stephenguerin.live\server.js`). The predecessor [`e0cca7db`](https://redfish.acequia.io/guerin/.agents/e0cca7db-ed8c-43a5-a027-b406d985e402/about.md) overstepped by rewriting `server.js` and had to revert; we do not repeat that. For now the bead runs under `dev-serve.mjs` locally.
## How to run (DEV) ``` # safe: apply + git-commit, but do NOT publish to the live page NO_PUBLISH=1 node dev-serve.mjs 4327 # then open http://127.0.0.1:4327/ # live publish (PUTs the real page): omit NO_PUBLISH (needs simtable.com WebDAV creds on the node) node dev-serve.mjs 4327 ```
## Open questions (gated on Stephen) 1. **Publish trigger.** Today `POST /request {apply:true}` applies+publishes immediately (live loop). Should accepted edits instead queue for a review/approval step before they hit the live page? (An owner editing live pre-sales copy may want a staging gate.) 2. **Registration.** Who wires `/simtable-learnmore-anyhazard` into the live runtime, and is the editor served publicly (auth-gated) or only locally? (Offer is in `agent.json`.) 3. **CRDT depth.** Paragraph-LWW is v0. Do we need real concurrent co-editing (Yjs/Automerge, character-level)? Only if multiple people edit the same paragraph simultaneously. 4. **Editable scope.** Only the `.intro` paragraphs are editable now. Should the video-card descriptions / titles be editable too? (Easy to extend `crdt.parseParagraphs`.) 5. **Markup in replacements.** Replacements are inner-HTML strings (so `<strong>` survives). Do we want a richer editor (toolbar) or is plain-text-with-preserved-strong enough?
## References (bead cross-links) - Bead: Simtable Marketing · [canonical](https://redfish.acequia.io/guerin/.agents/d119bda6-7258-4f67-a742-7aa87cfafe72/) - Bead: Orchestrator · [canonical](https://redfish.acequia.io/guerin/.agents/4c6470f9-b74a-4aba-b436-5e998f469cce/) - Bead: E0cca7db · [canonical](https://redfish.acequia.io/guerin/.agents/e0cca7db-ed8c-43a5-a027-b406d985e402/)