host P2: all state changes emit canonical activities (LIVE-VERIFIED)

Generalizes emission beyond publish to the full event source. TWO ActivityPub-faithful classes:
- CONTENT (host/blog--content-activity): Create on first publish, Update on a subsequent published
  edit. object-type is DERIVED from the post's is-a (host/blog--post-type), not hardcoded 'article'.
- RELATION (host/blog--relation-activity): Add/Remove, carrying :relation + :target (the edge).

host/blog--emit! runs any activity through behavior/process (logged + matched). emit-content-change!
(create/update) wired into form-submit + edit-submit; emit-relation! (add/remove) wired into
relate-submit + unrelate-submit.

DEBT #1 FIXED — per-EVENT :id (not the bare CID): content = create:/update:+cid; relation =
add:/remove:+src:kind:dst (EDGE-based, because a relation change doesn't shift the CID, so a
CID-based id would false-dedup different edges on one object).

The activity log is now the DURABLE EVENT SOURCE (string-keyed records under 'activitylog',
boot-loaded), surfaced at /activities — what TA will push to peers.

LIVE PROOF (blog.rose-ash.com): publish → /activities 'create article <cid>'; relate → 'add article
p2-events — add welcome related'; unrelate → 'remove …'. blog 217/217 (+4 P2, reframed P0.3 fire
tests for Update semantics), full host conformance 614/614.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 16:43:57 +00:00
parent 9d29295820
commit d13c4dd5fe
4 changed files with 165 additions and 41 deletions

View File

@@ -217,10 +217,22 @@ without touching the DAG or the wiring.
scan ALL posts, not filter by is-type? (article didn't pass is-type? on the durable store though it
did in-memory) — the type declaration is authoritative, the is-type? classification isn't reliable enough.
## P2 — state-change → activity emission (ALL events, not just publish)
<!-- PREREQ (review): fix activity identity (DEBT #1) — :id must not be the bare CID, or relation events false-dedup. -->
- [ ] Wire the host write path: put!/set-comp!/edit-submit → Create/Update; relate!/unrelate!/tag →
Add/Remove. Emit canonical activities into the transport log. Define the delta summary.
## P2 — state-change → activity emission (ALL events) — DONE + LIVE-VERIFIED 2026-07-02
- [x] TWO event classes emit canonical activities through the seam: CONTENT (host/blog--content-
activity: Create on first publish, Update on a subsequent published edit — object-type DERIVED from
is-a, not hardcoded) and RELATION (host/blog--relation-activity: Add/Remove, carrying :relation +
:target). host/blog--emit! runs any activity through behavior/process (logged + matched);
emit-content-change! (create/update) wired into form-submit + edit-submit; emit-relation!
(add/remove) wired into relate-submit + unrelate-submit.
- [x] DEBT #1 FIXED — per-EVENT :id, not the bare CID. Content = "create:"/"update:"+cid; relation =
"add:"/"remove:"+src:kind:dst (EDGE-based, since a relation change doesn't shift the CID, so a
CID-based id would false-dedup different edges on one object). Verified: different edges → different ids.
- [x] The activity log is the DURABLE EVENT SOURCE (host/blog--activity-log, string-keyed records
persisted under "activitylog", boot-loaded via host/blog-load-activitylog!). Surfaced at /activities.
This is what TA will push to peers.
- LIVE PROOF: on blog.rose-ash.com — publish → /activities "create article <cid>"; relate → "add
article p2-events — add welcome related"; unrelate → "remove …". All three classes, durable.
blog 217/217 (+4 P2, reframed P0.3 fire-once tests for Update semantics), full conformance 614/614.
## RA — the ERLANG (durable) RUNNER adapter ← the old "fed-sx spike", now an adapter
<!-- PREREQ (review): move dispatch OFF the request path (DEBT #3) — background loop calls behavior/pump; suspend can't block a request. -->
@@ -291,6 +303,12 @@ 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 — P2 DONE + LIVE-VERIFIED. All observable state changes now emit canonical activities
through the seam: content Create/Update + relation Add/Remove. DEBT #1 fixed (per-event ids; edge-
based for relations). The activity log is the durable event source, surfaced at /activities. Live:
publish→create, relate→add, unrelate→remove all logged. blog 217/217, conformance 614/614. The
event source is now complete + federatable — NEXT: RA-live (persistent kernel) or TA (fed-sx
transport pushes /activities to peers → federation).
- 2026-07-02 — P1 DONE + LIVE-VERIFIED. Types DECLARE :behavior (stored on the type-post, gathered
into a registry at boot); the trigger match consults the registry; the runner is DERIVED via
host/flow--select-runner over the fleet (DEBT #2 fixed — no hardcoded trigger, no runner hint). The