host P0.1: publish-activity contract for federated composition-flows

Business logic as federated composition-flows (plans/business-logic-fed-flows.md). P0.1: the
host describes a published post as a fed-sx activity — host/blog--publish-activity(slug) →
{:type "create" :actor "site" :id <CID> :object {:type "article" :slug :category}} — the
exact shape next/'s trigger machinery consumes (verified: next/tests/triggers_e2e.sh 10/10).
category (drives the flow branch: newsletter suspends / urgent fires / else skip) comes from
the "category" field-value, else the first tag, else "urgent". + host/blog--post-category.

Design decided: activity log = every CID delta (event source); triggers = declared subscriptions
(DefineTrigger); flows hybrid (SX composition for simple via the execute-fold, named Erlang flows
for complex); federated execution = Erlang (next/); the type carries content+relations+behavior.

blog 200/200 (+3: contract, category fallback, missing-post nil).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 12:55:08 +00:00
parent 4c0a48834e
commit 3675d059b5
3 changed files with 110 additions and 0 deletions

View File

@@ -1160,6 +1160,29 @@
(host-bl-test "by-cid of an unknown CID is nil"
(host/blog-by-cid "znope-nope") nil)
;; ── P0.1: business-logic fed-flows — the publish-activity contract ──
;; a published post is described as a fed-sx create activity that next/'s trigger machinery
;; consumes; category (drives the flow branch) comes from a field-value, else a tag, else urgent.
(host-bl-test "publish-activity describes a published post as a fed-sx create activity"
(begin
(host/blog-put! "pub1" "Pub One" "(article (h1 \"P\"))" "published")
(host/blog--set-field-values! "pub1" {"category" "newsletter"})
(let ((a (host/blog--publish-activity "pub1")))
(list (get a :type) (get (get a :object) :type) (get (get a :object) :category)
(get (get a :object) :slug) (not (nil? (get a :id))))))
(list "create" "article" "newsletter" "pub1" true))
(host-bl-test "publish-activity category falls back to a tag, else urgent"
(begin
(host/blog-put! "pub2" "Pub Two" "(article (h1 \"Q\"))" "published")
(host/blog-seed! "urgent" "Urgent" "(article (h1 \"u\"))" "published")
(host/blog-relate! "pub2" "urgent" "tagged")
(host/blog-put! "pub3" "Pub Three" "(article (h1 \"R\"))" "published") ;; no field, no tag
(list (get (get (host/blog--publish-activity "pub2") :object) :category)
(get (get (host/blog--publish-activity "pub3") :object) :category)))
(list "urgent" "urgent"))
(host-bl-test "publish-activity of a missing post is nil"
(host/blog--publish-activity "nope-nope-nope") nil)
(define
host-bl-tests-run!
(fn ()