Audit of GitHub Actions settings across the five repositories that run GPU CI on RunsOn, done 2026-07-30 while planning compute capability. Four config items came out of it — all hardening, none urgent.
Item 1 as originally written was wrong and has been corrected in place — it recommended reverting the on-demand decision from #330. See the correction comment for detail.
Repos in scope: lecture-jax, lecture-python.myst, lecture-python-programming, lecture-stats, iuj_feb_2026.
1. Spot pricing is switched off where most of the GPU volume is — CORRECTED, do not action
This item was wrong. See the correction comment below. spot=false is a deliberate org-wide reliability decision from #330 (spot reclamation was killing GPU builds mid-run), not an oversight. The correct action is the opposite: finish the #330 rollout by adding spot=false to the 7 GPU workflows that still lack it — all four in lecture-stats, both in iuj_feb_2026, and publish.yml in lecture-python-programming. The measurements below are accurate; the recommendation drawn from them was not.
Original text, kept for the record
spot=false is set in 10 of 17 GPU workflow files, across lecture-jax (4 of 4), lecture-python.myst (4 of 4) and lecture-python-programming (2 of 3 — publish.yml doesn't set it). lecture-stats and iuj_feb_2026 never set spot, and RunsOn defaults to spot, so those already get it.
Measured over 2026-01-31 → 2026-07-30, 98% of GPU CI wall-clock runs on spot=false — 245.9 of 251.3 hours. Flipping those 10 files to spot=true cuts that portion of the bill by roughly 58–61% at zero cost and with no downside I can see: RunsOn tries spot first and falls back to on-demand automatically when spot capacity is unavailable, at a 2–3 second launch penalty.
The single largest consumer is lecture-python.myst/ci.yml at 123.9 hours — about half of all GPU CI.
2. Fork-PR workflow approval is on GitHub's default rather than the strict setting
All five repos are set to first_time_contributors. The stricter option is all_external_contributors, which requires maintainer approval before any outside contributor's workflow runs rather than only a first-time one.
This is hardening rather than a live problem — it would start to matter if we ever attached a self-hosted runner to these repos, which we haven't. It's a five-click change and worth doing ahead of that rather than as part of it.
3. Actions can approve pull requests on four of five repos
can_approve_pull_request_reviews is true on all but iuj_feb_2026. We have no workflow that uses this, and we're planning triage and maintenance agents whose design says explicitly that a bot never approves or merges — so leaving the capability enabled makes that a convention rather than something actually enforced. Suggest turning it off so the guardrail is real.
4. Default workflow token permissions are write on four of five
default_workflow_permissions is write on all but iuj_feb_2026, which uses read. Broader than anything currently needs, and iuj_feb_2026 demonstrates read is workable. Per-workflow permissions: blocks can grant more where a workflow genuinely needs it.
Suggested order
|
Item |
Effort |
Why now |
| 1 |
Finish the #330 rollout — add spot=false to the 7 workflows still missing it |
One PR |
Closes a known reliability gap. Replaces the original item 1, which was wrong |
| 2 |
Set approval policy to all_external_contributors |
Five settings |
Free, and cheaper before a runner exists than after |
| 3 |
Disable Actions approving PRs |
Four settings |
Makes a planned agent guardrail enforceable |
| 4 |
Default token permissions to read |
Four settings |
Needs a check that nothing breaks |
Not established
The organisation-level Actions policy hasn't been read — that needs admin:org, which I don't have. It could constrain or override any of the repo-level settings above, so worth checking before acting on 2–4.
Also worth a sanity check by someone who knows the repos: whether runs-on accepts expressions and which contexts are available at job level isn't documented in GitHub's workflow-syntax reference, which matters if we later want conditional runner selection.
Context and working are in the private project-compute planning repo (research/2026-07-30-gpu-ci-settings-audit.md).
🤖 Generated with Claude Code
Audit of GitHub Actions settings across the five repositories that run GPU CI on RunsOn, done 2026-07-30 while planning compute capability. Four config items came out of it — all hardening, none urgent.
Item 1 as originally written was wrong and has been corrected in place — it recommended reverting the on-demand decision from #330. See the correction comment for detail.
Repos in scope:
lecture-jax,lecture-python.myst,lecture-python-programming,lecture-stats,iuj_feb_2026.1.
Spot pricing is switched off where most of the GPU volume is— CORRECTED, do not actionOriginal text, kept for the record
spot=falseis set in 10 of 17 GPU workflow files, acrosslecture-jax(4 of 4),lecture-python.myst(4 of 4) andlecture-python-programming(2 of 3 —publish.ymldoesn't set it).lecture-statsandiuj_feb_2026never setspot, and RunsOn defaults to spot, so those already get it.Measured over 2026-01-31 → 2026-07-30, 98% of GPU CI wall-clock runs on
spot=false— 245.9 of 251.3 hours. Flipping those 10 files tospot=truecuts that portion of the bill by roughly 58–61% at zero cost and with no downside I can see: RunsOn tries spot first and falls back to on-demand automatically when spot capacity is unavailable, at a 2–3 second launch penalty.The single largest consumer is
lecture-python.myst/ci.ymlat 123.9 hours — about half of all GPU CI.2. Fork-PR workflow approval is on GitHub's default rather than the strict setting
All five repos are set to
first_time_contributors. The stricter option isall_external_contributors, which requires maintainer approval before any outside contributor's workflow runs rather than only a first-time one.This is hardening rather than a live problem — it would start to matter if we ever attached a self-hosted runner to these repos, which we haven't. It's a five-click change and worth doing ahead of that rather than as part of it.
3. Actions can approve pull requests on four of five repos
can_approve_pull_request_reviewsistrueon all butiuj_feb_2026. We have no workflow that uses this, and we're planning triage and maintenance agents whose design says explicitly that a bot never approves or merges — so leaving the capability enabled makes that a convention rather than something actually enforced. Suggest turning it off so the guardrail is real.4. Default workflow token permissions are
writeon four of fivedefault_workflow_permissionsiswriteon all butiuj_feb_2026, which usesread. Broader than anything currently needs, andiuj_feb_2026demonstratesreadis workable. Per-workflowpermissions:blocks can grant more where a workflow genuinely needs it.Suggested order
spot=falseto the 7 workflows still missing itall_external_contributorsreadNot established
The organisation-level Actions policy hasn't been read — that needs
admin:org, which I don't have. It could constrain or override any of the repo-level settings above, so worth checking before acting on 2–4.Also worth a sanity check by someone who knows the repos: whether
runs-onaccepts expressions and which contexts are available at job level isn't documented in GitHub's workflow-syntax reference, which matters if we later want conditional runner selection.Context and working are in the private
project-computeplanning repo (research/2026-07-30-gpu-ci-settings-audit.md).🤖 Generated with Claude Code