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

@@ -290,13 +290,22 @@ the flow instance Id is the resume handle.
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). This is "everything works over
fed-sx" proven at the seam. Full host conformance green.
- [ ] **TA-LIVE (deferred — same shape as RA-live).** Swap the mem-wire for the REAL next/ delivery
wire (outbox → http_server → peer inbox). Needs: (a) a PERSISTENT next/ kernel process (gen_servers
don't survive across erlang-eval-ast calls — the RA-live finding; next/ outbox/http_server are the
persistent side); (b) the ACTOR MODEL real (:actor is a "site" placeholder — peer_actors /
follower_graph / per-author identity decide WHO the out-wire delivers to); (c) push /activities
(the P2 event source) onto the out-wire. RISK: next/ delivery M2 blockers (er-scheduler context).
The transport contract + serialization + the loop are proven; TA-live is the wire impl + placement.
- [x] **TA-LIVE DONE + LIVE-VERIFIED 2026-07-02 (real two-instance A→B federation over HTTP).** The
wire is the HOST's own http-request (not next/ delivery — simpler + already persistent). host/ta--
{post, make-http-wire, federate}; the host gains a POST /inbox (host/blog-inbox → host/blog--receive!
→ process locally, does NOT re-federate). A DURABLE OUTBOX (host/blog--outbox, persisted) gives fed-
sx RELIABILITY: emit! processes locally (always succeeds), QUEUES per-peer, and delivers best-effort
— a peer being DOWN does not fail the local publish (delivery is guarded; failed items stay queued +
retry on next emit / on boot / manual /flows?flush=1). serve.sh: SX_PEERS → host/blog--set-peers!,
boot load+flush. docker-compose: a 2nd host `sx_host_b` (its own store, no peers) as peer B.
LIVE PROOF: (1) a peer POSTs a create/article to blog.rose-ash.com/inbox → A fires validate+notify.
(2) publish on A → federates to B → B's /flows fires validate+notify on A's activity; B's /activities
shows the received create. (3) RESILIENCE — publish with B DOWN → A returns 303 (was 500), activity
queued; start B + flush → B receives the backlog + fires. blog 218/218, conformance green.
NOTE on placement/domains: A = blog.rose-ash.com (Caddy/externalnet); B = sx_host_b, internal-only
(docker DNS, no public domain) — a real peer would get its own Caddy subdomain. FUTURE: the actor
model (:actor "site" placeholder → follower_graph decides WHO to deliver to); a background delivery
loop (currently retry is opportunistic on emit/boot/flush, not a timer); signature verification on /inbox.
## AX — artdag GROWS control-flow (business logic MIGRATES to artdag) [DEMAND-DRIVEN]
Today artdag is pure dataflow and the execute-fold is the synchronous control-flow runner. That's
@@ -325,6 +334,14 @@ 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 — RA-LIVE + TA-LIVE DONE + LIVE-VERIFIED. (1) sx_kernel container (durable-execution
service) deployed; the host's RA kernel-runner drives it over HTTP — editing a newsletter article →
durable Update → kernel SUSPENDS (pending) → /flows?resume → done. (2) TA federation: host POST
/inbox receives peers' activities + fires; a 2nd instance sx_host_b (peer B) — publish on A →
federates to B → B fires ITS behaviors on A's activity. (3) DURABLE OUTBOX for fed-sx reliability
(user-driven): B down → A's publish still succeeds (303, was 500) + queues; B up + flush → backlog
delivers. The whole distributed half is LIVE. Remaining polish: actor model, background delivery
timer, /inbox signature verify, expose B on a public domain.
- 2026-07-02 — the REAL KERNEL SERVICE built (next/kernel/host_kernel.erl + serve.sh + tests/
host_kernel.sh, 4/4 over HTTP). A persistent durable-execution service: flow_store + named-flow
registry, parameterised flow routes (GET /flow/start/<category> → "<id>:<status>", GET