host: factor the shared composition CORE — one fold, N domains (composition step 8)
The roadmap's capstone: now that two folds exist (render, execute), extract the machinery
they share. host/comp-fold (compose.sx) is the reusable core — the seq/alt/each combinator
dispatch + the `when` predicate set (host/comp--pred?) + the context-environment + the `each`
source (host/comp--source) + recursion + the depth guard, ALL in one place. A domain plugs in
via a small dict {:empty :combine :leaf :overflow}; only its leaves and how results combine
differ:
render = {:empty "" :combine str …} leaf -> markup (+ row/grid layout combinators)
execute = {:empty (list) :combine concat …} leaf -> effect
host/comp-render and host/exec-run are now one-liners over host/comp-fold with their domain.
execute.sx shed its own seq/alt/each dispatch — it's just a dict + a leaf. A THIRD domain
(eval/reduce/extent over the same algebra) is now only a new dict + leaf, no new control flow.
Both folds went through the core with ZERO behaviour change: new tests/compose.sx exercises
the core + render domain directly (17/17 — leaves, seq, row, alt+when (has/eq/not), each
(items/query/empty), tmpl recursion over a (children) tree + depth guard, ref transclude, one
object two contexts); execute 13/13; blog 162/164 (2 pre-existing relate-picker fails). Full
host conformance 388/390. Wired tests/compose.sx into conformance.
plans/composition-objects.md roadmap steps 1-8 COMPLETE.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -134,8 +134,17 @@ Transclusion = a `ref` leaf. Sort/filter/limit/group = the *source query* langua
|
||||
execute picks the SAME branch → effect. A publish workflow (validate→branch→notify-each) runs as
|
||||
one execute-fold. The behaviour model (Slice 9) is "an execute-fold over a composition object",
|
||||
not a separate system. 13/13 (execute suite). Wired into conformance + serve.
|
||||
8. **Factor out the shared machinery** once two folds exist: the fork model (ordered, labelled,
|
||||
`when`), the combinator dispatch, the context-environment, and recursion become a reusable
|
||||
`compose` core; each domain (`render`, `execute`, `eval`, …) supplies only its leaf + combinator
|
||||
semantics. The block editor + the metamodel UI then generalise to *every* fold — one composition
|
||||
editor authors documents, workflows, queries, and pipelines alike.
|
||||
8. **(done)** Factor out the shared machinery. `host/comp-fold` (compose.sx) is the reusable
|
||||
core: the seq/alt/each combinator dispatch + the `when` predicate set + the context-environment
|
||||
+ the `each` source + recursion + the depth guard, ALL in one place. A domain plugs in via a
|
||||
dict `{:empty :combine :leaf :overflow}` — only its leaves and how results combine. render =
|
||||
`{:empty "" :combine str …}` (leaf → markup, + row/grid layout combinators); execute =
|
||||
`{:empty (list) :combine concat …}` (leaf → effect). Both folds went through the core with zero
|
||||
behaviour change (compose suite 17/17, execute 13/13, blog 162/164 — the 2 fails pre-existing).
|
||||
A third domain (`eval`/`reduce`/`extent`) is now just a new dict + leaf. The block editor +
|
||||
metamodel UI generalise to *every* fold — one composition editor for documents, workflows,
|
||||
queries, pipelines alike.
|
||||
|
||||
## Status: roadmap COMPLETE (steps 1-8). Remaining polish: Playwright live-swap check for the
|
||||
block editor; `alt`/`each` block insertion in the editor; a live workflow object executed via the
|
||||
execute-fold (the way `/compose-demo` shows the render-fold); a third domain to exercise the core.
|
||||
|
||||
Reference in New Issue
Block a user