Skip to content

Align CI with the control-toolbox Handbook (+ split CI by runner) - #302

Open
jbcaillau wants to merge 2 commits into
mainfrom
ci/align-with-handbook
Open

Align CI with the control-toolbox Handbook (+ split CI by runner)#302
jbcaillau wants to merge 2 commits into
mainfrom
ci/align-with-handbook

Conversation

@jbcaillau

@jbcaillau jbcaillau commented Jul 30, 2026

Copy link
Copy Markdown
Member

Applies the workflow rules from Handbook/WORKFLOWS.md.

Why

CI.yml, Documentation.yml and Breakage.yml fired on every event of every PR with no gate — exactly the waste §2 exists to prevent. §4's distribution table also lists CTParser.jl as needing AddToProject, which was missing. Finally, CI is now split per runner (§3.1).

Changes

File Change
CI.yml split into two jobs per §3.1 (see below)
Documentation.yml run documentation gate + types:; tags restricted to v[0-9]+\.[0-9]+\.[0-9]+ so -beta tags stop deploying docs
Breakage.yml run breakage gate + types:; +CTDirect in the matrix
Coverage.yml name: coverageCoverage (cosmetic)
AddToProject.yml new, copied verbatim from CTBase.jl/CTModels.jl

Untouched (already conforming): Formatter, SpellCheck, CompatHelper, AutoAssign, TagBot, UpdateReadme.

CI split (§3.1, modelled on CTFlows.jl)

Job Runner Julia Label
test-github-runner ubuntu + macos + windows 1.10, 1.12 github-runner
test-kkt-runner self-hosted kkt (GPU/CUDA) 1 kkt-runner

§3.1's table classifies CTParser.jl as having no GPU-relevant code and keeping a single run ci job. That is stale: test/Project.toml depends on CUDA, MadNLPGPU, KernelAbstractions and ExaModels, and test/runtests.jl loads them unconditionally — so the GPU job has real work to do. Worth a Handbook correction separately.

Label names are github-runner / kkt-runner as requested, rather than the run ci cpu / run ci gpu pair used by CTFlows/CTSolvers/OptimalControl.

opened is deliberately excluded from the gated workflows' types: — per §2 it duplicates the labeled run when a PR is created with its label already applied. AddToProject/AutoAssign correctly keep it.

Gate behaviour verified on this PR

  • Unlabelled: CI, Documentation, Breakagezero runs; ungated SpellCheck ran, and the new AddToProject fired on opened. ✅
  • +github-runner: test-github-runner fanned out to 6 jobs; test-kkt-runner skipped. ✅
  • On synchronize with neither runner label: both CI jobs skipped. ✅
  • Adding a label fires exactly one run, never two — the opened-exclusion working. ✅

