Skip to content

Commit f541ccc

Browse files
mmckyclaude
andcommitted
CI: make the execution cache engine-aware, pin JAX
Hardening after the preallocation-race incident. The cache key now hashes myst_requirements.txt and ci.yml itself alongside the lectures, so any engine SHA bump, JAX bump, XLA env change or requirements change busts the cache and is validated by a cold build automatically -- hashing only the lectures is how the b9cc649 engine swap shipped green without executing a notebook. JAX is pinned to 0.11.0 (the version the 2026-08-03 diagnosis and fix were validated against); a bump is now a deliberate ci.yml edit that itself forces cold validation. Also rewords the diagnosis-era comments: the memory monitor and dmesg read-back stay as standing telemetry. This commit changes the cache key, so its own CI run is cold -- which doubles as a second cold-green validation of the XLA_PYTHON_CLIENT_PREALLOCATE fix under the pinned engine. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 94a7e52 commit f541ccc

1 file changed

Lines changed: 26 additions & 11 deletions

File tree

.github/workflows/ci.yml

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,19 @@ jobs:
66
steps:
77
- uses: actions/checkout@v7
88

9+
# The key hashes everything cached execution outputs depend on: the
10+
# lectures themselves, the Python requirements, and this workflow file
11+
# (which pins the mystmd engine SHA, the JAX version and the XLA env).
12+
# Hashing only the lectures is how the b9cc649 engine swap shipped
13+
# green without ever executing a notebook: the cache replayed outputs
14+
# from the old engine. Any engine/env/requirements change now forces a
15+
# cold build automatically.
916
- name: Cache Notebook Execution
1017
uses: actions/cache@v6
1118
id: cache-execution
1219
with:
1320
path: ./lectures/_build/execute
14-
key: ${{ runner.os }}-execute-cache-${{ hashFiles('lectures/**/*.md') }}
21+
key: ${{ runner.os }}-execute-cache-${{ hashFiles('lectures/**/*.md', 'myst_requirements.txt', '.github/workflows/ci.yml') }}
1522

1623
# Node 24 matches the theme's .nvmrc (quantecon-theme.mystmd), which runs
1724
# as a Remix server during `myst build --html`.
@@ -34,12 +41,15 @@ jobs:
3441
run: python -m pip install -r myst_requirements.txt
3542

3643
# The GPU lectures (jax_intro, autodiff, numpy_vs_numba_vs_jax) need JAX
37-
# on the g4dn runner — same install as the jupyter-book 1.x workflow on
38-
# main. Without it those notebooks execute to ModuleNotFoundError cells.
44+
# on the g4dn runner. Without it those notebooks execute to
45+
# ModuleNotFoundError cells. Pinned to the version validated on
46+
# 2026-08-03; unpinned, the executed environment drifts between runs of
47+
# the same commit. Bumping it here busts the execution cache (the key
48+
# hashes this file), so the bump is validated by a cold build.
3949
- name: Install JAX
4050
if: steps.cache-execution.outputs.cache-hit != 'true'
4151
run: |
42-
pip install -U "jax[cuda13]"
52+
pip install "jax[cuda13]==0.11.0"
4353
python scripts/test-jax-install.py
4454
4555
# Pinned to the exact SHA of the fork's main (unmoved since 2026-06-12,
@@ -65,10 +75,12 @@ jobs:
6575
- name: Verify mystmd version
6676
run: myst --version
6777

68-
# DIAGNOSIS (PR #363 cold-cache jax_intro kernel death): sample host
69-
# RAM, top-RSS processes and GPU memory every 5s for the rest of the
70-
# job. The nohup'd loop survives step boundaries; the runner reaps it
71-
# at job end. Read back in the always() step after the build.
78+
# Standing telemetry: sample host RAM, top-RSS processes and GPU memory
79+
# every 5s for the rest of the job. The nohup'd loop survives step
80+
# boundaries; the runner reaps it at job end. Read back in the always()
81+
# step after the build. This is what diagnosed the 2026-08-03 jax_intro
82+
# kernel death (GPU preallocation race — see the Build HTML env below);
83+
# it costs nothing, so it stays for the next one.
7284
- name: Start memory monitor
7385
run: |
7486
nohup bash -c 'while true; do
@@ -101,9 +113,12 @@ jobs:
101113
XLA_PYTHON_CLIENT_PREALLOCATE: 'false'
102114
run: myst build --html --execute
103115

104-
# A kernel death with no Python traceback is consistent with a SIGKILL
105-
# from the host OOM killer, but that has never been confirmed. dmesg
106-
# covers the whole job because runs-on boots a fresh instance per run.
116+
# Reads the telemetry back. dmesg covers the whole job because runs-on
117+
# boots a fresh instance per run — an OOM-killed process appears there
118+
# with its RSS, so this cleanly separates host OOM kills from in-process
119+
# aborts (the 2026-08-03 death was the latter: dmesg was clean while the
120+
# GPU sampler showed the preallocation collision). Start from this
121+
# output for any future kernel death.
107122
- name: Execution diagnostics
108123
if: always()
109124
run: |

0 commit comments

Comments
 (0)