fix(ci): install from uv.lock so CI stops resolving dependencies itself
CI & Build / Python lint (push) Successful in 3s
CI & Build / integration (push) Failing after 10s
CI & Build / Python tests (push) Failing after 16s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Build & push image (push) Has been skipped

Closes the reproducibility hole that turned `main` red an hour ago. CI ran
`uv pip install -e ".[dev]"`, which resolves from the pyproject constraints
and ignores uv.lock completely — so every dependency floated. uv.lock pinned
mcp 1.27.2; CI installed the 2.0.0 published mid-session and the identical
tree that passed on `dev` failed on `main`.

Both Python lanes now run `uv sync --locked --extra dev`. `--locked` also
fails when the lock is stale against pyproject, so a dependency change has to
go through a deliberate `uv lock` instead of arriving on its own — which also
restores the point of the Renovate dashboard-approval flow.

Dropped the http-ece install and the setuptools/wheel step that existed only
to support it: nothing in src/ or tests/ imports http_ece. It is a leftover
from the web-push subsystem removed in the MCP-First pivot, and it was never
in pyproject or uv.lock — CI was installing an unused package and carrying a
--no-build-isolation workaround for it.

Cache key moves from pyproject.toml to uv.lock, since the lock is now what
determines the installed set.

uv.lock's recorded root requirement updated to match the mcp cap. Edited by
hand rather than regenerated: uv isn't installed on this workstation, the
resolved mcp 1.27.2 already satisfies `<2`, so no re-resolution is needed —
only the staleness check needed satisfying.

The Dockerfile still resolves independently (`pip install .`, and it doesn't
even copy uv.lock), so the shipped image is not yet covered. Following
separately so a build break can't strand `main`. Refs #2194.
This commit is contained in:
2026-07-28 12:50:52 -04:00
parent aa850ac1e1
commit ef7ebddadf
2 changed files with 24 additions and 20 deletions
+23 -19
View File
@@ -126,20 +126,25 @@ jobs:
uses: actions/cache@v4
with:
path: ~/.cache/uv
key: uv-${{ hashFiles('pyproject.toml') }}
# Keyed on the LOCK, not pyproject: the lock is what determines the
# installed set now, and a pyproject edit that doesn't change
# resolution shouldn't throw the cache away.
key: uv-${{ hashFiles('uv.lock') }}
restore-keys: uv-
- name: Create virtual environment
run: uv venv /opt/venv
- name: Install package with dev deps
run: |
# http-ece doesn't declare setuptools as a build dep, and uv
# creates bare venvs without it. Install setuptools first so
# --no-build-isolation can find it.
uv pip install --python /opt/venv/bin/python setuptools wheel
uv pip install --python /opt/venv/bin/python --no-build-isolation http-ece
uv pip install --python /opt/venv/bin/python -e ".[dev]"
# Installs exactly what uv.lock pins. `--locked` additionally FAILS if the
# lock is stale against pyproject, so a dependency change has to go through
# a deliberate `uv lock` — it can't drift in silently.
#
# This replaced `uv pip install -e ".[dev]"`, which resolved from the
# pyproject constraints and ignored the lock entirely. Every dependency
# floated: on 2026-07-28 mcp 2.0.0 shipped mid-session and turned `main`
# red with no repo change (issue #2194). Green CI has to mean "these exact
# versions passed", or it isn't evidence of anything.
- name: Install locked dependencies
env:
UV_PROJECT_ENVIRONMENT: /opt/venv
run: uv sync --locked --extra dev
- name: Run tests
# Integration tests (real Postgres) run in the `integration` job below.
@@ -179,13 +184,12 @@ jobs:
--health-retries 10
steps:
- uses: actions/checkout@v6
- name: Create virtual environment
run: uv venv /opt/venv
- name: Install package with dev deps
run: |
uv pip install --python /opt/venv/bin/python setuptools wheel
uv pip install --python /opt/venv/bin/python --no-build-isolation http-ece
uv pip install --python /opt/venv/bin/python -e ".[dev]"
# Same locked install as the unit lane — the two must agree on versions,
# or "unit green, integration red" stops being a signal about the code.
- name: Install locked dependencies
env:
UV_PROJECT_ENVIRONMENT: /opt/venv
run: uv sync --locked --extra dev
- name: Integration suite (resolve service IP, migrate, test)
run: |
set -eux
Generated
+1 -1
View File
@@ -393,7 +393,7 @@ requires-dist = [
{ name = "httpx", specifier = ">=0.27" },
{ name = "hypercorn", specifier = ">=0.17" },
{ name = "icalendar", specifier = ">=5.0" },
{ name = "mcp", extras = ["cli"], specifier = ">=1.0" },
{ name = "mcp", extras = ["cli"], specifier = ">=1.0,<2" },
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" },
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23" },
{ name = "quart", specifier = ">=0.19" },