From 8e4a2b4992a66fdd2748386b897aed8a3eb5de9d Mon Sep 17 00:00:00 2001 From: Drewry Pope Date: Thu, 29 Oct 2026 00:26:42 -0500 Subject: [PATCH] =?UTF-8?q?ci:=20fast=20PR=20tier,=20full=20main=20tier=20?= =?UTF-8?q?=E2=80=94=20cancel-in-progress=20+=20PR=20slimming=20(#1780,=20?= =?UTF-8?q?#1781)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 1 (#1780): goreleaser gains the standard §4 concurrency block; auto-assign flips cancel-in-progress on its existing per-issue/per-PR group (per-target keying means cancellation can only supersede a stale run for the same issue/PR). jules.yml and scheduled singleton cip=false workflows untouched. Phase 2 (#1781): nix-ci flake-check moves to main+nightly (treefmt stays on PRs); id keeps guard+affected-crate matrix on PRs and gains a full flake-check job on main+nightly (id-e2e-nightly remains a second nightly backstop); mcpx conformance legs+records move to main, spec-parity stays on PRs (28s measured exec); id bench main-only; go-modules/identity/map/mcpx-nix builds fire on PRs only for class-3 paths and always on push to main. Change-class policy shipped as .github/ci-policy.md; every touched workflow points at it. --- .github/ci-policy.md | 61 ++++++++++++++++++++++++++ .github/workflows/auto-assign.yml | 5 ++- .github/workflows/go-modules-build.yml | 41 ++++++++++------- .github/workflows/goreleaser.yml | 5 +++ .github/workflows/id-bench.yml | 9 ++-- .github/workflows/id-check.yml | 33 ++++++++++++++ .github/workflows/identity-build.yml | 16 ++++--- .github/workflows/map-build.yml | 16 ++++--- .github/workflows/mcpx-conformance.yml | 8 +++- .github/workflows/mcpx-nixbuild.yml | 14 +++--- .github/workflows/nix-ci.yml | 7 +++ 11 files changed, 177 insertions(+), 38 deletions(-) create mode 100644 .github/ci-policy.md diff --git a/.github/ci-policy.md b/.github/ci-policy.md new file mode 100644 index 000000000..8c2b6dd82 --- /dev/null +++ b/.github/ci-policy.md @@ -0,0 +1,61 @@ +# CI tier policy — fast PR tier, full main tier + +Design: developing-today/code#1779 (ci-fast-pr-full-main). Phases: +#1780 (cancel-in-progress), #1781 (this policy), #1782 (main-breakage +chain, .github/workflows/main-broken.yml). Tracker: #1599. + +Every workflow touched by the tier redesign carries the header +comment . Tuning the tiers +means editing THIS table by PR — never ad-hoc pipeline changes. + +## Change classes (§3.3 of the design) + +| class | trigger paths (examples) | PR tier | +|---|---|---| +| 0 — prose | , docs/, comments-only changes | nothing, or markdown lint only | +| 1 — config/data | non-build, (non-workflow) | syntax parse + lint of changed files | +| 2 — package source (default) | one package's src + tests | lint/format + typecheck/syntax of affected packages + affected unit tests | +| 3 — elevated | lockfiles, / roots, /, build definitions (), , shared/core libraries | class 2 + compile check of affected packages | +| 4 — nix expressions | | class 1 + parse/eval of the changed files only (never full flake check on a PR) | + +Default when a change spans classes: the highest class wins. The +policy ships conservative (more class 3) and loosens as the +main-breakage rate (issues labelled ) proves out. + +## Tier assignment in this repo (after #1781) + +| workflow | PR tier | main tier | nightly | +|---|---|---|---| +| nix ci | treefmt/format gate only | treefmt + full flake-check | schedule in nix-ci.yml | +| id | guard + affected-crate matrix () | + full job | schedule in id-check.yml + id-e2e-nightly.yml (full flake check) | +| mcpx conformance | spec-parity leg only (measured 28s exec, run 40801660942, 2026-10-29 — under the 5m fast-leg limit) | all conformance legs + records + spec-parity | — (main covers it) | +| id bench | — (removed) | yes | — | +| go modules build / identity build / map build / mcpx nix build | class-3 paths only (see each workflow) | always (push to main, no path filter) | — | +| mcpx, lab-ops-hub, mod-tidy, research-workflow | unchanged path-gated PR checks (already PR-tier weight) | push to main | — | + +## Coverage rule + +Nothing removed from PRs may vanish: the union of main-tier + +nightly jobs must cover the old PR matrix. For pkgs/id the full +flake check runs on main (id-check full-flake-check job) and +nightly twice over (id-check schedule, id-e2e-nightly). For nix ci +the flake-check job runs on main and on the nix-ci nightly +schedule. mcpx conformance legs run on every mcpx-touching merge +to main. + +## Dedup rule + +A commit must not run the same suite twice via push + +pull_request. Standard shape: for PRs, +restricted to (plus tags where already +applicable, e.g. goreleaser). + +## Concurrency rule (#1780) + +Standard block (design §4): group keyed by for +push-to-main, by otherwise, +— PR/branch runs cancel on supersede; main runs are never +cancelled. Exceptions: (load-bearing cip=false, #304) +and scheduled singleton/deploy workflows (cip=false) are NOT +touched. Issue-event workflows (auto-assign) use a per-issue group +so cancel-in-progress can only supersede a run for the same issue. diff --git a/.github/workflows/auto-assign.yml b/.github/workflows/auto-assign.yml index 1a3e911cd..0527d0e46 100755 --- a/.github/workflows/auto-assign.yml +++ b/.github/workflows/auto-assign.yml @@ -9,8 +9,11 @@ concurrency: # events github.ref is always the default/base branch, so a ref-keyed group # is one repo-wide group and a burst of opened events silently replaces the # pending run (queue: single is the default), dropping its assignment (#302). + # The group below is per-target, so cancel-in-progress only ever supersedes + # a stale run for the SAME issue/PR; the assignment is idempotent and the + # newest event wins (Phase 1, #1780). CI tier policy: see .github/ci-policy.md group: ${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }} - cancel-in-progress: false + cancel-in-progress: true jobs: run: diff --git a/.github/workflows/go-modules-build.yml b/.github/workflows/go-modules-build.yml index a197d5aac..4ed4b1311 100644 --- a/.github/workflows/go-modules-build.yml +++ b/.github/workflows/go-modules-build.yml @@ -1,5 +1,7 @@ name: go modules build +# CI tier policy: see .github/ci-policy.md + # Build verification for the small pkgs/{chat,database,graph,import, # launcher,tea} Go modules (#342). # @@ -28,24 +30,33 @@ name: go modules build on: pull_request: + # PR tier (Phase 2, #1781): builds fire on PRs only for class-3 + # changes (lockfiles, module roots, flake files, build definitions, + # workflow files, shared libs); on push to main they always run. paths: - - "pkgs/chat/**" - - "pkgs/database/**" - - "pkgs/graph/**" - - "pkgs/import/**" - - "pkgs/launcher/**" - - "pkgs/tea/**" - - ".github/workflows/go-modules-build.yml" + - "pkgs/chat/go.mod" + - "pkgs/chat/go.sum" + - "pkgs/database/go.mod" + - "pkgs/database/go.sum" + - "pkgs/graph/go.mod" + - "pkgs/graph/go.sum" + - "pkgs/import/go.mod" + - "pkgs/import/go.sum" + - "pkgs/launcher/go.mod" + - "pkgs/launcher/go.sum" + - "pkgs/tea/go.mod" + - "pkgs/tea/go.sum" + - "pkgs/chat/package.nix" + - "pkgs/database/package.nix" + - "pkgs/graph/package.nix" + - "pkgs/import/package.nix" + - "pkgs/launcher/package.nix" + - "pkgs/tea/package.nix" + - "flake.nix" + - "flake.lock" + - ".github/workflows/**" push: branches: [main] - paths: - - "pkgs/chat/**" - - "pkgs/database/**" - - "pkgs/graph/**" - - "pkgs/import/**" - - "pkgs/launcher/**" - - "pkgs/tea/**" - - ".github/workflows/go-modules-build.yml" permissions: contents: read diff --git a/.github/workflows/goreleaser.yml b/.github/workflows/goreleaser.yml index 6d88cfcc5..13aab6a21 100644 --- a/.github/workflows/goreleaser.yml +++ b/.github/workflows/goreleaser.yml @@ -11,6 +11,11 @@ on: permissions: contents: write +# CI tier policy: see .github/ci-policy.md +concurrency: + group: ${{ github.workflow }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && github.run_id || github.ref }} + cancel-in-progress: true + jobs: dump_contexts_to_log: runs-on: ubuntu-latest diff --git a/.github/workflows/id-bench.yml b/.github/workflows/id-bench.yml index 1bd44975a..d5879f804 100644 --- a/.github/workflows/id-bench.yml +++ b/.github/workflows/id-bench.yml @@ -5,6 +5,8 @@ # using .github/scripts/id-bench-compare.sh. The report lands in the job # summary and as a run artifact. # +# Main tier only (Phase 2, #1781): benchmarks no longer run on PRs. +# # NON-BLOCKING BY DESIGN: this workflow is separate from the required # "nix flake check" gate in id-check.yml, the bench step is # continue-on-error, and the compare script always exits 0. A regression @@ -15,6 +17,8 @@ name: id bench +# CI tier policy: see .github/ci-policy.md + on: push: branches: [main] @@ -22,11 +26,6 @@ on: - "pkgs/id/**" - ".github/workflows/id-bench.yml" - ".github/scripts/id-bench-compare.sh" - pull_request: - paths: - - "pkgs/id/**" - - ".github/workflows/id-bench.yml" - - ".github/scripts/id-bench-compare.sh" workflow_dispatch: permissions: diff --git a/.github/workflows/id-check.yml b/.github/workflows/id-check.yml index 60eabf8e4..f9bdd2a72 100644 --- a/.github/workflows/id-check.yml +++ b/.github/workflows/id-check.yml @@ -39,6 +39,8 @@ name: id +# CI tier policy: see .github/ci-policy.md + on: push: branches: [main] @@ -55,6 +57,10 @@ on: - ".github/scripts/id-pr-checks.txt" - ".github/scripts/check-id-pr-checks.sh" - ".github/scripts/check-crash-gate-coverage.sh" + schedule: + # Nightly backstop for the full flake check (main tier, #1781). + - cron: "41 8 * * *" + workflow_dispatch: permissions: contents: read @@ -166,3 +172,30 @@ jobs: echo "::error::one or more PR check jobs did not succeed (result: $result) — see the per-check jobs above." exit 1 fi + + # Main tier (Phase 2, #1781): the FULL flake check for pkgs/id. The PR + # tier above keeps guard + the affected-crate matrix from + # id-pr-checks.txt; the full check (including the heavy checks the PR + # list excludes) runs once per merge on main, plus the nightly + # schedule above -- and nightly in id-e2e-nightly.yml as a second + # backstop. Nothing from the old PR matrix is lost: the union of this + # job, id-e2e-nightly, and the PR matrix covers it. + full-flake-check: + name: nix flake check (full, main tier) + if: github.event_name != 'pull_request' + runs-on: ubuntu-latest + timeout-minutes: 180 + steps: + - uses: actions/checkout@v7 + - uses: DeterminateSystems/nix-installer-action@3138316df39ed29be04236d7ffc686fa525866aa # v23 + with: + extra-conf: | + accept-flake-config = true + - uses: DeterminateSystems/magic-nix-cache-action@84c0677f58dcedf3b91f8223ce36a9ea5b3c84b7 # v15 + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + - name: Run full nix flake check + run: nix flake check ./pkgs/id/ -L --keep-going diff --git a/.github/workflows/identity-build.yml b/.github/workflows/identity-build.yml index 350473ffe..0abcde730 100644 --- a/.github/workflows/identity-build.yml +++ b/.github/workflows/identity-build.yml @@ -1,5 +1,7 @@ name: identity build +# CI tier policy: see .github/ci-policy.md + # Build verification for the pkgs/identity Go module (#340). # # pkgs/identity builds only with a build tag: its charm fork keeps the @@ -11,14 +13,18 @@ name: identity build on: pull_request: + # PR tier (Phase 2, #1781): builds fire on PRs only for class-3 + # changes (lockfiles, module roots, flake files, build definitions, + # workflow files, shared libs); on push to main they always run. paths: - - "pkgs/identity/**" - - ".github/workflows/identity-build.yml" + - "pkgs/identity/go.mod" + - "pkgs/identity/go.sum" + - "pkgs/identity/package.nix" + - "flake.nix" + - "flake.lock" + - ".github/workflows/**" push: branches: [main] - paths: - - "pkgs/identity/**" - - ".github/workflows/identity-build.yml" permissions: contents: read diff --git a/.github/workflows/map-build.yml b/.github/workflows/map-build.yml index 5fd2505df..a2a37b403 100644 --- a/.github/workflows/map-build.yml +++ b/.github/workflows/map-build.yml @@ -1,5 +1,7 @@ name: map build +# CI tier policy: see .github/ci-policy.md + # Build verification for the small pkgs/map Go module (#338). # # Nothing built pkgs/map in CI at all, so it rotted silently: its @@ -11,14 +13,18 @@ name: map build on: pull_request: + # PR tier (Phase 2, #1781): builds fire on PRs only for class-3 + # changes (lockfiles, module roots, flake files, build definitions, + # workflow files, shared libs); on push to main they always run. paths: - - "pkgs/map/**" - - ".github/workflows/map-build.yml" + - "pkgs/map/go.mod" + - "pkgs/map/go.sum" + - "pkgs/map/package.nix" + - "flake.nix" + - "flake.lock" + - ".github/workflows/**" push: branches: [main] - paths: - - "pkgs/map/**" - - ".github/workflows/map-build.yml" permissions: contents: read diff --git a/.github/workflows/mcpx-conformance.yml b/.github/workflows/mcpx-conformance.yml index 68009b185..fd679efd5 100644 --- a/.github/workflows/mcpx-conformance.yml +++ b/.github/workflows/mcpx-conformance.yml @@ -1,5 +1,7 @@ name: mcpx conformance +# CI tier policy: see .github/ci-policy.md + # The official MCP conformance suite (github.com/modelcontextprotocol/conformance) against mcpx, # one job per leg. A leg is one side of the protocol (mcpx as a server, or as a client) checked # against one spec revision. The suite has frozen requirement sets for 2025-11-25 and 2026-07-28; @@ -54,6 +56,10 @@ env: jobs: leg: name: ${{ matrix.leg }} + # Main tier only (Phase 2, #1781): the conformance legs move off PRs. + # The spec-parity job below stays on PRs: measured exec 28s on run + # 40801660942 (2026-10-29), well under the 5m fast-leg limit. + if: github.event_name != 'pull_request' runs-on: ubuntu-latest timeout-minutes: 20 strategy: @@ -343,7 +349,7 @@ jobs: records: name: compare with the records needs: leg - if: always() + if: always() && github.event_name != 'pull_request' runs-on: ubuntu-latest timeout-minutes: 10 steps: diff --git a/.github/workflows/mcpx-nixbuild.yml b/.github/workflows/mcpx-nixbuild.yml index 1f311ba84..68ab837ec 100644 --- a/.github/workflows/mcpx-nixbuild.yml +++ b/.github/workflows/mcpx-nixbuild.yml @@ -1,5 +1,7 @@ name: mcpx nix build +# CI tier policy: see .github/ci-policy.md + # Narrow package-build verification (#297). # # The mcpx workflow's PR gate is a direct-Go test job — it no longer builds @@ -17,18 +19,18 @@ name: mcpx nix build on: pull_request: + # PR tier (Phase 2, #1781): builds fire on PRs only for class-3 + # changes (lockfiles, module roots, flake files, build definitions, + # workflow files, shared libs); on push to main they always run. paths: - "pkgs/mcpx/go.mod" - "pkgs/mcpx/go.sum" - "pkgs/mcpx/package.nix" - - ".github/workflows/mcpx-nixbuild.yml" + - "flake.nix" + - "flake.lock" + - ".github/workflows/**" push: branches: [main] - paths: - - "pkgs/mcpx/go.mod" - - "pkgs/mcpx/go.sum" - - "pkgs/mcpx/package.nix" - - ".github/workflows/mcpx-nixbuild.yml" permissions: contents: read diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index fbc44888e..3570190af 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -1,9 +1,14 @@ name: nix ci +# CI tier policy: see .github/ci-policy.md on: push: branches: [main] pull_request: + schedule: + # Nightly backstop: the full flake check runs on main + nightly, not PRs. + - cron: "17 8 * * *" + workflow_dispatch: permissions: contents: read @@ -58,6 +63,8 @@ jobs: flake-check: name: Nix flake evaluation + # Main tier only (Phase 2, #1781): PRs keep the treefmt/format gate above. + if: github.event_name != 'pull_request' runs-on: ubuntu-latest timeout-minutes: 15 steps: