Skip to content

JupyterLite: dual-build dispatcher (JSPI-capable vs. legacy Pyodide) to unstick the pinned kernel version #631

Description

@petercorke

Background

ci.yml's JupyterLite build pins jupyterlite-pyodide-kernel==0.6.1 (bundling Pyodide 0.27.6) deliberately, to stay behind Pyodide's default-on WebAssembly JSPI ("stack switching", on by default since 0.27.7) — Safari has no JSPI support as of 2026-08, Firefox only behind a flag. Without this pin, jupyterlite-pyodide-kernel's use of run_until_complete() either crashes the kernel outright in those browsers, or (with the enableRunUntilComplete: false workaround) silently races package installs. Full rationale in the toolbox-maintainer skill's JupyterLite version-pinning section. Same pin, same reason, on MVTB and bdsim.

As of the pure-Python-wheel fix (see the PR this issue was filed alongside), RTB's own wasm wheel no longer has any ABI coupling to a specific Pyodide/Emscripten version — a py3-none-any wheel works under any Pyodide version. So the pin is no longer needed for our own package's sake. It's still needed for the kernel-crash/JSPI reason above, independent of anything RTB ships.

The remaining cost of staying pinned: everything Pyodide bundles internally (numpy, scipy, etc., for anyone micropip.install-ing them in a live notebook) stays frozen at whatever versions Pyodide 0.27.6 shipped, indefinitely — until Safari/Firefox ship JSPI for real.

Proposed idea (not yet designed/committed to)

A lightweight client-side dispatcher page in front of the JupyterLite "Try it Now" link: feature-detect real JSPI support (typeof WebAssembly.Suspending === "function") and redirect to one of two parallel JupyterLite deployments — a modern build (current kernel/Pyodide, JSPI on) for browsers that support it, and today's pinned legacy build for those that don't. Feature detection (not user-agent sniffing) means Safari/Firefox users automatically graduate to the modern build the day their browser ships JSPI, with no code changes needed here.

Why not done now

This is a real but secondary problem — it predates and is independent of the pure-Python-wheel fix, which was this session's actual scope. The dispatcher approach is a genuine scope increase: two parallel JupyterLite deployments, extra CI build time, extra static hosting, a dispatcher page, and testing both paths. Per the toolbox-maintainer skill's cross-repo consistency principle, doing this "properly" means MVTB and bdsim too, not just RTB, since all three carry the identical pin for the identical reason.

Next steps, if picked up

  • Confirm WebAssembly.Suspending is still the correct JSPI feature-detection API at the time this is implemented.
  • Decide whether to build this once as a shared pattern (e.g. documented in rvc-ecosystem) rather than three independent implementations.
  • Weigh the hosting/CI cost against the actual benefit (how stale do Pyodide's bundled scientific packages actually get in practice, and does anyone's notebook usage actually hit that staleness).

Metadata

Metadata

Assignees

No one assigned

    Labels

    tech-debtKnown technical debt / deferred cleanup, not a live bug

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions