Summary
The CI workflow has no dependency caching and no concurrency cancellation. Add cache: pip
to the Python setup and a concurrency group with cancel-in-progress, so the gate that
fronts every review runs faster and stops burning runner time on superseded pushes.
Why this matters
CI is the feedback loop that gates review here, and this repo has a high push cadence per PR
(many fix: address Copilot review … / address review feedback fix-up commits — e.g.
5f004af, b2be0e0, d252c9a, a03f631). Each push triggers a full matrix run, and:
- No caching:
pip install -e ".[dev]" reinstalls every dependency from scratch on each
of the 3 matrix jobs (.github/workflows/ci.yml:18,28-29), on every push and PR. grep -nE "cache|concurrency" .github/workflows/ci.yml → no matches.
- No concurrency cancellation: there is no top-level
concurrency: block, so when a PR is
pushed again (common, given the fix-up cadence) the now-stale run keeps executing to
completion instead of being cancelled.
Together these slow the time-to-green and waste runner minutes, which lengthens review cycles.
Current evidence
.github/workflows/ci.yml — actions/setup-python@v5 is used with no cache: key;
dependencies installed via pip install -e ".[dev]" (lines 23-29) with nothing cached
across runs.
- No
concurrency: block anywhere in the workflow.
Scope / relationship to existing issues
This is complementary to and does not overlap:
Coordinate the final YAML with whichever of those lands first.
Proposed implementation
- Add caching to the Python setup step:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml
- Add a top-level concurrency group:
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
(Use a github.ref-based group so pushes to a PR cancel the prior run while distinct
branches/PRs remain independent.)
AI-agent execution notes
- Inspect first:
.github/workflows/ci.yml, .github/workflows/publish.yml, pyproject.toml.
- Be careful applying
cancel-in-progress to publish.yml — do not cancel in-progress
release/publish runs. Limit the concurrency block to ci.yml (or scope publish's group to
never cancel).
- Cache key must invalidate when
pyproject.toml deps change (cache-dependency-path).
Acceptance criteria
- CI restores a pip cache on repeat runs (visible "Cache restored" in setup-python logs).
- Pushing a new commit to an open PR cancels the prior in-progress CI run.
publish.yml release runs are never cancelled by the new concurrency rule.
Test plan
Open a trial PR, push twice in quick succession, and confirm the first run is cancelled and
the second restores a cache. Confirm publish workflow behavior is unchanged.
Documentation plan
No doc change required beyond an optional CHANGELOG Changed (CI) note. If #210 lands first,
fold the caching/concurrency keys into the make-target-based workflow.
Migration and compatibility notes
CI-only change; no impact on the package or its consumers.
Risks and tradeoffs
A stale or poisoned cache can mask dependency issues; keying on pyproject.toml and using
pip install -e (which still resolves) keeps risk low. cancel-in-progress could cancel a
run a maintainer wanted to watch — acceptable for a pre-merge gate.
Suggested labels
reliability, contributor-experience, performance
Summary
The CI workflow has no dependency caching and no concurrency cancellation. Add
cache: pipto the Python setup and a
concurrencygroup withcancel-in-progress, so the gate thatfronts every review runs faster and stops burning runner time on superseded pushes.
Why this matters
CI is the feedback loop that gates review here, and this repo has a high push cadence per PR
(many
fix: address Copilot review …/address review feedbackfix-up commits — e.g.5f004af,b2be0e0,d252c9a,a03f631). Each push triggers a full matrix run, and:pip install -e ".[dev]"reinstalls every dependency from scratch on eachof the 3 matrix jobs (
.github/workflows/ci.yml:18,28-29), on every push and PR.grep -nE "cache|concurrency" .github/workflows/ci.yml→ no matches.concurrency:block, so when a PR ispushed again (common, given the fix-up cadence) the now-stale run keeps executing to
completion instead of being cancelled.
Together these slow the time-to-green and waste runner minutes, which lengthens review cycles.
Current evidence
.github/workflows/ci.yml—actions/setup-python@v5is used with nocache:key;dependencies installed via
pip install -e ".[dev]"(lines 23-29) with nothing cachedacross runs.
concurrency:block anywhere in the workflow.Scope / relationship to existing issues
This is complementary to and does not overlap:
make cito eliminate drift #210 (make CI callmaketargets to remove drift) — about what runs, not run speed.Coordinate the final YAML with whichever of those lands first.
Proposed implementation
github.ref-based group so pushes to a PR cancel the prior run while distinctbranches/PRs remain independent.)
AI-agent execution notes
.github/workflows/ci.yml,.github/workflows/publish.yml,pyproject.toml.cancel-in-progresstopublish.yml— do not cancel in-progressrelease/publish runs. Limit the concurrency block to
ci.yml(or scope publish's group tonever cancel).
pyproject.tomldeps change (cache-dependency-path).Acceptance criteria
publish.ymlrelease runs are never cancelled by the new concurrency rule.Test plan
Open a trial PR, push twice in quick succession, and confirm the first run is cancelled and
the second restores a cache. Confirm publish workflow behavior is unchanged.
Documentation plan
No doc change required beyond an optional CHANGELOG
Changed(CI) note. If #210 lands first,fold the caching/concurrency keys into the make-target-based workflow.
Migration and compatibility notes
CI-only change; no impact on the package or its consumers.
Risks and tradeoffs
A stale or poisoned cache can mask dependency issues; keying on
pyproject.tomland usingpip install -e(which still resolves) keeps risk low.cancel-in-progresscould cancel arun a maintainer wanted to watch — acceptable for a pre-merge gate.
Suggested labels
reliability, contributor-experience, performance