3.8 KiB
content-on-sx: Documents, blocks & collaborative editing on Smalltalk
DRAFT outline. The CMS vertical — blog, WYSIWYG editor, Ghost sync. Depends on
persist-on-sx(document history as an event log). Ghost/CMS sync stays a thin external adapter (Python/FFI) until a native replacement exists.
rose-ash's blog domain is content management: a block-based WYSIWYG editor,
navigation, Ghost CMS sync. A document is a tree of live blocks; editing is a
stream of operations; collaboration needs conflict-free merge. That is an object
model — blocks are objects, edits are messages, and a document is the object graph
responding to them. Smalltalk's "everything is an object responding to messages"
maps directly to a block/WYSIWYG model, and a semilattice (CRDT) merge keeps
concurrent edits conflict-free.
End-state: a Smalltalk-on-SX document model (typed blocks, structural ops), operation log + CRDT merge for collaborative editing, versioning/history via the event store, and a render boundary to HTML/SX. External CMS (Ghost) sync is an injected adapter, not core.
Status (rolling)
bash lib/content/conformance.sh → 0/0 (not yet started)
Ground rules
- Scope: only
lib/content/**andplans/content-on-sx.md. May import fromlib/smalltalk/, and (once it exists)lib/persist/. Do not edit substrates. - Architecture: a document is an ordered tree of blocks (objects); an edit is a
message (
insert/update/move/delete); concurrent edits merge via a commutative (CRDT/semilattice) operation so order doesn't matter. History is thepersistevent stream; any version is a replay. - Determinism: merge must be commutative + idempotent (test: apply ops in any order / twice → same document).
- Commits: one feature per commit. Progress log + tick boxes.
Architecture sketch
Edit op Rendered document
(insert block after id) ... HTML / SX tree
│ ▲
▼ │
lib/content/block.sx lib/content/render.sx
— typed blocks as objects — block tree → HTML/SX
— heading/text/image/embed — (reuses SX render boundary)
│ ▲
▼ │
lib/content/doc.sx lib/content/merge.sx
— ordered block tree — CRDT/semilattice op merge
— apply op, structural moves — concurrent-edit reconciliation
│ ▲
▼ │
lib/content/api.sx ── (content/edit) (content/render) (content/history) ──┐
│ │
├── op log + versions → persist │
└── Ghost/CMS sync → injected external adapter (thin, non-core) ──┘
Phase 1 — Block document model
block.sx— typed block objectsdoc.sx— ordered tree, apply edit op, structural movesrender.sx— block tree → HTML/SXapi.sx+ tests + scoreboard + conformance.sh
Phase 2 — Op log + versioning
- edit ops as
persistevents; replay to any version (content/history doc), diff between versions
Phase 3 — Collaborative merge (CRDT)
- commutative/idempotent op merge
- concurrent-edit tests (any order, double-apply → identical)
Phase 4 — External sync + federation
- Ghost/CMS sync via injected adapter (import/export)
- federated documents (peer-authored blocks) — trust-gated stub
- tests: round-trip import/export, conflict on concurrent external edit
Progress log
(loop fills this in)
Blockers
(loop fills this in)