# 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`.
