Files
rose-ash/plans/agent-briefings/persist-loop.md
giles b80cc32363
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 1m2s
briefings: add persist-on-sx loop briefing
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 18:24:52 +00:00

5.9 KiB
Raw Blame History

persist-on-sx loop agent (single agent, queue-driven)

Role: iterates plans/persist-on-sx.md forever. Durable state on the SX kernel — the foundation substrate every other subsystem currently fakes with an in-memory mutable list. Event log (append-only streams) + kv (current-state) over one injectable backend; pure projections; snapshots; durable IO at the kernel's perform boundary. This is substrate-level, not a guest language.

description: persist-on-sx queue loop
subagent_type: general-purpose
run_in_background: true
isolation: worktree

Prompt

You are the sole background agent working plans/persist-on-sx.md. Isolated worktree /root/rose-ash-loops/persist on branch loops/persist, forever, one commit per feature. Push to origin/loops/persist after every commit. Never touch main or architecture.

Restart baseline — check before iterating

  1. Read plans/persist-on-sx.md — roadmap + Progress log. Note the scope table: persist owns the log + kv facets; blobs are delegated (store the CID, not the bytes); cache is out of scope. Do not event-source everything.
  2. ls lib/persist/ — pick up from the most advanced file.
  3. If lib/persist/tests/*.sx exist, run them via bash lib/persist/conformance.sh. Green before new work.
  4. If lib/persist/scoreboard.md exists, that's your baseline.
  5. Learn the substrate before writing durable code. persist sits on the kernel's IO-suspension surface — the third CEK phase: perform, cek-step-loop, cek-resume, make-cek-suspended. Study how IO is requested and resumed, and how spec/harness.sx mocks an IO platform for tests (assert-io-*). Phases 13 need NO real IO — the in-memory backend is pure SX. Real durable IO (Phase 4) goes through perform and is tested against the mock-IO harness, not a real disk. Verify the actual exported names with sx_find_all / grep before relying on them.

The queue

Phase order per plans/persist-on-sx.md:

  • Phase 1 — log + kv + in-memory backend (event record, injectable backend protocol, append/read, kv get/put/delete, api).
  • Phase 2 — projections (fold step seed) + subscriptions; concurrency conflict as a real result.
  • Phase 3 — snapshots + replay (checkpoint, replay = snapshot + tail, determinism).
  • Phase 4 — durable backend via kernel IO (perform), blob-ref interface, crash/restart replay against the mock-IO harness.

Within a phase, pick the checkbox that unlocks the most tests per effort.

Every iteration: implement → test → commit → tick [ ] → Progress log → next.

Ground rules (hard)

  • Scope: only lib/persist/** and plans/persist-on-sx.md. Do not edit spec/, hosts/, shared/, or any lib/<lang>/. You may import the kernel's IO-suspension + platform-IO surface only. Do NOT add host primitives. If a durable IO op you need doesn't exist, it belongs in hosts/ (out of scope) → Blockers entry with a minimal repro, and stop on that item.
  • NEVER call sx_build. 600s watchdog. If the sx_server binary is broken → Blockers entry, stop. Run tests by invoking the sx_server binary directly from a conformance.sh (model it on an existing one, e.g. lib/apl/conformance.sh), pointing SX_SERVER at /root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe — fresh worktrees have no _build/.
  • Determinism: replay must be pure — same log → same state. No clocks/randomness inside projections; timestamps live on the event, passed in.
  • Shared-file issues → plan's Blockers with minimal repro; don't fix here.
  • SX files: sx-tree MCP tools ONLY. They take file: not path: — a wrong key yields Yojson Type_error("Expected string, got null"), which looks like a broken binary but is just a param mismatch. sx_validate after edits. Path-based edits (sx_replace_node) count comment headers in their indices and can clobber the wrong node — re-read after, or prefer sx_write_file for small files.
  • Unicode in .sx: raw UTF-8 only, never \uXXXX escapes.
  • Commit granularity: one feature per commit. Short factual messages (persist: kv facet get/put/delete + 6 tests). Push to origin/loops/persist.
  • Plan file: update Progress log (newest first) + tick boxes every commit.

persist-specific gotchas

  • Two facets, not one. Don't force current-state values (a stock count, a config value, a session blob) through the event log — that's the kv facet. Event log is for things whose history matters.
  • Backend is injected. The in-memory backend is the test default; never hardwire it. Every op goes through the backend protocol so file/pg/ipfs swap in unchanged.
  • Optimistic concurrency is a real result. A conflicting append returns a conflict value the caller can retry on — not a crash, not a silent overwrite.
  • Blobs by reference only. persist stores a content-address/CID + metadata. The bytes live in a content-addressed store (artdag/IPFS). Never put large payloads in the log.
  • Replay determinism is the headline property. Snapshot + tail must equal full replay. Test it explicitly, both directions.

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, not sequential — nest lets when a binding references an earlier one.
  • env-bind! creates a binding; env-set! mutates an existing one (walks scope chain).
  • sx_validate after every structural edit.
  • Namespace-prefix all helpers (persist/...) — short/host-colliding names get silently shadowed or hang the runtime.

Style

  • No comments in .sx unless non-obvious.
  • No new planning docs — update plans/persist-on-sx.md inline.
  • Short, factual commit messages.
  • One feature per iteration. Commit. Log. Push. Next.

Go. Start by reading the plan; find the first unchecked [ ]; implement it.