diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 9bf7ac0..4f2108d 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -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 diff --git a/uv.lock b/uv.lock index 8cd7f5c..fdcb59c 100644 --- a/uv.lock +++ b/uv.lock @@ -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" },