Repository navigation
fix(bundles): bind saved bundle locks to third-party root versions - #886
Conversation
Each saved bundle manifest bound the SHA256 of the whole root uv.lock. A release PR refresh rewrites the workspace package versions in that file, so every manifest went stale and the verifier rejected all 16 targets with "bundle lock inputs changed" although no closure input changed. Recompiling the 16 targets against the 0.11.0 release branch with the existing 2026-10-18T00:00:00Z cutoff leaves every pylock.toml byte-identical; only the root lock hash moves. Bind the manifest to the exact third-party name/version set of the root lock, which is what compilation constrains. Workspace members and lock serialization no longer invalidate a closure. Artifact sources remain checked on every verification through the exception policy, and any root version change still requires recompilation. Regenerate all 16 manifests with the same cutoff and uv 0.9.28. No pylock.toml changes; manifests change only in policy_sha256 and the renamed root_versions_sha256 input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
The root lock records torchvision 0.24.1 from two registries. Hashing the version list made the binding depend on how many source rows share a version, so dropping or adding one source row would invalidate all 16 manifests although the compilation constraints stay the same. Hash the set of exact versions; artifact sources stay checked on every verification through the exception policy. Regenerate all 16 manifests with the 2026-10-18T00:00:00Z cutoff and uv 0.9.28. No pylock.toml changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
Bundle-lock owner review is needed to confirm that narrowing integrity checks from all root-lock bytes to version-only binding plus exception-policy checks preserves supply-chain guarantees across supported targets.
No open issues 🎉
What changed in this PR
This PR prevents release-only workspace version bumps from invalidating SIE’s saved bundle locks, addressing the release failure described in #884. It replaces the whole-file root-lock digest introduced in #802 with a digest of exact third-party package versions.
Changes:
- Update compilation and verification to use
root_versions_sha256, while retaining artifact validation through the exception policy. - Add regression tests for tolerated workspace and serialization changes and rejected artifact substitutions.
- Refresh all 16 manifests and document the revised binding; no
pylock.tomlfiles change.
| File | Description |
|---|---|
tools/ci/bundle_lock.py |
Write the third-party version digest during compilation. |
packages/sie_server/tests/core/test_bundle_lock.py |
Test the revised invalidation and artifact checks. |
packages/sie_server/src/sie_server/bundle_lock.py |
Compute and verify the third-party version digest. |
packages/sie_server/bundle-locks/README.md |
Document the revised lock-binding contract. |
packages/sie_server/bundle-locks/cuda13-tensorrt-llm-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cuda13-sglang-cu130-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cuda12-transformers5-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cuda12-sglang-vision-extract-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cuda12-sglang-embedding-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cuda12-sglang-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cuda12-default-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cuda12-ctranslate2-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cpu-transformers5-arm64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cpu-transformers5-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cpu-sglang-arm64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cpu-sglang-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cpu-default-arm64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cpu-default-amd64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cpu-ctranslate2-arm64/manifest.json |
Refresh root-version and policy digests. |
packages/sie_server/bundle-locks/cpu-ctranslate2-amd64/manifest.json |
Refresh root-version and policy digests. |
Review effort: Balanced
Summary
The 0.11.0 release PR (#884) fails 17 checks: Bundle resolution, every server image build, CPU containers, both CUDA 13 compatibility jobs, and Release candidate / Complete. Every one fails with
bundle lock inputs changed; recompile and review the complete closure.Each saved bundle manifest binds the SHA256 of the whole root
uv.lock. The release PR refresh runsuv lock, which rewrites the workspace package versions (0.10.1 -> 0.11.0). That makes all 16 manifests stale, even though no input of any bundle closure changed. 0.11.0 is the first release since the saved bundle locks landed in #802.This change binds each manifest to the exact third-party versions in the root lock instead of to the file's bytes. The input digest is renamed from
uv_lock_sha256toroot_versions_sha256. All 16 manifests are regenerated with the existing2026-10-18T00:00:00Zcutoff. Nopylock.tomlchanges.Why not recompile in the release workflow
release-automationjob, which holds the release App's write token. It deliberately runs no third-party code (--ignore-scripts). A compile there would need a full root environment sync and uv 0.9.28. The resolve would also have to build metadata for 10 sdist-only distributions and one Git source, so third-party build code would run next to the write token.Evidence
ff398c2) with the existing cutoff and uv 0.9.28. All 16pylock.tomlfiles stay byte-identical. The only change in each manifest isuv_lock_sha256.main(370 distributions). The release job's uv 0.5.31 also drops the graalpy wheels ofjiter,pybase64andpydantic-core. No bundle closure uses those wheels, so the exception check still passes.pylock.tomlbyte-identical. Each manifest changes in two places only:policy_sha256, because the verifier and compiler sources changed, and the renamed input digest.tools/ci/bundle_lock.py checkpasses on this branch. It also passes, without a recompile, on the release-branch tree with this change applied.What stays bound
+cu129. Any root version change still invalidates every manifest.check_lockalready rerunsvalidate_exceptionsagainst the current root lock on every check. A new test shows that substituting an artifact at the same version still fails.Workspace members and lock serialization are no longer bound. They never reach
bundle-libs:root_packagesalready skips editable and virtual workspace entries when it derives constraints.Release flow
This needs no change to the workflow or the release contract. After it merges, the next release-PR refresh rewrites
uv.lockwithout invalidating the saved locks.This changes the bundle-lock integrity binding from #802, so it needs review from the bundle-lock owner.
Test plan
pytest packages/sie_server/tests/core/test_bundle_lock.pypython tools/ci/bundle_lock.py check(this branch, and the release-branch tree with this change)SIE_RUN_IMAGE_RESOLUTION=1 pytest packages/sie_server/tests/core/test_bundle_image_resolution.pywith uv 0.9.28python tools/ci/check_release_contract.pymise run lint,mise run typecheck🤖 Generated with Claude Code
Summary by CodeRabbit