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
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:
+11
-11
@@ -40,6 +40,9 @@ on:
|
|||||||
- "frontend/**"
|
- "frontend/**"
|
||||||
- "tests/**"
|
- "tests/**"
|
||||||
- "pyproject.toml"
|
- "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/**"
|
||||||
- "alembic.ini"
|
- "alembic.ini"
|
||||||
- "Dockerfile"
|
- "Dockerfile"
|
||||||
@@ -140,19 +143,16 @@ jobs:
|
|||||||
# red with no repo change (issue #2194). Green CI has to mean "these exact
|
# red with no repo change (issue #2194). Green CI has to mean "these exact
|
||||||
# versions passed", or it isn't evidence of anything.
|
# versions passed", or it isn't evidence of anything.
|
||||||
#
|
#
|
||||||
# `--frozen`, not `--locked`, and that difference is a known gap: --locked
|
# `--locked` also FAILS when uv.lock is stale against pyproject, so a
|
||||||
# additionally fails when the lock is STALE against pyproject, which is the
|
# dependency edit has to go through a deliberate `uv lock` — it can't
|
||||||
# guard that would catch someone editing a dependency without re-locking.
|
# arrive on its own. That check earned its place immediately: it caught
|
||||||
# It can't be turned on until uv.lock is regenerated with `uv lock` — the
|
# that the lock had been missing `pgvector` entirely (added to pyproject,
|
||||||
# mcp cap edited pyproject, so the lock no longer matches, and this
|
# never re-locked), which the old install path had been silently papering
|
||||||
# workstation has no uv (or pip) to regenerate it with. --frozen still
|
# over by resolving from pyproject instead.
|
||||||
# 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.
|
|
||||||
- name: Install locked dependencies
|
- name: Install locked dependencies
|
||||||
env:
|
env:
|
||||||
UV_PROJECT_ENVIRONMENT: /opt/venv
|
UV_PROJECT_ENVIRONMENT: /opt/venv
|
||||||
run: uv sync --frozen --extra dev
|
run: uv sync --locked --extra dev
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
# Integration tests (real Postgres) run in the `integration` job below.
|
# Integration tests (real Postgres) run in the `integration` job below.
|
||||||
@@ -197,7 +197,7 @@ jobs:
|
|||||||
- name: Install locked dependencies
|
- name: Install locked dependencies
|
||||||
env:
|
env:
|
||||||
UV_PROJECT_ENVIRONMENT: /opt/venv
|
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)
|
- name: Integration suite (resolve service IP, migrate, test)
|
||||||
run: |
|
run: |
|
||||||
set -eux
|
set -eux
|
||||||
|
|||||||
@@ -354,54 +354,6 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
|
{ url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scribe"
|
|
||||||
version = "0.1.0"
|
|
||||||
source = { editable = "." }
|
|
||||||
dependencies = [
|
|
||||||
{ name = "aiosmtplib" },
|
|
||||||
{ name = "alembic" },
|
|
||||||
{ name = "apscheduler" },
|
|
||||||
{ name = "asyncpg" },
|
|
||||||
{ name = "bcrypt" },
|
|
||||||
{ name = "caldav" },
|
|
||||||
{ name = "fastembed" },
|
|
||||||
{ name = "httpx" },
|
|
||||||
{ name = "hypercorn" },
|
|
||||||
{ name = "icalendar" },
|
|
||||||
{ name = "mcp", extra = ["cli"] },
|
|
||||||
{ name = "quart" },
|
|
||||||
{ name = "sqlalchemy", extra = ["asyncio"] },
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.optional-dependencies]
|
|
||||||
dev = [
|
|
||||||
{ name = "pytest" },
|
|
||||||
{ name = "pytest-asyncio" },
|
|
||||||
{ name = "ruff" },
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.metadata]
|
|
||||||
requires-dist = [
|
|
||||||
{ name = "aiosmtplib", specifier = ">=3.0" },
|
|
||||||
{ name = "alembic", specifier = ">=1.13" },
|
|
||||||
{ name = "apscheduler", specifier = ">=3.10,<4.0" },
|
|
||||||
{ name = "asyncpg", specifier = ">=0.29" },
|
|
||||||
{ name = "bcrypt", specifier = ">=4.0" },
|
|
||||||
{ name = "caldav", specifier = ">=1.3" },
|
|
||||||
{ name = "fastembed", specifier = ">=0.4" },
|
|
||||||
{ name = "httpx", specifier = ">=0.27" },
|
|
||||||
{ name = "hypercorn", specifier = ">=0.17" },
|
|
||||||
{ name = "icalendar", specifier = ">=5.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" },
|
|
||||||
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6" },
|
|
||||||
{ name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0" },
|
|
||||||
]
|
|
||||||
provides-extras = ["dev"]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastembed"
|
name = "fastembed"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
@@ -1038,6 +990,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
{ url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pgvector"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/a7/ec/6eb80aebc728200f95229219882994c1b0585b956ca47da5edb9d062627a/pgvector-0.5.0.tar.gz", hash = "sha256:07a9dcf735696879406983afc6eba9a787cef7c0cf6c367ca1a5779f036dee74", size = 35170, upload-time = "2026-07-06T18:27:27.767Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5c/e4/a5573f2c579ca9ad133293bfb624148ba0893674ca4a6eeec85ced9a6a09/pgvector-0.5.0-py3-none-any.whl", hash = "sha256:fedc9800894e6da2be51358d7b7c574bf34f247ca741a5a09513622135f5964f", size = 30958, upload-time = "2026-07-06T18:27:26.797Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pillow"
|
name = "pillow"
|
||||||
version = "12.2.0"
|
version = "12.2.0"
|
||||||
@@ -1496,6 +1457,56 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" },
|
{ url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scribe"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { editable = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "aiosmtplib" },
|
||||||
|
{ name = "alembic" },
|
||||||
|
{ name = "apscheduler" },
|
||||||
|
{ name = "asyncpg" },
|
||||||
|
{ name = "bcrypt" },
|
||||||
|
{ name = "caldav" },
|
||||||
|
{ name = "fastembed" },
|
||||||
|
{ name = "httpx" },
|
||||||
|
{ name = "hypercorn" },
|
||||||
|
{ name = "icalendar" },
|
||||||
|
{ name = "mcp", extra = ["cli"] },
|
||||||
|
{ name = "pgvector" },
|
||||||
|
{ name = "quart" },
|
||||||
|
{ name = "sqlalchemy", extra = ["asyncio"] },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "pytest" },
|
||||||
|
{ name = "pytest-asyncio" },
|
||||||
|
{ name = "ruff" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "aiosmtplib", specifier = ">=3.0" },
|
||||||
|
{ name = "alembic", specifier = ">=1.13" },
|
||||||
|
{ name = "apscheduler", specifier = ">=3.10,<4.0" },
|
||||||
|
{ name = "asyncpg", specifier = ">=0.29" },
|
||||||
|
{ name = "bcrypt", specifier = ">=4.0" },
|
||||||
|
{ name = "caldav", specifier = ">=1.3" },
|
||||||
|
{ name = "fastembed", specifier = ">=0.4" },
|
||||||
|
{ name = "httpx", specifier = ">=0.27" },
|
||||||
|
{ name = "hypercorn", specifier = ">=0.17" },
|
||||||
|
{ name = "icalendar", specifier = ">=5.0" },
|
||||||
|
{ name = "mcp", extras = ["cli"], specifier = ">=1.0,<2" },
|
||||||
|
{ name = "pgvector", specifier = ">=0.3" },
|
||||||
|
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" },
|
||||||
|
{ name = "pytest-asyncio", marker = "extra == 'dev'", specifier = ">=0.23" },
|
||||||
|
{ name = "quart", specifier = ">=0.19" },
|
||||||
|
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6" },
|
||||||
|
{ name = "sqlalchemy", extras = ["asyncio"], specifier = ">=2.0" },
|
||||||
|
]
|
||||||
|
provides-extras = ["dev"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shellingham"
|
name = "shellingham"
|
||||||
version = "1.5.4"
|
version = "1.5.4"
|
||||||
|
|||||||
Reference in New Issue
Block a user