Files
rose-ash/plans/agent-briefings/ocaml-loop.md
giles 9dd9fb9c37 plans: layered-stack framing + chisel sequence + loop scaffolding
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>
2026-05-08 22:27:50 +00:00

8.3 KiB
Raw Blame History

ocaml-on-sx loop agent (single agent, queue-driven)

Role: iterates plans/ocaml-on-sx.md forever. Strict ML on the SX CEK — Phases 15 + 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 58 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.