Problem
Server images install each bundle's dependencies outside the lock. The image builders in packages/sie_server/Dockerfile.cpu, Dockerfile.cuda12, and Dockerfile.cuda13 do two steps:
python -m sie_server.cli resolve-deps --bundle <bundle> writes the bundle's dependency specifiers to a requirements file.
pip install --target=/app/bundle-libs -r that file installs them.
/app/bundle-libs is then put ahead of the shared virtualenv on sys.path. Bundle YAMLs mostly use ranges, so pip resolves each one to the newest matching release at build time. That release then shadows the version pinned in uv.lock, which is the one CI tests against.
For example, the default bundle declares gliner>=0.2.26,<1, and uv.lock pins gliner 0.2.26. PyPI now has 0.2.27, 0.2.28, and 0.2.29, so a default image built today serves gliner 0.2.29, a version no test ran against. The same applies to every ranged bundle dependency, such as gliclass, gliner2, glirel, and docling.
Consequences:
- Two builds of the same commit can ship different dependency versions.
- A dependency release can change serving behaviour without any change in this repository.
- Code that checks a dependency it patches or wraps, as some adapters do, can pass CI and fail in the image.
Proposal
Make bundle installs reproducible from the repository:
- Constrain bundle installs to the lock. Export the locked versions (for example
uv export --frozen --no-hashes) and pass them to the bundle install as a constraints file (pip install -c). Any package the lock already resolves then keeps its locked version. Only packages absent from the lock float.
- Or lock each bundle. Have
resolve-deps emit exact versions from a per-bundle lock, checked in and refreshed like uv.lock.
- Record what shipped. Write the resolved
pip freeze of /app/bundle-libs into the image, so any deployed version can be checked.
Acceptance
- Building the same commit twice installs the same versions in
/app/bundle-libs.
- Every package that
uv.lock pins is installed at its locked version in each bundle image, unless the bundle deliberately overrides it (for example the transformers 5 bundle), and that override is written down.
- CI fails if a bundle image resolves a locked package to a different version without such an override.
Problem
Server images install each bundle's dependencies outside the lock. The image builders in
packages/sie_server/Dockerfile.cpu,Dockerfile.cuda12, andDockerfile.cuda13do two steps:python -m sie_server.cli resolve-deps --bundle <bundle>writes the bundle's dependency specifiers to a requirements file.pip install --target=/app/bundle-libs -rthat file installs them./app/bundle-libsis then put ahead of the shared virtualenv onsys.path. Bundle YAMLs mostly use ranges, so pip resolves each one to the newest matching release at build time. That release then shadows the version pinned inuv.lock, which is the one CI tests against.For example, the default bundle declares
gliner>=0.2.26,<1, anduv.lockpinsgliner0.2.26. PyPI now has 0.2.27, 0.2.28, and 0.2.29, so a default image built today serves gliner 0.2.29, a version no test ran against. The same applies to every ranged bundle dependency, such asgliclass,gliner2,glirel, anddocling.Consequences:
Proposal
Make bundle installs reproducible from the repository:
uv export --frozen --no-hashes) and pass them to the bundle install as a constraints file (pip install -c). Any package the lock already resolves then keeps its locked version. Only packages absent from the lock float.resolve-depsemit exact versions from a per-bundle lock, checked in and refreshed likeuv.lock.pip freezeof/app/bundle-libsinto the image, so any deployed version can be checked.Acceptance
/app/bundle-libs.uv.lockpins is installed at its locked version in each bundle image, unless the bundle deliberately overrides it (for example the transformers 5 bundle), and that override is written down.