refactor(gossamer): tighten loader stubs from PR #212 review#217
Closed
hyperpolymath wants to merge 5 commits into
Closed
refactor(gossamer): tighten loader stubs from PR #212 review#217hyperpolymath wants to merge 5 commits into
hyperpolymath wants to merge 5 commits into
Conversation
Hypatia-side preparatory work for #196. Upstream hyperpolymath/ephapax#36 (single .eph→.wasm CLI subcommand) is still open, so the workflow's compile step continues to auto-promote when that lands. This commit lands the verification + loader pieces of the DoD that don't need the upstream: - Workflow: install wabt and run `wasm-validate` on the produced artifact between compile and upload. Upload is now gated on validation success. - loader.js: replace the `wasi_snapshot_preview1` stub with a `gossamer` import namespace whose surface mirrors the `extern "gossamer"` block in bridge.eph (window_open / _set_body / _close, ipc_open / _recv / _send / _close, JSON helpers). Browser stubs are minimal but sufficient to instantiate the module so the TEA exports (init/update/view/subs) remain callable from index.html. - loader.js readString: keep the {ptr, leading-i32-len} convention but add bounds checking so an Ephapax ABI mismatch surfaces as a clear RangeError instead of a silent garble. - README.adoc: note the wasm-validate step, link upstream blocker, and document the manual browser smoke procedure (the DoD allows this as a documented manual step until CI produces an artifact).
The pinned SHA `8d0a9443...` (tagged v2.51.11) is no longer resolvable by Actions and was breaking the Build Gossamer GUI workflow at "Set up job", before any of the new wasm-validate plumbing ran. Bump only this workflow's pin for now; the same SHA appears in 4 other workflows in the repo and is out of scope here.
The verify step previously hard-coded `ephapax-cli` as the binary name. Upstream Ephapax v1.0.0 doesn't currently produce a binary by that exact name (the unified CLI subcommand pinned in hyperpolymath/ephapax#36 is what would also fix the name). Until that lands, accept the first match from a known list (ephapax-cli, ephapax, epcc, ephapax_cli) and fall back to whatever executable cargo built under target/release/. The discovered path is exported to GITHUB_ENV as EPHAPAX_CLI and the compile step picks it up.
Address review nits from PR #212 before the loader becomes load-bearing: - ipc_recv now returns 0 (no bytes available) instead of the channel handle. Returning ch would have been dereferenced by wasm as a bogus bytes pointer the moment bridge.eph's run loop ran against this loader. - Remove the dead pendingRecv list. Nothing pushed onto it, so the onmessage handler's pendingRecv branch was unreachable; messages now go straight to recvQueue. - Factor out readEphapaxString as a shared bounds-checked helper. HypatiaTEA.readString and makeGossamerHost both call it, so host decodes see the same RangeError-on-mismatch behaviour the class decodes already had. - README manual smoke step now names the real launcher (iex -S mix / mix run --no-halt for the Bandit + Plug.Router OTP listener), not mix phx.server -- the repo isn't a Phoenix app. Remaining loader follow-ups (single global ws, ipc_send body bytes, automated host-import harness) are tracked separately. https://claude.ai/code/session_017sazwaVffMFokKDHPKaEj7
12 tasks
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
Owner
Author
|
Superseded by #219, which lands the full set of changes promised in this PR's description (only the Closing as superseded — please review #219 instead. Generated by Claude Code |
hyperpolymath
added a commit
that referenced
this pull request
May 12, 2026
#219) Merges the scope-extended PR that replaces #217 and addresses #218. Loader work: - Multi-channel IPC with per-handle Map (Map<handle, {ws, recvQueue, pendingSends, endpoint}>) - ipc_send reads body bytes + buffers across the WebSocket connect race - ipc_recv hands frames back to wasm via an allocator probe (__alloc / alloc / hypatia_alloc / gossamer_alloc / __wbindgen_malloc / malloc), falls back to "no bytes available" when no allocator export exists - DataView caching via WeakMap keyed by ArrayBuffer identity; memory.grow drops out automatically - Shared readEphapaxString helper, ipc_recv returns 0 (not channel ptr), dead pendingRecv list removed - Node smoke harness (test/gossamer/loader_smoke.test.mjs) — 26/26 tests, hand-built fixture wasm, wired into Build Gossamer GUI workflow as `loader-smoke` job - README launcher fix (iex -S mix / mix run --no-halt instead of mix phx.server) - Workflow probe for `ephapax compile` (the real v1.0.0 subcommand) CI hygiene picked up while debugging: - Bumped multiple pinned action SHAs that were unresolvable on Actions (dtolnay/rust-toolchain, taiki-e/install-action, erlef/setup-beam) - Removed orphaned duplicate Python heredoc in rsr-antipattern.yml (was causing exit 127 on every PR) - Python anti-pattern check now allowlists scripts/ / bin/ / tools/ - Gated Haskell jobs across ci.yml / security.yml / security-audit.yml / release.yml / integration.yml on `registry/cicd-hyper-a.cabal` existence — they skip cleanly when the sub-tree isn't in the repo - Gated pr-fuzzing on fuzz/ / .clusterfuzzlite/ existence - Trimmed Trivy matrix to the Containerfile that actually exists - Build Test Images: corrected Containerfile path + added missing workspace member (clients/rust/hypatia-client) + bumped builder image to rust:1.94-slim-bookworm - cargo fmt --all on the workspace; semgrep nosemgrep directives repositioned to fmt-stable spots in clients/rust/hypatia-client/src/ffi.rs; added .semgrepignore for that file's by-design FFI unsafe - Resolved cargo clippy --workspace -- -D warnings under rust 1.95 (was failing on the new clippy::unnecessary_sort_by lint plus pre-existing field_reassign_with_default, format_in_format_args, ptr_arg, type_complexity, should_implement_trait, dead_code, etc.) A2ML / K9 manifest fills: - 13 .a2ml files now satisfy a2ml-validate-action's name/project/version/SPDX requirements - 3 .k9.ncl files now satisfy k9-validate-action's pedigree.name + pedigree.leash + signature_required requirements Closes #217 (superseded; this PR is the actual implementation). Closes most of #218 — see the latest comment there; the single remaining checkbox (CI-driven smoke replacing the manual section) is hard-blocked on hyperpolymath/ephapax#36.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacks on top of #212 with the small fixes raised in review so the loader stubs aren't left in their current state once
ephapax#36lands and someone actually runsbridge.eph'srunloop against this loader.Merge after #212 (or fold these commits into #212 and close this).
Changes
src/ui/gossamer/loader.jsipc_recvnow returns0(no bytes available) instead of the channel handle. Returningchwould have been dereferenced by wasm as a bogus bytes pointer the momentbridge.eph'srunloop ran against this loader.pendingRecvlist. Nothing ever pushed onto it, so theonmessagebranch that calledpendingRecv.shift()was unreachable; messages now go straight torecvQueue.readEphapaxStringas a shared bounds-checked helper.HypatiaTEA.readStringand the host closure inmakeGossamerHostboth call it, so host-side decodes pick up the sameRangeError-on-mismatch behaviour the class already had (previously the host closure had its own unchecked copy).src/ui/gossamer/README.adociex -S mix/mix run --no-haltfor the Bandit + Plug.Router OTP listener), notmix phx.server— the repo isn't a Phoenix app. The port is configurable via:hypatia, :http_port.What's still open
Tracked in the follow-up issue (filed separately). In short:
wsinmakeGossamerHost(multipleipc_openleaks the prior socket).ipc_sendreads nothing from_bodyPtr— silent no-op even when WS is open.makeGossamerHostagainst a fixture wasm.hyperpolymath/ephapax#36still gates the compile step itself.Test plan
readEphapaxStringstandalone in Node: well-formed decode, OOB header throwsRangeError, oversized len throwsRangeError, host closure returns expected handles,ipc_recvreturns0.Build Gossamer GUIworkflow still passes (compile step continues to skip untilephapax#36).wasm-validateruns against the produced artifact andindex.htmlloads in the browser without console errors.Generated by Claude Code