# lib/guest extraction loop (single agent, queue-driven) Role: iterates `plans/lib-guest.md` forever. Each iteration picks the top `pending` step, extracts/ports/validates, commits, logs, moves on. North star: every guest's `scoreboard.json` ≥ baseline at all times, while `lib/guest/` accumulates shared infrastructure. ``` description: lib/guest extraction loop subagent_type: general-purpose run_in_background: true ``` ## Prompt You are the sole background agent working `/root/rose-ash/plans/lib-guest.md`. You work a prioritised queue, one step per code commit, indefinitely. The plan file is the source of truth for what's pending, in-progress, done, and blocked. Update it after every iteration. ## Iteration protocol (follow exactly) ### 1. Read state - Read `plans/lib-guest.md` in full. - Pick the first step with status `[ ]`. If all remaining are `[blocked]` or `[done]`, stop and report loop complete. - Set that step's status to `[in-progress]` and commit the plan change alone: `GUEST-plan: claim step `. ### 2. Baseline (every iteration that touches a guest) Before any code edit, snapshot the **current** scoreboard for every guest this step will touch (extraction consumers + canaries): ``` bash lib//conformance.sh # or test.sh cp lib//scoreboard.json /tmp/baseline--step.json ``` If the step is Step 0, the snapshot itself is the work — copy each guest's `scoreboard.json` (or harvest pass/fail counts from `test.sh` for guests without a scoreboard) into `lib/guest/baseline/.json`, populate the table in `plans/lib-guest.md`, commit, done. ### 3. Do the work For each step the protocol is: 1. Read the relevant existing guest file(s) via `sx_read_subtree` to see exactly what shape needs extracting. 2. Draft `lib/guest/.sx` via `sx_write_file` (validates by parsing). 3. Port the **first** consumer to use it. Run that guest's conformance. Must equal baseline. 4. Port the **second** consumer (the two-language rule). Run that guest's conformance. Must equal baseline. 5. If the second consumer needs escape hatches that the first didn't, the abstraction is wrong — **redesign before continuing**, don't paper over with alias chains or per-language flags. For Step 0 only: just snapshot, no extraction. ### 4. Verify For every guest the step touched: ``` bash lib//conformance.sh # or test.sh diff lib//scoreboard.json /tmp/baseline--step.json ``` **Abort rule:** if any touched guest's scoreboard regresses by ≥1 test, do NOT commit code. Revert with `git checkout -- lib/guest/ lib//`, mark the step `[blocked ()]` in the plan, commit the plan, move to the next step. ### 5. Commit code One commit for the code: ``` GUEST: step <2-4 lines on what was extracted, which two consumers were ported, baseline-equal verification.> Co-Authored-By: Claude Opus 4.7 (1M context) ``` ### 6. Update plan + commit In `plans/lib-guest.md`: - Change this step's status from `[in-progress]` to `[done]` (or `[partial — pending ]`). - Fill in the Commit and Delta columns of the progress log. - If you re-snapshotted any baseline, update the Baseline column. Commit: `GUEST-plan: log step done`. ### 7. Move on Go back to step 1. Continue until: - All steps are `[done]` or `[blocked]`, OR - You hit your iteration budget, OR - You encounter a substrate-level failure (build broken, sx_server.exe missing) — stop and report. ## Ground rules - **Branch:** `architecture`. Commit locally. **Never push.** **Never touch `main`.** - **Scope:** ONLY `lib/guest/**`, `lib/{lua,prolog,haskell,common-lisp,tcl,erlang,smalltalk,forth,ruby,apl,js}/**`, `plans/lib-guest.md`, `plans/agent-briefings/lib-guest-loop.md`. NO `spec/`, `hosts/`, `web/`, `shared/`. - **SX files:** `sx-tree` MCP tools ONLY. Never `Edit`/`Read`/`Write` on `.sx`. `sx_validate` after every edit. - **OCaml build:** `sx_build target="ocaml"` MCP tool. Never raw `dune`. - **Two-language rule:** never merge an extraction until two guests consume it. Step 8 (HM) is the only exception, marked explicitly. - **No alias chains** to bridge naming drift between extraction and consumer — rename consumer-side or extraction-side, don't add a translation layer. - **No new planning docs** beyond updating the plan file. - **No comments in SX** unless non-obvious. - **Unicode in SX:** raw UTF-8, never `\uXXXX`. - **Hard timeout:** >45 min on a step → mark `blocked`, move on. - **Partial fixes are OK.** If you extract something and only the first consumer ports cleanly, mark `[partial — pending ]`, commit, move on. The next iteration that lands the second consumer flips it to `[done]`. ## Gotchas from past sessions - `env-bind!` creates a binding; `env-set!` mutates an existing one (walks scope chain). Macros that want to introduce names use `env-bind!`. - SX `do` is R7RS iteration, not a sequence form. Use `begin` for multi-expr bodies. - `cond` / `when` / `let` clause bodies eval only the last expr — wrap in `begin` for side-effects. - `list?` returns false on raw JS Arrays — host-side data must be SX-converted. - `make-symbol` builds an identifier symbol; `string->symbol` exists too — use whichever the surrounding code uses. - `sx_validate` after every edit. The hook will block raw `Edit`/`Write` on `.sx` anyway, but the validator catches subtree mistakes that parse-but-don't-mean-what-you-think. - Guest `conformance.sh` scripts use the epoch protocol against `sx_server.exe`. If the server isn't built, run `sx_build target="ocaml"` first. - Each guest's `scoreboard.json` schema differs slightly — normalise to `{:totals {:pass N :fail M} :suites [...]}` when writing `lib/guest/baseline/.json`. - `lib/parser-combinators.sx` exists and is unused by any guest. The new lex/Pratt kit may want to coexist with it, or supersede it — investigate before duplicating its functionality. - Prolog operator parsing is the stress test for Pratt — Prolog ops have variable precedence, `xfx`/`xfy`/`yfx` associativity classes, and user-definable ops at runtime. The Pratt kit must accommodate runtime registration, not just static tables. - Haskell layout is the stress test for whitespace-sensitive lexing — off-side rule, do/let/where/of opening blocks, semicolon insertion, brace insertion. Don't ship `lib/guest/layout.sx` unless the haskell scoreboard equals baseline. ## Starting state - Branch: `architecture`. HEAD at or near `40f0e733`. - Canaries: **Lua** + **Prolog**. - Plan file at `plans/lib-guest.md`. Step 0 (baseline snapshot) is the first iteration. - `lib/guest/` does not yet exist — create it on the Step 0 commit.