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>
111 lines
6.3 KiB
Markdown
111 lines
6.3 KiB
Markdown
# Dream-on-SX: OCaml's Dream web framework on the SX CEK
|
||
|
||
`[deferred — depends on ocaml-on-sx + a target user]`
|
||
|
||
Carved out of `plans/ocaml-on-sx.md`. The OCaml-on-SX plan was scoped down to **substrate validation + HM + reference oracle** (Phases 1–5 + minimal stdlib slice). Dream is the practical alternative-stack story — the opposite framing — and only makes sense if a real user wants to write rose-ash apps in OCaml/Dream.
|
||
|
||
**Do not start without:**
|
||
1. OCaml-on-SX Phases 1–5 + Phase 6 minimal stdlib green.
|
||
2. A concrete target user. "OCaml programmers in general" is not a target. "Person X wants to write feature Y on rose-ash in Dream" is.
|
||
|
||
If those conditions are not met, this plan stays cold.
|
||
|
||
## Why this might be worth doing (when the time comes)
|
||
|
||
Dream is the cleanest middleware-shaped HTTP framework in any language:
|
||
- `handler = request -> response promise`
|
||
- `middleware = handler -> handler`
|
||
- `m1 @@ m2 @@ handler` — left-fold composition
|
||
|
||
It maps onto SX with almost no impedance — `@@` is function composition, `request → response promise` is `(perform (:http-respond ...))`, middleware chain is plain SX function composition. So the integration cost is low *if* the OCaml-on-SX foundation is in place.
|
||
|
||
The user-facing story: rose-ash users who'd never touch s-expressions might write Dream/OCaml apps that integrate with the same federation, auth, and storage primitives. Demo: a Dream app serving sx.rose-ash.com — the framework that describes the runtime it runs on.
|
||
|
||
## Dream semantic mappings
|
||
|
||
| Dream construct | SX mapping |
|
||
|----------------|-----------|
|
||
| `handler = request -> response promise` | `(fn (req) (perform (:http-respond ...)))` |
|
||
| `middleware = handler -> handler` | `(fn (next) (fn (req) ...))` |
|
||
| `Dream.router [routes]` | `(ocaml-dream-router routes)` — dispatch on method+path |
|
||
| `Dream.get "/path" h` | route record `{:method "GET" :path "/path" :handler h}` |
|
||
| `Dream.scope "/p" [ms] [rs]` | prefix mount with middleware chain |
|
||
| `Dream.param req "name"` | path param extracted during routing |
|
||
| `m1 @@ m2 @@ handler` | `(m1 (m2 handler))` — left-fold composition |
|
||
| `Dream.session_field req "k"` | `(perform (:session-get req "k"))` |
|
||
| `Dream.set_session_field req "k" v` | `(perform (:session-set req "k" v))` |
|
||
| `Dream.flash req` | `(perform (:flash-get req))` |
|
||
| `Dream.form req` | `(perform (:form-parse req))` — returns Ok/Error ADT |
|
||
| `Dream.websocket handler` | `(perform (:websocket handler))` |
|
||
| `Dream.run handler` | starts SX HTTP server with handler as root |
|
||
|
||
## Roadmap
|
||
|
||
The five types: `request`, `response`, `handler = request -> response`, `middleware = handler -> handler`, `route`. Everything else is a function over these.
|
||
|
||
- [ ] **Core types** in `lib/dream/types.sx`: request/response records, route record.
|
||
- [ ] **Router** in `lib/dream/router.sx`:
|
||
- `dream-get path handler`, `dream-post path handler`, etc. for all HTTP methods.
|
||
- `dream-scope prefix middlewares routes` — prefix mount with middleware chain.
|
||
- `dream-router routes` — dispatch tree, returns handler; no match → 404.
|
||
- Path param extraction: `:name` segments, `**` wildcard.
|
||
- `dream-param req name` — retrieve matched path param.
|
||
- [ ] **Middleware** in `lib/dream/middleware.sx`:
|
||
- `dream-pipeline middlewares handler` — compose middleware left-to-right.
|
||
- `dream-no-middleware` — identity.
|
||
- Logger: `(dream-logger next req)` — logs method, path, status, timing.
|
||
- Content-type sniffer.
|
||
- [ ] **Sessions** in `lib/dream/session.sx`:
|
||
- Cookie-backed session middleware.
|
||
- `dream-session-field req key`, `dream-set-session-field req key val`.
|
||
- `dream-invalidate-session req`.
|
||
- [ ] **Flash messages** in `lib/dream/flash.sx`:
|
||
- `dream-flash-middleware` — single-request cookie store.
|
||
- `dream-add-flash-message req category msg`.
|
||
- `dream-flash-messages req` — returns list of `(category, msg)`.
|
||
- [ ] **Forms + CSRF** in `lib/dream/form.sx`:
|
||
- `dream-form req` — returns `(Ok fields)` or `(Err :csrf-token-invalid)`.
|
||
- `dream-multipart req` — streaming multipart form data.
|
||
- CSRF middleware: stateless signed tokens, session-scoped.
|
||
- `dream-csrf-tag req` — returns hidden input fragment for SX templates.
|
||
- [ ] **WebSockets** in `lib/dream/websocket.sx`:
|
||
- `dream-websocket handler` — upgrades request; handler `(fn (ws) ...)`.
|
||
- `dream-send ws msg`, `dream-receive ws`, `dream-close ws`.
|
||
- [ ] **Static files:** `dream-static root-path` — serves files, ETags, range requests.
|
||
- [ ] **`dream-run`**: wires root handler into SX's `perform (:http-listen ...)`.
|
||
- [ ] **Demos** in `lib/dream/demos/`:
|
||
- `hello.ml` → `lib/dream/demos/hello.sx`: "Hello, World!" route.
|
||
- `counter.ml` → `lib/dream/demos/counter.sx`: in-memory counter with sessions.
|
||
- `chat.ml` → `lib/dream/demos/chat.sx`: multi-room WebSocket chat.
|
||
- `todo.ml` → `lib/dream/demos/todo.sx`: CRUD list with forms + CSRF.
|
||
- [ ] Tests in `lib/dream/tests/`: routing dispatch, middleware composition, session round-trip, CSRF accept/reject, flash read-after-write — 60+ tests.
|
||
|
||
## Stdlib additions Dream will need
|
||
|
||
Dream pushes beyond OCaml-on-SX's Phase 6 minimal stdlib slice. When this plan activates, OCaml-on-SX gets a follow-on phase that adds at minimum:
|
||
|
||
- `Bytes` (binary buffers — request bodies, websocket frames)
|
||
- `Buffer` (mutable string building)
|
||
- `Format` (full pretty-printer, not just `Printf.sprintf`)
|
||
- More `String` (`index_opt`, `contains`, `starts_with`, `ends_with`, `replace_all`)
|
||
- `Sys` (`argv`, `getenv_opt`, `getcwd`)
|
||
- `Hashtbl` extensions (`iter`, `fold`, `length`, `remove`)
|
||
- `Map.Make` / `Set.Make` functors
|
||
|
||
Confirm scope before starting; some of these may be addable as Dream-internal helpers rather than full stdlib modules.
|
||
|
||
## Ground rules
|
||
|
||
- **Scope:** only `lib/dream/**` and `plans/dream-on-sx.md`. Plus the stdlib additions listed above which land in `lib/ocaml/runtime.sx`.
|
||
- **Hard prerequisite:** OCaml-on-SX Phases 1–5 + Phase 6 minimal stdlib. Verify scoreboard before starting.
|
||
- **SX files:** `sx-tree` MCP tools only.
|
||
- **Don't reinvent the SX HTTP server.** Dream wraps the existing `perform (:http-listen ...)` — it does not implement its own listener loop.
|
||
|
||
## Progress log
|
||
|
||
_(awaiting activation conditions)_
|
||
|
||
## Blockers
|
||
|
||
_(none yet — plan is cold)_
|