spike: PERSISTENT next/ kernel is viable — unblocks RA-live + TA-live

The shared prerequisite for both live steps was: does a next/ kernel process hold gen_server state
(flow_store) across HTTP requests? Confirmed yes. plans/ra_kernel.erl is a minimal kernel
(flow_store + register the publish-digest flow, then a blocking http:listen that keeps the
er-scheduler + gen_server alive); plans/ra-kernel-spike.sh boots it as a background sx_server and
drives it with two SEPARATE curls: GET /start suspends instance 1, GET /resume resumes that SAME
live instance → done. So durable suspend→resume across requests works on a persistent kernel.

Design decision (per the discussion): chose the persistent-kernel path (B) over host-side replay-log
(A). B serves BOTH durability (RA) and federation (TA) on one fed-sx-native substrate and exposes the
full next/ kernel (projections, outbox, actor model); A only solves flow durability and mixes Erlang
into the host process. The er-scheduler-context bug (which kills an in-process kernel, option C) does
NOT bite a separate-process kernel — er-bif-http-listen spawns each handler in-scheduler, so
gen_server:call completes. Gotchas recorded: a blocking listener hangs any in-process
erlang-eval-ast (the kernel must be a dedicated TCP-driven process), and binary =:= is buggy (always
true) so routes must pattern-match paths as byte-list binaries.

RA-live + TA-live are now BUILD work (a real kernel service + the host as HTTP client + the actor
model), not research — the prerequisite is proven.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-02 17:00:32 +00:00
parent 39e5f906f2
commit 836d32474f
3 changed files with 132 additions and 5 deletions

View File

@@ -264,11 +264,20 @@ the flow instance Id is the resume handle.
spawned processes across separate erlang-eval-ast invocations"). So a boot-per-call proves the
module (done), but TRUE async (suspend → return the request → resume LATER in another call) needs a
PERSISTENT next/ kernel PROCESS holding flow_store — the async boundary (DEBT #3) is deeper than
"off the request path". REMAINING: (a) stand up a long-lived next/ kernel (nx_kernel/http_server
already run persistently for TCP) that RA talks to; (b) wire a DURABLE behavior binding ({:erl-flow
"blog_digest" :needs (effect branch suspend)}) into the live publish engine, routed to RA via
select-runner; (c) the resumed completion re-enters via the transport inbound + behavior/pump.
The runner + marshalling + suspend/resume mechanics are all proven; this is process lifecycle + wiring.
"off the request path".
**PERSISTENT-KERNEL SPIKE PASSED 2026-07-02 (plans/ra-kernel-spike.sh + ra_kernel.erl).** A
background sx_server running `ra_kernel:start` (flow_store + a blocking http:listen keeps the
er-scheduler + gen_server alive) survives across HTTP requests: GET /start suspends instance 1, a
SEPARATE GET /resume resumes that SAME live instance → done. So a persistent kernel process IS
viable, and the er-scheduler-context fear does NOT bite (er-bif-http-listen spawns each handler
IN-scheduler, so gen_server:call completes). Gotchas: start blocking http:listen hangs any
in-process erlang-eval-ast (so the kernel is a DEDICATED process, driven over TCP, not epoch cmds);
binary =:= is buggy (always true) → dispatch paths by PATTERN (byte-list binaries), not =:=.
REMAINING for RA-live: (a) a real kernel module (flow + inbox/outbox routes) run as a persistent
service (its own container/placement); (b) the host's RA runner POSTs activities to it (start) +
the completion re-enters via the transport inbound + behavior/pump (resume); (c) a durable behavior
binding ({:erl-flow "blog_digest" :needs (effect branch suspend)}) routed to RA via select-runner.
The prerequisite is PROVEN; this is now build (kernel service + host HTTP client), not research.
## TA — the FED-SX TRANSPORT adapter ← federation proper
- [x] **TA TRANSPORT BUILT + the federation LOOP PROVEN 2026-07-02.** lib/host/ta.sx — a seam
@@ -316,6 +325,15 @@ 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 — PERSISTENT-KERNEL SPIKE PASSED (plans/ra-kernel-spike.sh + ra_kernel.erl). The shared
prerequisite for RA-live + TA-live is REACHABLE: a background sx_server (flow_store + blocking
http:listen) holds gen_server state across HTTP requests — /start suspends instance 1, a separate
/resume resumes the SAME live instance → done. The er-scheduler-context fear doesn't bite (handlers
spawn in-scheduler). Chose the persistent-kernel path (B) over host-side replay-log (A) — it serves
BOTH durability + federation on one fed-sx-native substrate + gives the full next/ kernel. Gotchas:
a blocking listener hangs in-process erlang-eval-ast (kernel = a dedicated TCP-driven process);
binary =:= buggy → pattern-match paths. RA-live/TA-live are now BUILD (kernel service + host HTTP
client + actor model), not research. NEXT: build the real kernel service + wire the host as client.
- 2026-07-02 — TA TRANSPORT built + the federation LOOP proven (lib/host/ta.sx, ta 5/5). A seam
transport over a directional wire (serialization boundary; activities cross as SX-source). Proven
in-memory: A emits → wire → B pump → B's engine fires ITS behavior on A's activity (directional, no