lib/host/ta.sx — a seam transport {:emit :deliver} over a DIRECTIONAL wire (out = outbox→followers,
in = inbox←follows). The transport is the SERIALIZATION boundary: activities cross the wire as
SX-source strings (host/ta--serialize/deserialize map the keyword-keyed activity ↔ a flat
string-keyed wire form of the P2 activity fields). host/ta--make-transport(out-wire, in-wire) +
host/ta--make-mem-wire (an in-memory directional queue for tests).
Proven (ta 5/5): content + relation activities round-trip through the wire; the FEDERATION LOOP —
instance A emits an activity → the wire carries it → instance B's behavior/pump delivers + processes
it → B's engine fires ITS behavior on A's activity; DIRECTIONAL (B re-emits to its own outbox, not
back into the inbox — no loop). 'Everything works over fed-sx', proven at the seam.
TA-live (deferred, same shape as RA-live): swap the mem-wire for the real next/ delivery wire —
needs a PERSISTENT next/ kernel (gen_servers don't survive across erlang-eval-ast calls) + the ACTOR
MODEL (peer_actors/follower_graph decide who the out-wire delivers to) + pushing /activities onto it.
Full host conformance green (+ta 5).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
42 lines
2.4 KiB
Plaintext
42 lines
2.4 KiB
Plaintext
;; lib/host/ta.sx — TA: the fed-sx TRANSPORT ADAPTER (plans/business-logic-fed-flows.md). A seam
|
|
;; transport {:emit :deliver} (behavior.sx) over a directional WIRE, so an activity emitted on one
|
|
;; instance reaches another instance's engine and fires ITS behaviors — federation.
|
|
;;
|
|
;; The transport is the SERIALIZATION boundary: activities cross the wire as SX-source strings
|
|
;; (string-keyed for persist/wire safety, reconstructed on arrival). The wire is dumb string
|
|
;; transport {:send :recv}; the REAL wire is next/ delivery (outbox→peers / inbox), DEFERRED to
|
|
;; TA-live (same persistent-kernel prerequisite as RA-live); a mem-wire drives the tests.
|
|
;;
|
|
;; DIRECTIONAL: :emit → an OUT wire (this instance's outbox → followers); :deliver → an IN wire
|
|
;; (its inbox ← those it follows). Separate channels, so processing a delivered activity (which the
|
|
;; seam re-emits to log it) goes to THIS instance's outbox, NOT back into the inbox — no loop.
|
|
|
|
;; canonical activity (keyword-keyed) <-> the flat string-keyed WIRE form (persist/serialise-safe).
|
|
(define host/ta--activity->wire
|
|
(fn (a)
|
|
{"verb" (get a :verb) "actor" (get a :actor) "object" (get a :object)
|
|
"type" (get a :object-type) "slug" (get a :slug) "category" (get a :category)
|
|
"relation" (get a :relation) "target" (get a :target)
|
|
"delta" (get a :delta) "id" (get a :id)}))
|
|
(define host/ta--wire->activity
|
|
(fn (w)
|
|
{:verb (get w "verb") :actor (get w "actor") :object (get w "object")
|
|
:object-type (get w "type") :slug (get w "slug") :category (get w "category")
|
|
:relation (get w "relation") :target (get w "target")
|
|
:delta (get w "delta") :id (get w "id")}))
|
|
(define host/ta--serialize (fn (a) (serialize (host/ta--activity->wire a))))
|
|
(define host/ta--deserialize (fn (s) (host/ta--wire->activity (parse-safe s))))
|
|
|
|
;; the transport: emit serialises to the OUT wire; deliver deserialises from the IN wire.
|
|
(define host/ta--make-transport
|
|
(fn (out-wire in-wire)
|
|
{:emit (fn (a) ((get out-wire :send) (host/ta--serialize a)))
|
|
:deliver (fn () (map host/ta--deserialize ((get in-wire :recv))))}))
|
|
|
|
;; an in-memory directional wire {:send :recv} (a captured mutable queue) — the test substrate.
|
|
(define host/ta--make-mem-wire
|
|
(fn ()
|
|
(let ((q (list)))
|
|
{:send (fn (s) (set! q (concat q (list s))))
|
|
:recv (fn () (let ((batch q)) (begin (set! q (list)) batch)))})))
|