fix(ci): regenerate uv.lock and enforce it with --locked
CI & Build / Python lint (push) Successful in 3s
CI & Build / integration (push) Successful in 18s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 50s
CI & Build / Build & push image (push) Successful in 17s

Completes the previous two commits. `--frozen` failed run 3007 with
`ModuleNotFoundError: No module named 'pgvector'` — the lock wasn't merely
stale in its recorded metadata, it was missing a real dependency. pgvector
was added to pyproject for the vector-search work and the lock was never
regenerated, and nothing noticed because CI resolved from pyproject and never
read the lock. The lock has been dead weight for some time.

Regenerated with `uv lock` inside a throwaway `ci-python:3.14` container —
this workstation has no uv and no pip, and the CI image already carries the
right toolchain, so nothing was installed to do it. uv was conservative as
promised: pgvector 0.5.0 added, and NOT ONE existing pin moved (verified by
diffing name=version pairs across all 106 packages).

Both lanes now run `uv sync --locked`, so a dependency edit without a re-lock
fails loudly at install rather than resolving around the lock. The check paid
for itself on its first run by surfacing the missing pgvector.

Also added uv.lock to the workflow's `paths:` filter. It was absent, so a
lock-only change — exactly what a dependency bump looks like now — would not
have triggered CI at all.

Closes the CI half of #2194. The Dockerfile still resolves independently and
is tracked there.
This commit is contained in:
2026-07-28 12:58:18 -04:00
parent 8bab0c762b
commit a47e1b9c4e
2 changed files with 70 additions and 59 deletions
+11 -11
View File
@@ -40,6 +40,9 @@ on:
- "frontend/**"
- "tests/**"
- "pyproject.toml"
# The lock now determines what gets installed, so a lock-only change has
# to trigger a run — otherwise a dependency bump lands untested.
- "uv.lock"
- "alembic/**"
- "alembic.ini"
- "Dockerfile"
@@ -140,19 +143,16 @@ jobs:
# red with no repo change (issue #2194). Green CI has to mean "these exact
# versions passed", or it isn't evidence of anything.
#
# `--frozen`, not `--locked`, and that difference is a known gap: --locked
# additionally fails when the lock is STALE against pyproject, which is the
# guard that would catch someone editing a dependency without re-locking.
# It can't be turned on until uv.lock is regenerated with `uv lock` — the
# mcp cap edited pyproject, so the lock no longer matches, and this
# workstation has no uv (or pip) to regenerate it with. --frozen still
# delivers the reproducibility this fix is for; a forgotten re-lock shows
# up as a loud ImportError rather than a silent version drift. Flip to
# --locked in the same change that regenerates the lock.
# `--locked` also FAILS when uv.lock is stale against pyproject, so a
# dependency edit has to go through a deliberate `uv lock` — it can't
# arrive on its own. That check earned its place immediately: it caught
# that the lock had been missing `pgvector` entirely (added to pyproject,
# never re-locked), which the old install path had been silently papering
# over by resolving from pyproject instead.
- name: Install locked dependencies
env:
UV_PROJECT_ENVIRONMENT: /opt/venv
run: uv sync --frozen --extra dev
run: uv sync --locked --extra dev
- name: Run tests
# Integration tests (real Postgres) run in the `integration` job below.
@@ -197,7 +197,7 @@ jobs:
- name: Install locked dependencies
env:
UV_PROJECT_ENVIRONMENT: /opt/venv
run: uv sync --frozen --extra dev
run: uv sync --locked --extra dev
- name: Integration suite (resolve service IP, migrate, test)
run: |
set -eux