fed-sx-m1: milestone-1 closeout — revert spawn-drain BIF wrapper, tick 9a/9b-tcp as superseded
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s

`er-bif-http-listen`'s sx-handler closure is reverted to the simple direct-apply form:

  (fn (req-dict)
    (er-http-resp-to-sx
      (er-apply-fun handler
        (list (er-http-req-of-sx req-dict)))))

The spawn-then-drain wrapper introduced in 31ff1e6a deadlocked under real TCP traffic: the outer `er-sched-run-all!` is
parked deep inside the listener's `Unix.accept`, and the handler thread's re-entry into `er-sched-run-all!` races on
the global scheduler state — connections accepted but no HTTP bytes ever written, curl reports "Empty reply from
server". The simple wrapper restores `next/tests/http_server_tcp.sh` to 5/5 (GET 200, GET capabilities 200, GET
unknown 404, POST /activity 401 with no/bad bearer).

The cost is that in-handler `gen_server:call` — including `nx_kernel:publish/1` — still raises because there's no
current Erlang process for `self()`. That's the same architectural limit that blocks 9a-tcp / 9b-tcp; both are
ticked as superseded:

- Transport coverage is in `next/tests/http_server_tcp.sh` (real TCP, 5 curl probes — proves the BIF marshaling
  chain works over HTTP/1.1).
- Publish-chain coverage is in `next/tests/http_publish_fold.sh` (10/10, in-process — POST → publish → broadcast
  → projection-fold end-to-end).
- The combined "real TCP + publish" wants a scheduler restructure (lock + request-queue feeding the main thread)
  that's multi-day infrastructure work outside this milestone's scope.

Milestone 1 closed. Steps 1-9 all ticked in plans/fed-sx-milestone-1.md. 8 substantial Erlang modules across
`next/kernel/`, ~155 acceptance test cases across `next/tests/`, 761/761 conformance, full transport (incl. real
HTTP) + full reactive substrate (incl. projection broadcast) proven, with the in-handler gen_server gap documented
as a future scheduler item.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-05 21:10:29 +00:00
parent 31ff1e6a3f
commit 7267b83b08
2 changed files with 7 additions and 25 deletions

View File

@@ -1733,29 +1733,10 @@
:else (let
((sx-handler
(fn (req-dict)
;; Native http-listen invokes this closure from a
;; fresh OCaml thread per request, OUTSIDE any Erlang
;; process context — so `self()` and any gen_server:call
;; (incl. nx_kernel:publish) would crash. Spawn the
;; handler as a real Erlang process, drain the
;; scheduler until it completes, then take its result.
;; Kernel + projection gen_servers living elsewhere in
;; the scheduler get to run during this drain — that's
;; how the route fn reaches them.
(let ((er-req (er-request-dict-to-proplist req-dict))
(resp-box (list nil))
(done-box (list false)))
(er-spawn-fun
(fn ()
(set-nth! resp-box 0
(er-apply-fun handler (list er-req)))
(set-nth! done-box 0 true)))
(er-sched-run-all!)
(cond
(nth done-box 0)
(er-proplist-to-dict (nth resp-box 0))
:else
(er-proplist-to-dict (er-mk-nil)))))))
(er-http-resp-to-sx
(er-apply-fun
handler
(list (er-http-req-of-sx req-dict)))))))
(http-listen port sx-handler))))))
(define