host: polish — a third fold domain (deps) + a live execute-fold demo (/workflow-demo)

Two concrete demonstrations of the composition architecture:

THIRD DOMAIN (proves step 8's "a new domain is just a dict + leaf, no new control flow").
host/comp-deps folds a composition to the object ids it TRANSCLUDES — the static contains
DAG of a body. It reuses host/comp-fold's seq/alt/each dispatch verbatim; only the leaf
(collect `(ref ID)`) + accumulator (concat) are new. Useful in its own right (what a
(seq (ref c0) (each … (ref …))) body pulls in; context-specific — alt picks the taken
branch). compose suite 20/20.

LIVE EXECUTE-FOLD DEMO (makes step 7 tangible, parallel to /compose-demo for render).
/workflow-demo runs ONE composition object's :body through host/exec-run — the SAME structure
the render-fold would turn into HTML, folded by execute into a plan of effects (validate →
branch on status → notify each recipient). host/blog-seed-workflow-demo! + host/blog-workflow-
demo + route + serve.sh seed. Shows the behaviour model IS an execute-fold over a composition
object — the same object the block editor authors. blog suite 165/165.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-01 05:16:56 +00:00
parent 10bc091890
commit af3d81d108
5 changed files with 77 additions and 0 deletions

View File

@@ -733,6 +733,39 @@
(each (query is-a compose-item)
(seq (text "<li><a href=\"/") (val :slug) (text "\">") (field :title) (text "</a></li>")))
(text "</ul>")))))))
;; A live demo of the EXECUTE-fold (the second fold): ONE composition object whose :body is
;; a WORKFLOW — the SAME structure the render-fold renders, folded by execute -> an effect
;; log. Parallels /compose-demo (render). GET /workflow-demo runs it and shows the effects.
(define host/blog-seed-workflow-demo!
(fn ()
(begin
(host/blog-seed! "workflow-demo" "Workflow Demo" "(article (h1 \"Workflow\"))" "published")
(host/blog--set-body! "workflow-demo"
(quote (seq
(effect validate (field :slug))
(alt (when (eq "status" "ready") (effect publish (field :slug)))
(else (effect hold (field :slug))))
(each (items {:to "alice@x"} {:to "bob@x"}) (effect notify (field :to)))))))))
;; GET /workflow-demo — run the workflow object through the execute-fold and render its
;; effect log. The same object's :body, folded by RENDER, would produce HTML; folded by
;; EXECUTE it produces this plan of effects. The behaviour model IS an execute-fold.
(define host/blog-workflow-demo
(fn (req)
(let ((effects (host/exec-run (host/blog-body-of "workflow-demo") {"slug" "post-1" "status" "ready"})))
(let ((rows (map (fn (e) (quasiquote
(li (b (unquote (get e :verb))) " "
(unquote (str (get e :args)))))) effects)))
(host/blog--resp req 200
(host/blog--page req "Workflow Demo"
(quasiquote
(div (h1 "Workflow Demo")
(p "This is ONE composition object (its :body). The render-fold would turn it into HTML; the "
(b "execute-fold") " turns the SAME structure into a plan of effects — leaves are effects, "
(code "seq") " = steps, " (code "alt") " = branch, " (code "each") " = for-each:")
(unquote (cons (quote ol) rows))
(p :style "margin-top:1em;color:#555"
"(validate → branch on status=ready → notify each recipient. The behaviour model is an execute-fold over a composition object — the same object the block editor authors.)")
(p (a :href "/compose-demo/" "→ the render-fold demo (same algebra, folded to HTML)"))))))))))
;; replace every (field "name") node in a parsed template tree with values[name] ("" if
;; absent). Pure: a tree-walk over the already-parsed template + pre-fetched values.
(define host/blog--instantiate
@@ -1871,6 +1904,7 @@
(dream-get "/new" host/blog-new-form)
(dream-get "/tags" host/blog-tags-index)
(dream-get "/meta" host/blog-meta-index)
(dream-get "/workflow-demo" host/blog-workflow-demo)
(dream-get "/:slug/source" host/blog-source)
(dream-get "/:slug/relate-options" host/blog-relate-options)
(dream-get "/:slug" host/blog-post)))