fed-sx-m2: resolve Blockers #1 — fix er-bif-http-listen marshaller bridge
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s
The er-bif-http-listen BIF body in lib/erlang/runtime.sx referenced
er-http-resp-to-sx / er-http-req-of-sx — helpers deleted by 78eae9ef
("fed-sx-m1: 8b-bridge cleanup") because the BIF body never picked
them up. Listener bound but every request handler crashed on first
call to the undefined helpers; curl got 000 / empty body.
Rewrote the sx-handler bridge to thread through the live marshallers
that the cleanup commit's message claimed were already in use:
Inbound: SX Dict {:method :path :query :headers :body}
-> er-request-dict-to-proplist
-> Erlang request proplist matching http_server:route/2 shape
(binaries for path/method/body, dict-like proplist for headers)
Outbound: Erlang [{status, N}, {headers, [{Bin, Bin}, ...]}, {body, Bin}]
-> er-proplist-to-dict
-> SX Dict matching what native http-listen serialises
(er-to-sx-deep auto-converts binary values to strings and
flattens the 2-tuple headers cons to a nested SX dict)
This is technically substrate work in lib/erlang/runtime.sx but
stays within the m2 briefing's allowed exception scope — the http
BIF wrappers (Step 8a / 8e / now 12-prep) are the explicit substrate
carve-outs. Unblocks Step 12's REAL two-instance smoke test rather
than an in-process loopback variant.
Test: next/tests/http_server_tcp.sh 5/5
- GET / -> 200
- GET /.well-known/sx-capabilities -> 200 (body contains "kernel:")
- GET /no-such-path -> 404
- POST /activity (no bearer) -> 401
- POST /activity (bad bearer) -> 401
No-regression gates green: Erlang conformance 761/761,
httpc_request 10/10, dispatch_http 10/10, http_listen_bif 5/5,
discovery_fetch 11/11, http_multi_actor 44/44, http_marshal 10/10.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1590,7 +1590,33 @@
|
||||
(not (er-fun? handler))
|
||||
(raise (er-mk-error-marker (er-mk-atom "badarg")))
|
||||
:else (let
|
||||
((sx-handler (fn (req-dict) (er-http-resp-to-sx (er-apply-fun handler (list (er-http-req-of-sx req-dict)))))))
|
||||
;; Bridge between native http-listen and Erlang handler.
|
||||
;;
|
||||
;; Inbound: native passes Req as SX Dict
|
||||
;; {:method :path :query :headers :body}
|
||||
;; converted to Erlang request proplist via the live
|
||||
;; er-request-dict-to-proplist marshaller — that's the
|
||||
;; same shape http_server:route/2 consumes (binaries
|
||||
;; for path/method/body, dict-like proplist for headers).
|
||||
;;
|
||||
;; Outbound: Erlang handler returns
|
||||
;; [{status, Int}, {headers, [{Bin, Bin}, ...]}, {body, Bin}]
|
||||
;; converted back to SX Dict via er-proplist-to-dict —
|
||||
;; binary values become SX strings, the headers cons
|
||||
;; flattens to a nested SX dict (via er-to-sx-deep's
|
||||
;; proplist-2tuple detection). Matches what native
|
||||
;; http-listen serialises to the wire.
|
||||
;;
|
||||
;; (Step 8b-bridge originally shipped parallel
|
||||
;; er-http-req-of-sx / er-http-resp-to-sx helpers; commit
|
||||
;; 78eae9ef deleted them as dead because the BIF body
|
||||
;; still referenced them — Blockers #1. This rewrite
|
||||
;; threads through the live marshallers instead.)
|
||||
((sx-handler
|
||||
(fn (req-dict)
|
||||
(let ((req-pl (er-request-dict-to-proplist req-dict)))
|
||||
(let ((resp-pl (er-apply-fun handler (list req-pl))))
|
||||
(er-proplist-to-dict resp-pl))))))
|
||||
(http-listen port sx-handler))))))
|
||||
|
||||
;; httpc:request/4(Url, Method, Headers, Body) - BRIEFING-EXCEPTION:
|
||||
|
||||
@@ -1041,21 +1041,17 @@ Pre-existing regressions inherited from the M1 closeout. Out of m2
|
||||
scope (substrate, not `next/**`), tracked here so iteration can
|
||||
proceed.
|
||||
|
||||
1. **`next/tests/http_server_tcp.sh` 0/5** — pre-existing regression
|
||||
introduced by `78eae9ef` (`fed-sx-m1: 8b-bridge cleanup`).
|
||||
`lib/erlang/runtime.sx:1593` still references `er-http-resp-to-sx`
|
||||
and `er-http-req-of-sx` in `er-bif-http-listen`'s sx-handler body,
|
||||
but the cleanup commit removed both helpers without rewriting the
|
||||
BIF. Listener binds (TCP socket accepts), but every request handler
|
||||
crashes on first call to the undefined helpers — curl gets 000 /
|
||||
empty body. Fix needs to rewrite the sx-handler body around the
|
||||
live `er-request-dict-to-proplist` / `er-proplist-to-dict`
|
||||
helpers (which the cleanup commit's message claimed are already
|
||||
in use, but which the BIF body never picked up). Substrate work,
|
||||
belongs on `loops/erlang`. m2 work continues against the in-process
|
||||
HTTP layer (`http_marshal.sh` 10/10, `http_publish_fold.sh` 10/10)
|
||||
until resolved. Confirmed pre-existing by stashing 1a's changes and
|
||||
re-running on the unmodified m1 closeout HEAD.
|
||||
1. **`next/tests/http_server_tcp.sh` 0/5** — ~~pre-existing
|
||||
regression~~ **RESOLVED 2026-06-07** during Step 12 prep. The
|
||||
`er-bif-http-listen` sx-handler in `lib/erlang/runtime.sx`
|
||||
referenced the now-deleted `er-http-resp-to-sx` /
|
||||
`er-http-req-of-sx` helpers; rewrote the bridge to thread
|
||||
through the live `er-request-dict-to-proplist` (inbound) +
|
||||
`er-proplist-to-dict` (outbound) marshallers — the same shape
|
||||
`http_server:route/2` already consumes and emits. 5/5 now
|
||||
passing. This is the surface Step 12's real two-instance smoke
|
||||
test (rather than an in-process loopback) uses to spin up each
|
||||
instance's HTTP listener.
|
||||
|
||||
2. **Native `http-request` (HTTP client) primitive missing** —
|
||||
~~discovered during Step 8e prep~~ **RESOLVED 2026-06-07** by
|
||||
@@ -1086,6 +1082,34 @@ proceed.
|
||||
|
||||
Newest first.
|
||||
|
||||
- **2026-06-07** — Blockers #1 RESOLVED. The
|
||||
`er-bif-http-listen` sx-handler in `lib/erlang/runtime.sx`
|
||||
referenced `er-http-resp-to-sx` / `er-http-req-of-sx` —
|
||||
helpers deleted by `78eae9ef` because the BIF body never
|
||||
picked them up. Rewrote the bridge to thread through the
|
||||
live marshallers `er-request-dict-to-proplist` (inbound
|
||||
SX Dict → Erlang request proplist matching what
|
||||
`http_server:route/2` consumes) and `er-proplist-to-dict`
|
||||
(outbound Erlang response proplist → SX Dict matching
|
||||
what the native http-listen primitive serialises to the
|
||||
wire). The marshallers convert binary header values to
|
||||
strings + flatten the nested headers proplist via
|
||||
`er-to-sx-deep`'s 2-tuple detection, so the response
|
||||
shape matches what http-listen expects without any
|
||||
additional shape coercion.
|
||||
`next/tests/http_server_tcp.sh` 5/5 (GET /, capabilities,
|
||||
unknown → 404, POST /activity no/bad bearer → 401).
|
||||
Conformance 761/761 + 6 adjacent gates (httpc_request,
|
||||
dispatch_http, http_listen_bif, discovery_fetch,
|
||||
http_multi_actor, http_marshal) all green.
|
||||
|
||||
This is technically substrate work in lib/erlang/runtime.sx,
|
||||
but stays within the m2 briefing's allowed exception scope
|
||||
(the http BIF wrappers — Step 8a / 8e / now 12-prep — are
|
||||
the explicit substrate carve-outs). Unblocks Step 12's
|
||||
REAL two-instance smoke test (rather than an in-process
|
||||
loopback variant).
|
||||
|
||||
- **2026-06-07** — Step 10c (closes Step 10): peer-actor doc
|
||||
fetch + cache write. New `next/kernel/discovery_fetch.erl`
|
||||
produces a 1-arity FetchFn closure for
|
||||
|
||||
Reference in New Issue
Block a user