From 4aa3d4829e757dd47f4583572a82ee37cc55e061 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Mon, 19 Oct 2026 15:05:57 +0200 Subject: [PATCH 1/3] ci: release workflows and ct-conventions v0.7.0 The release callers of CTBase.jl#623: ReleaseGate, ReleaseTag, Breakage on breakage-suite, Documentation dispatchable; AGENTS.md pins ct-conventions v0.7.0. Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/Breakage.yml | 28 +++++++++++++--------------- .github/workflows/Documentation.yml | 2 ++ .github/workflows/ReleaseGate.yml | 12 ++++++++++++ .github/workflows/ReleaseTag.yml | 18 ++++++++++++++++++ AGENTS.md | 18 ++++++++++++++---- CHANGELOG.md | 9 +++++++++ 6 files changed, 68 insertions(+), 19 deletions(-) create mode 100644 .github/workflows/ReleaseGate.yml create mode 100644 .github/workflows/ReleaseTag.yml diff --git a/.github/workflows/Breakage.yml b/.github/workflows/Breakage.yml index 7853e16e..6db0672b 100644 --- a/.github/workflows/Breakage.yml +++ b/.github/workflows/Breakage.yml @@ -1,11 +1,15 @@ -# Ref: https://securitylab.github.com/research/github-actions-preventing-pwn-requests name: Breakage -# read-only repo token -# no access to secrets +# The packages that depend on CTModels, tested against it; one report per run. On push to +# main and by hand, the run is the baseline the next release PR compares with (REL1); see +# CTActions docs/workflows/breakage-suite.md. + on: pull_request: types: [labeled, synchronize, reopened] + push: + branches: [main] + workflow_dispatch: jobs: call: @@ -13,22 +17,16 @@ jobs: # *current* full label set — so adding several labels in a row would otherwise # re-run this job on every subsequent label add. Only react to 'labeled' when it's # this specific label; for other trigger types (synchronize/reopened), fall back to - # checking the current label set as before. + # checking the current label set as before. On push to main and by hand, always. if: > + github.event_name != 'pull_request' || (github.event.action == 'labeled' && github.event.label.name == 'run breakage') || (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'run breakage')) - strategy: - fail-fast: false - matrix: - pkgname: [CTDirect, CTFlows, CTSolvers, OptimalControl] - pkgversion: [latest, stable] - include: - - pkgpath: control-toolbox - uses: control-toolbox/CTActions/.github/workflows/breakage.yml@main + uses: control-toolbox/CTActions/.github/workflows/breakage-suite.yml@main with: - pkgname: ${{ matrix.pkgname }} - pkgpath: ${{ matrix.pkgpath }} - pkgversion: ${{ matrix.pkgversion }} + targets: >- + [{"name": "CTDirect"}, {"name": "CTFlows"}, {"name": "CTSolvers"}, + {"name": "OptimalControl"}] use_ct_registry: true secrets: SSH_KEY: ${{ secrets.SSH_KEY }} diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml index 6d294efe..e5d05f33 100644 --- a/.github/workflows/Documentation.yml +++ b/.github/workflows/Documentation.yml @@ -8,6 +8,8 @@ on: - 'v[0-9]+\.[0-9]+\.[0-9]+' # v0.5.0 yes, v0.5.0-beta no pull_request: types: [labeled, synchronize, reopened] + # run on a tag by ReleaseTag.yml: a tag it creates triggers no push event + workflow_dispatch: jobs: call: diff --git a/.github/workflows/ReleaseGate.yml b/.github/workflows/ReleaseGate.yml new file mode 100644 index 00000000..38d4eb3a --- /dev/null +++ b/.github/workflows/ReleaseGate.yml @@ -0,0 +1,12 @@ +name: Release gate + +# REL1-REL7 of ct-conventions on every PR (a PR that does not change the version passes at +# once); see CTActions docs/workflows/release-gate.md. + +on: + pull_request: + types: [opened, synchronize, reopened, labeled, unlabeled, edited] + +jobs: + call: + uses: control-toolbox/CTActions/.github/workflows/release-gate.yml@main diff --git a/.github/workflows/ReleaseTag.yml b/.github/workflows/ReleaseTag.yml new file mode 100644 index 00000000..d5b784d5 --- /dev/null +++ b/.github/workflows/ReleaseTag.yml @@ -0,0 +1,18 @@ +name: Release tag + +# Tags the merge commit of a release PR, creates its GitHub release and runs the +# documentation on the tag; see CTActions docs/workflows/release-tag.md. + +on: + push: + branches: [main] + paths: [Project.toml] + workflow_dispatch: + +permissions: + contents: write + actions: write + +jobs: + call: + uses: control-toolbox/CTActions/.github/workflows/release-tag.yml@main diff --git a/AGENTS.md b/AGENTS.md index 50f38ae9..7829dfc3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,10 +29,10 @@ is not the pinned tag, (re)create it: ```bash rm -rf .conventions -git -c advice.detachedHead=false clone --quiet --depth 1 --branch v0.5.2 https://github.com/control-toolbox/ct-conventions.git .conventions +git -c advice.detachedHead=false clone --quiet --depth 1 --branch v0.7.0 https://github.com/control-toolbox/ct-conventions.git .conventions ``` -**Pinned version: ct-conventions v0.5.2.** Cite rules by identifier (`MOD3`, `TST1`), and +**Pinned version: ct-conventions v0.7.0.** Cite rules by identifier (`MOD3`, `TST1`), and state the version you applied in plans and reports. Read in this order: @@ -40,7 +40,7 @@ Read in this order: | File | Content | | --- | --- | | [`rules/general.md`](.conventions/rules/general.md) | Rules that hold everywhere — **always read** | -| [`README.md`](.conventions/README.md) | Index of the rule files, one per area (`MOD`, `TYP`, `DIM`, `EXC`, `PERF`, `DOC`, `TST`, `SITE`, `CHG`) | +| [`README.md`](.conventions/README.md) | Index of the rule files, one per area (`MOD`, `TYP`, `DIM`, `EXC`, `PERF`, `DOC`, `TST`, `SITE`, `CHG`, `REL`) | | [`method.md`](.conventions/method.md) | How to work: tests, coverage, docs build, output capture | | [`plan-template.md`](.conventions/plan-template.md) | Template for a substantial piece of work | @@ -60,4 +60,14 @@ How agents behave on these repositories is described in - **1-D is a scalar** — a one-dimensional state/control/variable is a `Number` (`DIM1`). - **Plan before code** — a local agent proposes a plan ([`plan-template.md`](.conventions/plan-template.md)) and waits for confirmation before working on code. The process for remote agents is still to be defined. - **Docstrings last** — written once the implementation is stable (`DOC1`–`DOC8`). -- **The human merges** — an agent never merges a pull request. +- **The human merges** — an agent never merges a pull request, except a release PR in `autonomous` mode, and then only with `release.jl merge` (see below). + +--- + +## Recurring tasks + +- **Release.** When asked, in any language, to prepare a release, follow + [`recipes/release.md`](https://github.com/control-toolbox/ct-agents/blob/main/recipes/release.md) + of ct-agents (rules `REL1`–`REL7`). Read it with + `gh api repos/control-toolbox/ct-agents/contents/recipes/release.md -H "Accept: application/vnd.github.raw"`. + Stable or beta is the human's choice: if the request does not say, ask; never infer it. diff --git a/CHANGELOG.md b/CHANGELOG.md index 32401d4a..686ec0b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New page *Switching structure*; the `build_solution` contract, plotting and export/import pages describe it. +- ct-conventions pinned at `v0.7.0` in `AGENTS.md`: the release rules `REL1`–`REL7` in the + index, and a *Recurring tasks* section pointing to the release recipe of ct-agents. + +### 🧪 Testing + +- Release workflows: `ReleaseGate.yml` (the gate of a release PR, `REL1`–`REL7`) and + `ReleaseTag.yml` (tag and GitHub release of a merged release PR) call CTActions; + `Breakage.yml` moves to `breakage-suite.yml` (one report, the `REL1` check of a release + PR) and also runs on push to `main`; `Documentation.yml` accepts `workflow_dispatch`. ## [0.19.8] - 2026-10-14 From b7df6ca5aa55e0f9932f18c730f750cdde3de844 Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Mon, 19 Oct 2026 15:08:23 +0200 Subject: [PATCH 2/3] ci(breakage): add the consumers listed in the Project.toml files Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/Breakage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Breakage.yml b/.github/workflows/Breakage.yml index 6db0672b..47e8002d 100644 --- a/.github/workflows/Breakage.yml +++ b/.github/workflows/Breakage.yml @@ -25,7 +25,7 @@ jobs: uses: control-toolbox/CTActions/.github/workflows/breakage-suite.yml@main with: targets: >- - [{"name": "CTDirect"}, {"name": "CTFlows"}, {"name": "CTSolvers"}, + [{"name": "CTDirect"}, {"name": "CTFlows"}, {"name": "CTParser"}, {"name": "CTSolvers"}, {"name": "OptimalControl"}] use_ct_registry: true secrets: From 4e885d2b9c5af66acd523315f05b8fbe580338fc Mon Sep 17 00:00:00 2001 From: Olivier Cots Date: Mon, 19 Oct 2026 15:35:30 +0200 Subject: [PATCH 3/3] ci(breakage): derive the consumers, no list Co-Authored-By: Claude Sonnet 5.5 --- .github/workflows/Breakage.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Breakage.yml b/.github/workflows/Breakage.yml index 47e8002d..30f4da9e 100644 --- a/.github/workflows/Breakage.yml +++ b/.github/workflows/Breakage.yml @@ -1,7 +1,8 @@ name: Breakage -# The packages that depend on CTModels, tested against it; one report per run. On push to -# main and by hand, the run is the baseline the next release PR compares with (REL1); see +# The packages that depend on CTModels, derived from the Project.toml files of the +# organization, tested against it; one report per run. On push to main and by hand, the +# run is the baseline the next release PR compares with (REL1); see # CTActions docs/workflows/breakage-suite.md. on: @@ -24,9 +25,6 @@ jobs: (github.event.action != 'labeled' && contains(github.event.pull_request.labels.*.name, 'run breakage')) uses: control-toolbox/CTActions/.github/workflows/breakage-suite.yml@main with: - targets: >- - [{"name": "CTDirect"}, {"name": "CTFlows"}, {"name": "CTParser"}, {"name": "CTSolvers"}, - {"name": "OptimalControl"}] use_ct_registry: true secrets: SSH_KEY: ${{ secrets.SSH_KEY }}