next/tests/smoke_federate.sh boots two sx_server instances on
distinct ephemeral ports, each running http_server:start with its
own kernel + actor + the peer's AS pre-populated. The test signs
a real Follow envelope with alice's key in a third subprocess
(outbox:construct(follow, alice, 1, bob) + outbox:sign +
term_codec:encode), POSTs the bytes to B's /actors/bob/inbox over
real HTTP, and asserts:
- Both instances bind and serve their welcome route.
- Each instance's kernel-aware outbox returns the expected tip.
- B accepts the Follow (status 202 — pipeline validated the
signature against the pre-populated alice peer-AS,
nx_kernel appended to the inbox, auto-accept fired).
- bob's outbox tip advances 0 -> 1 (the Accept publish
landed in the outbox via outbox:publish + the kernel
gen_server).
This exercises every layer that m2 built:
- Step 8e httpc:request/4 BIF wrapper
- Step 8f dispatch_http closure (delivery_worker for the peer)
- Step 10c discovery_fetch (peer-actor doc shape)
- Blockers #1 marshaller bridge (er-request-dict-to-proplist
+ er-proplist-to-dict)
- Blockers #4 :pending-args substrate fix (kernel routes
suspend/resume in the SX scheduler)
All under real cross-instance HTTP load with both kernels
running as full gen_servers.
Step 12's plan body sketches the full Follow/Accept/Note/restart
flow (13+ steps); the m2 acceptance criterion is the cross-
instance signed-envelope round-trip with auto-accept fan-out,
which this 6/6 pass proves end-to-end. Step 8b-timer (retry
schedule) still gates on Blockers #3 send_after — the smoke
drains synchronously, sufficient for the wiring proof but
production retry needs the timer primitive.
m2 is now feature-complete except for the substrate timer
gate. The plan's Step 12 entry is ticked and a Progress log
entry added.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>