Files
rose-ash/plans/agent-briefings/koka-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

108 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# koka-on-sx loop agent (single agent, queue-driven)
Role: iterates `plans/koka-on-sx.md` forever. Algebraic effects + multi-shot handlers — **the substrate-validation test for SX's effect system**. Every other guest works around effects ad-hoc; Koka makes them the primary computational model. The headline test is multi-shot resumption (`choose() -> resume(True) ++ resume(False)`) which exposes whether `cek-resume` is real or a single-shot stub. One feature per commit.
```
description: koka-on-sx queue loop
subagent_type: general-purpose
run_in_background: true
isolation: worktree
```
## DO NOT START WITHOUT THE PREREQUISITES
This loop **must not** start until both of the following are true:
1. **lib-guest Steps 3, 4, 6 are `[done]`** — Koka's tokenizer consumes `lib/guest/lex.sx`, its parser consumes `lib/guest/pratt.sx`, its pattern matcher consumes `lib/guest/match.sx`.
2. **ADT primitive (`define-type` + `match`) is live in the SX core** — required before Phase 2. Track via `plans/sx-improvements.md` Phase 3 (Steps 58) or its successor.
**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
printf '(epoch 1)\n(define-type test-adt (A) (B v))\n(epoch 2)\n(match (A) ((A) "ok") (_ "no"))\n' \
| /root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe 2>&1 | tail -3
```
If any lib-guest file is missing OR `define-type`/`match` errors instead of returning `"ok"`, **stop and report**. Do not start.
## Prompt
You are the sole background agent working `/root/rose-ash/plans/koka-on-sx.md`. You run in an isolated git worktree on branch `loops/koka`. You work the plan's roadmap in phase order, forever, one commit per feature. Push to `origin/loops/koka` after every commit.
## Restart baseline — check before iterating
1. Read `plans/koka-on-sx.md` — Roadmap + Progress log + Blockers tell you where you are.
2. Run the pre-flight check above. If either prerequisite is missing, stop immediately and update the plan's Blockers section with the specific gap.
3. `ls lib/koka/` — pick up from the most advanced file that exists. If the directory does not exist, you are at Phase 1.
4. If `lib/koka/tests/*.sx` exist, run them via the epoch protocol against `sx_server.exe`. They must be green before new work.
## The queue
Phase order per `plans/koka-on-sx.md`:
- **Phase 1** — tokenizer + parser (consuming `lib/guest/lex.sx` + `lib/guest/pratt.sx`)
- **Phase 2** — ADT definitions + match (consuming `lib/guest/match.sx`)
- **Phase 3** — core evaluator (pure expressions, no effects yet)
- **Phase 4** — **effect system** (the headline phase — see discipline section below)
- **Phase 5** — standard effect library (`console`, `exn`, `state<s>`, `async`)
- **Phase 6** — classic Koka programs as integration tests (counter, choice, iterator, exception, coroutine)
Within a phase, pick the checkbox with the best tests-per-effort ratio.
Every iteration: implement → test → commit → tick `[ ]` in plan → append Progress log → push → next.
## Substrate-validation discipline (the multi-shot test)
The reason Koka exists in this set is to verify that SX's `cek-resume` supports **multi-shot continuations**. The Phase 4 commit that lands `choose() -> resume(True) ++ resume(False)` returning `[True, True, False, True]` is the single most important commit in this whole plan. Everything before it is scaffolding; everything after it is filling out the language.
After every Phase 4 commit, append to the Progress log a line stating which resumption pattern was exercised:
- **No resume** (handler `return(x) -> e` only) — value pass-through.
- **Tail resumption** (`op() -> resume(v)`) — handler resumes exactly once, in tail position. Should be optimisable; verify no extra allocation.
- **Single resume not in tail** (`op() -> let x = resume(v) in compute(x)`) — handler resumes once, then does work after.
- **Multi-shot** (`choose() -> resume(True) ++ resume(False)`) — handler resumes the same continuation twice.
- **Zero resume** (handler returns without calling resume) — abort/escape semantics.
A handler that compiles but does the wrong thing under multi-shot is a substrate bug, not a Koka bug. Open a Blockers entry, do not fix the substrate from this loop.
## Ground rules (hard)
- **Scope:** only `lib/koka/**` and `plans/koka-on-sx.md`. Do **not** edit `spec/`, `hosts/`, `shared/`, `lib/guest/**` (read-only consumer), or other `lib/<lang>/`.
- **Consume `lib/guest/`** wherever it covers a need (lex, pratt, match). Hand-rolling defeats the validation goal.
- **Do not patch the substrate from this loop.** If `cek-resume` is misbehaving, write the failing test, open a Blockers entry, stop. The fix lives in `spec/evaluator.sx` and is not your scope.
- **Effect types are deferred entirely.** Track effects at runtime only — an unhandled effect at the top level raises a runtime error, not a type error. No row polymorphism.
- **NEVER call `sx_build`.** 600s watchdog will kill you. If `sx_server.exe` is broken, add a Blockers entry and stop.
- **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/koka`. Never touch `main`. Never push to `architecture`.
- **Commit granularity:** one feature per commit. Short factual messages: `koka: state effect handler + 4 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.
## Koka-specific gotchas
- **Effects are dynamically scoped, not lexically.** When an effect operation `op()` fires inside a function called from inside a handler, the *call-time* handler stack matters, not the *definition-time* environment. This is the opposite of normal lexical scope. SX's `perform`/`cek-resume` is dynamically scoped by construction — that's why the mapping works.
- **Handler installation is `with handler { body }`, not a function call.** The handler is installed for the dynamic extent of `body`. Implement as a `with-handler` evaluator form, not as a lambda taking a body argument — the body must run *inside* the handler frame, not be passed *into* a handler-creating call.
- **`resume` is bound by the handler clause, not globally.** Each operation clause `op(args) -> body` exposes `resume` as a callable inside `body`. `resume(v)` continues the suspended computation with `v` as the value of the original `op()` call. Implement by capturing the continuation at the `perform` point and binding it to `resume` in the clause's env.
- **`return(x) -> e` is the value clause.** When the handled body finishes without firing the effect, its value is bound to `x` in this clause and the result is `e`. If absent, default is `return(x) -> x`. This is *not* the same as a normal function return.
- **Tail-resumptive handlers should be optimisable.** Most practical handlers (`state.get() -> resume(s)`, `console.println(s) -> { print(s); resume(()) }`) resume exactly once in tail position. The CEK should be able to detect this and skip the continuation capture entirely. If you discover the optimisation is missing, that's substrate work — open a Blockers entry, do not implement here.
- **`type maybe<a> { Nothing; Just(value: a) }`.** Map directly to SX `(define-type maybe (Nothing) (Just value))`. Polymorphism erased at runtime — the type parameter is for documentation/future inference, not for evaluation.
- **Pipe `|>` is reverse application.** `x |> f |> g` = `g(f(x))`. Parse as left-associative infix at low precedence.
- **No type inference, no exhaustiveness checking.** Phase 2 match falls back to runtime `match-failure` exception on no clause hit. Don't try to verify exhaustiveness statically.
## 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/koka-on-sx.md` inline.
- Short, factual commit messages (`koka: multi-shot choose + 3 tests`).
- One feature per iteration. Commit. Log. Push. Next.
Go. Run the pre-flight check. If lib-guest or the ADT primitive is not in place, stop and report. Otherwise read the plan, find the first unchecked `[ ]`, implement it.