Files
rose-ash/plans/agent-briefings/sx-vm-extensions-loop.md
giles 183bfeebe1 vm-ext: bootstrap loops/sx-vm-extensions plan + loop briefing
plans/sx-vm-opcode-extension.md ports over from loops/erlang (f6a68656)
with the opcode partition adjusted to match real VM usage: 1-199 core
(current ceiling 175 = OP_DEC), 200-247 extensions, 248-255 reserved.

plans/agent-briefings/sx-vm-extensions-loop.md captures the per-fire
workflow and ground rules.
2026-05-14 22:29:15 +00:00

87 lines
3.8 KiB
Markdown

# sx-vm-extensions loop agent
Role: drives `plans/sx-vm-opcode-extension.md` to completion. One phase per
fire (A → B → C → D → E). Bounded loop — after Phase E acceptance, the loop
is done.
```
description: sx-vm-extensions queue loop
subagent_type: general-purpose
run_in_background: true
isolation: worktree (already on loops/sx-vm-extensions)
```
## What this loop is for
Mechanism in `hosts/ocaml/lib/` that lets language ports register specialized
bytecode opcodes without modifying the SX VM core. Direct prerequisite for
**erlang-on-sx Phase 9** (the BEAM analog) and a structural enabler for any
future language port that wants performance-critical opcodes.
## The queue
Per `plans/sx-vm-opcode-extension.md`, in order:
- **Phase A** — Opcode ID partition + dispatch fallthrough in `sx_vm.ml`.
Add `Invalid_opcode of int` exception, `extension_dispatch_ref`, the
`| op when op >= 200 -> !extension_dispatch_ref op vm frame` arm, and a
partition comment near the opcode list.
- **Phase B** — Extension registry module (`sx_vm_extensions.ml`).
`register`, `dispatch`, `id_of_name`, `state_of_extension`. Wire dispatch
into Phase A's ref at module init.
- **Phase C** — Compiler-side opcode lookup primitive (`extension-opcode-id`).
- **Phase D** — Test extension at `hosts/ocaml/lib/extensions/test_ext.ml`,
end-to-end SX → bytecode → VM dispatch flow.
- **Phase E** — JIT awareness: extension opcodes mark a lambda as
interpret-only.
## Per-fire workflow (hard)
1. Read `plans/sx-vm-opcode-extension.md` — find the first un-ticked phase.
2. Implement the phase (only files in `hosts/ocaml/**` and the plan file).
3. Build via `sx_build target=ocaml`.
4. Run regression: every existing language-port conformance suite plus
the OCaml unit tests. The list lives at `lib/<lang>/conformance.sh`
13 suites at last count (apl, common-lisp, datalog, erlang, forth, guest,
haskell, js, lua, ocaml, prolog, smalltalk, tcl).
5. If green, commit (short factual message — `vm-ext: phase A — dispatch
fallthrough` style).
6. Tick the `[ ]` for the completed phase in the plan, append one dated
line to the Progress log (newest first).
7. Stop. Wait for the next fire.
## Ground rules (hard)
- **Scope:** only `hosts/ocaml/**` and `plans/sx-vm-opcode-extension.md`.
Do **not** edit `lib/<lang>/**`, `spec/**`, `shared/**`, or any other
language port's tests.
- **One phase per fire.** Don't combine phases even if a phase looks small.
The point of the loop is incremental commits.
- **Commit locally only.** Do **not** push. Do **not** touch `main`.
- **Worktree:** you are on `loops/sx-vm-extensions` in
`/root/rose-ash-loops/sx-vm-extensions`.
- **OCaml SX VM gotchas:**
- `vm` and `frame` types are defined in `sx_vm.ml`, not `sx_types.ml`.
Forward refs (like the existing `jit_compile_ref` pattern) are how
sibling modules avoid circular dependency.
- Current core opcode ceiling is 175 (OP_DEC). The extension threshold
is 200, leaving 24 spare slots for future core opcodes.
- JIT compilation is lazy per-lambda. See `project_jit_compilation.md`
in memory for the cache + sentinel pattern.
- **SX edits:** `sx-tree` MCP tools only (none expected for this loop, but
if needed).
- **OCaml edits:** Edit/Write tools are fine — these aren't `.sx` files.
## Done condition
Phase E acceptance: all 13 (or however many exist at the time) language-port
conformance suites pass, OCaml unit tests pass, the test extension from
Phase D demonstrates end-to-end flow including JIT routing. Loop is
complete; mark and stop.
## After acceptance
Hand off to the Erlang loop: `hosts/ocaml/lib/extensions/erlang.ml` becomes
the first real consumer, written against this mechanism instead of the
Phase 9b stub dispatcher in `lib/erlang/vm/dispatcher.sx`.