TA-live: real A→B federation over HTTP + a durable outbox (LIVE-VERIFIED)

Step 3 — federation, live-verified with TWO real host instances.

- host/ta.sx: host/ta--post/make-http-wire/federate (POST a serialized activity to a peer's /inbox
  over real HTTP). host/blog.sx: POST /inbox (host/blog-inbox → receive! → process locally, does NOT
  re-federate — no loops).
- DURABLE OUTBOX (fed-sx reliability, after the user asked 'if B is down does it still work?'):
  emit! processes locally (always succeeds), QUEUES per-peer to a persisted outbox, delivers
  best-effort. A peer being DOWN no longer fails the publish — delivery is GUARDED (SX guard catches
  the http-request connection error), failed items stay queued and retry on next emit / on boot /
  manual /flows?flush=1. /flows shows the outbox depth.
- serve.sh: SX_PEERS → peers; boot load+flush of the outbox. docker-compose: a 2nd host sx_host_b
  (peer B, own store, no peers).

LIVE PROOF: (1) a peer POSTs create/article to blog.rose-ash.com/inbox → A fires validate+notify.
(2) publish on A → federates to B → B fires ITS behaviors on A's activity (B's /flows + /activities).
(3) RESILIENCE: publish with B DOWN → A returns 303 (was 500) + queues; start B + flush → B receives
the backlog + fires. blog 218/218 (+TA receive test), full host conformance green.

A = blog.rose-ash.com (public/Caddy); B = sx_host_b (internal docker DNS only, no public domain).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 19:47:07 +00:00
parent cb0d866002
commit afb9ce5e90
6 changed files with 155 additions and 11 deletions

View File

@@ -39,3 +39,17 @@
(let ((q (list)))
{:send (fn (s) (set! q (concat q (list s))))
:recv (fn () (let ((batch q)) (begin (set! q (list)) batch)))})))
;; TA-LIVE: an HTTP fed-wire — :send POSTs a serialized activity to a PEER's /inbox over real HTTP
;; (http-request, native primitive). :recv is unused: a peer's /inbox route pushes received
;; activities straight into its engine (host/blog--receive!), so delivery is push, not poll. This is
;; the fed-sx transport in production — an activity emitted here fires a REMOTE instance's behaviors.
;; POST a pre-serialized wire string to a peer's /inbox (may raise on connection failure — callers
;; that must not fail the local emit wrap this in a guard, per the durable-outbox pattern).
(define host/ta--post (fn (peer-base s) (http-request "POST" (str peer-base "/inbox") {"content-type" "text/plain"} s)))
(define host/ta--make-http-wire
(fn (peer-base)
{:send (fn (s) (host/ta--post peer-base s))
:recv (fn () (list))}))
;; serialize an activity + POST it to a peer (direct; the outbox path serializes-then-queues instead).
(define host/ta--federate (fn (peer-base a) (host/ta--post peer-base (host/ta--serialize a))))