host P0.4: canonical seam activity shape + RA marshaller (LIVE-VERIFIED) — P0 COMPLETE

host/blog--publish-activity now emits the CANONICAL seam shape {:verb :actor :object <cid>
:object-type :slug :category :delta :id}: :object is a content-addressed REFERENCE (the CID, not an
inlined dict), :id the dedup identity, :slug+:category the domain fields the DAG reads. Consumers
reconciled — the on-publish trigger matches :verb+:object-type; publish-ctx reads top-level
:category+:slug. Added host/blog--activity->erl: marshals the canonical activity → next/'s Erlang
proplist for the Erlang runner adapter (RA) — defined + tested, unused until RA so the reconcile is
complete and RA's bridge is ready. (:ts/:prev omitted — no clock primitive in the host; deferred.)

LIVE PROOF: published on blog.rose-ash.com → /flows fired validate+notify with the canonical
activity. blog 209/209, full host conformance 597/597.

P0 COMPLETE: the synchronous publish workflow runs end-to-end on the live host through the
substrate-agnostic seam, durably, in the canonical shape, with the RA marshaller staged. RA (Erlang
runner) + TA (fed-sx transport) plug in next without touching the DAG or the wiring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 15:07:58 +00:00
parent 5b6a5e4f19
commit 77e89a9965
3 changed files with 66 additions and 23 deletions

View File

@@ -63,9 +63,8 @@ object's state changes emit activities; the platform picks runner/transport/plac
· **behavior bindings** (triggers → DAG). All composition, all editable in the type-def editor.
- **CANONICAL ACTIVITY = the seam shape** `{:verb :actor :object <cid> :object-type :delta :prev
:ts :id}`; each runner adapter MARSHALS it to its substrate (e.g. the Erlang runner → next/'s
`[{type,…},{object,[…]}]` proplist). NOTE: P0.1's host/blog--publish-activity currently emits the
next/-Erlang shape ({:type :object-dict}); P0.4 reconciles it to the canonical seam shape + a
marshaller.
`[{type,…},{object,[…]}]` proplist via host/blog--activity->erl). DONE (P0.4): host/blog--publish-
activity emits the canonical shape; host/blog--activity->erl is the RA marshaller (staged).
**Reference (one durable-runner substrate, verified):** `next/tests/triggers_e2e.sh` = 10/10 —
next/'s trigger_registry + flow_dispatch + blog_publish_digest (suspend/resume/guard/dedup). This
@@ -156,8 +155,20 @@ fed-sx yet — those are adapter phases (RA/TA). Every piece swaps later; the DA
595/595. GAP: the flow log is IN-MEMORY (clears on restart) — "durable record" is P0.3b (persist
the log to the blog store + boot-load, string-keyed to dodge the keyword/persist split). Also: the
live test post `p0.3-seam-live-test` persists (no delete route) — harmless, clean up if wanted.
- [ ] **P0.4 — canonical activity + reconcile.** Move host/blog--publish-activity to the seam shape
{:verb :actor :object <cid> :object-type :delta :ts :id}; keep the category/slug fields the DAG reads.
- [x] **P0.4 — canonical activity + reconcile. DONE + LIVE-VERIFIED 2026-07-02.** host/blog--
publish-activity now emits the CANONICAL seam shape {:verb :actor :object <cid> :object-type :slug
:category :delta :id} — :object is a content-addressed REFERENCE (the CID, was an inlined dict),
:id the dedup identity, :slug+:category the domain fields the DAG reads. Consumers reconciled: the
trigger matches :verb+:object-type; publish-ctx reads top-level :category+:slug. Added the runner
MARSHALLER host/blog--activity->erl (canonical → next/'s proplist, for RA — defined+tested, unused
until RA). (:ts/:prev omitted — no clock primitive in the host; deferred.) LIVE: published on
blog.rose-ash.com → /flows fired validate+notify with the canonical activity. blog 209/209,
conformance 597/597.
**P0 COMPLETE** — the synchronous publish workflow runs end-to-end on the LIVE host through the
substrate-agnostic seam, durably, in the canonical activity shape, with the Erlang-runner marshaller
staged. Every piece is a swappable adapter: RA (Erlang runner) + TA (fed-sx transport) plug in next
without touching the DAG or the wiring.
## P1 — types DECLARE behavior (generalize)
- [ ] The type carries :behavior = [{:on {:verb :object-type :guard} :dag <ref>}] — edited in the
@@ -214,6 +225,13 @@ covers everything until a DAG's cost/latency/placement forces the substrate.
activities), so business logic can change state, which federates, which triggers more flows.
## Progress log (newest first)
- 2026-07-02 — P0.4 DONE + LIVE-VERIFIED → **P0 COMPLETE**. Canonical seam activity shape
({:verb :object=cid :object-type :slug :category :delta :id}); consumers reconciled (trigger match,
publish-ctx); host/blog--activity->erl marshaller staged for RA. Published live → /flows fired
validate+notify with the canonical activity. blog 209/209, conformance 597/597. The synchronous
publish workflow is end-to-end on the live host through the substrate-agnostic seam, durable, in
the canonical shape. NEXT: P1 (types declare :behavior, engine built per type, runner derived via
caps) — or RA (Erlang durable runner, the marshaller is ready).
- 2026-07-02 — P0.3b DONE + LIVE-VERIFIED. The flow log is now DURABLE: the driver
persists string-keyed effect records to the blog store (dodging the keyword/persist top-level
split); host/blog-load-flowlog! rebuilds it on boot (serve.sh). Proof: published on