ci: the shared workflows themselves must never use a GitHub-hosted runner#4
Conversation
…nner The SSOT was the bug. Four of the six reusable workflows already targeted the Spartan org pool, but `auto-merge-to-develop.yml` (1 job) and `cla.yml` (2 jobs) still declared `runs-on: ubuntu-latest`. Every repo in the ecosystem is about to consume these workflows. Migrating onto them unfixed would have propagated the violation ~68 times and called it "unified" — a violation that LOOKS compliant is worse than 68 honest ones. All three jobs now target the scitex-ai org runner pool ([self-hosted, Linux, X64, spartan-cpu]: spartan-cpu-org-01/-02, spartan-pooled-cpu-01), not per-repo labels — a per-repo label cannot work for 68 consumers, and pooled org-level runners are the standing preference. Operator mandate (2026-07-14): zero GitHub-hosted runners, no exceptions. If Spartan cannot run something, we fix Spartan; we never fall back. Verified: all 6 workflows parse (yaml.safe_load); zero hosted-runner references remain in the repo.
…erge) Answers the question that gates moving auto-merge + cla onto Spartan: does the org-pool runner actually have `gh`? Merging that change blind would break PR auto-merge and the CLA check org-wide if it does not.
The probe did its job: a workflow requesting the org pool ([self-hosted, Linux, X64, spartan-cpu]) sat QUEUED for 10+ minutes and was never assigned a runner, while all three org runners reported online + idle. Result recorded on the scitex-hpc card; the probe itself is not merged.
DO NOT MERGE YET — blocked on the org runner pool actually dispatchingThis diff is correct, but merging it today would cause a silent org-wide outage. I probed the runner before trusting it, and the result changes the sequencing. What I measuredI pushed a temporary probe workflow requesting exactly what this PR targets — Meanwhile the org pool reports itself perfectly healthy: Group membership: For contrast, the runner that demonstrably does execute jobs is the repo-level one: Org plan is Why this blocks the merge
(Separately: none of the four workflows already on Spartan invoke Sequencing
Per the mandate — 「スパルタンがうまく動かない場合は我々の問題です。github runner に決して逃げないでください」 — the answer here is to fix Spartan, not to revert these three jobs to |
Dispatch is PROVEN — the gate on this PR is clearedThis PR was held until the org runner pool was shown to actually dispatch. It does. Verified live today, not inferred from the runners API. Method.
Same repo, same push, same instant. A ran; B never got a runner. That confirms both the exclusion mechanism and the fix. Toolchain on the runner (this PR migrates
End-to-end pilot. One blocker remains, and it is in this PRs blast radius
This is currently masked: ~65 of 71 repos have their own repo-level runner (which carries Fix is one call — put the pooled runner in the group that allows public repos: gh api --method PUT /orgs/scitex-ai/actions/runner-groups/3/runners/348The six reusable workflows here all correctly target |
|
| before the group move | after | |
|---|---|---|
scitex-ci |
queued 11m54s, runner: null, never assigned |
assigned in 3s → spartan-pooled-cpu-01, group spartan-cpu → success |
spartan-cpu (positive control) |
assigned ~3s | assigned 3s → spartan-cpu-org-02 → success |
The positive control is there on purpose: had scitex-ci hung and spartan-cpu hung, the pool would simply have been down and the test would prove nothing. Both dispatched, so the result is attributable to the group move.
Consequence: the pypi-publish templates baked-in runs-on fallback —
runs-on: ${{ fromJSON(vars.CI_RUNS_ON || [self-hosted,Linux,X64,scitex-ci]) }}
— is now safe on a public repo with no repo-level runner. That was the last thing standing between this PR and a merge. Both org runner groups now allow public repos, and Default is empty.
This PR is unblocked. Its six reusable workflows all target spartan-cpu; gh 2.40.1 is present on the runner, so the two workflows this PR migrates (auto-merge-to-develop.yml, cla.yml) will work.
Carry this rule into the rollout
Migrating a repo onto these reusable workflows renames its status checks (a <caller-job-id> / prefix is added). Branch protection must be flipped to the new names in the same change, or the repo goes green-but-unmergeable — silently. Verified on scitex-config: PR #23 sat mergeStateStatus=BLOCKED with all 7 checks green until protection was patched. Read the names off a real PR; never guess them.
Re-validated against today's main (2026-07-22) — merging as-is, hardcoded label confirmed correctThis PR sat 8 days and today's 74-repo sweep raised a fair challenge against it: the sweep counted three runner regimes ( runs-on: ${{ fromJSON(vars.CI_RUNS_ON || '["self-hosted","Linux","X64","scitex-ci"]') }}I resolved the variable instead of counting its occurrences, and that inverts the conclusion.
So the 441 Runner capacity agrees: Three runners serve Why not the
|
self-test.yml landed on main today, after #4 was cut, so #4 could not see it. That left the repo that DEFINES the zero-hosted-runner mandate as the only workflow in it still declaring runs-on: ubuntu-latest. Uses uv rather than actions/setup-python: setup-python depends on a runner tool-cache the Spartan image does not populate, whereas every other workflow here already builds its interpreter with uv on this exact pool.
Operator mandate (2026-07-14): zero GitHub-hosted runners across the scitex ecosystem, no exceptions. 「PR用のテストとgithub側のランナーというのは本当にもう一切使わないでください」
The SSOT was the bug
This repo is about to become the single source of truth that ~68 ecosystem repos consume as thin callers. Before this PR, two of its six reusable workflows still declared
runs-on: ubuntu-latest:auto-merge-to-develop.ymlautomergeubuntu-latest[self-hosted, Linux, X64, spartan-cpu]cla.ymlowner-bypassubuntu-latest[self-hosted, Linux, X64, spartan-cpu]cla.ymlCLAssistantubuntu-latest[self-hosted, Linux, X64, spartan-cpu]The other four (
import-smoke,pytest-matrix,quality-audit,rtd-sphinx-build) were already correct.Migrating the ecosystem onto these workflows unfixed would have propagated the violation ~68 times and called it "unified." A violation that looks compliant is worse than 68 honest ones, because nothing downstream would ever flag it. Hence this lands first, before any consumer repo is touched.
Why the org pool, not per-repo labels
runs-ontargets the scitex-ai org runner pool (spartan-cpu-org-01,spartan-cpu-org-02,spartan-pooled-cpu-01— all online, label set[self-hosted, Linux, X64, spartan-cpu]). A per-repo runner label cannot work for 68 consumers, and pooled org-level runners are the standing preference (fewer machines, better utilisation, fewer surfaces to drift).Verification
yaml.safe_load).rg ubuntu-latest|ubuntu-2x|macos-|windows-→ no matches).runs-on:-only; noon:/permissions:/step logic touched.Known follow-up (raised with scitex-hpc, not a blocker for this PR)
auto-merge-to-developandclashell out to theghCLI, which is preinstalled onubuntu-latestbut is not guaranteed on the Spartan runner image. Tracked on the scitex-hpc card along with org-pool capacity (3 runners for 68 repos) and a live shared-venv contamination bug (scitex-stats --versionprintsscitex-dev 0.29.0on the runner). Per the mandate, if Spartan cannot run something we fix Spartan — we never fall back to a hosted runner.