Repository navigation
Fix hosted to vendored takeover onto a newer patch (#1105) - #1713
Mikola Lysenko (mikolalysenko) merged 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
After a hosted scan with patch A and a `uv sync` or `poetry install`, the venv holds A's patched bytes. When a newer patch B for the same release arrived, `scan --mode vendored` / `vendor` dropped the package as "no installed package found on disk" and exited 1, leaving the project hosted on A, while the dry run previewed success. The installed copy is recognised as a superseded install only through the vendor ledger. A live hosted pin at another patch uuid now counts too (for a sole release variant, since the pin names none), so the takeover restores the upstream entry and vendors B from the pristine artifact. Fixes #1105 Assisted-by: Claude Code:claude-opus-5-5
The issue also reproduces in the uv pip requirements.txt lane, which goes through the same check, so the regression test runs it too. Assisted-by: Claude Code:claude-opus-5-5
A venv synced from an older hosted patch can sit under a lock a later hosted scan already moved to the patch being vendored, and a package can carry hosted pins at two uuids in different files. Treat any live hosted pin as the superseded install, keep the rule to PyPI so gems still refuse a platform gem from their installed dir, and give the download planner the same hosted check as the vendor loop. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit ae32e91. Configure here.
|
Labeled Ready for review by the burn-down agent.
Generated by Claude Code |
Final review briefWhat it does: When a PyPI project moves from hosted to vendored mode and the API now serves a newer patch (B) than the one the venv was synced with (A), Risk: low. One extra Look here:
Verified:
Changes I made: none. Open questions: none blocking. Known follow-ups are listed in the PR body (several variant records under a hosted pin still refuse; Auto-merge is armed, so approving sends it straight to the merge queue. Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1105
Summary
A project moving from hosted to vendored mode now picks up a newer patch even when its venv still holds the old hosted patch's bytes. This covers
uv sync,poetry installanduv pip install -rafter a hosted scan.Root cause
vendor/scan --mode vendoredchecks the installed copy of a PyPI package against the patch it is about to vendor (the release-variant probe). If the installed bytes match neither the pristine release nor this patch's output, the probe drops the package unlesssuperseded_installsays the install is an older patch generation. Before this change,superseded_installonly looked at the vendor ledger.After a hosted scan with patch A and a sync, the venv holds A's bytes and the lock carries a live hosted pin, but there is no ledger entry. So once the API served a superseding patch B, the package was dropped as
package_not_installed("no installed package found on disk"). The run exited 1 and the hosted takeover was never reached.scan --mode vendored --dry-runstops before the probe, so it previewed success.Fix (
crates/socket-patch-cli/src/commands/vendor.rs)superseded_installalso counts a live hosted pin on the candidate as a superseded install. Any pin counts, whatever uuid it names. That covers a lock a later hosted scan already moved to B over a venv still synced from A, and pins at two uuids in different files. The takeover then restores the upstream entry, and the backend takes the pristine artifact from the lock or registry, as it already does for the ledger case (Vendored Pipenv never picks up a superseding patch: re-vendor to a new uuid fails with pypi_pipenv_source_already_exists (lock-only) or a false package_not_installed (venv present), exit 1 #769).plan_service_downloads) gets the same hosted check as the vendor loop.Tests
mode_migration_pypi::hosted_to_vendored_takes_a_superseding_patch_over_a_hosted_venvpackage_not_installedcommands::vendor::plan_gate_tests::hosted_pin_marks_a_pypi_install_superseded(unit)Local runs (Linux, as root):
cargo fmt --all -- --checkandcargo clippy --workspace --all-features -- -D warnings: clean.cargo test --workspace --all-features, run one target at a time to fit the disk allowance: 218 of 221 targets pass, includingmode_migration_pypi(70),in_process_vendor_pypi_takeover(7),hosted_superseding_pypi(4) and the CLI lib (934).main'svendor.rs, so they are environmental:in_process_redirect: chmod-based write-failure tests can't fail as root.e2e_bun_lockb: needs the pinned bun 1.0/1.1 toolchain that CI installs.npm/,pypi/,gem/) changes are needed: the change is internal to the Rust vendor loop.Review notes
/code-review highfindings that were fixed: any hosted pin counts (not only one at another uuid), multiple pins per purl, the planner using the same check, the gem platform guard, and a shadowed test const.Not changed:
vendor --dry-runover any uv hosted pin, even at the same uuid, previewspypi_uv_source_already_exists, because the dry run doesn't apply the restore. That predates this PR.Generated by Claude Code