Summary
Most lecture repos catch a broken notebook cell in CI, but three do not, because the ci.yml step that actually executes the notebooks — "Build Download Notebooks (sphinx-tojupyter)", jb build lectures ... --custom-builder=jupyter — is missing the -n -W flags in those three. Without -W on that step a CellExecutionError is a non-fatal warning; the later -W "Build HTML" step runs under execute_notebooks: "cache" and reuses the already-executed (possibly-errored) notebooks, so it never re-catches the failure. Net effect: a lecture whose code is broken passes CI green in those repos.
Audit (the execution step's flags)
| Repo |
-W on the sphinx-tojupyter execution step |
Broken cell fails CI? |
| lecture-python.myst |
✅ -n -W --keep-going |
yes |
| lecture-python-programming |
✅ |
yes |
| lecture-python-programming.zh-cn |
✅ |
yes |
| lecture-python-programming.fa |
✅ |
yes |
| lecture-python.zh-cn |
❌ missing |
no |
| lecture-intro.zh-cn |
❌ missing |
no |
| lecture-python-intro |
❌ missing |
no |
It is not a translation-vs-source split: the programming family (source + editions) all catch it, the intro family masks on both the source and the edition, and the intermediate family catches on the source (myst) while the zh-cn edition dropped it. lecture-python-programming.fr has no custom-builder=jupyter step yet.
Evidence
Surfaced during the lecture-python.zh-cn resync wave (2026-07): a cold Build Cache run reported success while its execution-reports artifact held 19 notebook execution failures, and the resync only stayed safe because of a manual workaround — every fix was pushed as a new commit to force a cold rebuild, and the reports were read by hand. The repos that carry -W on the execution step (myst, programming) do not need that workaround; their CI goes red on a broken cell.
Fix
Add -n -W --keep-going to the "Build Download Notebooks (sphinx-tojupyter)" step in the three repos, matching the repos that already catch failures — no _config.yml change required, and the working repos prove the pattern:
- name: Build Download Notebooks (sphinx-tojupyter)
run: |
jb build lectures -n -W --keep-going --path-output ./ --builder=custom --custom-builder=jupyter
Repos to change: lecture-python.zh-cn, lecture-intro.zh-cn, lecture-python-intro. One caveat before flipping it on: any lecture with an intentionally-erroring cell needs a raises-exception tag first, or it will (correctly) start failing.
Secondary note — cache.yml
The weekly Build Cache job builds with the default HTML builder under execute_notebooks: "cache", which does not catch execution errors even with -W present (the HTML builder reuses the cache rather than re-executing — this is what let the 19 failures above pass). Aligning ci.yml fixes the PR gate, which is the priority; if the cache job should also gate on execution, that is a separate change (run the tojupyter execution builder in cache.yml, or set a raise-on-error config).
References
Summary
Most lecture repos catch a broken notebook cell in CI, but three do not, because the
ci.ymlstep that actually executes the notebooks — "Build Download Notebooks (sphinx-tojupyter)",jb build lectures ... --custom-builder=jupyter— is missing the-n -Wflags in those three. Without-Won that step aCellExecutionErroris a non-fatal warning; the later-W"Build HTML" step runs underexecute_notebooks: "cache"and reuses the already-executed (possibly-errored) notebooks, so it never re-catches the failure. Net effect: a lecture whose code is broken passes CI green in those repos.Audit (the execution step's flags)
-Won the sphinx-tojupyter execution step-n -W --keep-goingIt is not a translation-vs-source split: the programming family (source + editions) all catch it, the intro family masks on both the source and the edition, and the intermediate family catches on the source (myst) while the zh-cn edition dropped it.
lecture-python-programming.frhas nocustom-builder=jupyterstep yet.Evidence
Surfaced during the
lecture-python.zh-cnresync wave (2026-07): a cold Build Cache run reported success while its execution-reports artifact held 19 notebook execution failures, and the resync only stayed safe because of a manual workaround — every fix was pushed as a new commit to force a cold rebuild, and the reports were read by hand. The repos that carry-Won the execution step (myst, programming) do not need that workaround; their CI goes red on a broken cell.Fix
Add
-n -W --keep-goingto the "Build Download Notebooks (sphinx-tojupyter)" step in the three repos, matching the repos that already catch failures — no_config.ymlchange required, and the working repos prove the pattern:Repos to change:
lecture-python.zh-cn,lecture-intro.zh-cn,lecture-python-intro. One caveat before flipping it on: any lecture with an intentionally-erroring cell needs araises-exceptiontag first, or it will (correctly) start failing.Secondary note —
cache.ymlThe weekly Build Cache job builds with the default HTML builder under
execute_notebooks: "cache", which does not catch execution errors even with-Wpresent (the HTML builder reuses the cache rather than re-executing — this is what let the 19 failures above pass). Aligningci.ymlfixes the PR gate, which is the priority; if the cache job should also gate on execution, that is a separate change (run the tojupyter execution builder incache.yml, or set a raise-on-error config).References
lecture-python.zh-cnresync wave; recorded in project-translation#12.