Skip to content

feat(wasmgc): handlers, subscriptions and spawn in the browser - #291

Merged
howlcipher merged 7 commits into
mainfrom
feat/wasmgc-handlers
Oct 31, 2026
Merged

howlcipher merged 7 commits into
mainfrom
feat/wasmgc-handlers

Conversation

@howlcipher

Copy link
Copy Markdown
Owner

M3 task 3: closures and event dispatch (plan: "Handlers").

  • A lambda (the last argument of on_event, on_media, on_visible, on_scroll or spawn) is lifted to a function (env, a0, a1); a closure is a $Closure (function reference and an environment of $Cells). Variables any lambda in a function names live in cells made afresh at each binding, so handlers share variables with the code around them, as JavaScript closures do, and a handler made in a loop keeps its iteration's variable. Every binding site of the compiler goes through one binding abstraction now.
  • The host calls a closure with __hf_invoke; the loader wraps it as a JavaScript function returning a promise, like the JavaScript backend's async handlers: a handler's uncaught error or exit rejects that promise alone.
  • on_event now calls one shared runtime function in both backends (howlFrameOnEvent); the subscriptions use the JavaScript backend's runtime; the table gives a lambda's parameters kinds (event, element, bool) that the loader converts by.
  • spawn is a browser import that runs the closure at once (no capability: a task, not a process).
  • A lambda of more than two parameters, and spawn outside the browser, fail closed.

Test Impact Assessment

  • Behavior changed: on_event, the subscriptions and spawn build for the browser; the JavaScript backend's on_event emits howlFrameOnEvent(...) (same effect).
  • Tests that prove it: TestBrowserHandlersLikeJavaScript (12 programs on both backends; the stand-in page clicks every listened element, scrolls, flips a media query, makes an element visible and records rejections and unhandled rejections: shared and per-iteration captures, captured lists and dicts, nested handlers, handlers made in a function, handler errors and exits, a missing element, spawn, subscriptions and off), TestBrowserFailsClosed updated; the existing JavaScript browser tests (on_event, subscriptions) pass unchanged; the differential corpus passes after the binding refactor.
  • Gaps: asynchronous handlers (next PR).
  • Tests actually run: HOWLSCENE_HF=… scripts/wasmgc_gate.sh on the tree before merging main (d9b884e6); merging main changed no file.
  • Gate summary: tools go1.26.0, node v22.22.1, wasmtime 47.0.3, wasm-tools 1.254.0; HowlScene HF 247365e. Go 1.26: 4355 passed, 31 skipped by design; Go 1.27.2: 4353 passed, 33 skipped by design; HowlScene HF gates: 6 passed. wasmgc gate: passed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AcSTmyDDtEcBifmcTbNcRW

howlcipher and others added 7 commits October 31, 2026 01:03
A lambda (the handler of on_event, on_media, on_visible, on_scroll or
spawn) is lifted to a function taking its environment, the cells of the
variables it captures. As in JavaScript a handler shares those variables
with the code around it, and a variable bound in a loop is that
iteration's. The loader turns a closure into a JavaScript handler that
returns a promise, as the JavaScript backend's async handlers do: a
handler's uncaught error or exit rejects it alone. on_event shares one
runtime function, howlFrameOnEvent, with the JavaScript backend, and the
table gives a lambda's parameters their kinds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AcSTmyDDtEcBifmcTbNcRW
# Conflicts:
#	internal/backend/wasmgc/browser_test.go
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AcSTmyDDtEcBifmcTbNcRW
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AcSTmyDDtEcBifmcTbNcRW
@howlcipher

Copy link
Copy Markdown
Owner Author

The merge went through as bd868833 ("Merge pull request #291 from howlcipher/feat/wasmgc-handlers" is main's head; this branch is 0 commits ahead of main), but the merge request returned a 502 and GitHub did not record the pull request as merged. Nothing of this branch is missing from main.

🤖 Generated with Claude Code

@howlcipher
howlcipher merged commit bd86883 into main Oct 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant