You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Tracking issue for the Gossamer loader / GUI bring-up items that remain after PR #212 (workflow + initial loader prep) and PR #217 (loader stub tightening). All items are scoped to src/ui/gossamer/ unless noted.
hyperpolymath/ephapax#36 — single .eph → .wasm CLI subcommand. The build workflow already auto-promotes when just compile-affine, ephapax-cli compile-eph, or ephapax-cli compile-affine ships upstream; nothing hypatia-side is needed until it lands.
Loader runtime (src/ui/gossamer/loader.js)
Multi-channel IPC.makeGossamerHost holds a single global ws. A second ipc_open call clobbers the first without closing it (socket leak) and any prior recvQueue is lost. Replace with a Map<handle, { ws, recvQueue }> keyed by handle; allocate fresh handles per ipc_open, look them up in ipc_recv / ipc_send / ipc_close.
ipc_send reads no bytes. Currently a no-op even when the WS is open. Once the bytes ABI is pinned (likely "ptr + leading i32 len" mirroring strings, but unconfirmed), read [ptr+4, ptr+4+len) from memory.buffer and ws.send(bytes). Surface the assumption in the same comment as readEphapaxString.
ipc_recv real return path. Currently returns 0 (stubbed in refactor(gossamer): tighten loader stubs from PR #212 review #217). Real signature returns a bytes pointer into wasm memory; needs cooperation with a wasm-side allocator export (__alloc(len) -> ptr or equivalent). Spec out with bridge.eph maintainer before implementing.
ws.send race on open. WebSocket isn't OPEN immediately after new WebSocket(). If ipc_send is called before onopen fires, the message is silently dropped. Buffer pending sends in the per-handle state and flush on onopen.
DataView recreation per readEphapaxString call. Minor perf — cache and invalidate on memory.grow (buffer detaches on grow, so listen via a manual flag or rebuild on each byteLength mismatch).
ipc_send body ABI assumption. Once chore(deps): bump actions/checkout from 4.1.1 to 6.0.2 #36 lands and emits a real wasm artifact, confirm whether bytes are {ptr, len} vs {ptr-to-header, header=i32-len}. The latter is what strings use; bytes may differ.
Loader smoke harness (no upstream dep)
Add a Node-side test (Vitest or plain node --test) that builds a tiny fixture .wasm (or assembles WAT with wabt) declaring the gossamer imports + a no-op hypatia_init/_update/_view/_subs and instantiates it through loader.js. Locks the import-surface contract so a future bridge.eph rename breaks CI rather than the browser smoke test.
Once the harness exists, drop a CI job that runs it on PRs touching src/ui/gossamer/**. Lightweight — should run on the existing Elixir runner.
After ephapax#36 lands and the workflow produces a real artifact, replace the "manual smoke" section with the actual CI-driven smoke (e.g. Playwright loading the uploaded artifact against a backing OTP listener in CI).
Tracking issue for the Gossamer loader / GUI bring-up items that remain after PR #212 (workflow + initial loader prep) and PR #217 (loader stub tightening). All items are scoped to
src/ui/gossamer/unless noted.Upstream gate (blocks DoD item 1 of #196)
hyperpolymath/ephapax#36— single.eph→.wasmCLI subcommand. The build workflow already auto-promotes whenjust compile-affine,ephapax-cli compile-eph, orephapax-cli compile-affineships upstream; nothing hypatia-side is needed until it lands.Loader runtime (
src/ui/gossamer/loader.js)makeGossamerHostholds a single globalws. A secondipc_opencall clobbers the first without closing it (socket leak) and any priorrecvQueueis lost. Replace with aMap<handle, { ws, recvQueue }>keyed by handle; allocate fresh handles peripc_open, look them up inipc_recv/ipc_send/ipc_close.ipc_sendreads no bytes. Currently a no-op even when the WS is open. Once the bytes ABI is pinned (likely "ptr + leading i32 len" mirroring strings, but unconfirmed), read[ptr+4, ptr+4+len)frommemory.bufferandws.send(bytes). Surface the assumption in the same comment asreadEphapaxString.ipc_recvreal return path. Currently returns0(stubbed in refactor(gossamer): tighten loader stubs from PR #212 review #217). Real signature returns a bytes pointer into wasm memory; needs cooperation with a wasm-side allocator export (__alloc(len) -> ptror equivalent). Spec out with bridge.eph maintainer before implementing.ws.sendrace on open. WebSocket isn't OPEN immediately afternew WebSocket(). Ifipc_sendis called beforeonopenfires, the message is silently dropped. Buffer pending sends in the per-handle state and flush ononopen.DataViewrecreation perreadEphapaxStringcall. Minor perf — cache and invalidate onmemory.grow(bufferdetaches on grow, so listen via a manual flag or rebuild on eachbyteLengthmismatch).ipc_sendbody ABI assumption. Once chore(deps): bump actions/checkout from 4.1.1 to 6.0.2 #36 lands and emits a real wasm artifact, confirm whether bytes are{ptr, len}vs{ptr-to-header, header=i32-len}. The latter is what strings use; bytes may differ.Loader smoke harness (no upstream dep)
node --test) that builds a tiny fixture.wasm(or assembles WAT withwabt) declaring thegossamerimports + a no-ophypatia_init/_update/_view/_subsand instantiates it throughloader.js. Locks the import-surface contract so a future bridge.eph rename breaks CI rather than the browser smoke test.src/ui/gossamer/**. Lightweight — should run on the existing Elixir runner.Docs
README.adoc(PR feat(gossamer): prep for end-to-end .eph→.wasm compile (#196) #212).iex -S mix/mix run --no-halt, notmix phx.server) (PR refactor(gossamer): tighten loader stubs from PR #212 review #217).Cross-links
Filed by Claude Code from review of PR #212.