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
Updated 2026-08-21. The seed is now on main via #938 (ci/wasm/environment.yml, ci/wasm/smoke_test.py, the Playwright harness ci/wasm/test_jupyterlite.py, and the native gate in ci_wasm_smoke.yml), so the Approach below names it instead of "the config from #928", and a task list for the runner PR has been added. What that list corrects: the parked job (2026-08-19 comment) still needs triggers, the gini expectation in both suite files is inverted now that numba 0.67.0 build 1 serialises parallel=True (patch 0010, emscripten-forge/recipes#6293), the two jitted-generator tests will hang without a real guard, test_simplex_grid fails on a warm cache (#944), and smoke_test.py is not yet shipped into the kernel. The original text is preserved in the edit history.
Browser support must not regress once established: add a wasm job to GitHub Actions that runs a smoke suite in the real browser stack.
Approach
Seed: PR WASM: JupyterLite environment config and browser smoke suite #938 (merged 2026-08-21) — ci/wasm/environment.yml (xeus-python kernel env, emscripten-forge-4x + conda-forge channels), the sentinel-driven Playwright harness ci/wasm/test_jupyterlite.py, and the native gate job native in .github/workflows/ci_wasm_smoke.yml, which runs ci/wasm/smoke_test.py against repo source on every PR. The Emscripten runner job is parked in the 2026-08-19 comment below.
Track the emscripten-forge numba/llvmlite versions in the job the way conda-forge versions are tracked today; environment.yml pins bare numba, so have the job log the resolved build (only 0.67.0 build 1 carries patch 0010, see task 2).
This job is also the natural watchpoint for upstreaming: the blog post signals intent to merge the WASM engine into Numba mainline, and once that ships, the patched-recipe caveats (the recipe now carries ten patches, e.g. the serial fallback for parallel=True added by patch 0010 and the ufunc caching disabled by patch 0007) may start dissolving. Until then the job tests the released conda-forge noarch quantecon, not repo source, so per-PR triggering is not useful long-term.
Tasks for the runner PR
Add the parked wasm job with its own triggers. The snippet in the 2026-08-19 comment is a job block and has no on:; ci_wasm_smoke.yml's on: is push/pull_request to main. Either add schedule + workflow_dispatch to that shared on: block and guard the job with if: github.event_name != 'pull_request', or move it to its own workflow file — in which case needs: native no longer resolves (it only sees jobs in the same workflow) and must be dropped or replaced. Iterate under pull_request first, as the 2026-08-19 comment describes, then flip.
Ship smoke_test.py into the kernel and run it in-kernel. The parked job runs only the Playwright harness (6 cells: kernel boot, import, tauchen, np.linalg.solve, support_enumeration, gini), so a green run fills at most 5 of WASM: JupyterLite proof-of-concept deployment and browser smoke suite #928's 13 rows. WASM: JupyterLite environment config and browser smoke suite #938 assigned in-kernel pytest execution of smoke_test.py (16 tests) here (commit 1e0c598 also dropped pytest from environment.yml, so it has to be added back). Copy the file into the site contents, invoke pytest inside the xeus-python kernel, and surface per-test results.
Bump mamba-org/setup-micromamba@v2 to @v3 in the parked YAML (v3.0.0 moved to Node 24; the inputs used — micromamba-binary-path, init-shell, generate-run-shell — are unchanged). actions/checkout@v7 and actions/setup-python@v7 are current.
Expected outcome of the first browser run once 1–6 are done, on numba 0.67.0 build 1: test_gini_coefficient passes; test_support_enumeration, test_vertex_enumeration and the bare-generator test are skipped/xfail(run=False) pending the upstream generator report (#927); test_simplex_grid passes cold and fails warm (#944); everything else is expected to pass. Record the per-function table in #928.
Acceptance criteria
A CI job builds a JupyterLite deployment containing quantecon and runs the smoke suite in a headless browser
Note
Updated 2026-08-21. The seed is now on
mainvia #938 (ci/wasm/environment.yml,ci/wasm/smoke_test.py, the Playwright harnessci/wasm/test_jupyterlite.py, and the native gate inci_wasm_smoke.yml), so the Approach below names it instead of "the config from #928", and a task list for the runner PR has been added. What that list corrects: the parked job (2026-08-19 comment) still needs triggers, the gini expectation in both suite files is inverted now that numba 0.67.0 build 1 serialisesparallel=True(patch 0010, emscripten-forge/recipes#6293), the two jitted-generator tests will hang without a real guard,test_simplex_gridfails on a warm cache (#944), andsmoke_test.pyis not yet shipped into the kernel. The original text is preserved in the edit history.Part of #925 (Phase 3 — keep it working).
Goal
Browser support must not regress once established: add a
wasmjob to GitHub Actions that runs a smoke suite in the real browser stack.Approach
ci/wasm/environment.yml(xeus-python kernel env, emscripten-forge-4x + conda-forge channels), the sentinel-driven Playwright harnessci/wasm/test_jupyterlite.py, and the native gate jobnativein.github/workflows/ci_wasm_smoke.yml, which runsci/wasm/smoke_test.pyagainst repo source on every PR. The Emscripten runner job is parked in the 2026-08-19 comment below.pytester, emscripten-forge's pyjs-based recipe-test harness, remains the alternative only if quantecon is later packaged on emscripten-forge (WASM: contribute a quantecon recipe to emscripten-forge #932).smoke_test.py) and grow from there.environment.ymlpins barenumba, so have the job log the resolved build (only 0.67.0 build 1 carries patch 0010, see task 2).This job is also the natural watchpoint for upstreaming: the blog post signals intent to merge the WASM engine into Numba mainline, and once that ships, the patched-recipe caveats (the recipe now carries ten patches, e.g. the serial fallback for
parallel=Trueadded by patch 0010 and the ufunc caching disabled by patch 0007) may start dissolving. Until then the job tests the released conda-forge noarchquantecon, not repo source, so per-PR triggering is not useful long-term.Tasks for the runner PR
wasmjob with its own triggers. The snippet in the 2026-08-19 comment is a job block and has noon:;ci_wasm_smoke.yml'son:ispush/pull_requesttomain. Either addschedule+workflow_dispatchto that sharedon:block and guard the job withif: github.event_name != 'pull_request', or move it to its own workflow file — in which caseneeds: nativeno longer resolves (it only sees jobs in the same workflow) and must be dropped or replaced. Iterate underpull_requestfirst, as the 2026-08-19 comment describes, then flip.@njit(parallel=True)to the serial pipeline, and the barenumbapin resolves to it.test_gini_coefficient'sxfail(IS_EMSCRIPTEN, strict=True)insmoke_test.pywould XPASS and fail;test_gini_fails_on_emscriptenintest_jupyterlite.pyasserts an error and would fail. Both become plain pass assertions (browser-unverified; inferred from the merged patch). PR Rewrite Gini coefficient in O(n log n) #937's O(n log n) rewrite (WASM: remove @njit(parallel=True) from gini_coefficient via an O(n log n) rewrite #926) is a performance change on top of this, not a prerequisite.test_support_enumerationandtest_vertex_enumerationinsmoke_test.pycall@njitgenerators (support_enumeration.py:96,vertex_enumeration.py:118) that never return on Emscripten (WASM: support_enumeration and vertex_enumeration hang in the browser — root cause is jitted generators (numba.np.linalg._LAPACK verified working) #927, WASM: support_enumeration and vertex_enumeration hang in the browser — root cause is jitted generators (numba.np.linalg._LAPACK verified working) #927 (comment)). Usepytest.mark.skipif(IS_EMSCRIPTEN, ...)orxfail(IS_EMSCRIPTEN, run=False, strict=True)— a plainxfailstill executes the test, andpytest-timeout(SIGALRM /threading.Timer) cannot interrupt a native loop in the single-threaded kernel. Intest_jupyterlite.py, skiptest_support_enumerationor run it last: Playwright'sEXEC_MS(180 s) bounds it host-side, but the module-scoped kernel stays wedged and the following test fails spuriously. Add the minimal bare@njitgenerator test (for i in range(n): yield i) alongside, guarded the same way, as the isolated upstream repro and regression watch.test_simplex_gridas expected to fail on a warm cache and cite WASM: cache=True functions that link a cache-restored callee fail with "no compiled object yet" (simplex_grid → num_compositions_jit → comb_jit) #944. Its comment currently says "(WASM: audit 32-bit intp behaviour on wasm32 (overflow guards, simplex_index wrapping, dtypes) #929)"; the actual failure isRuntimeError: no compiled object yet for comb_jit(WASM: cache=True functions that link a cache-restored callee fail with "no compiled object yet" (simplex_grid → num_compositions_jit → comb_jit) #944, reported upstream as Numba:RuntimeError: no compiled object yetemscripten-forge/recipes#6309), which triggers only when acache=Truecaller links a callee restored from the persistent cache — a cold single-session run passes. A regression test needs a second session or a pre-seeded/drive/.cache/numba.smoke_test.pyinto the kernel and run it in-kernel. The parked job runs only the Playwright harness (6 cells: kernel boot, import, tauchen,np.linalg.solve,support_enumeration, gini), so a green run fills at most 5 of WASM: JupyterLite proof-of-concept deployment and browser smoke suite #928's 13 rows. WASM: JupyterLite environment config and browser smoke suite #938 assigned in-kernel pytest execution ofsmoke_test.py(16 tests) here (commit 1e0c598 also droppedpytestfromenvironment.yml, so it has to be added back). Copy the file into the site contents, invoke pytest inside the xeus-python kernel, and surface per-test results.mamba-org/setup-micromamba@v2to@v3in the parked YAML (v3.0.0 moved to Node 24; the inputs used —micromamba-binary-path,init-shell,generate-run-shell— are unchanged).actions/checkout@v7andactions/setup-python@v7are current.Expected outcome of the first browser run once 1–6 are done, on numba 0.67.0 build 1:
test_gini_coefficientpasses;test_support_enumeration,test_vertex_enumerationand the bare-generator test are skipped/xfail(run=False) pending the upstream generator report (#927);test_simplex_gridpasses cold and fails warm (#944); everything else is expected to pass. Record the per-function table in #928.Acceptance criteria
ci/wasm/smoke_test.pyexecutes inside the xeus-python kernel (not only the Playwright harness), so every WASM: JupyterLite proof-of-concept deployment and browser smoke suite #928 row gets a browser resultcomb_jit) are guarded so they cannot consume the job's time limit, and each guard cites its issueRelated
ci/wasm/environment.yml,smoke_test.py,test_jupyterlite.py, native gatesmoke_test.pyis its checklistsupport_enumeration,vertex_enumeration); LAPACK verified workingcache=Truecallers of cache-restored functions fail on a warm cache (simplex_grid→num_compositions_jit→comb_jit); upstream Numba:RuntimeError: no compiled object yetemscripten-forge/recipes#6309parallel=True(numba 0.67.0 build 1)pytesterbecomes an option