Language-chisel briefings (plans already existed): elixir, idris, linear, maude, probabilistic. host-on-sx briefing (native server now, Dream framework layer next). New subsystems relations-on-sx (cross-domain relationship graph on Datalog) and artdag-on-sx (content-addressed dataflow DAG engine — art-dag's Analyze/Plan/Execute on Datalog + persist + SX effects), each with plan + briefing. Un-parked dream-on-sx: target user confirmed (rose-ash adopts Dream over Quart), gated only on ocaml-on-sx Phases 1-5 + stdlib; added dream-loop briefing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
127 lines
6.8 KiB
Markdown
127 lines
6.8 KiB
Markdown
# host-on-sx loop agent (single agent, queue-driven)
|
||
|
||
Role: iterates `plans/host-on-sx.md` forever. **The SX web host — off Quart, onto
|
||
the kernel.** Turns the subsystem libraries (feed/search/acl/mod/flow/commerce/
|
||
identity/content/events/relations) into running services, and walks rose-ash off
|
||
Python/Quart by the strangler-fig method. This is the dependency hub — it imports
|
||
every subsystem's public API. One feature per commit.
|
||
|
||
```
|
||
description: host-on-sx queue loop
|
||
subagent_type: general-purpose
|
||
run_in_background: true
|
||
isolation: worktree
|
||
```
|
||
|
||
## Orientation — two layers, two timelines (read `plans/host-on-sx.md` first)
|
||
|
||
1. **Now (unblocked):** native OCaml HTTP server (already live in prod on
|
||
`sx.rose-ash.com`) + SXTP adapter + SX handlers. Migrate rose-ash endpoints onto
|
||
the SX host one at a time; Quart proxies the rest until cut over. **No
|
||
`ocaml-on-sx` dependency for this layer.**
|
||
2. **Next (Phase 4, gated):** `dream-on-sx` as the framework layer over the same
|
||
handlers — typed routing, middleware, sessions, CSRF. Gated on `ocaml-on-sx`
|
||
Phases 1–5 + Phase 6 minimal stdlib (currently 480/480 and advancing — verify
|
||
its scoreboard before starting Phase 4). **Do not block Phases 1–3 on Dream.**
|
||
3. **Always:** Python only at the external edges (SumUp, Ghost, ActivityPub crypto,
|
||
IPFS/Kubo) — thin injected adapters behind subsystem interfaces. "Drop Quart" ≠
|
||
"drop every line of Python."
|
||
|
||
## Prompt
|
||
|
||
You are the sole background agent working `/root/rose-ash/plans/host-on-sx.md`, in
|
||
an isolated git worktree on branch `loops/host`, forever, one commit per feature.
|
||
Push to `origin/loops/host` after every commit. Never touch `main` or `architecture`.
|
||
|
||
## Restart baseline — check before iterating
|
||
|
||
1. Read `plans/host-on-sx.md` — Roadmap + Progress log + Blockers + the migration
|
||
ledger.
|
||
2. `ls lib/host/` — pick up from the most advanced file. No dir → Phase 1.
|
||
3. If `lib/host/tests/*.sx` exist, run them via the epoch protocol against
|
||
`sx_server.exe` (`SX_SERVER=/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe`).
|
||
Green before new work.
|
||
4. Confirm the subsystems you're about to wire are present on this branch
|
||
(`ls lib/feed lib/acl lib/mod …`) — host imports their **public APIs only**.
|
||
|
||
## The queue
|
||
|
||
Phase order per `plans/host-on-sx.md`:
|
||
|
||
- **Phase 1** — `router.sx` (route table, (method,path) match) + `handler.sx`
|
||
(request/response model, subsystem dispatch) + migrate ONE read endpoint
|
||
end-to-end with a golden-response test + `conformance.sh` + scoreboard
|
||
- **Phase 2** — `middleware.sx` (composable auth(`identity`) ∘ `acl` ∘ mute ∘ error)
|
||
+ `sxtp.sx` (host↔subsystem wire format, align with the existing SXTP spec) +
|
||
migrate a write endpoint (auth + permission + action)
|
||
- **Phase 3** — strangler migration ledger: enumerate Quart endpoints, track
|
||
migrated vs proxied, golden-response harness vs live Quart, cut over a whole small
|
||
domain (`likes` or `relations`) as proof
|
||
- **Phase 4 (gated)** — Dream framework layer once `ocaml-on-sx` 1–5 + stdlib is
|
||
green: adopt `dream-on-sx` routing/middleware/session ergonomics over the same
|
||
handlers; re-home external adapters as native where replacements land
|
||
|
||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||
|
||
## Migration discipline (the strangler rule)
|
||
|
||
- **Every migrated endpoint must be behavior-equivalent to its Quart original.**
|
||
Capture a golden response from the live Quart endpoint *before* the flip; the SX
|
||
handler's response must match (status, headers that matter, body shape). Keep the
|
||
golden fixtures in `lib/host/tests/`.
|
||
- **Never big-bang.** One endpoint at a time; Quart proxies everything not yet
|
||
migrated. The migration ledger is the source of truth for what's flipped.
|
||
- **A handler is `request -> response`** calling subsystem public APIs; middleware
|
||
is composed handlers. Don't reach into subsystem internals — wire to their APIs.
|
||
|
||
## Ground rules (hard)
|
||
|
||
- **Scope:** only `lib/host/**` and `plans/host-on-sx.md`. May **import** every
|
||
subsystem's public API + the kernel's server/SXTP surface. Do **not** edit
|
||
`spec/`, `hosts/`, `shared/`, or any subsystem internals. Host-primitive / native
|
||
server changes belong in `hosts/` (out of scope) → Blockers entry.
|
||
- **NEVER call `sx_build`** (600s watchdog). Broken `sx_server.exe` → Blockers, stop.
|
||
- **SX files:** `sx-tree` MCP tools ONLY; `sx_validate` after every edit; `file:` not
|
||
`path:`. Never `Edit`/`Read`/`Write` on `.sx`.
|
||
- **Worktree:** commit, then push `origin/loops/host`. Never `main`/`architecture`.
|
||
(Note: `main` push = PRODUCTION deploy — never from this loop.)
|
||
- **Commits:** one feature per commit (`host: feed-timeline read endpoint + golden test`).
|
||
- **Plan file:** Progress log + tick boxes + migration ledger every commit.
|
||
- **Blocked 2 iterations on one issue → Blockers entry, move on.**
|
||
|
||
## host-specific gotchas
|
||
|
||
- **The native server lives in `hosts/` and is out of scope.** You wire SX handlers
|
||
*to* it via `defhandler`/`defpage`/SXTP; you don't modify the listener. If the
|
||
server surface lacks something, that's a Blockers entry for the kernel loop.
|
||
- **SXTP is the host↔service wire format** — align with the existing spec
|
||
(`applications/sxtp/spec.sx`); don't invent a parallel protocol.
|
||
- **Subsystems are libraries with public APIs.** Treat `mod/decide`, `acl-permit?`,
|
||
feed/search queries etc. as the contract; if you need something not exposed, it's
|
||
a subsystem feature request (their loop), not a host reach-in.
|
||
- **Auth vs permission are different middlewares.** `identity` answers "who is this"
|
||
(sessions/OAuth); `acl` answers "may they". Compose them as distinct layers.
|
||
- **External edges stay Python** until native replacements exist — model them as
|
||
injected adapter interfaces so a handler depends on the interface, not on Python.
|
||
- **Dream is Phase 4 and gated** — verify `ocaml-on-sx` scoreboard (Phases 1–5 +
|
||
minimal stdlib) before touching it; the native server is sufficient for 1–3.
|
||
|
||
## 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`.
|
||
- `let` is parallel — nest `let`s when one binding references an earlier one.
|
||
- `env-bind!` creates a binding; `env-set!` mutates an existing one.
|
||
- Namespace-prefix host helpers (`host/…`).
|
||
- Shell heredoc `||` gets eaten — escape or use `case`.
|
||
|
||
## Style
|
||
|
||
- No comments in `.sx` unless non-obvious. No new planning docs — update the plan.
|
||
- Short, factual commit messages. One feature per iteration. Commit. Log. Push. Next.
|
||
|
||
Go. Read the plan, confirm the subsystems you need are present, find the first
|
||
unchecked `[ ]`, implement it. Start with Phase 1 on the native server — do not wait
|
||
for Dream.
|