Design + ops scaffolding for the next phase of work, none of it touching
substrate or guest code.
lib-guest.md: rewrites Architectural framing as a 5-layer stack
(substrate → lib/guest → languages → shared/ → applications),
recursive dependency-direction rule, scaled two-consumer rule. Adds
Phase B (long-running stratification) with sub-layer matrix
(core/typed/relational/effects/layout/lazy/oo), language profiles, and
the long-running-discipline section. Preserves existing Phase A
progress log and rules.
ocaml-on-sx.md: scope reduced to substrate validation + HM + reference
oracle. Phases 1-5 + minimal stdlib slice + vendored testsuite slice.
Dream carved out into dream-on-sx.md; Phase 8 (ReasonML) deferred.
Records lib-guest sequencing dependency.
datalog-on-sx.md: adds Phase 4 built-in predicates + body arithmetic,
Phase 6 magic sets, safety analysis in Phase 3, Non-goals section.
New chisel plans (forward-looking, not yet launchable):
kernel-on-sx.md — first-class everything, env-as-value endgame
idris-on-sx.md — dependent types, evidence chisel
probabilistic-on-sx.md — weighted nondeterminism + traces
maude-on-sx.md — rewriting as primitive
linear-on-sx.md — resource model, artdag-relevant
Loop briefings (4 active, 1 cold):
minikanren-loop.md, ocaml-loop.md, datalog-loop.md, elm-loop.md, koka-loop.md
Restore scripts mirror the loop pattern:
restore-{minikanren,ocaml,datalog,jit-perf,lib-guest}.sh
Each captures worktree state, plan progress, MCP health, tmux status.
Includes the .mcp.json absolute-path patch instruction (fresh worktrees
have no _build/, so the relative mcp_tree path fails on first launch).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
107 lines
8.3 KiB
Markdown
107 lines
8.3 KiB
Markdown
# ocaml-on-sx loop agent (single agent, queue-driven)
|
||
|
||
Role: iterates `plans/ocaml-on-sx.md` forever. Strict ML on the SX CEK — Phases 1–5 + minimal stdlib slice + vendored testsuite oracle. Goals: substrate validation, HM inferencer extractable into `lib/guest/hm.sx`, reference oracle for other guest languages. **Dream is out of scope** (separate plan); ReasonML deferred. One feature per commit.
|
||
|
||
```
|
||
description: ocaml-on-sx queue loop
|
||
subagent_type: general-purpose
|
||
run_in_background: true
|
||
isolation: worktree
|
||
```
|
||
|
||
## DO NOT START WITHOUT THE PREREQUISITE
|
||
|
||
This loop **must not** start until the lib-guest kits are shipped. OCaml's tokenizer should consume `lib/guest/lex.sx` (lib-guest Step 3); its parser should consume `lib/guest/pratt.sx` (Step 4); its pattern matcher should consume `lib/guest/match.sx` (Step 6); its HM inferencer should consume `lib/guest/hm.sx` (Step 8). Hand-rolling defeats the substrate-validation goal.
|
||
|
||
**Pre-flight check:**
|
||
```
|
||
ls /root/rose-ash/lib/guest/lex.sx /root/rose-ash/lib/guest/pratt.sx \
|
||
/root/rose-ash/lib/guest/match.sx /root/rose-ash/lib/guest/layout.sx \
|
||
/root/rose-ash/lib/guest/hm.sx
|
||
```
|
||
The lib-guest loop reached a "ship + defer second consumer" outcome where every kit is shipped but several steps are `[partial]` because porting the existing engines would have risked their scoreboards. That's the **expected** state — `[partial — kit shipped]` for Steps 5/6/7/8 is fine to start on. **OCaml-on-SX is itself the deferred second consumer for Step 8 (HM)** — closing it from this side is the plan. Only stop if any of those `lib/guest/*.sx` files are missing.
|
||
|
||
## Prompt
|
||
|
||
You are the sole background agent working `/root/rose-ash/plans/ocaml-on-sx.md`. You run in an isolated git worktree on branch `loops/ocaml`. You work the plan's roadmap in phase order, forever, one commit per feature. Push to `origin/loops/ocaml` after every commit.
|
||
|
||
## Restart baseline — check before iterating
|
||
|
||
1. Read `plans/ocaml-on-sx.md` — Roadmap + Progress log + Blockers tell you where you are.
|
||
2. Run the pre-flight check above. If any of the listed `lib/guest/*.sx` files are missing, stop immediately and update the plan's Blockers section. `[partial — kit shipped]` status on Steps 5–8 is expected and fine to start on.
|
||
3. `ls lib/ocaml/` — pick up from the most advanced file that exists. If the directory does not exist, you are at Phase 1.
|
||
4. If `lib/ocaml/tests/*.sx` exist, run them via the epoch protocol against `sx_server.exe`. They must be green before new work.
|
||
5. If `lib/ocaml/scoreboard.json` exists (Phase 5.1 onwards), that is your starting number — read it each iteration and attack the worst failure mode you can plausibly fix in < a day.
|
||
|
||
## The queue
|
||
|
||
Phase order per `plans/ocaml-on-sx.md`:
|
||
|
||
- **Phase 1** — tokenizer + parser (consuming `lib/guest/lex.sx` + `lib/guest/pratt.sx`)
|
||
- **Phase 2** — core evaluator (untyped: let/lambda/match/refs/try-with)
|
||
- **Phase 3** — ADTs + pattern matching (consuming `lib/guest/match.sx`)
|
||
- **Phase 4** — modules + functors (**the hardest test of the substrate** — track LOC vs equivalent native OCaml stdlib as substrate-validation signal)
|
||
- **Phase 5** — Hindley-Milner type inference (the headline payoff; seed for `lib/guest/hm.sx`)
|
||
- **Phase 5.1** — vendor OCaml testsuite slice; create `lib/ocaml/conformance.sh` + `scoreboard.json` (oracle role becomes mechanical)
|
||
- **Phase 6** — minimal stdlib slice (~30 functions: List/Option/Result/String/Printf.sprintf/Hashtbl)
|
||
- **Phase 7** — Dream — **out of scope, see `plans/dream-on-sx.md`**
|
||
- **Phase 8** — ReasonML — `[deferred]`, do not work without explicit go-ahead
|
||
|
||
Within a phase, pick the checkbox with the best tests-per-effort ratio. Once the scoreboard exists (Phase 5.1), it is your north star.
|
||
|
||
Every iteration: implement → test → commit → tick `[ ]` in plan → append Progress log → push → next.
|
||
|
||
## Substrate-validation discipline
|
||
|
||
Phase 4 (modules + functors) is the single most informative phase for whether the substrate earns its claims. After every Phase 4 commit, append to the Progress log a line like:
|
||
|
||
```
|
||
2026-MM-DD <commit-sha> Phase 4 — functor application; lib/ocaml/runtime.sx +120 LOC, total Phase 4 LOC = 580.
|
||
```
|
||
|
||
If the Phase 4 total exceeds **2000 LOC**, stop and add a Blockers entry: `Phase 4 LOC over budget — substrate gap suspected, needs review.` The substrate is supposed to do the heavy lifting; if it isn't, we want to know early.
|
||
|
||
## Ground rules (hard)
|
||
|
||
- **Scope:** only `lib/ocaml/**`, `lib/reasonml/**` (Phase 8 only, deferred), and `plans/ocaml-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, `lib/dream/**` (separate plan), `lib/guest/**` (read-only consumer), or other `lib/<lang>/`.
|
||
- **Consume `lib/guest/`** wherever it covers a need (lex, pratt, match, ast). Hand-rolling instead of consuming defeats the whole point of the sequencing.
|
||
- **NEVER call `sx_build`.** 600s watchdog will kill you before OCaml finishes. If `sx_server.exe` is broken, add a Blockers entry and stop.
|
||
- **Shared-file issues** → plan's Blockers section with a minimal repro. Don't fix them.
|
||
- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after every edit. Never `Edit`/`Read`/`Write` on `.sx`.
|
||
- **Worktree:** commit, then push to `origin/loops/ocaml`. Never touch `main`. Never push to `architecture`.
|
||
- **Commit granularity:** one feature per commit. Short factual messages: `ocaml: functor application + 6 tests`.
|
||
- **Plan file:** update Progress log + tick boxes every commit.
|
||
- **If blocked** for two iterations on the same issue, add to Blockers and move on.
|
||
- **Phase 7 (Dream) is forbidden.** Even tempting "while I'm here" detours into `lib/dream/` are forbidden. That plan is cold for a reason.
|
||
- **Phase 8 (ReasonML) is forbidden** without explicit user go-ahead via the plan or briefing being updated.
|
||
|
||
## OCaml-specific gotchas
|
||
|
||
- **Strict, not lazy.** Argument evaluation is left-to-right and eager. `let x = (print_endline "a"; 1) in let y = (print_endline "b"; 2) in x + y` prints "a" then "b". Don't reuse Haskell-on-SX patterns that assume thunks.
|
||
- **Curried by default.** `let f x y = e` is `(define (f x y) e)` *and* `(f 1)` is a partial application returning a 1-ary lambda. The CEK already handles this — don't auto-uncurry.
|
||
- **`let rec` mutual recursion via `and`.** `let rec f x = ... and g x = ...` — both visible in each other's bodies. Map to nested `letrec` in SX.
|
||
- **Pattern match is on the value, not on shape inference.** `match x with | None -> ... | Some y -> ...` — runtime tag dispatch via `lib/guest/match.sx`. Exhaustiveness error if no clause matches (Phase 3).
|
||
- **Polymorphic variants** (`` `Tag value ``) use the same runtime as nominal constructors but are not declared in a type. Treat `` `A 1 `` as `(:A 1)` — same shape as `A 1` from `type t = A of int`.
|
||
- **`open M` is scope merge, not import.** It injects M's bindings into the current scope, shadowing earlier bindings. Use `env-merge` not aliasing. Subsequent `M.x` references still work (M is still bound separately).
|
||
- **First-class modules deferred to Phase 5.** Phase 4 modules are dicts; Phase 5 wraps them in a typed envelope. Don't try to do both at once.
|
||
- **HM error messages are the test.** Type errors that say "type clash" without pointing at expected/actual + the source position are useless. Phase 5 tests should include error-message assertions, not just inference success.
|
||
- **The reference oracle is the OCaml REPL on this machine.** When you're not sure what `let f x = ref x in let g = f 1 in (!g, !g)` should produce, run it in `ocaml` and match. Don't guess.
|
||
|
||
## 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.
|
||
- No new planning docs — update `plans/ocaml-on-sx.md` inline.
|
||
- Short, factual commit messages (`ocaml: HM let-polymorphism (+11)`).
|
||
- One feature per iteration. Commit. Log. Push. Next.
|
||
|
||
Go. Run the pre-flight check. If lib-guest is not done, stop and report. Otherwise read the plan, find the first unchecked `[ ]`, implement it.
|