plans: briefings for 5 language chisels + host/relations/artdag/dream
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>
This commit is contained in:
126
plans/agent-briefings/artdag-loop.md
Normal file
126
plans/agent-briefings/artdag-loop.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# artdag-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/artdag-on-sx.md` forever. **Content-addressed dataflow DAG
|
||||
engine** — the SX heart of art-dag's Analyze→Plan→Execute pipeline: dependency
|
||||
analysis, scheduling, content-addressed memoization, incremental recompute,
|
||||
composable s-expression effects. Media kernels (JAX) and storage (IPFS) stay opaque
|
||||
— this is the *engine*, not the pixels. One feature per commit.
|
||||
|
||||
```
|
||||
description: artdag-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prerequisites — check before starting
|
||||
|
||||
1. **`lib/datalog/` present** (Analyze, Phase 2) — public API `lib/datalog/datalog.sx`.
|
||||
2. **`lib/persist/` present** (memo cache / result store, Phase 4) — public API.
|
||||
|
||||
**Pre-flight:**
|
||||
```
|
||||
ls /root/rose-ash/lib/datalog/datalog.sx
|
||||
ls /root/rose-ash/lib/persist/ 2>/dev/null
|
||||
```
|
||||
Phase 1 (DAG model + content addressing) needs neither and can start immediately.
|
||||
Datalog is needed at Phase 2, persist at Phase 4 — if a dependency is missing when
|
||||
you reach its phase, record a Blockers entry and work earlier phases / other boxes.
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/artdag-on-sx.md`,
|
||||
in an isolated git worktree on branch `loops/artdag`, forever, one commit per
|
||||
feature. Push to `origin/loops/artdag` after every commit. Never touch `main` or
|
||||
`architecture`.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/artdag-on-sx.md` — Roadmap + Progress log + Blockers.
|
||||
2. Run the pre-flight; record gaps in Blockers (per-phase, not all-or-nothing).
|
||||
3. `ls lib/artdag/` — pick up from the most advanced file. No dir → Phase 1.
|
||||
4. If `lib/artdag/tests/*.sx` exist, run them via `bash lib/artdag/conformance.sh`
|
||||
(`SX_SERVER=/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe`). Green
|
||||
before new work.
|
||||
5. **Read the existing Python engine for design lineage** — repo top-level
|
||||
`artdag/core/` (DAG, effects, analysis, planning) and `artdag/l1/sexp_effects/`.
|
||||
Understand the 3-phase model + the effect language. **Do not import or port its
|
||||
code** — this is a fresh SX implementation.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/artdag-on-sx.md`:
|
||||
|
||||
- **Phase 1** — DAG model + **content addressing** (node id = digest of
|
||||
`(op, sorted input-ids, params)`; identical subgraphs share an id); validate +
|
||||
topo order. *No substrate deps — start here.*
|
||||
- **Phase 2** — Analyze on **Datalog**: deps/dependents/reachable + **dirty-closure**
|
||||
propagation
|
||||
- **Phase 3** — Plan: topological **batches** + parallelism cap; incremental (dirty-only)
|
||||
- **Phase 4** — Execute: effect interpreter (`perform` per node) + **content-addressed
|
||||
memo** on `lib/persist/` + **incremental recompute** (only the dirty closure)
|
||||
- **Phase 5** — Optimize: DCE + CSE (free from content ids) + adjacent-op fusion;
|
||||
result-preserving (optional: rule-based via `maude-on-sx`)
|
||||
- **Phase 6** — Federation: shared content-addressed cache across instances
|
||||
(L2-style), trust-gated result import, invalidation
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||||
|
||||
## artdag-specific gotchas
|
||||
|
||||
- **Content addressing is the whole game.** A node's id must be a *deterministic
|
||||
structural digest* of its spec (op + sorted input ids + params). Get this stable
|
||||
and order-insensitive on inputs where the op is commutative, or sharing/caching
|
||||
silently misses. Never let a clock, randomness, or insertion order into the id.
|
||||
- **Media ops are opaque.** In tests a node op is a pure SX function over inputs;
|
||||
never compute real media. Production kernels (JAX) and storage (IPFS) are injected
|
||||
adapters behind an interface — depend on the interface, not the impl.
|
||||
- **Analyze is the acl/relations reachability shape** — recursive Datalog. Read
|
||||
`lib/acl/engine.sx` / `lib/relations/` for the worked shape; re-derive, don't import.
|
||||
- **Incremental = recompute only the dirty closure.** The Phase 4 keystone test
|
||||
asserts that re-running after one leaf change recomputes *only* the transitive
|
||||
dependents and cache-hits everything else (count the recomputes). If it recomputes
|
||||
more, the dirty closure (Phase 2) or the memo key (Phase 4) is wrong.
|
||||
- **The memo key is the content-id, not the node identity.** Two different DAGs that
|
||||
contain the same subgraph share cache slots — that's the point. Don't key on
|
||||
position or DAG-local node index.
|
||||
- **Effects are composable s-expressions** (art-dag's `sexp_effects`) — Phase 5
|
||||
optimization rewrites the effect DAG; keep ops as data you can fuse/eliminate, not
|
||||
opaque closures, so the optimizer can reason about them.
|
||||
- **persist stores results by reference where large** — for big blobs, persist holds
|
||||
the ref/CID and the bytes live in the content-addressed store (see
|
||||
`plans/persist-on-sx.md`); the engine caches the *result handle*, not megabytes.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/artdag/**` and `plans/artdag-on-sx.md`. Do **not** edit
|
||||
`spec/`, `hosts/`, `shared/`, `lib/datalog/**` / `lib/persist/**` (read-only —
|
||||
import public APIs), other `lib/<lang>/`, or the top-level `artdag/` Python engine
|
||||
(read-only, design lineage only).
|
||||
- **Don't modify the substrates.** Datalog/persist issues → failing test + Blockers.
|
||||
- **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/artdag`. Never `main`/`architecture`.
|
||||
- **Commits:** one feature per commit (`artdag: dirty-closure propagation + 6 tests`).
|
||||
- **Plan file:** Progress log (newest first) + tick boxes every commit.
|
||||
- **Blocked 2 iterations on one issue → Blockers entry, move on.**
|
||||
|
||||
## 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 guest helpers (`artdag/…`) — short/host-colliding names get shadowed.
|
||||
- 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 and the existing `artdag/` engine for design lineage, then start
|
||||
Phase 1 (DAG model + content addressing) — it needs no substrate dependency. Find
|
||||
the first unchecked `[ ]`, implement it.
|
||||
125
plans/agent-briefings/dream-loop.md
Normal file
125
plans/agent-briefings/dream-loop.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# dream-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/dream-on-sx.md` forever. **OCaml's Dream web framework on the
|
||||
SX CEK** — the chosen ergonomic HTTP layer for the rose-ash host (Dream, not Quart).
|
||||
Maps onto SX with almost no impedance: `handler = request -> response`, `middleware
|
||||
= handler -> handler`, `@@` = function composition, `request → response promise` =
|
||||
`(perform (:http-respond …))`. One feature per commit.
|
||||
|
||||
```
|
||||
description: dream-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## DO NOT START WITHOUT THE PREREQUISITE (the one gate)
|
||||
|
||||
Dream is **activated** (target user confirmed — rose-ash is moving off Quart onto
|
||||
Dream) but **gated** on the OCaml foundation:
|
||||
|
||||
1. **`ocaml-on-sx` Phases 1–5 + Phase 6 minimal stdlib green.** Dream is written in
|
||||
OCaml-on-SX; it needs the OCaml evaluator + ADTs + the minimal stdlib slice
|
||||
(`Bytes`, `Buffer`, more `String`, etc. — see the plan's "Stdlib additions").
|
||||
|
||||
**Pre-flight:**
|
||||
```
|
||||
cat /root/rose-ash/lib/ocaml/scoreboard.md 2>/dev/null | head -15
|
||||
```
|
||||
Confirm the scoreboard shows Phases 1–5 + the stdlib slice green. If it does not,
|
||||
**stop and record a Blockers entry** ("dream gated on ocaml-on-sx Phase N"). Do not
|
||||
start. The native server (`host-on-sx` Phases 1–3) carries the host until then.
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/dream-on-sx.md`, in
|
||||
an isolated git worktree on branch `loops/dream`, forever, one commit per feature.
|
||||
Push to `origin/loops/dream` after every commit. Never touch `main` or `architecture`.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/dream-on-sx.md` — Roadmap + Progress log + Blockers + the semantic
|
||||
mapping table.
|
||||
2. Run the pre-flight. If the ocaml gate is not green, stop and update Blockers.
|
||||
3. `ls lib/dream/` — pick up from the most advanced file. No dir → start at Core types.
|
||||
4. If `lib/dream/tests/*.sx` exist, run them via the epoch protocol against
|
||||
`sx_server.exe`. Green before new work.
|
||||
|
||||
## The queue
|
||||
|
||||
Roadmap per `plans/dream-on-sx.md` (five types: request, response, handler,
|
||||
middleware, route — everything else is a function over them):
|
||||
|
||||
- **Core types** (`lib/dream/types.sx`) — request/response/route records
|
||||
- **Router** (`lib/dream/router.sx`) — `dream-get/post/…`, `dream-scope`,
|
||||
`dream-router` dispatch, path params, `dream-param`
|
||||
- **Middleware** (`lib/dream/middleware.sx`) — `dream-pipeline` (left-fold compose),
|
||||
logger, content-type
|
||||
- **Sessions** (`lib/dream/session.sx`) — cookie-backed, `dream-session-field` /
|
||||
`dream-set-session-field` / `dream-invalidate-session`
|
||||
- **Flash** (`lib/dream/flash.sx`) — single-request cookie store
|
||||
- **Forms + CSRF** (`lib/dream/form.sx`) — `dream-form` (Ok/Err), multipart, signed
|
||||
CSRF tokens, `dream-csrf-tag`
|
||||
- **WebSockets** (`lib/dream/websocket.sx`) — upgrade, send/receive/close
|
||||
- **Static files** — `dream-static`, ETags, ranges
|
||||
- **`dream-run`** — wire root handler into `perform (:http-listen …)`
|
||||
- **Demos** (`lib/dream/demos/`) — hello, counter (sessions), chat (ws), todo (forms+CSRF)
|
||||
- **Tests** (`lib/dream/tests/`) — routing, middleware compose, session round-trip,
|
||||
CSRF accept/reject, flash read-after-write (60+)
|
||||
|
||||
Within a section, pick the box with the best tests-per-effort ratio.
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||||
|
||||
## Dream-specific gotchas
|
||||
|
||||
- **Don't reinvent the SX HTTP server.** Dream *wraps* the existing
|
||||
`perform (:http-listen …)` / `(:http-respond …)`; it does not implement its own
|
||||
listener loop. `dream-run` installs the root handler, no socket code.
|
||||
- **Middleware is plain composition.** `m1 @@ m2 @@ handler` = `(m1 (m2 handler))`,
|
||||
left-fold. `dream-pipeline` folds a list; identity = `dream-no-middleware`. No
|
||||
framework magic.
|
||||
- **Handler is `request -> response`** (the promise is the SX effect). Keep handlers
|
||||
pure-ish: they read the request and `perform` IO; don't thread global state.
|
||||
- **Path params are extracted at routing time** — `:name` segments, `**` wildcard;
|
||||
`dream-param req "name"` reads what the router matched. Don't re-parse the path in
|
||||
the handler.
|
||||
- **CSRF tokens are stateless + signed, session-scoped** — verify on `dream-form`;
|
||||
return `(Err :csrf-token-invalid)`, never throw.
|
||||
- **Stdlib gaps are ocaml-on-sx's job, mostly.** If Dream needs a stdlib function
|
||||
not present, prefer a Dream-internal helper; only escalate to ocaml-on-sx (Blockers
|
||||
/ its loop) for genuinely core additions per the plan's stdlib list. Per the plan,
|
||||
those land in `lib/ocaml/runtime.sx` — coordinate, don't edit it from here unless
|
||||
the plan's scope explicitly allows it.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/dream/**` and `plans/dream-on-sx.md` (plus the named stdlib
|
||||
additions in `lib/ocaml/runtime.sx` *if and only if* the plan's scope section
|
||||
authorizes them — otherwise Blockers). Do **not** edit `spec/`, `hosts/`,
|
||||
`shared/`, or other `lib/<lang>/`.
|
||||
- **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/dream`. Never `main`/`architecture`.
|
||||
(`main` push = PRODUCTION deploy — never from this loop.)
|
||||
- **Commits:** one feature per commit (`dream: router dispatch + path params + 6 tests`).
|
||||
- **Plan file:** Progress log + tick boxes every commit.
|
||||
- **Blocked 2 iterations on one issue → Blockers entry, move on.**
|
||||
|
||||
## 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 guest helpers (`dream-…` is the public surface; internal helpers `dr/…`).
|
||||
- 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. Run the pre-flight. If the ocaml-on-sx gate is not green, stop and report.
|
||||
Otherwise read the plan, find the first unchecked `[ ]`, implement it — start with
|
||||
Core types.
|
||||
122
plans/agent-briefings/elixir-loop.md
Normal file
122
plans/agent-briefings/elixir-loop.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# elixir-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/elixir-on-sx.md` forever. **Elixir on the CEK/VM** — the
|
||||
companion to `lib/erlang/`. Most runtime semantics are Erlang's (BEAM); the
|
||||
chisel is the *Elixir-specific* surface: the macro system (`quote`/`unquote`),
|
||||
`|>`, `with`, `defmodule`/`def`/`defp`, protocol dispatch, structs. One feature
|
||||
per commit.
|
||||
|
||||
```
|
||||
description: elixir-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prerequisites — check before starting
|
||||
|
||||
1. **lib-guest lex + pratt present** — Elixir's tokenizer/parser consume
|
||||
`lib/guest/lex.sx` + `lib/guest/pratt.sx`.
|
||||
2. **`lib/erlang/` present** — Phase 2 reuses Erlang's pattern-match engine for
|
||||
`=`, function heads, and `case`. Do not re-implement unification; import it.
|
||||
3. **ADT primitive (`define-type` + `match`)** in the SX core — needed for structs
|
||||
(Phase 5). Track via `plans/sx-improvements.md`.
|
||||
|
||||
**Pre-flight:**
|
||||
```
|
||||
ls /root/rose-ash/lib/guest/lex.sx /root/rose-ash/lib/guest/pratt.sx /root/rose-ash/lib/erlang/runtime.sx
|
||||
```
|
||||
If lib-guest or lib/erlang is missing, stop and record a Blockers entry. (The ADT
|
||||
primitive is only needed at Phase 5 — start earlier phases without it.)
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/elixir-on-sx.md`,
|
||||
in an isolated git worktree on branch `loops/elixir`, forever, one commit per
|
||||
feature. Push to `origin/loops/elixir` after every commit. Never touch `main` or
|
||||
`architecture`.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/elixir-on-sx.md` — Roadmap + Progress log + Blockers tell you where
|
||||
you are.
|
||||
2. Run the pre-flight. Record any missing prerequisite in Blockers.
|
||||
3. `ls lib/elixir/` — pick up from the most advanced file. No dir → Phase 1.
|
||||
4. If `lib/elixir/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.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/elixir-on-sx.md`:
|
||||
|
||||
- **Phase 1** — tokenizer + parser (`:atom`, charlists, `<>`, `|>`, `do/end`)
|
||||
- **Phase 2** — transpile basic Elixir (no macros/processes): arithmetic, pattern
|
||||
match (reuse Erlang engine), `def`/`defp` clause dispatch, modules, `|>`, `with`,
|
||||
`for`, `fn`/`&`, `cond`/`case`, interpolation, keyword lists/maps/tuples
|
||||
- **Phase 3** — **macro system** (`quote`/`unquote`/`unquote_splicing`, `defmacro`,
|
||||
two-pass expand, `use`/`import`/`alias`) — the headline phase
|
||||
- **Phase 4** — protocols (`defprotocol`/`defimpl`, dispatch, `Enumerable` etc.)
|
||||
- **Phase 5** — structs + behaviours (`defstruct`, `%Mod{}`, `@behaviour`)
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||||
|
||||
## Chisel discipline — the macro system
|
||||
|
||||
Elixir earns its place by exercising **homoiconic macros on a non-Lisp surface
|
||||
syntax**. `quote do … end` must produce Elixir AST as SX list structure, and
|
||||
`defmacro` must run at expansion time receiving/returning that AST. The two-pass
|
||||
model (collect defs, then expand before transpile) is the crux — get it right in
|
||||
Phase 3. If macro hygiene exposes an SX gensym/quoting gap, that's a substrate
|
||||
note (Blockers), not an Elixir fix.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/elixir/**` and `plans/elixir-on-sx.md`. Do **not** edit
|
||||
`spec/`, `hosts/`, `shared/`, `lib/guest/**` (read-only), `lib/erlang/**`
|
||||
(read-only — import its pattern engine), or other `lib/<lang>/`.
|
||||
- **Reuse, don't re-implement.** Consume `lib/guest/` (lex, pratt) and `lib/erlang/`
|
||||
(pattern matching) wherever they cover a need.
|
||||
- **Don't patch the substrate from this loop.** Failing core behavior → failing
|
||||
test + Blockers entry + stop.
|
||||
- **NEVER call `sx_build`** (600s watchdog). Broken `sx_server.exe` → Blockers, stop.
|
||||
- **SX files:** `sx-tree` MCP tools ONLY; `sx_validate` after every edit. Never
|
||||
`Edit`/`Read`/`Write` on `.sx`. They take `file:` not `path:`.
|
||||
- **Worktree:** commit, then push `origin/loops/elixir`. Never `main`/`architecture`.
|
||||
- **Commits:** one feature per commit. Short factual messages
|
||||
(`elixir: |> pipe desugaring + 6 tests`).
|
||||
- **Plan file:** Progress log (newest first) + tick boxes every commit.
|
||||
- **Blocked 2 iterations on one issue → Blockers entry, move on.**
|
||||
|
||||
## Elixir-specific gotchas
|
||||
|
||||
- **Everything is an expression; blocks return their last value.** `do/end` is a
|
||||
block, not a statement list — map to SX `(begin …)`.
|
||||
- **`|>` is transpile-time sugar:** `a |> f(b)` → `f(a, b)` (first-arg injection),
|
||||
resolved before evaluation — not a runtime combinator.
|
||||
- **`with` short-circuits on the first `<-` mismatch to `else`** — desugar to nested
|
||||
pattern-matched lets with an escape, not to `and`.
|
||||
- **Maps vs keyword lists:** `%{k: v}` → SX dict; `[k: v]` → SX list of `{:k v}`
|
||||
(ordered, dup keys allowed). Don't conflate them.
|
||||
- **Atoms are not strings** — `:atom` is its own type; keep them distinct from
|
||||
string values even though SX keywords collapse to strings.
|
||||
- **Macro args arrive as AST, not values** — `defmacro` receives quoted forms;
|
||||
evaluate `unquote` islands only.
|
||||
|
||||
## 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 guest helpers (`ex/…`) — short/host-colliding names get shadowed.
|
||||
- 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. Run the pre-flight. If lib-guest or lib/erlang is missing, stop and report.
|
||||
Otherwise read the plan, find the first unchecked `[ ]`, implement it.
|
||||
126
plans/agent-briefings/host-loop.md
Normal file
126
plans/agent-briefings/host-loop.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# 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.
|
||||
120
plans/agent-briefings/idris-loop.md
Normal file
120
plans/agent-briefings/idris-loop.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# idris-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/idris-on-sx.md` forever. **Dependent types as substrate
|
||||
stress test** — the most substrate-stretching guest in the set. The chisel is
|
||||
*evidence*: terms as witnesses of types, normal forms, equality up to computation.
|
||||
**Idris 2** is the target. One feature per commit.
|
||||
|
||||
```
|
||||
description: idris-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prerequisites — check before starting
|
||||
|
||||
1. **lib-guest lex + pratt + layout present** — Idris uses Haskell-like
|
||||
indentation; the parser consumes `lib/guest/lex.sx`, `lib/guest/pratt.sx`,
|
||||
`lib/guest/layout.sx`.
|
||||
2. **ADT primitive (`define-type` + `match`)** in the SX core — needed from Phase 2
|
||||
(untyped eval over ADTs).
|
||||
|
||||
**Pre-flight:**
|
||||
```
|
||||
ls /root/rose-ash/lib/guest/lex.sx /root/rose-ash/lib/guest/pratt.sx /root/rose-ash/lib/guest/layout.sx
|
||||
printf '(epoch 1)\n(define-type nat (Z) (S n))\n(epoch 2)\n(match (S (Z)) ((S k) "ok") (_ "no"))\n' \
|
||||
| /root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe 2>&1 | tail -3
|
||||
```
|
||||
If a lib-guest file is missing OR `define-type`/`match` errors instead of `"ok"`,
|
||||
**stop and record a Blockers entry.** Phases 1–2 can proceed once these are in.
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/idris-on-sx.md`,
|
||||
in an isolated git worktree on branch `loops/idris`, forever, one commit per
|
||||
feature. Push to `origin/loops/idris` after every commit. Never touch `main` or
|
||||
`architecture`.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/idris-on-sx.md` — Roadmap + Progress log + Blockers.
|
||||
2. Run the pre-flight; record gaps in Blockers.
|
||||
3. `ls lib/idris/` — pick up from the most advanced file. No dir → Phase 1.
|
||||
4. If `lib/idris/tests/*.sx` exist, run them via the epoch protocol against
|
||||
`sx_server.exe`. Green before new work.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/idris-on-sx.md` (this plan is unusually deep — expect each
|
||||
phase to take many commits):
|
||||
|
||||
- **Phase 1** — parser + layout (sigs `name : Type`, multi-clause defs)
|
||||
- **Phase 2** — untyped evaluator (strip types; ADTs + recursion run) — sanity
|
||||
check the runtime before the type checker
|
||||
- **Phase 3** — bidirectional simply-typed checking + universe hierarchy
|
||||
- **Phase 4** — Pi types + dependent functions + **NbE** conversion check (the
|
||||
evidence chisel: normalisation-by-evaluation, canonical vs neutral terms)
|
||||
- **Phase 5** — indexed families + dependent pattern matching + coverage
|
||||
- **Phase 6** — totality / termination checking
|
||||
- **Phase 7** — erasure (proof-only args deleted at runtime)
|
||||
- **Phase 8** — holes + interactive elaboration (`?name`, small tactic set)
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||||
|
||||
## Chisel discipline — evidence & normal forms
|
||||
|
||||
The substrate-validation payoff is **Phase 4's NbE conversion check**: deciding
|
||||
whether two types are equal *up to computation*. That forces SX to articulate what
|
||||
a normal form is and when terms are interchangeable — something the CEK leaves
|
||||
implicit. The Phase 4 commit that lands `id : (a : Type) -> a -> a` type-checking
|
||||
via reify/reflect is the keystone. Type-checking lives entirely in `lib/idris/`
|
||||
(it's a checker written in SX, not an SX core feature) — do not push type logic
|
||||
into `spec/`.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/idris/**` and `plans/idris-on-sx.md`. Do **not** edit
|
||||
`spec/`, `hosts/`, `shared/`, `lib/guest/**` (read-only), or other `lib/<lang>/`.
|
||||
- **Consume `lib/guest/`** (lex, pratt, layout, match). Hand-rolling defeats the goal.
|
||||
- **The type checker is yours; the evaluator is the substrate's.** Implement
|
||||
checking/NbE in SX. If the CEK can't represent a needed value form (e.g. neutral
|
||||
terms), write the failing test + Blockers entry; do not patch `spec/`.
|
||||
- **NEVER call `sx_build`** (600s watchdog). Broken binary → 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/idris`. Never `main`/`architecture`.
|
||||
- **Commits:** one feature per commit (`idris: NbE conversion for Pi + 5 tests`).
|
||||
- **Plan file:** Progress log + tick boxes every commit.
|
||||
- **Blocked 2 iterations → Blockers, move on.** This plan is hard; expect blockers.
|
||||
|
||||
## Idris-specific gotchas
|
||||
|
||||
- **Types and terms share one universe.** `Type 0 : Type 1 : …` — a type is a value;
|
||||
evaluation and checking interleave. Don't build a separate "type AST".
|
||||
- **Conversion is by normalisation, not syntax.** `2 + 2` and `4` are the *same type
|
||||
index*. Use NbE (reify after evaluate) — never structural AST equality.
|
||||
- **Dependent pattern matching refines indices.** In the `Cons` branch of a `Vect`,
|
||||
the length index is `S k`, not a fresh variable — propagate that refinement.
|
||||
- **Erased args still type-check but don't run.** Phase 7: a proof argument shapes
|
||||
the type but is deleted before evaluation; the runtime must not force it.
|
||||
- **Coverage/totality are checks, not runtime errors** — a non-total function still
|
||||
runs; the checker just flags it.
|
||||
|
||||
## 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 guest helpers (`idr/…`).
|
||||
- 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. Run the pre-flight. If lib-guest or the ADT primitive is missing, stop and
|
||||
report. Otherwise read the plan, find the first unchecked `[ ]`, implement it.
|
||||
120
plans/agent-briefings/linear-loop.md
Normal file
120
plans/agent-briefings/linear-loop.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# linear-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/linear-on-sx.md` forever. **Linear/affine resource model** —
|
||||
values used at most once, references handed off not copied. Target: **Granule**
|
||||
(graded modal types over HM). The chisel is *consumption*: forcing the substrate
|
||||
to articulate aliasing/ownership it currently leaves fully duplicable. One feature
|
||||
per commit.
|
||||
|
||||
```
|
||||
description: linear-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prerequisites — check before starting
|
||||
|
||||
1. **lib-guest lex + pratt present** — parser consumes `lib/guest/lex.sx` +
|
||||
`lib/guest/pratt.sx`.
|
||||
2. **ADT primitive (`define-type` + `match`)** for linear pairs/sums (Phase 3).
|
||||
|
||||
**Pre-flight:**
|
||||
```
|
||||
ls /root/rose-ash/lib/guest/lex.sx /root/rose-ash/lib/guest/pratt.sx
|
||||
```
|
||||
If missing, stop and record a Blockers entry.
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/linear-on-sx.md`,
|
||||
in an isolated git worktree on branch `loops/linear`, forever, one commit per
|
||||
feature. Push to `origin/loops/linear` after every commit. Never touch `main` or
|
||||
`architecture`.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/linear-on-sx.md` — Roadmap + Progress log + Blockers.
|
||||
2. Run the pre-flight; record gaps in Blockers.
|
||||
3. `ls lib/linear/` — pick up from the most advanced file. No dir → Phase 1.
|
||||
4. If `lib/linear/tests/*.sx` exist, run them via the epoch protocol against
|
||||
`sx_server.exe`. Green before new work.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/linear-on-sx.md`:
|
||||
|
||||
- **Phase 1** — parser (HM core + linear arrows `-o`, modality annotations)
|
||||
- **Phase 2** — type system: linear vs unrestricted worlds; **per-variable usage
|
||||
counting**; reject use-zero / use-twice of a linear var (the chisel)
|
||||
- **Phase 3** — linear functions + linear pattern matching (linear pairs, destructure)
|
||||
- **Phase 4** — modalities: `!A` unrestricted, promotion `[e]`, graded `[n]A`
|
||||
(semiring algebra over grades)
|
||||
- **Phase 5** — linear references / channels / file handles (type-tracked transitions)
|
||||
- **Phase 6** — effects + linearity (linear values through `perform`/handlers;
|
||||
capabilities as linear values)
|
||||
- **Phase 7** — lightweight borrowing (`borrow x as y in body`, lexical, no regions)
|
||||
- **Phase 8** — artdag idioms demo (each effect node holds a linear CID → new CID)
|
||||
- **Phase 9** — propose `lib/guest/linear/` extraction (wait for a 2nd consumer)
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||||
|
||||
## Chisel discipline — consumption
|
||||
|
||||
The payoff is **Phase 2's usage checker**: SX values are fully duplicable today;
|
||||
linearity makes "at most one use" a first-class, statically-enforced property. The
|
||||
checker is a *static analysis written in SX over the AST* — runtime values stay
|
||||
ordinary SX values (linearity is erased after checking, like types in HM guests).
|
||||
Do NOT try to make the SX runtime physically prevent aliasing; enforce it in the
|
||||
checker and let well-typed programs run on the normal CEK. Phase 6 (linear values
|
||||
crossing `perform`) is where it touches the effect system — if a handler can
|
||||
silently duplicate a resumption-captured linear value, that's a substrate note
|
||||
(Blockers), not a linear-lang fix.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/linear/**` and `plans/linear-on-sx.md`. Do **not** edit
|
||||
`spec/`, `hosts/`, `shared/`, `lib/guest/**` (read-only), or other `lib/<lang>/`.
|
||||
- **Consume `lib/guest/`** (lex, pratt, match, hm where useful).
|
||||
- **Linearity is a checker, not a runtime guard.** Enforce statically; run on the
|
||||
normal CEK. Substrate gaps → failing test + Blockers, never a `spec/` patch.
|
||||
- **NEVER call `sx_build`** (600s watchdog). Broken binary → 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/linear`. Never `main`/`architecture`.
|
||||
- **Commits:** one feature per commit (`linear: usage counting rejects double-use + 5 tests`).
|
||||
- **Plan file:** Progress log + tick boxes every commit.
|
||||
- **Blocked 2 iterations → Blockers, move on.**
|
||||
|
||||
## Linear-specific gotchas
|
||||
|
||||
- **Two type worlds, one value space.** `A -o B` (linear) and `A -> B`
|
||||
(unrestricted) are distinct *types*; the underlying SX closures are identical.
|
||||
The distinction lives only in the checker's context discipline.
|
||||
- **Context splitting is the heart of linear checking.** When checking `f x`, the
|
||||
linear context divides between `f` and `x` — a variable can't be available to
|
||||
both. Model contexts as multisets and split, don't share.
|
||||
- **Promotion has a side condition:** `[e]` is `!A` only if `e` used no linear
|
||||
variables. Enforce it; it's the usual soundness leak.
|
||||
- **Grades form a semiring** (`+` for sequencing alternatives, `*` for nesting).
|
||||
`[2]A` then used under `[3]` → `[6]A`. Get the algebra right or graded use breaks.
|
||||
- **Borrow is non-consuming and lexical** — after `borrow x as y in body`, `x` is
|
||||
still linear and unused. No lifetimes, just scopes.
|
||||
|
||||
## 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 guest helpers (`lin/…`).
|
||||
- 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. Run the pre-flight. If lib-guest is missing, stop and report. Otherwise read
|
||||
the plan, find the first unchecked `[ ]`, implement it.
|
||||
119
plans/agent-briefings/maude-loop.md
Normal file
119
plans/agent-briefings/maude-loop.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# maude-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/maude-on-sx.md` forever. **Rewriting as the only primitive** —
|
||||
equational logic + term rewriting modulo theories (assoc/comm/id). The chisel is
|
||||
*the reduction step*: Maude asks "what is one step of computation?" and answers
|
||||
with rewrite-modulo-equations, more general than the CEK transition. One feature
|
||||
per commit.
|
||||
|
||||
```
|
||||
description: maude-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prerequisites — check before starting
|
||||
|
||||
1. **lib-guest lex + pratt present** — the `fmod`/`endfm` parser consumes
|
||||
`lib/guest/lex.sx` + `lib/guest/pratt.sx`.
|
||||
|
||||
**Pre-flight:**
|
||||
```
|
||||
ls /root/rose-ash/lib/guest/lex.sx /root/rose-ash/lib/guest/pratt.sx
|
||||
```
|
||||
If missing, stop and record a Blockers entry. (Maude needs no special core
|
||||
primitive — it builds its own term/rewrite machinery in SX.)
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/maude-on-sx.md`,
|
||||
in an isolated git worktree on branch `loops/maude`, forever, one commit per
|
||||
feature. Push to `origin/loops/maude` after every commit. Never touch `main` or
|
||||
`architecture`.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/maude-on-sx.md` — Roadmap + Progress log + Blockers.
|
||||
2. Run the pre-flight; record gaps in Blockers.
|
||||
3. `ls lib/maude/` — pick up from the most advanced file. No dir → Phase 1.
|
||||
4. If `lib/maude/tests/*.sx` exist, run them via the epoch protocol against
|
||||
`sx_server.exe`. Green before new work.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/maude-on-sx.md`:
|
||||
|
||||
- **Phase 1** — parser + signatures (`fmod`/`endfm`, sorts + subsorts, op decls,
|
||||
equations; overloading by arity+sort)
|
||||
- **Phase 2** — syntactic equational reduction (apply eqs left-to-right to a fixpoint;
|
||||
strict pattern match)
|
||||
- **Phase 3** — **equational matching modulo assoc/comm/id** (the chisel: flatten AC
|
||||
operators, match across permutations/multisets; return *all* matches)
|
||||
- **Phase 4** — conditional equations (`ceq L = R if Cond`)
|
||||
- **Phase 5** — system modules + rewrite rules (`rl … => …`, asymmetric, fairness)
|
||||
- **Phase 6** — strategy language (`;`, `|`, `*`, fixed-point; named strategies)
|
||||
- **Phase 7** — reflection (META-LEVEL: terms-as-data, meta-interpretation)
|
||||
- **Phase 8** — propose `lib/guest/rewriting/` extraction (wait for a 2nd consumer)
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||||
|
||||
## Chisel discipline — the reduction step
|
||||
|
||||
The payoff is **Phase 3's AC matching**: matching modulo associativity/commutativity/
|
||||
identity is genuinely harder than the substitution the CEK does, and it's where
|
||||
Maude's "reduction step" diverges from SX's. Implement it as a term-rewriting
|
||||
engine *in SX* (terms are SX data; matching returns substitution sets). Do NOT try
|
||||
to bend the CEK into a rewriter — Maude runs *on* the CEK as an interpreter, it does
|
||||
not replace it. Note for the integrator: the AC-matching + normal-form engine is the
|
||||
prime candidate to feed an eventual `artdag-on-sx` effect-pipeline optimizer
|
||||
(`plans/artdag-on-sx.md`) — keep it cleanly separable (Phase 8).
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/maude/**` and `plans/maude-on-sx.md`. Do **not** edit
|
||||
`spec/`, `hosts/`, `shared/`, `lib/guest/**` (read-only), or other `lib/<lang>/`.
|
||||
- **Consume `lib/guest/`** (lex, pratt). The rewrite engine itself is yours.
|
||||
- **Don't patch the substrate.** Maude is an interpreter over SX terms; substrate
|
||||
gaps → failing test + Blockers entry, never a `spec/` patch.
|
||||
- **NEVER call `sx_build`** (600s watchdog). Broken binary → 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/maude`. Never `main`/`architecture`.
|
||||
- **Commits:** one feature per commit (`maude: AC matching for assoc-comm ops + 6 tests`).
|
||||
- **Plan file:** Progress log + tick boxes every commit.
|
||||
- **Blocked 2 iterations → Blockers, move on.**
|
||||
|
||||
## Maude-specific gotchas
|
||||
|
||||
- **Equations vs rules.** `eq`/`ceq` are *equational* (`=`, applied to a fixpoint to
|
||||
normalise, confluent-by-intent); `rl` are *transitions* (`=>`, asymmetric,
|
||||
possibly nondeterministic). Don't apply rules during equational reduction.
|
||||
- **AC operators flatten.** `_+_` assoc means `a + (b + c)` and `(a + b) + c` are the
|
||||
same term — normalise to a flat sequence/multiset before matching, and match
|
||||
across orderings for `comm`.
|
||||
- **Matching returns a set of substitutions, not one.** AC matching is multi-valued;
|
||||
Phase 3 must yield all matches and let the caller drive (rule application picks).
|
||||
- **Identity is a rewrite, not a special case.** `id: e` for `_*_` means `X * e ≡ X`
|
||||
in both directions — handle as an equation in the AC matcher, carefully (avoid
|
||||
infinite insertion of identities).
|
||||
- **Strategies make the same rules mean different things** — Phase 6 evaluation
|
||||
result depends on strategy; keep rule set and strategy orthogonal.
|
||||
|
||||
## 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 guest helpers (`mau/…`).
|
||||
- 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. Run the pre-flight. If lib-guest is missing, stop and report. Otherwise read
|
||||
the plan, find the first unchecked `[ ]`, implement it.
|
||||
130
plans/agent-briefings/probabilistic-loop.md
Normal file
130
plans/agent-briefings/probabilistic-loop.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# probabilistic-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/probabilistic-on-sx.md` forever. **Weighted nondeterminism +
|
||||
traces + inference** — programs declare distributions, the runtime infers.
|
||||
Church-flavoured core. The chisel is *trace*: what it means to record a weighted
|
||||
execution, and how `sample`/`observe` differ from plain nondeterminism. One
|
||||
feature per commit.
|
||||
|
||||
```
|
||||
description: probabilistic-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prerequisites — check before starting
|
||||
|
||||
1. **lib-guest lex + pratt present** — the Scheme-flavoured parser consumes
|
||||
`lib/guest/lex.sx` + `lib/guest/pratt.sx`.
|
||||
2. **Multi-shot continuations (`perform`/`cek-resume`)** must be real, not a
|
||||
single-shot stub — MH (Phase 6) re-executes from a changed choice point. This is
|
||||
the same capability `koka-on-sx` validates; confirm it before Phase 4.
|
||||
|
||||
**Pre-flight:**
|
||||
```
|
||||
ls /root/rose-ash/lib/guest/lex.sx /root/rose-ash/lib/guest/pratt.sx
|
||||
```
|
||||
If lib-guest is missing, stop and record a Blockers entry. (Phases 1–3 don't need
|
||||
multi-shot; verify multi-shot before starting Phase 4/6.)
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working
|
||||
`/root/rose-ash/plans/probabilistic-on-sx.md`, in an isolated git worktree on
|
||||
branch `loops/probabilistic`, forever, one commit per feature. Push to
|
||||
`origin/loops/probabilistic` after every commit. Never touch `main` or
|
||||
`architecture`.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/probabilistic-on-sx.md` — Roadmap + Progress log + Blockers.
|
||||
2. Run the pre-flight; record gaps in Blockers.
|
||||
3. `ls lib/probabilistic/` — pick up from the most advanced file. No dir → Phase 1.
|
||||
4. If `lib/probabilistic/tests/*.sx` exist, run them via the epoch protocol against
|
||||
`sx_server.exe`. Green before new work.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/probabilistic-on-sx.md`:
|
||||
|
||||
- **Phase 1** — parser + deterministic Scheme core on the CEK
|
||||
- **Phase 2** — `sample`/`observe` as effects (`perform :sample` / `:observe`);
|
||||
default = forward sampling
|
||||
- **Phase 3** — distribution library (uniform/normal/gamma/beta/bernoulli/
|
||||
categorical/dirichlet/poisson), each `(sample-fn, log-prob-fn)`
|
||||
- **Phase 4** — **trace recording + replay** (the chisel: a tracing handler logs
|
||||
`{:id :value :log-weight}`; a replay handler forces recorded values)
|
||||
- **Phase 5** — importance sampling (run N times, accumulate `observe` log-weights)
|
||||
- **Phase 6** — Metropolis-Hastings (**multi-shot**: re-execute from a changed
|
||||
choice point; accept/reject by Hastings ratio)
|
||||
- **Phase 7** — mean-field VI (ELBO + `lib/probabilistic/autodiff.sx`, forward-mode)
|
||||
- **Phase 8** — stdlib/idioms (mixtures, GPs, HMMs, change-point)
|
||||
- **Phase 9** — propose `lib/guest/probabilistic/` extraction (wait for a 2nd consumer)
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||||
|
||||
## Chisel discipline — trace & weight
|
||||
|
||||
Two substrate payoffs. (1) **Phase 4 trace/replay** forces SX to articulate what
|
||||
recording an execution means — every `sample` is a labelled, weighted choice in a
|
||||
trace value. (2) **Phase 6 MH** is the multi-shot continuation stress test from the
|
||||
inference side: re-running from a proposed-changed point requires `cek-resume` to
|
||||
resume the *same* captured continuation more than once. If MH gives wrong
|
||||
posteriors and the math checks out, suspect single-shot resumption — write the
|
||||
failing test + Blockers entry (the fix is in `spec/`, not this loop).
|
||||
Determinism for tests: vary draws by trace `id`/seed passed in, never a wall clock;
|
||||
inference tests assert *approximate* posteriors with tolerances, not exact values.
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/probabilistic/**` and `plans/probabilistic-on-sx.md`. Do
|
||||
**not** edit `spec/`, `hosts/`, `shared/`, `lib/guest/**` (read-only), or other
|
||||
`lib/<lang>/`.
|
||||
- **Consume `lib/guest/`** (lex, pratt). Inference machinery (IS/MH/VI, autodiff) is
|
||||
yours, in SX.
|
||||
- **Don't patch the substrate.** Multi-shot misbehavior → failing test + Blockers
|
||||
entry; the fix lives in `spec/evaluator.sx`, not here.
|
||||
- **NEVER call `sx_build`** (600s watchdog). Broken binary → 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/probabilistic`. Never
|
||||
`main`/`architecture`.
|
||||
- **Commits:** one feature per commit (`prob: trace/replay handler + 5 tests`).
|
||||
- **Plan file:** Progress log + tick boxes every commit.
|
||||
- **Blocked 2 iterations → Blockers, move on.**
|
||||
|
||||
## Probabilistic-specific gotchas
|
||||
|
||||
- **`sample` choices ≠ `conde`-style nondeterminism.** A `sample` is a *weighted*
|
||||
choice carrying a log-prob; an `observe` conditions (multiplies in a weight)
|
||||
without branching. Keep weight bookkeeping in the log domain to avoid underflow.
|
||||
- **Trace identity is the linchpin.** Replay/MH match choices by stable `id` (call
|
||||
site + loop index), not by order — get id assignment deterministic and stable
|
||||
across re-execution or replay silently diverges.
|
||||
- **MH proposes a local change, then re-executes the tail.** Only the chosen site's
|
||||
value changes; downstream `sample`s are replayed where possible. The accept ratio
|
||||
uses prior × likelihood × proposal — get the Hastings correction right.
|
||||
- **Inference is approximate.** Never assert exact posteriors; use ESS/tolerance
|
||||
checks. Seed-dependent flakiness means deterministic seeds in tests.
|
||||
- **Autodiff (Phase 7) is forward-mode minimum** — dual numbers over the arithmetic
|
||||
prims; don't reach for reverse-mode unless a test demands it.
|
||||
|
||||
## 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 guest helpers (`prob/…`).
|
||||
- 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. Run the pre-flight. If lib-guest is missing (or multi-shot is unverified before
|
||||
Phase 4), stop and report. Otherwise read the plan, find the first unchecked `[ ]`,
|
||||
implement it.
|
||||
113
plans/agent-briefings/relations-loop.md
Normal file
113
plans/agent-briefings/relations-loop.md
Normal file
@@ -0,0 +1,113 @@
|
||||
# relations-on-sx loop agent (single agent, queue-driven)
|
||||
|
||||
Role: iterates `plans/relations-on-sx.md` forever. **Cross-domain relationship
|
||||
graph on Datalog** — the internal `relations` service. Where acl asks "may X do Y"
|
||||
on Datalog, relations asks "how is X connected to Y": children, ancestors,
|
||||
reachability, the connecting path, cycles. Sits on `lib/datalog/` (its public API);
|
||||
adds a relationship vocabulary on top. One feature per commit.
|
||||
|
||||
```
|
||||
description: relations-on-sx queue loop
|
||||
subagent_type: general-purpose
|
||||
run_in_background: true
|
||||
isolation: worktree
|
||||
```
|
||||
|
||||
## Prerequisites — check before starting
|
||||
|
||||
1. **`lib/datalog/` present** with its public API (`lib/datalog/datalog.sx`).
|
||||
relations imports it; it does not reimplement the engine.
|
||||
|
||||
**Pre-flight:**
|
||||
```
|
||||
ls /root/rose-ash/lib/datalog/datalog.sx
|
||||
```
|
||||
If missing, stop and record a Blockers entry. (Investigate the Datalog public API —
|
||||
how to assert facts, add recursive rules, and run queries — before writing any
|
||||
relationship code; the plan cites `datalog.sx` as the entry point.)
|
||||
|
||||
## Prompt
|
||||
|
||||
You are the sole background agent working `/root/rose-ash/plans/relations-on-sx.md`,
|
||||
in an isolated git worktree on branch `loops/relations`, forever, one commit per
|
||||
feature. Push to `origin/loops/relations` after every commit. Never touch `main` or
|
||||
`architecture`.
|
||||
|
||||
## Restart baseline — check before iterating
|
||||
|
||||
1. Read `plans/relations-on-sx.md` — Roadmap + Progress log + Blockers.
|
||||
2. Run the pre-flight; record gaps in Blockers.
|
||||
3. `ls lib/relations/` — pick up from the most advanced file. No dir → Phase 1.
|
||||
4. If `lib/relations/tests/*.sx` exist, run them via `bash lib/relations/conformance.sh`
|
||||
(`SX_SERVER=/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe`). Green
|
||||
before new work.
|
||||
5. Read the `lib/datalog/` public API once — assert facts, recursive rules, queries.
|
||||
The acl-on-sx engine (`lib/acl/engine.sx`) is a worked example of recursive
|
||||
reachability on Datalog — read it for the *shape*, do not import it.
|
||||
|
||||
## The queue
|
||||
|
||||
Phase order per `plans/relations-on-sx.md`:
|
||||
|
||||
- **Phase 1** — schema (`rel(Src, Dst, Kind)` facts) + assert/retract api + direct
|
||||
children/parents/related queries + conformance harness
|
||||
- **Phase 2** — recursive reachability (ancestors/descendants/`reachable?`), roots/
|
||||
leaves, **cycle detection** (`reachable(X,X)`)
|
||||
- **Phase 3** — typed relations coexisting + **path explanation** (the connecting
|
||||
chain from the Datalog derivation) + distance / shortest path
|
||||
- **Phase 4** — federation (cross-instance links via mock fed-sx, peer-trust gating
|
||||
like acl's non-transitive trust, revocation)
|
||||
|
||||
Within a phase, pick the checkbox with the best tests-per-effort ratio.
|
||||
Every iteration: implement → test → commit → tick `[ ]` → Progress log → push → next.
|
||||
|
||||
## relations-specific gotchas
|
||||
|
||||
- **Reachability is the acl inheritance pattern.** `reach(X,Y) :- edge(X,Y).` /
|
||||
`reach(X,Y) :- edge(X,Z), reach(Z,Y).` — recursive Datalog, bottom-up. Read
|
||||
acl's engine for the worked shape; re-derive, don't import.
|
||||
- **Nodes are opaque ids.** relations is content-agnostic — a node is a string id;
|
||||
domains own what ids mean. Don't bake in domain semantics.
|
||||
- **Kind isolation matters.** Reachability over `parent` must not leak through
|
||||
`reply` edges unless asked — parameterize rules by kind, or filter the edge
|
||||
relation per query.
|
||||
- **Cycles are real data, not errors.** Some graphs legitimately cycle; `cycle?`/
|
||||
`acyclic?` are *queries*, not exceptions. Don't assume a DAG.
|
||||
- **The path IS the explanation** — Phase 3's connecting chain is relations' answer
|
||||
to acl's proof tree; build it from the derivation, not by re-walking edges ad hoc.
|
||||
- **Federation trust is non-transitive and gated, not auto-applied** — a peer's link
|
||||
binds only under a local trust fact (mirror acl; don't copy acl code).
|
||||
|
||||
## Ground rules (hard)
|
||||
|
||||
- **Scope:** only `lib/relations/**` and `plans/relations-on-sx.md`. Do **not** edit
|
||||
`spec/`, `hosts/`, `shared/`, `lib/datalog/**` (read-only — import its public API),
|
||||
`lib/acl/**` (read-only — reference for shape only), or other `lib/<lang>/`.
|
||||
- **Don't modify Datalog.** Shared-engine issues → failing test + 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/relations`. Never `main`/`architecture`.
|
||||
- **Commits:** one feature per commit (`relations: transitive ancestors + cycle? + 6 tests`).
|
||||
- **Plan file:** Progress log (newest first) + tick boxes every commit.
|
||||
- **Blocked 2 iterations on one issue → Blockers entry, move on.**
|
||||
- **acl convergence:** flag the shared recursive-reachability shape in the Progress
|
||||
log if you see it, but **do not extract** — see the extraction note in
|
||||
`plans/mod-on-sx.md` (extraction is the integrator's post-merge job, not a loop's).
|
||||
|
||||
## 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 guest helpers (`relations/…`) — short/host-colliding names get shadowed.
|
||||
- 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. Run the pre-flight. If `lib/datalog/` is missing, stop and report. Otherwise
|
||||
read the plan and the Datalog public API, find the first unchecked `[ ]`, implement it.
|
||||
143
plans/artdag-on-sx.md
Normal file
143
plans/artdag-on-sx.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# artdag-on-sx: Content-addressed dataflow DAG engine
|
||||
|
||||
art-dag is rose-ash's media-processing engine: a content-addressed DAG of effects,
|
||||
executed in three phases — **Analyze → Plan → Execute**. Today it's a separate
|
||||
Python stack (FastAPI + Celery + JAX + IPFS). Its *engine logic* — dependency
|
||||
analysis, scheduling, content-addressed memoization, incremental recompute,
|
||||
composable s-expression effects — is exactly the kind of declarative, substrate-shaped
|
||||
work SX excels at, and art-dag already speaks s-expressions (its `sexp_effects`).
|
||||
|
||||
This subsystem rebuilds the **engine** on SX (not the pixel-pushing): the DAG model,
|
||||
the three-phase pipeline, and the incremental/memoized executor. Media ops
|
||||
themselves (JAX kernels, IPFS pins) stay opaque — modelled as abstract node
|
||||
functions in tests, delegated to injected adapters in production. The win is that
|
||||
the same SX substrates already serve the phases:
|
||||
|
||||
- **Analyze** (deps, reachability, dirtiness) → **Datalog** (recursive reachability —
|
||||
the acl/relations shape).
|
||||
- **Plan** (schedule under constraints) → topological batching now; **miniKanren**
|
||||
for constraint-based scheduling later (optional).
|
||||
- **Execute** (composable effects + content-addressed memo) → SX's own
|
||||
`perform`/`cek-resume` + a **persist**-backed content-addressed result cache;
|
||||
incremental recompute drops the cost of re-rendering to the dirty subgraph.
|
||||
- **Optimize** (fuse/dedup effect pipelines) → term rewriting (a later, optional
|
||||
consumer of `maude-on-sx`'s engine — see `plans/maude-on-sx.md`).
|
||||
|
||||
End-state: a content-addressed dataflow engine in `lib/artdag/` with analyze, plan,
|
||||
incremental execute, effect-pipeline optimization, and a shared-cache federation
|
||||
extension — the SX heart of art-dag, with media kernels and storage injected at the
|
||||
edges.
|
||||
|
||||
## Status (rolling)
|
||||
|
||||
`bash lib/artdag/conformance.sh` → **0/0** (not yet started)
|
||||
|
||||
## Ground rules
|
||||
|
||||
- **Scope:** only `lib/artdag/**` and `plans/artdag-on-sx.md`. Do **not** edit
|
||||
`spec/`, `hosts/`, `shared/`, `lib/datalog/**`, `lib/persist/**`, or other
|
||||
`lib/<lang>/`. You may **import** the public APIs of `lib/datalog/` (analyze) and
|
||||
`lib/persist/` (memo cache / result store).
|
||||
- **Design lineage, not code reuse.** The existing Python engine lives in the
|
||||
repo's top-level `artdag/` (core/ engine, `sexp_effects/`, l1/ tasks). **Read it
|
||||
for design lineage** (the 3-phase model, the effect language, content addressing)
|
||||
— do **not** import or port its code; this is a fresh SX implementation.
|
||||
- **Media ops are opaque.** A node's op is an abstract SX function over its inputs
|
||||
in tests (e.g. `(fn (a b) …)`); real JAX/IPFS kernels are injected adapters
|
||||
behind an interface. The engine is about *scheduling/memo/incremental*, never
|
||||
pixels. Determinism: content ids and tests use only the node spec, never a clock.
|
||||
- **Content addressing is structural.** A node's id is a deterministic digest of
|
||||
`(op, sorted input-ids, params)` so identical subgraphs share an id and a cache
|
||||
slot — the core property. Use a structural digest helper; if a real SHA-256/CID
|
||||
is needed it's an injected host primitive (Blockers if absent), not hand-rolled.
|
||||
- **Shared-file issues** → "Blockers" with a minimal repro; do not fix here.
|
||||
- **SX files:** `sx-tree` MCP tools only; `sx_validate` after every edit.
|
||||
- **Commits:** one feature per commit. Keep Progress log updated and tick boxes.
|
||||
|
||||
## Architecture sketch
|
||||
|
||||
```
|
||||
DAG spec (nodes + edges) rendered results
|
||||
│ ▲
|
||||
▼ │
|
||||
lib/artdag/dag.sx lib/artdag/execute.sx
|
||||
— node = {op, inputs, params} — effect interp (perform per node)
|
||||
— content-id = digest(spec) — content-addressed memo (persist)
|
||||
— topo order, validate — incremental: only dirty nodes
|
||||
│ ▲
|
||||
▼ │
|
||||
lib/artdag/analyze.sx lib/artdag/plan.sx
|
||||
— Datalog: deps/dependents/reach — schedule: topo batches, parallelism
|
||||
— dirty propagation (dirty closure) — (miniKanren constraints, later/opt)
|
||||
│ ▲
|
||||
▼ │
|
||||
lib/artdag/optimize.sx lib/artdag/federation.sx
|
||||
— fuse adjacent ops, dead-node elim, — shared cache by content-id (L2-style)
|
||||
CSE (free from content-addressing) result import/export + provenance/trust
|
||||
```
|
||||
|
||||
## Phase 1 — DAG model + content addressing
|
||||
|
||||
- [ ] `lib/artdag/dag.sx` — node `{:op :inputs :params}`; structural content-id =
|
||||
digest of `(op, sorted input-ids, params)`; build/validate a DAG (no dangling
|
||||
inputs, no accidental cycles); topological order
|
||||
- [ ] identical-subgraph sharing: two structurally-equal nodes get the same id
|
||||
- [ ] `lib/artdag/tests/dag.sx` — id determinism, subgraph sharing, cycle/dangling
|
||||
rejection, topo order
|
||||
- [ ] `lib/artdag/conformance.sh` + scoreboard
|
||||
|
||||
## Phase 2 — Analyze (Datalog)
|
||||
|
||||
- [ ] `lib/artdag/analyze.sx` — project edges to Datalog; `deps-of`, `dependents-of`,
|
||||
transitive `reachable` (the recursive-reachability shape)
|
||||
- [ ] **dirty propagation:** given a set of changed nodes, compute the transitive
|
||||
set of dependents that must recompute (`dirty-closure`)
|
||||
- [ ] `lib/artdag/tests/analyze.sx` — deep chains, diamonds, dirty closure
|
||||
correctness, unaffected nodes stay clean
|
||||
|
||||
## Phase 3 — Plan
|
||||
|
||||
- [ ] `lib/artdag/plan.sx` — schedule into topological **batches** (each batch's
|
||||
nodes have all deps satisfied → run in parallel); respect a max-parallelism limit
|
||||
- [ ] plan over the *dirty* subset only (incremental plan)
|
||||
- [ ] `lib/artdag/tests/plan.sx` — batch correctness, parallelism cap, dirty-only plan
|
||||
- [ ] (optional/later) miniKanren constraint scheduling — flag, don't block on it
|
||||
|
||||
## Phase 4 — Execute (incremental + memoized)
|
||||
|
||||
- [ ] `lib/artdag/execute.sx` — interpret a plan: each node op runs via `perform`
|
||||
(mocked op in tests); results keyed by content-id
|
||||
- [ ] **content-addressed memo cache** backed by `lib/persist/`: a node whose
|
||||
content-id already has a stored result is skipped (cache hit)
|
||||
- [ ] **incremental execute:** re-running after a leaf change recomputes only the
|
||||
dirty closure; everything else is a cache hit
|
||||
- [ ] `lib/artdag/tests/execute.sx` — full run, cache-hit on re-run, incremental
|
||||
recompute touches only dirty nodes (assert recompute count)
|
||||
|
||||
## Phase 5 — Effect-pipeline optimization
|
||||
|
||||
- [ ] `lib/artdag/optimize.sx` — rewrite the DAG before execution: dead-node
|
||||
elimination (unreachable from outputs), common-subexpression sharing (free from
|
||||
content ids), adjacent-op fusion
|
||||
- [ ] optimizations are content-id-preserving where semantically identical; assert
|
||||
the optimized DAG produces identical results
|
||||
- [ ] `lib/artdag/tests/optimize.sx` — DCE, CSE dedup, fusion equivalence
|
||||
- [ ] (optional/later) rule-based optimization via `maude-on-sx`'s rewriting engine —
|
||||
flag the integration point, don't block on it
|
||||
|
||||
## Phase 6 — Federation (shared content-addressed cache)
|
||||
|
||||
- [ ] a result computed on one instance is reusable on another by content-id (the
|
||||
L2-registry analog): export/import `{content-id → result}` with provenance
|
||||
- [ ] trust gating — accept a remote result only from a trusted peer (mirror the
|
||||
fed trust shape; mock the transport in tests)
|
||||
- [ ] revocation/invalidation — drop a remote result if its provenance is withdrawn
|
||||
- [ ] `lib/artdag/tests/fed.sx` — remote cache hit, trust gating, invalidation
|
||||
|
||||
## Progress log
|
||||
|
||||
(loop fills this in)
|
||||
|
||||
## Blockers
|
||||
|
||||
(loop fills this in)
|
||||
@@ -1,14 +1,15 @@
|
||||
# Dream-on-SX: OCaml's Dream web framework on the SX CEK
|
||||
|
||||
`[deferred — depends on ocaml-on-sx + a target user]`
|
||||
`[activated — target user confirmed; gated only on ocaml-on-sx]`
|
||||
|
||||
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.
|
||||
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 is now the **chosen framework layer for the rose-ash host**: the decision is to move off Quart and adopt Dream (not Quart) as the ergonomic HTTP front door over the native SX server. `plans/host-on-sx.md` Phase 4 is the concrete consumer that pulls 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.
|
||||
**Target user — CONFIRMED.** The earlier "needs a concrete target user" condition is met: rose-ash itself is the user — the subsystems (feed/acl/mod/commerce/identity/…) need an ergonomic HTTP front door, and the project owner has chosen Dream over Quart for it. This plan is no longer cold; it is *gated*, not deferred.
|
||||
|
||||
If those conditions are not met, this plan stays cold.
|
||||
**Do not start without (the one remaining gate):**
|
||||
1. OCaml-on-SX Phases 1–5 + Phase 6 minimal stdlib green. (As of writing ocaml-on-sx is at 480/480 and advancing — verify its scoreboard covers Phases 1–5 + the stdlib slice before starting.)
|
||||
|
||||
Until that gate is green, the native server (host-on-sx Phases 1–3) carries the host; do not block host migration on Dream.
|
||||
|
||||
## Why this might be worth doing (when the time comes)
|
||||
|
||||
|
||||
107
plans/relations-on-sx.md
Normal file
107
plans/relations-on-sx.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# relations-on-sx: Cross-domain relationship graph on Datalog
|
||||
|
||||
rose-ash's internal `relations` service tracks parent/child and peer relationships
|
||||
*across* domains — a blog post's comments, a thread's replies, a product's
|
||||
variants, an order's line items, a resource's containment tree, a federated
|
||||
content's origin. The questions are graph questions: who are X's children? its
|
||||
ancestors? is A reachable from B? what's the chain that connects them? is there a
|
||||
cycle?
|
||||
|
||||
That is recursive Datalog in one rule — the same bottom-up reachability `acl-on-sx`
|
||||
uses for group/resource inheritance. Decisions come with a **trace**: not just
|
||||
"yes, related," but the path that proves it. relations is an **internal-only**
|
||||
service (no public URL); other domains call it to resolve hierarchy and linkage.
|
||||
|
||||
End-state: a Datalog-on-SX layer for typed relationship facts, with reachability,
|
||||
path explanation, cycle detection, and a federation extension for cross-instance
|
||||
links. Reuses `lib/datalog/` — does not reimplement the engine.
|
||||
|
||||
## Status (rolling)
|
||||
|
||||
`bash lib/relations/conformance.sh` → **0/0** (not yet started)
|
||||
|
||||
## Ground rules
|
||||
|
||||
- **Scope:** only `lib/relations/**` and `plans/relations-on-sx.md`. Do **not** edit
|
||||
`spec/`, `hosts/`, `shared/`, `lib/datalog/**`, or other `lib/<lang>/`. You may
|
||||
**import** from `lib/datalog/` (public API in `lib/datalog/datalog.sx`); do not
|
||||
copy or modify Datalog.
|
||||
- **Shared-file issues** → "Blockers" with a minimal repro; do not fix here.
|
||||
- **SX files:** `sx-tree` MCP tools only; `sx_validate` after every edit.
|
||||
- **Architecture:** relationships are `rel(Src, Dst, Kind)` Datalog facts;
|
||||
reachability/ancestry are recursive rules; the proof tree is the connecting path;
|
||||
the lifecycle (assert/retract) is an SX layer over the db. Keep relations
|
||||
*content-agnostic* — a node is an opaque id string; domains own what ids mean.
|
||||
- **Shared with acl-sx:** both run on Datalog and both lean on the same recursive-
|
||||
reachability shape (`reach(X,Y) :- edge(X,Y).` / `reach(X,Y) :- edge(X,Z), reach(Z,Y).`).
|
||||
Watch for it; flag convergence in the Progress log, but **do not extract** —
|
||||
`plans/mod-on-sx.md` records why cross-subsystem extraction waits for the
|
||||
architecture integrator with all consumers in view.
|
||||
- **Commits:** one feature per commit. Keep Progress log updated and tick boxes.
|
||||
|
||||
## Architecture sketch
|
||||
|
||||
```
|
||||
relate(src, dst, kind) query
|
||||
│ │
|
||||
▼ ▼
|
||||
lib/relations/schema.sx lib/relations/engine.sx
|
||||
— rel(Src,Dst,Kind) facts — children/parents/ancestors/descendants
|
||||
— kind vocabulary — reachable?(A,B), cycle?(X)
|
||||
│ ▲
|
||||
▼ │
|
||||
lib/relations/api.sx lib/relations/explain.sx
|
||||
— relate / unrelate — path(A,B): the connecting chain
|
||||
— registry over a live db (from the Datalog derivation)
|
||||
│
|
||||
▼
|
||||
lib/relations/federation.sx
|
||||
— cross-instance links via fed-sx (replicated rel facts, peer-trust gated)
|
||||
```
|
||||
|
||||
## Phase 1 — Schema + direct relations
|
||||
|
||||
- [ ] `lib/relations/schema.sx` — `rel(Src, Dst, Kind)` fact projection; a small
|
||||
kind vocabulary (`parent`, `member`, `reply`, `variant`, `origin`, …) kept open
|
||||
- [ ] `lib/relations/api.sx` — `(relations/relate src dst kind)` / `(unrelate …)`
|
||||
over a live Datalog db (assert/retract); `(children-of db node kind)`,
|
||||
`(parents-of db node kind)`, `(related db node kind)`
|
||||
- [ ] `lib/relations/tests/direct.sx` — assert/retract, direct children/parents,
|
||||
kind filtering, unknown node → empty
|
||||
- [ ] `lib/relations/conformance.sh` + scoreboard
|
||||
|
||||
## Phase 2 — Reachability + cycles
|
||||
|
||||
- [ ] recursive reachability rules: `ancestors`, `descendants`, `reachable?(A,B)`
|
||||
(transitive closure over a kind, the acl inheritance shape)
|
||||
- [ ] `roots` / `leaves` (no parents / no children) for a kind
|
||||
- [ ] cycle detection: `cycle?(X)` ⇔ `reachable(X, X)`; `acyclic?(db, kind)`
|
||||
- [ ] `lib/relations/tests/reach.sx` — deep chains, diamonds, disconnected nodes,
|
||||
self-loops, multi-kind isolation
|
||||
|
||||
## Phase 3 — Typed relations + path explanation
|
||||
|
||||
- [ ] multiple kinds coexisting; mixed-kind vs single-kind reachability
|
||||
- [ ] `lib/relations/explain.sx` — `(path db a b kind)` returns the connecting
|
||||
chain (the relationship equivalent of acl's proof tree), nil if unreachable
|
||||
- [ ] `(distance db a b kind)` (hops) + shortest-path selection
|
||||
- [ ] `lib/relations/tests/path.sx` — path correctness, shortest among many, no-path
|
||||
|
||||
## Phase 4 — Federation
|
||||
|
||||
- [ ] cross-instance relationships — a peer asserts `rel(local, remote, kind)`;
|
||||
replicate rel facts via fed-sx (mock the transport in tests)
|
||||
- [ ] trust gating — a peer's link binds locally only under a local trust fact
|
||||
(mirror acl's non-transitive `trust`/gate-in-engine model; do NOT copy acl code,
|
||||
re-derive the shape)
|
||||
- [ ] revocation — retract a replicated link; reachability re-saturates
|
||||
- [ ] `lib/relations/tests/fed.sx` — federated reachability chains, trust gating,
|
||||
revocation
|
||||
|
||||
## Progress log
|
||||
|
||||
(loop fills this in)
|
||||
|
||||
## Blockers
|
||||
|
||||
(loop fills this in)
|
||||
Reference in New Issue
Block a user