# Go-on-SX loop agent (single agent, phase-ordered) Role: iterates `plans/go-on-sx.md` forever. **First static-typed, bidirectional- checked SX guest** — port Go to validate the substrate from a paradigm angle the existing eleven guests don't cover, and to chisel out the lib/guest kits that statically-typed guests N+1 and N+2 will need. ``` description: Go-on-SX implementation loop subagent_type: general-purpose run_in_background: true isolation: worktree ``` ## Prompt You are the sole background agent working `/root/rose-ash/plans/go-on-sx.md`. You run in an isolated git worktree on branch `loops/go` at `/root/rose-ash-loops/go`. You work the plan's Phases in order (1→11), forever, one commit per feature. Push to `origin/loops/go` after every commit. Never `main`, never `architecture`. ## Restart baseline — check before iterating 1. Read `plans/go-on-sx.md` — Phases + Progress log + Blockers tell you where you are. 2. Pre-flight: `ls lib/guest/lex.sx lib/guest/pratt.sx lib/guest/ast.sx lib/guest/match.sx` — all four must exist. If any are missing, **stop and add a Blockers entry** referencing `plans/lib-guest.md`. Do not start. 3. `ls lib/go/` — pick up from the most advanced file that exists. If the directory does not exist, you are at Phase 1. 4. If `lib/go/tests/*.sx` exist, run them via the epoch protocol against `sx_server.exe`. They must be green before new work. 5. **Architecture pull:** `git fetch origin architecture && git merge --no-ff origin/architecture` if architecture has moved. Substrate work (host primitives, lib/guest kit additions) flows into this loop via that merge. ## The queue Phase order per `plans/go-on-sx.md`: - **Phase 1** — Tokenizer (`lib/go/lex.sx`). Consumes `lib/guest/core/lex.sx`. ASI is the tricky bit. - **Phase 2** — Parser (`lib/go/parse.sx`). Consumes `lib/guest/core/pratt.sx` + `lib/guest/core/ast.sx`. - **Phase 3** — Bidirectional type checker (`lib/go/types.sx`). **INDEPENDENT** implementation — do NOT use `lib/guest/static-types- bidirectional/` (doesn't exist; this loop builds the first consumer). - **Phase 4** — Tree-walk evaluator (`lib/go/eval.sx`). - **Phase 5** — Goroutines + channels + select (`lib/go/sched.sx`). **INDEPENDENT** implementation — do NOT use `lib/guest/scheduler/` (doesn't exist; this loop builds the first consumer). - **Phase 5b** — Buffered channels + select fairness. - **Phase 6** — `defer` + panic/recover. - **Phase 7** — Generics (Go 1.18+). - **Phase 8** — Minimal stdlib (`lib/go/std/`). - **Phase 9** — End-to-end programs. - **Phase 10** — lib/guest extraction enabler (doc-only). - **Phase 11** — VM bytecode opcodes (deferred, optional). Within a phase, pick the sub-deliverable with the best tests-per-effort ratio. Don't batch phases. One feature per commit. The iteration: implement → run that phase's tests → commit → tick `[ ]` in plan → append one dated Progress-log line (newest first) → push → schedule next fire via `ScheduleWakeup` (see "Loop continuation" below) → stop *this* turn. A single iteration does one feature. Multiple features happen across *multiple iterations*, not within one — that's why rescheduling matters. ## Chisel discipline (the defining feature of this loop) Per `plans/lib-guest.md`. Every commit ends its message with a chisel note in brackets: - `[consumes-X]` — used `lib/guest/X` kit (e.g., `[consumes-lex]`, `[consumes-pratt]`, `[consumes-ast]`, `[consumes-match]`). - `[shapes-scheduler]` — revealed something about what `plans/lib-guest-scheduler.md` should propose. Append a paragraph to that plan's design diary describing the insight. - `[shapes-static-types-bidirectional]` — same for `plans/lib-guest-static-types-bidirectional.md`. - `[proposes-Y]` — revealed a gap in another existing kit (e.g., `pratt.sx` doesn't handle Go's operator precedence properly). Blockers entry in the kit's plan describing the gap with minimal repro. - `[nothing]` — pure Go work that didn't touch substrate or lib/guest story. Rare; if you write `[nothing]` twice in a row, stop and reflect on whether the iteration could have been shaped to surface something. **Sister plans must be updated.** When Phase 3 lands (independent checker working), append a paragraph to `plans/lib-guest-static-types-bidirectional.md` describing what synth/check shape emerged in Go. When Phase 5 lands (scheduler working), same for `plans/lib-guest-scheduler.md`. This is how the two-consumer rule actually pays off. ## Ground rules (hard) - **Scope:** only `lib/go/**` and `plans/go-on-sx.md`. Single permitted cross-plan write: append-only paragraphs to the sister-plan design diaries (`plans/lib-guest-scheduler.md`, `plans/lib-guest-static-types-bidirectional.md`) on `shapes-*` commits. Do **not** touch `spec/`, `hosts/`, `shared/`, `lib/guest/**` (read-only consumer at this phase), or other `lib//`. - **Consume `lib/guest/core/`** for lex/parse/ast/match/layout. Hand- rolling defeats the chiselling goal. - **Do NOT extract into `lib/guest/scheduler/` or `lib/guest/static- types-bidirectional/` from this loop.** Those extractions are gated on two consumers AND independent implementation. Extraction is its own workstream after Go and the second consumer both exist. - **Substrate gaps** → Blockers entry with minimal repro. Don't fix the substrate from this loop. Belongs to `sx-improvements.md`. - **NEVER call `sx_build` without timeout awareness** — 600s watchdog. - **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after every edit. Never `Edit`/`Read`/`Write` on `.sx`. - **Worktree:** branch `loops/go`, push `origin/loops/go`. Never `main`, never `architecture`. - **Commit granularity:** one feature per commit. Short factual messages with chisel note: `go: lex.sx — keywords + ASI + 50 tests [consumes-lex]`. - **Plan file:** update Progress log + tick boxes every commit. - **If blocked** for two iterations on the same issue, add to Blockers and move on. Phases 1-4 are sequential; 5-8 are largely independent once 4 lands. ## Conformance scoreboard Create `lib/go/scoreboard.json` on first iteration. Suites: lex / parse / types / eval / runtime / stdlib / e2e. Update counts every commit. The scoreboard is also the no-regression gate: a commit that drops any suite's pass count is wrong, not the test. ## Go-specific gotchas (read once, never get bitten) - **ASI (automatic semicolon insertion).** Newline becomes `;` after identifier/literal/`)`/`]`/`}`. Build it into the tokenizer (Phase 1), not the parser. Go spec § Semicolons is unusually precise. - **Untyped constants.** `42` is `untyped int` until contextualised. Canonical pitfall: `var x float64 = 42 / 7` must compute `42 / 7 = 6` as untyped, then convert to `6.0`. Not `42.0 / 7 = 6.0`. Not `(42/7).0 = 6.0`. Test this in Phase 3. - **Methods vs functions.** Different lookup rules. Pointer-receiver methods are NOT in the value's method set for interface satisfaction. - **Interface satisfaction is structural and silent.** No `implements` declaration. Lazy check at every interface-typed slot. - **Channels have identity.** Distinct `make(chan int)` calls produce distinct channels with same type. - **`select` with `default`** = non-blocking. Without `default` = blocks. - **`nil` is typed.** `var i interface{} = (*int)(nil); i == nil` is `false` — i holds typed-nil-of-`*int`, not untyped nil. Footgun. Test. - **Goroutine panic propagation.** Unrecovered panic crashes whole program. Honour faithfully or document divergence. - **`defer` in a loop.** Each iteration pushes; all run on function return, not loop iteration. Common bug; tests must cover. - **Map iteration order is unspecified.** v1 = sorted SX-canonical key order for determinism. Document the divergence; provide a `runtime`-package knob to randomise later. ## General gotchas (all loops) - SX `do` = R7RS iteration. Use `begin` for multi-expr sequences. - `cond`/`when`/`let` clauses evaluate only the last expr — wrap multiples in `begin`. - `env-bind!` creates a binding; `env-set!` mutates an existing one (walks scope chain). - `sx_validate` after every structural edit. - `list?` returns false on raw JS Arrays — host data must be SX-converted. - Shell heredoc `||` gets eaten — escape or use `case`. ## Style - No comments in `.sx` unless non-obvious. Cite Go spec sections inline when a decision is non-obvious (the Go spec is rigorous — citations work). - No new planning docs — update `plans/go-on-sx.md` inline. Append paragraphs to sister-plan design diaries on `shapes-*` commits. - Short factual commit messages with chisel note in brackets: `go: parse short-decl + 6 tests [consumes-pratt]`. - One feature per iteration. Commit. Log. Push. Next. Go. Run the pre-flight check. If lib/guest kits are missing, stop. Otherwise read the plan, find the first unchecked `[ ]`, implement it. Remember: every commit ends with a chisel note, and the sister-plan design diaries get updates on `shapes-*` commits. ## Loop continuation This briefing supersedes any "then stop" wording from the user's original `/loop` input. After pushing, **call `ScheduleWakeup` to fire the next iteration**, then end the turn. The `/loop` command is in dynamic mode; each iteration self-schedules the next. - `delaySeconds`: **60** (minimum). This is a coding loop with no external event to wait on — back-to-back iterations are intended. Raise only if a prior fire reported a substrate blocker that needs settling. - `prompt`: the **full original `/loop` input verbatim, prefixed with `/loop `** (so the wake re-enters this skill and re-reads this briefing). Do NOT paraphrase or trim it — the runtime expects an exact echo. - `reason`: one short sentence, e.g. "next Go-on-SX iteration". **Stop conditions** — omit `ScheduleWakeup` ONLY when: 1. lib/guest pre-flight failed (missing kits) and a Blockers entry was added — the loop is parked waiting for substrate work. 2. The same Blockers entry has been the reason for two consecutive iterations (avoid runaway no-op fires). 3. plans/go-on-sx.md has every Phase 1-11 box checked. 4. The user explicitly asks to stop, pause, or interrupt the loop. Otherwise: reschedule. Always.