6.6 KiB
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.mdin 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 <N> — <name>.
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/<guest>/conformance.sh # or test.sh
cp lib/<guest>/scoreboard.json /tmp/baseline-<guest>-step<N>.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/<lang>.json, populate the table in plans/lib-guest.md, commit, done.
3. Do the work
For each step the protocol is:
- Read the relevant existing guest file(s) via
sx_read_subtreeto see exactly what shape needs extracting. - Draft
lib/guest/<file>.sxviasx_write_file(validates by parsing). - Port the first consumer to use it. Run that guest's conformance. Must equal baseline.
- Port the second consumer (the two-language rule). Run that guest's conformance. Must equal baseline.
- 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/<guest>/conformance.sh # or test.sh
diff lib/<guest>/scoreboard.json /tmp/baseline-<guest>-step<N>.json
Abort rule: if any touched guest's scoreboard regresses by ≥1 test, do NOT commit code. Revert with git checkout -- lib/guest/ lib/<consumers>/, mark the step [blocked (<specific reason>)] in the plan, commit the plan, move to the next step.
5. Commit code
One commit for the code:
GUEST: step <N> — <name>
<2-4 lines on what was extracted, which two consumers were ported, baseline-equal verification.>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6. Update plan + commit
In plans/lib-guest.md:
- Change this step's status from
[in-progress]to[done](or[partial — pending <consumer>]). - 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 <N> 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 touchmain. - 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. NOspec/,hosts/,web/,shared/. - SX files:
sx-treeMCP tools ONLY. NeverEdit/Read/Writeon.sx.sx_validateafter every edit. - OCaml build:
sx_build target="ocaml"MCP tool. Never rawdune. - 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 <second consumer>], 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 useenv-bind!.- SX
dois R7RS iteration, not a sequence form. Usebeginfor multi-expr bodies. cond/when/letclause bodies eval only the last expr — wrap inbeginfor side-effects.list?returns false on raw JS Arrays — host-side data must be SX-converted.make-symbolbuilds an identifier symbol;string->symbolexists too — use whichever the surrounding code uses.sx_validateafter every edit. The hook will block rawEdit/Writeon.sxanyway, but the validator catches subtree mistakes that parse-but-don't-mean-what-you-think.- Guest
conformance.shscripts use the epoch protocol againstsx_server.exe. If the server isn't built, runsx_build target="ocaml"first. - Each guest's
scoreboard.jsonschema differs slightly — normalise to{:totals {:pass N :fail M} :suites [...]}when writinglib/guest/baseline/<lang>.json. lib/parser-combinators.sxexists 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/yfxassociativity 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.sxunless the haskell scoreboard equals baseline.
Starting state
- Branch:
architecture. HEAD at or near40f0e733. - 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.