Reproducible Dependencies¶
OpenMed keeps dependency resolution auditable through pyproject.toml, uv.lock, the existing lockfile-drift CI job, and the reproducible-lock gate. This page explains what the gate checks, how to refresh the lock, and how to read the reproducibility artifact.
CI Gate¶
The Reproducible Lock Gate workflow runs when pyproject.toml, uv.lock, or the workflow itself changes. It can also be run manually from GitHub Actions.
The workflow has three jobs:
lock-integritychecks thatuv.lockmatchespyproject.toml, every non-root package has an exact version, every checked package is registry backed, and every checked package has at least onesha256:hash in itssdistorwheelsentries.reproducibilitycreates two independent, cache-free frozen installs for the default Python 3.11 dependency environment and compares the sorteduv pip freezeoutput byte for byte.lock-gateis the summary status check that only passes when integrity and reproducibility both pass.
The root openmed project entry is skipped because uv.lock records it as the local editable project rather than a third-party distribution.
Digest Artifact¶
Successful runs upload reproducibility-digest.txt with three fields:
digestfingerprints the sorted package/version/hash tuples checked from the lockfile.packagesis the number of non-root packages included in that digest.uv-lock-sha256is the SHA-256 of the rawuv.lockfile.
Compare digest artifacts between releases when you need to prove that the dependency set did not change unexpectedly:
gh run download <run-id-1> -n reproducibility-digest -D run1/
gh run download <run-id-2> -n reproducibility-digest -D run2/
diff run1/reproducibility-digest.txt run2/reproducibility-digest.txt
Refresh Workflow¶
Refresh uv.lock whenever you add, remove, or change dependencies in pyproject.toml, or when the lockfile-drift job reports that the lock is out of date.
- Update the dependency declaration.
- Re-resolve the lockfile.
- Verify that the lock is consistent and inspect the diff.
- Test a frozen install from the new lock.
- Commit the dependency declaration and lockfile together.
For a new dependency, uv add updates pyproject.toml and uv.lock together:
Local Reproducibility Check¶
The CI workflow is the source of truth, but the install comparison can be replicated locally before pushing:
uv sync --frozen --no-cache --no-install-project --python 3.11
uv pip freeze | sort > /tmp/openmed-resolve-1.txt
rm -rf .venv
uv sync --frozen --no-cache --no-install-project --python 3.11
uv pip freeze | sort > /tmp/openmed-resolve-2.txt
diff /tmp/openmed-resolve-1.txt /tmp/openmed-resolve-2.txt
If the diff is empty, the two frozen installs produced the same package set.
Failure Guide¶
| Error | Meaning | Fix |
|---|---|---|
uv.lock is out of date | pyproject.toml and uv.lock disagree. | Run uv lock and commit the updated lockfile. |
MISSING VERSION | A checked lock entry has no exact version. | Re-run uv lock; do not edit the lockfile manually. |
UNSUPPORTED SOURCE | A checked dependency is not registry backed. | Replace local, git, URL, or editable dependencies with published package releases. |
MISSING HASHES | A checked dependency has no sha256: hash. | Re-run uv lock; if it persists, inspect the package publication. |
INVALID HASH TYPE | A checked dependency uses a non-SHA-256 hash. | Re-resolve with uv lock or replace the dependency source. |
Non-reproducible install | Two frozen clean installs produced different package lists. | Re-run the workflow once for transient index issues; investigate the package diff if it repeats. |