Notes for the reviewer

  • CTDirect added to the breakage matrix because it is a genuine downstream consumer (real [deps] + [compat], not just a test [extras]). Previously only OptimalControl was listed.
  • windows-latest is new for this package — first Windows run ever, so a failure there is a real finding, not a regression from this PR. (CTFlows.jl's Windows job is currently failing too.)
  • The run ci label is now inert — the split replaced it with the two runner labels. Delete it if you don't want it lingering.
  • kkt-runner has not been exercised yet; the kkt runner looked backed up (CTFlows' test-gpu-kkt had been queued ~40 min).

🤖 Generated with Claude Code

Apply the workflow rules from control-toolbox/Handbook/WORKFLOWS.md.

Label-gated triggers (§2): CI, Documentation and Breakage previously ran on
every event of every PR. They now subscribe to
`types: [labeled, synchronize, reopened]` — deliberately excluding `opened`,
which duplicates the run on PRs created with the label already applied — and
guard their job with the org-standard two-branch `if:` so that only the
relevant label firing triggers a run.

Workflow distribution (§4): add the missing AddToProject.yml, which the
handbook's table lists for CTParser.jl.

Other alignments with the CTBase.jl/CTModels.jl reference callers:
- CI: add windows-latest (§1, §6); rename job test-github -> call; drop the
  dead commented-out moonshot GPU block (CTParser has no GPU code, so it
  keeps a single `run ci` job per §3.1).
- Documentation: restrict tags to v[0-9]+.[0-9]+.[0-9]+ so -beta tags no
  longer deploy docs.
- Breakage: add CTDirect to the matrix — it is a real downstream consumer
  ([deps] + [compat]), alongside OptimalControl.
- Coverage: capitalise the workflow name.

The `run ci`, `run documentation` and `run breakage` labels have been created
in the repository, since the gates are inert without them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Apply the split-CI pattern of WORKFLOWS.md §3.1, using CTFlows.jl's CI.yml as
the reference: call the reusable ci.yml twice, once for the GitHub-hosted
matrix and once for the self-hosted kkt runner, each gated by its own label.

§3.1's table classifies CTParser.jl as having no GPU-relevant code and so
keeping a single `run ci` job, but that is stale: test/Project.toml depends on
CUDA, MadNLPGPU, KernelAbstractions and ExaModels, and test/runtests.jl loads
them unconditionally. The GPU job therefore has real work to do.

Labels are `github-runner` and `kkt-runner` as requested, rather than the
`run ci cpu` / `run ci gpu` pair used elsewhere in the org.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@jbcaillau jbcaillau added the github-runner Trigger CI on GitHub-hosted runners label Jul 30, 2026
@jbcaillau jbcaillau changed the title Align CI with the control-toolbox Handbook Align CI with the control-toolbox Handbook (+ split CI by runner) Jul 30, 2026
@jbcaillau jbcaillau removed the run ci label Jul 30, 2026
@jbcaillau jbcaillau added the kkt-runner Trigger CI on the self-hosted kkt runner (GPU/CUDA) label Jul 30, 2026
@jbcaillau
jbcaillau requested a review from ocots July 30, 2026 15:40
@jbcaillau

Copy link
Copy Markdown
Member Author

@ocots — diagnostic on the kkt-runner job, which is currently stuck on "Waiting for a runner to pick up this job…".

TL;DR

The workflow config is not the cause, and it is probably just queue latency — but there is one permission setting only an org admin can rule out, hence the ping.

1. The CI caller is identical to CTFlows.jl's

Diffing CTParser.jl/.github/workflows/CI.yml against CTFlows.jl/.github/workflows/CI.yml (comments stripped), the only differences are four naming strings:

CTFlows.jl CTParser.jl
job names test-cpu-github / test-gpu-kkt test-github-runner / test-kkt-runner
labels run ci cpu / run ci gpu github-runner / kkt-runner

The kkt job's dispatch inputs are character-for-character identical:

versions: '["1"]'
runs_on: '[["kkt"]]'
runner_type: 'self-hosted'
use_ct_registry: true
secrets:
  SSH_KEY: ${{ secrets.SSH_KEY }}

Both call the same control-toolbox/CTActions/.github/workflows/ci.yml@main, so both request a runner carrying exactly the label kkt. There is no config-level reason this repo would match differently from CTFlows.

The label gate itself is confirmed working: ticking kkt-runner dispatched only the kkt job — test-github-runner correctly shows skipped, so no duplicate CPU matrix was burned.

2. Most likely cause: kkt is simply slow to pick up

CTFlows.jl's own kkt job is not fast to start:

Repo Run created kkt job picked up Wait
CTFlows.jl 14:02 UTC ~15:43 UTC ~95 min
CTParser.jl 15:39 UTC still queued at 15:45 ~6 min so far

CTFlows' job sat queued through every check between 14:02 and 15:43 before starting. The runner also looks single-concurrency, so this repo's job is plausibly queued directly behind the CTFlows job currently occupying it.

Six minutes of waiting is not yet evidence of a fault, measured against a neighbour that just waited ninety-five.

3. The one thing that needs an org admin to rule out

If kkt belongs to an org runner group scoped to selected repositories, and CTParser.jl is not on that list, the job queues forever with exactly this message.

This is worth checking specifically because CTParser.jl has never run a kkt job before — its access has never actually been demonstrated, whereas CTFlows.jl's is proven by history. That asymmetry is precisely what runner-group scoping would produce.

Org Settings → Actions → Runners → (group containing kkt) → Repository access
confirm CTParser.jl is included.

I could not verify this myself: the API needs admin:org and returns 403 for me.

Suggested next step

Wait for the in-flight CTFlows kkt job to finish.

  • If this repo's job then starts → it was only the queue, nothing to fix.
  • If CTFlows completes and this one is still waiting → it is the runner-group permission above.

Everything else on this PR is green: ubuntu and windows pass on Julia 1.10 and 1.12 (Windows being new for this package), with only the macOS cells outstanding.

@jbcaillau

Copy link
Copy Markdown
Member Author

@ocots runs, but one test on GPU fails 👀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

github-runner Trigger CI on GitHub-hosted runners kkt-runner Trigger CI on the self-hosted kkt runner (GPU/CUDA)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants