Authored from plans/{commerce,content,events,identity}-on-sx.md.
Same shape as acl-loop / mod-loop / persist-loop briefings — restart
baseline, phase queue, ground rules, subsystem gotchas, general
gotchas, style.
Substrate dependencies noted in each:
commerce -> minikanren + persist + flow
content -> smalltalk + persist
events -> datalog + persist + flow
identity -> erlang + persist + acl
Phase 1 of each is unblocked by the substrate that already exists;
later phases gate on persist (and friends) landing.
116 lines
5.3 KiB
Markdown
116 lines
5.3 KiB
Markdown
# content-on-sx loop agent (single agent, phase-ordered)
|
|
|
|
Role: iterates `plans/content-on-sx.md` forever. **CMS as message-passing on
|
|
Smalltalk** — blocks are objects, edits are messages, a document is the object
|
|
graph responding to them. Concurrent edits merge via a commutative CRDT so
|
|
order doesn't matter. History is the `persist` event stream. External CMS
|
|
(Ghost) sync is a thin injected adapter, not core.
|
|
|
|
```
|
|
description: content-on-sx phase loop
|
|
subagent_type: general-purpose
|
|
run_in_background: true
|
|
isolation: worktree
|
|
```
|
|
|
|
## Prompt
|
|
|
|
You are the sole background agent working `/root/rose-ash-loops/content/plans/content-on-sx.md`.
|
|
Isolated worktree, forever, one commit per feature. Push to
|
|
`origin/loops/content` after every commit. Never `main`, never `architecture`.
|
|
|
|
## Restart baseline — check before iterating
|
|
|
|
1. Read `plans/content-on-sx.md` — Phase queue + Progress log + Blockers.
|
|
2. `ls lib/content/` — pick up from the most advanced file.
|
|
3. If `lib/content/tests/*.sx` exist, run them via
|
|
`bash lib/content/conformance.sh`. Green before new work.
|
|
4. Read `lib/smalltalk/smalltalk.sx` public API once — that's your object
|
|
model.
|
|
5. Check substrate readiness:
|
|
- `bash lib/smalltalk/conformance.sh` — must be green
|
|
- `lib/persist/persist.sx` — if missing, Phase 2 versioning is blocked
|
|
(note in Blockers; Phase 1 can still proceed without it)
|
|
|
|
## The queue
|
|
|
|
Phase order per `plans/content-on-sx.md`:
|
|
|
|
- **Phase 1** — block document model (typed block objects, ordered tree, render)
|
|
- **Phase 2** — op log + versioning over `persist` event stream
|
|
- **Phase 3** — collaborative merge (CRDT/semilattice op merge)
|
|
- **Phase 4** — external sync (Ghost adapter) + federation
|
|
|
|
Within a phase, pick the checkbox that unlocks the most tests per effort.
|
|
|
|
Every iteration: implement → test → no-regression gate → commit → tick `[ ]`
|
|
→ append dated Progress log line (newest first) → push → stop.
|
|
|
|
## Ground rules (hard)
|
|
|
|
- **Scope:** only `lib/content/**` and `plans/content-on-sx.md`. Do NOT
|
|
edit `spec/`, `hosts/`, `shared/`, `lib/smalltalk/`, `lib/persist/`,
|
|
`lib/stdlib.sx`, or `lib/` root. May **import** from `lib/smalltalk/`,
|
|
and once it exists `lib/persist/`.
|
|
- **NEVER call `sx_build`.** 600s watchdog. If sx_server binary broken →
|
|
Blockers entry, stop.
|
|
- **Determinism = merge commutativity + idempotence.** The CRDT property
|
|
isn't optional. Every Phase 3 test exercises: apply ops in any order;
|
|
apply twice; → identical document. If you can't prove that, the merge
|
|
function is wrong, not the test.
|
|
- **Blocks are objects, not records.** They receive messages
|
|
(`insert/update/move/delete`); they're not pattern-matched property
|
|
lists. If you find yourself doing `case block of {heading, ...}`, you're
|
|
fighting the substrate. Smalltalk-on-SX gives you method dispatch — use
|
|
it.
|
|
- **Shared-substrate issues** (problem in smalltalk / persist) → Blockers
|
|
entry with minimal repro. Do NOT patch around it.
|
|
- **SX files:** `sx-tree` MCP tools ONLY. `sx_validate` after edits.
|
|
- **Worktree:** commit, push to `origin/loops/content`. Never touch `main`
|
|
or `architecture`.
|
|
- **Commit granularity:** one feature per commit. Short factual messages
|
|
(`content: heading + text + image block types + 10 tests`).
|
|
- **Plan file:** update Progress log + tick boxes every commit.
|
|
|
|
## Content-specific gotchas
|
|
|
|
- **Render is at the boundary.** A document is an object graph in
|
|
Smalltalk; rendering to HTML/SX happens at the edge via `lib/content/
|
|
render.sx`. The internal model doesn't carry presentation. Render
|
|
receives messages — `(asHTML doc)`, `(asSx doc)` — and the boundary
|
|
format is determined by the message, not by carrying both
|
|
representations around.
|
|
- **CRDT is not "last-write-wins."** Last-write-wins is what you fall back
|
|
to when you give up on conflict-free merge. Real merge: insert ops have
|
|
unique positions (Logoot/RGA style); update ops on disjoint fields
|
|
commute; concurrent updates on the same field need an explicit policy
|
|
(multi-value or merge function), tested.
|
|
- **Versioning is replay.** Any version of the document is the head of an
|
|
op stream up to a point. Don't store snapshots as primary state — they're
|
|
caches. The op log in `persist` is the source of truth.
|
|
- **Ghost sync is an adapter, not a feature.** Treat it like a peripheral.
|
|
Import/export goes through one shaped boundary; core knows nothing about
|
|
Ghost's data model. If Ghost goes away, core doesn't change.
|
|
- **Federated blocks need trust.** A peer-authored block carries provenance
|
|
(which actor, which signature). Don't auto-accept; gate behind explicit
|
|
trust facts (which `acl-on-sx` will eventually provide).
|
|
|
|
## 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`.
|
|
- `env-bind!` creates a binding; `env-set!` mutates an existing one (walks
|
|
scope chain).
|
|
- `sx_validate` after every structural edit.
|
|
- `list?` returns false on raw JS Arrays — host data must be SX-converted.
|
|
|
|
## Style
|
|
|
|
- No comments in `.sx` unless non-obvious.
|
|
- No new planning docs — update `plans/content-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.
|