Skip to content

ci: test the interpreter we actually ship (3.12 + 3.14 matrix) - #46

Merged
berntpopp merged 1 commit into
mainfrom
chore/test-shipped-interpreter-2026-07-30
Jul 30, 2026
Merged

ci: test the interpreter we actually ship (3.12 + 3.14 matrix)#46
berntpopp merged 1 commit into
mainfrom
chore/test-shipped-interpreter-2026-07-30

Conversation

@berntpopp

Copy link
Copy Markdown
Owner

The gap

docker/Dockerfile ships python:3.14-slim, but the CI test job ran only on
Python 3.12. container-ci and conformance exercise the image on 3.14; the
test suite never ran on it. A 3.14-only stdlib or typing regression would have
shipped uncaught.

The fix

The quality job now runs a ["3.12", "3.14"] matrix — a matrix, not a swap:

  • 3.12 is the declared requires-python floor. Drop it and the floor is a
    false claim.
  • 3.14 is what actually reaches production.

The coverage gate still runs once (on 3.14, push to main), so the cost is
one extra fast test run per event, not two coverage runs.

UV_PYTHON is load-bearing

The matrix alone would have been a green lie. uv resolves its interpreter from
.python-version — pinned to 3.12 for local dev — before it consults
PATH, so actions/setup-python installing 3.14 changes nothing: both legs
would build a 3.12 environment and the "3.14" leg would test the floor twice.
The job therefore exports UV_PYTHON: ${{ matrix.python-version }}, which
outranks .python-version and applies to every uv run inside make ci-local,
not only the explicit uv sync.

Kept honest by a guard

New tests/unit/test_ci_python_matrix.py asserts the matrix contains the
requires-python floor and the Dockerfile's FROM python:<x.y>-slim, that
UV_PYTHON is wired to the matrix, and that the coverage gate runs once rather
than per leg. A future base-image bump that is not mirrored into CI now fails
instead of silently re-opening the blind spot.

requires-python, ruff target-version and mypy python_version are
deliberately unchanged at 3.12.

Verification

make ci-local locally on both interpreters — 478 passed, 2 skipped on each
(the 2 skips are the live conformance probes, which need a running server).

🤖 Generated with Claude Code

https://claude.ai/code/session_01EUS8yK2hqkNpfoTxFR4RPR

docker/Dockerfile ships python:3.14-slim, but the CI test job ran only on
Python 3.12. The image was exercised on 3.14 by container-ci and conformance;
the test suite never was. A 3.14-only stdlib or typing regression could ship
uncaught.

The quality job now runs a ["3.12", "3.14"] matrix. Both ends matter: 3.12 is
the declared requires-python floor and must stay tested or the floor is a false
claim, and 3.14 is what reaches production. The coverage gate still runs once
(on 3.14, push to main), so the cost is one extra fast test run per event.

The matrix needs UV_PYTHON to be real. uv resolves its interpreter from
.python-version -- pinned to 3.12 for local dev -- before it consults PATH, so
actions/setup-python alone does not move it: both legs would build a 3.12
environment and the "3.14" leg would test the floor twice, green and
meaningless. The job-level env var also covers every `uv run` inside
`make ci-local`, not just the explicit `uv sync`.

tests/unit/test_ci_python_matrix.py pins the matrix against pyproject's floor
and the Dockerfile's FROM python:<x.y>-slim, plus the UV_PYTHON wiring and the
single coverage run, so a base-image bump that is not mirrored into CI fails
instead of silently narrowing it.

requires-python, ruff target-version and mypy python_version are deliberately
unchanged at 3.12.

Verified locally on both interpreters: 478 passed, 2 skipped (live conformance
probes) on 3.12 and on 3.14.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUS8yK2hqkNpfoTxFR4RPR
@berntpopp
berntpopp merged commit 1c718b7 into main Jul 30, 2026
8 checks passed
@berntpopp
berntpopp deleted the chore/test-shipped-interpreter-2026-07-30 branch July 30, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant