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