ci: extend Python test matrix to include 3.13 and 3.14 (#349)#354
Conversation
ci.yml test job matrix changes from: python-version: ["3.10", "3.11", "3.12"] to: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] pyproject.toml declares `requires-python = ">=3.10"` — the package metadata allows 3.13 and 3.14 but CI never exercised them. This closes that gap. lint / typecheck / codecov jobs remain pinned to 3.12 — one representative version for static analysis is sufficient. Complements #348 (docker-smoke workflow). The matrix validates Python versions under actions/setup-python; docker-smoke validates the shipped image. Full CI coverage needs both. Closes #349. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
QA Active — reviewing the Python matrix extension (closes #349). Happy path: 3.13 and 3.14 both green on first try. |
cmeans
left a comment
There was a problem hiding this comment.
QA Review — Round 1
Verdict: Ready for QA Signoff.
Clean one-line matrix extension — and the load-bearing acceptance criterion already passed on this PR's own CI: both test (3.13) and test (3.14) are SUCCESS on their first run. No hidden dep/wheel compat issues surfaced. Happy path outcome from #349.
Steps verified
| Step | Result |
|---|---|
| 1. YAML parse | OK ✓ |
| 2. Matrix lists 5 entries in order | python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] ✓ (see note below — the PR body's grep command for this step has a small indent issue, so I used a corrected version) |
| 3. CI runs 5 test jobs on this PR | ✓ — test (3.10), test (3.11), test (3.12), test (3.13), test (3.14) all present in the check list |
| 4. All five test jobs pass | ✓ — all five SUCCESS |
| 5. Lint/typecheck unchanged | ✓ — lint 28s, typecheck 43s on this PR, consistent with recent main runs; both still pinned to 3.12 |
| 6. Diff stat | ci.yml (+1, -1), CHANGELOG.md (+3) — exactly as described ✓ |
Minor observation (non-blocking)
The PR body's step-2 grep uses ^ matrix: (8 spaces), but matrix: sits at 6-space indent in ci.yml:62 inside strategy: → matrix:. Running the command returns empty instead of the expected python-version: [...] line. Substantive property (matrix has 5 entries) is correct; only the verification regex is slightly off. Easy tidy if you want to fix it, but since the five matrix entries all actually ran and passed on this PR's CI, the substance of step 2 is demonstrated.
Other notes
pyproject.tomldeclaresrequires-python = ">=3.10"— metadata already allowed 3.13/3.14; CI now exercises them. Nopyproject.tomlchange needed.docker-smokeskipped as designed (noDockerfile/pyproject.toml/uv.lock/.dockerignore/ workflow-file-matching-its-trigger change).- CodeQL (actions) green — no new taint-flow sites introduced.
CI rollup on 5346ccce: all matrix test jobs + lint + typecheck + CodeQL + codecov + license/cla — all SUCCESS.
Maintainer to apply QA Approved.
|
Audit: applying Ready for QA Signoff as the final act on |
Follows up on Dependabot [#346](#346) (closed unmerged pending CI matrix coverage). ## Summary One-line change in `Dockerfile`: \`\`\`diff -FROM python:3.12-slim +FROM python:3.13-slim \`\`\` Plus a `CHANGELOG.md` `### Changed` entry. ### Why 3.13 and not 3.14 - **3.13** — GA October 2024, ~5 years of upstream support (EOL October 2029), well-represented in wheel coverage across our deps. Safe bump. - **3.14** — only GA'd October 2026. Our own suite passes (see #354's matrix), but transitive tooling outside our direct deps (container probes, operator scripts, downstream self-hoster environments) lags. Deferring until 3.14-slim has broader ecosystem saturation — revisit in a few months. ### Coverage this relies on - **#354 / #349** (merged `99860de`) — CI test matrix now exercises 3.13, so the Python version the image ships is the Python version the test suite ran on. - **#348 / #350** — `docker-smoke.yml` workflow fires on any `Dockerfile` change, building the image and running import + console-script smokes inside it. That will validate this PR end-to-end. ### What stays unchanged - `pyproject.toml` — `requires-python = ">=3.10"`; no metadata change. - `ci.yml` — `lint` / `typecheck` / `codecov` jobs still pinned to 3.12; `test` matrix still covers 3.10–3.14. - `docker-compose.yaml`, `docker-publish.yml` — untouched. - `uv.lock` — untouched; all deps already support 3.13. ## Risks and unknowns **Happy path:** `docker-smoke` green → merge. Image is marginally larger on first pull (new base layer) but subsequent pulls share layers as usual. **Unhappy path:** `docker-smoke` catches something that the `actions/setup-python` matrix didn't. Likeliest culprit would be a transitive-dep wheel that resolves differently in the slim image's glibc environment than it does on Ubuntu `ubuntu-latest` runners. Triage per-finding. ## Scope - `Dockerfile` — `+1, -1` (FROM line) - `CHANGELOG.md` — `+3` (new `### Changed` entry under `[Unreleased]`) No source, no tests, no compose changes, no migrations. ## References - Follows up on closed Dependabot [#346](#346) - Relies on merged [#354](#354) (3.13 matrix entry) and merged [#350](#350) (docker-smoke workflow) ## QA ### Prerequisites None. The `docker-smoke.yml` workflow runs automatically on any PR touching `Dockerfile`. ### Automated checks - **`docker-smoke` — load-bearing.** Builds the image and runs: - `python -c 'import mcp_awareness'` - `python -c 'from mcp_awareness import server'` - `command -v` on all six console scripts (`mcp-awareness`, `mcp-awareness-migrate`, `mcp-awareness-user`, `mcp-awareness-token`, `mcp-awareness-secret`, `mcp-awareness-register-schema`) - positive check that `docker-entrypoint.sh` has a valid shebang and executable bit - `test (3.10 / 3.11 / 3.12 / 3.13 / 3.14)` — unchanged by this PR but re-runs on CI; expected green. - `lint`, `typecheck`, `codecov/patch` — still pinned to 3.12; unchanged. - `CodeQL (actions)` — no workflow files touched; re-scans diff only. ### Manual tests (via MCP tools) This PR changes the shipped container only. There are no new MCP tools or behavior changes to exercise — the awareness tool surface is identical on 3.13-slim as it was on 3.12-slim. Listing the checks here for reviewer audit: 1. - [x] **`docker-smoke` all four sub-checks pass** on the PR run. Verify in the Actions tab that each smoke step shows green. 2. - [x] **Container boots cleanly** against a throwaway Postgres (CI environment or local). Optional belt-and-suspenders sanity check: \`\`\` docker build -t awareness-test . docker run --rm awareness-test python -c 'from mcp_awareness import server; print("ok")' \`\`\` Expected: `ok` printed, exit 0. 3. - [x] **Image base is Python 3.13.** Verify the built image reports the expected Python version: \`\`\` docker run --rm awareness-test python --version \`\`\` Expected: `Python 3.13.x`. 4. - [x] **No stray file changes.** `git diff --stat origin/main` shows exactly `Dockerfile` (+1, -1) and `CHANGELOG.md` (+3). Nothing else. ### Acceptance - ✅ `docker-smoke` green — **load-bearing** - ✅ Base image aligned with CI-covered Python version (3.13 now in matrix per #354) - ✅ `requires-python` floor unchanged; no consumer-facing metadata shift - ✅ Single-concern diff; no test, source, or compose changes 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: cmeans-claude-dev[bot] <3223881+cmeans-claude-dev[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Patch release stamping six PRs merged to `main` since v0.18.1 on 2026-04-20. ## Summary Two-file diff: - `pyproject.toml` — `version` bump `0.18.1` → `0.18.2` - `CHANGELOG.md` — `[Unreleased]` renamed to `[0.18.2] - 2026-04-21`; new empty `[Unreleased]` section seeded; comparison-link footer updated ## Why patch - No new MCP tools, no changed tool signatures, no resource changes. - No breaking config, no migration, no data-format change. - `requires-python = ">=3.10"` floor unchanged in `pyproject.toml`. - Dockerfile base bump (3.12 → 3.13) is runtime-transparent to image consumers; CI matrix widening (3.13, 3.14) is pure infra. - OAuth log-redaction is security-hardening with no behavior change on the happy path. - `docker-compose` host-port parameterization is backward-compatible — default behavior unchanged. Textbook patch bump for a 0.x project. ## Included PRs | PR | Title | Kind | |---|---|---| | [#351](#351) | ci: cascade env-routing to `pr-labels.yml` + workflow permissions | Security | | [#352](#352) | fix(oauth): redact URLs in log output (CodeQL #5-#9) | Security | | [#350](#350) | ci: add `docker-smoke` workflow — build + import smoke on Dockerfile PRs | Added | | [#353](#353) | chore(compose): parameterize host port in `docker-compose.yaml` | Changed | | [#354](#354) | ci: extend Python test matrix to include 3.13 and 3.14 | Added | | [#355](#355) | chore(docker): bump base image from `python:3.12-slim` to `3.13-slim` | Changed | All six merged via their own QA-Approved cycles — nothing in this release bypasses the standard pipeline. ## What's unchanged - `docker-compose.yaml` — uses `:latest`, no version bump needed - `README.md` — tool count (32) and text-mode content unchanged; no update needed - `uv.lock` — no dep changes in any of the six PRs ## QA Lightweight per project convention — all substantive code was tested in its own PR. Review-only checks: 1. - [x] **`pyproject.toml` version** is `0.18.2`. Verify line 3: `version = "0.18.2"`. 2. - [x] **CHANGELOG** — `[0.18.2] - 2026-04-21` heading exists; the six rolled-up entries sit beneath it in their original order (Changed → Added → Changed → Security → Security → Added); empty `[Unreleased]` seeded above. 3. - [x] **Comparison links** — `[0.18.2]: …v0.18.1...v0.18.2` added; `[Unreleased]` now points at `v0.18.2...HEAD`. 4. - [ ] **Scope** — `git diff --stat origin/main` shows exactly `CHANGELOG.md` (+4, -1) and `pyproject.toml` (+1, -1). Nothing else. 5. - [x] **No accidental content drift in rolled-up entries** — diff between this branch's `[0.18.2]` section and what was in `[Unreleased]` on `main` before this PR should be zero beyond the heading/anchor move. ### Acceptance - ✅ CI green - ☐ Merge + tag (Dev authorization, executed post-merge) ## Merge + tag (Dev post-merge action) After merge, Dev runs: \`\`\` git checkout main && git pull --ff-only origin main git tag -a v0.18.2 -m "v0.18.2 — CI matrix widening (3.13/3.14), Dockerfile to python:3.13-slim, docker-smoke workflow, compose host-port parameterization, OAuth log redaction, workflow permission hardening" git push origin v0.18.2 \`\`\` The tag triggers \`docker-publish.yml\` to build and publish the \`:v0.18.2\` + \`:latest\` images. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: cmeans-claude-dev[bot] <3223881+cmeans-claude-dev[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes #349.
Summary
One-line change in
.github/workflows/ci.yml:```diff
matrix:
```
pyproject.tomldeclaresrequires-python = \">=3.10\"— the package metadata allows 3.13 and 3.14, but CI never exercised them. That's a source of silent breakage for any self-hoster running the package under a newer Python than we tested.What stays unchanged
pyproject.tomlmetadata —requires-python = \">=3.10\"already allowed both. No lower-bound or classifier changes.docker-publish.yml,docker-smoke.yml— untouched. The Dockerfile pins topython:3.12-slim; bumping that is a separate decision (see chore(deps)(deps): bump python from 3.12-slim to 3.14-slim #346 / ci: add docker build + import smoke on PRs touching Dockerfile / pyproject.toml / uv.lock #348 / the earlier thread).Why this is additive, not redundant, with #348
This PR validates Python versions under
actions/setup-python; #348 (merged as PR #350) validates the shipped Docker image. Both are needed for full CI coverage:FROM python:X.Y-slimchanges,pip installfailures inside the slim image, entry-point registration).Neither substitutes for the other.
Risks and unknowns
This is the "may surface hidden work" case I flagged when we ordered the P3s. Two outcomes for the new matrix entries:
>=3.10floor more strictly as an upper bound inpyproject.toml.CI on this PR is the load-bearing test. If it's green, #349 is closed. If it's red, we'll have a triage list to work through.
Scope
.github/workflows/ci.yml—+1, -1(matrix list)CHANGELOG.md—+3(new### Addedentry under[Unreleased])No source, no tests, no compose-file changes, no migrations.
References
docker-smoke, merged via PR ci: add docker-smoke workflow — build + import smoke on Dockerfile PRs (#348) #350) — additive, both neededQA
Prerequisites
None. Pure CI-workflow change.
Automated checks
test (3.10/3.11/3.12)— existing entries; expected to remain green.test (3.13)andtest (3.14)— new entries; expected to exercise the fullpytest tests/suite against these versions. If any fail, that's the actual finding this PR surfaces.lint,typecheck,codecov/patch— pinned to 3.12; unchanged.docker-smoke— not triggered (noDockerfile/pyproject.toml/uv.lock/.dockerignore/ workflow-file-matching-its-trigger change).CodeQL (actions)— will re-scanci.yml; no new taint-flow sites introduced.Manual tests
```
python3 -c "import yaml; yaml.safe_load(open('.github/workflows/ci.yml')); print('OK')"
```
Expected:
OK.```
grep -A1 '^ matrix:' .github/workflows/ci.yml | tail -1
```
Expected:
python-version: [\"3.10\", \"3.11\", \"3.12\", \"3.13\", \"3.14\"].test (3.10),test (3.11),test (3.12),test (3.13),test (3.14)all appear in the check list for this PR.All five test jobs pass. The actual acceptance test — if 3.13 or 3.14 fails, this PR needs follow-up work before it can merge:
test (3.13)fails → read the log; common culprits:testcontainers/lingua-language-detector/mcpwithout a 3.13 wheeltest (3.14)fails → same, newer target; 3.14 wheel coverage is generally thinner than 3.13Each failure is a separate triage decision (bump the dep, exclude the matrix entry with a note, or tighten
requires-pythonupper bound).lintandtypecheckjobs still usepython-version: \"3.12\"— they should continue to run in their existing time envelope. Verify by checking that neither job's duration in this PR's CI is materially different from the last greenmainCI run.git diff --stat origin/mainshows exactly.github/workflows/ci.yml(+1, -1) andCHANGELOG.md(+3). Nothing else.Acceptance
pyproject.tomlrequires-python = \">=3.10\"now aligned with CI matrix coverage