federation production layer: actor model + follower graph + delivery timer + signatures (LIVE)
The full fed-sx production layer, live-verified across A (blog.rose-ash.com) and B (sx_host_b).
ACTOR MODEL + FOLLOWER GRAPH: activities carry a real :actor (SX_ACTOR); delivery targets FOLLOWERS,
not a static peer list. A peer subscribes by POSTing {verb:follow, actor, base} to /inbox
(host/blog--add-follower!); B follows A at boot (SX_FOLLOW) so A delivers to B. host/blog--{actor,
self-base, followers, follow!, delivery-bases} + durable followers store.
BACKGROUND DELIVERY TIMER: serve.sh's detached _fed_delivery_loop hits GET /fed-tick every 15s
(over /dev/tcp) → re-follow (idempotent, recovers a target that was down at boot) + flush the durable
outbox. Federation is eventually-consistent, not best-effort-at-emit.
SIGNATURE VERIFICATION: every federated POST is signed (host/blog--fed-sign = dr/sess-sig shared-secret
MAC over the body, SX_FED_SECRET); /inbox rejects a bad/missing signature with 403 (empty secret =
open). Applies to both follows and activity delivery.
PUBLIC DOMAIN: B joins externalnet so Caddy CAN reverse_proxy a subdomain to it — the DNS + Caddy
route itself is external ops config (no local Caddyfile).
LIVE PROOF: B follows A (followers:1); publish on A → SIGNED delivery to follower B → B verifies +
fires validate+notify; a forged POST (bad x-fed-sig) → 403; B down → publish queues → the background
timer auto-delivers the backlog when B returns (no manual flush). blog 218/218, full conformance green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -34,8 +34,11 @@ services:
|
||||
# 5.4x faster (1m43s -> 19s). Default-OFF gate, opt in here.
|
||||
SX_SERVING_JIT: "1"
|
||||
OCAMLRUNPARAM: "b"
|
||||
# TA-live: federate emitted activities to peer B's /inbox (real fed-sx over HTTP).
|
||||
SX_PEERS: "http://sx_host_b:8000"
|
||||
# TA-live ACTOR MODEL: A's actor identity + base URL. A is FOLLOWED (B follows it), so A has no
|
||||
# SX_FOLLOW; it delivers its activities to its followers. SX_FED_SECRET signs/verifies fed POSTs.
|
||||
SX_ACTOR: "blog.rose-ash.com"
|
||||
SX_SELF_URL: "http://sx_host:8000"
|
||||
SX_FED_SECRET: "rose-ash-fed-2026-shared-a3f9"
|
||||
volumes:
|
||||
# SX source (hot-reload on container restart)
|
||||
- ./spec:/app/spec:ro
|
||||
@@ -99,6 +102,12 @@ services:
|
||||
SX_SESSION_SECRET: "ta-host-b-sess-9d2e1f"
|
||||
SX_SERVING_JIT: "1"
|
||||
OCAMLRUNPARAM: "b"
|
||||
# TA-live ACTOR MODEL: B's identity + base. B FOLLOWS A (SX_FOLLOW = A's base) at boot, so A
|
||||
# delivers its activities to B. Same shared SX_FED_SECRET so signatures verify across A↔B.
|
||||
SX_ACTOR: "sx_host_b"
|
||||
SX_SELF_URL: "http://sx_host_b:8000"
|
||||
SX_FOLLOW: "http://sx_host:8000"
|
||||
SX_FED_SECRET: "rose-ash-fed-2026-shared-a3f9"
|
||||
volumes:
|
||||
- ./spec:/app/spec:ro
|
||||
- ./lib:/app/lib:ro
|
||||
@@ -108,6 +117,9 @@ services:
|
||||
- ./hosts/ocaml/_build/default/bin/sx_server.exe:/app/bin/sx_server:ro
|
||||
- /root/sx-host-b-persist:/data/persist
|
||||
networks:
|
||||
# externalnet too, so a Caddy route (e.g. blog-b.rose-ash.com) can reverse_proxy to B — the
|
||||
# public-domain step is external Caddy + DNS config (not in this repo). default = A↔B fed traffic.
|
||||
- externalnet
|
||||
- default
|
||||
restart: unless-stopped
|
||||
|
||||
|
||||
Reference in New Issue
Block a user