Repository navigation
After uv remove --script drops a vendored package from a PEP 723 script lock, scan --prune, vendor --revert, remove, rollback and the hosted takeover still drift-keep it, so vendor --check stays red and its prune remedy loops #1214
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:uvuvuv
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Triage: priority:p1 (PyPI/uv). Confirmed on main
f3c6313:revert_python_locks(crates/socket-patch-core/src/vendor/pypi_lock.rs:723) only has thevendor_lock_entry_driftedarm for script-metadata / script-lock records; the "nothing names the uuid" →vendor_lock_entry_removedarm #1147 added lives only inpypi_uv.rs. No open PR addresses it.
Generated by Claude Code
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (shared root cause:
revert_python_lockshas no "nothing names the uuid any more" arm for PEP 723 script records). Branch: agent/fix-uv-script-lock-removed-entry. Claim-ID: 2026-10-09T06:21:47Z-0e505c
Generated by Claude Code
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions- added 2 commits that reference this issue
on Oct 9, 2026 mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] uv bug-hunt run 35 (ledger #310): I checked PR #1231 (
eec1e33) against maine03a666, using uv 0.12.24 (and 0.5.31 for the two-script row).Single script (the shape in this issue): fixed. After
uv remove --script a.py six, all ofscan --prune,vendor --revert,removeandrollbackexit 0 (rollback reportsvendor_lock_entry_removed), the wheel is gone, andvendor --checkexits 0. On main they still drift-keep, with check 1. The hosted takeover still warnsvendor_ledger_entry_unwiredwith check 1, but itsscan --pruneremedy now works, so it's no longer a loop.Two scripts where only one drops six: still broken on #1231. Repro:
a.pyandb.pyboth declaresix==1.16.0, each has its own.py.lock, and both are vendored. Then:uv remove --script b.py six socket-patch vendor --revert --json # exit 0, status success, removed 0 # vendor_lock_entry_drifted "b.py.lock changed since vendoring; conflicting fields were preserved" # + vendor_artifact_kept + vendor_revert_kept # a.py is still wired to .socket/vendor, and `uv run --locked --script a.py` still runs the patched six socket-patch remove pkg:pypi/six@1.16.0 --yes # exit 1 vendor_revert_kept socket-patch rollback --yes # exit 1 vendor_artifact_kept + vendor_lock_entry_drifted socket-patch scan --mode hosted --yes # exit 0 redirect_vendored_revert_failed, a.py stays vendoredSo b.py's record is still classified as drift, not as removed, while another script keeps the uuid live. That blocks the whole unwind, including a.py, which didn't change. The results are the same on main and on #1231, with uv 0.5.31 and 0.12.24, and on repeated runs. A user-deleted
# six = { path = … }source line in one script, followed by a relock, unwinds cleanly on both builds.
Generated by Claude Code
mikolalysenko commented
on Oct 9, 2026 CollaboratorAuthorMore actions[agent] uv bug-hunt run 36 (ledger #310): I verified the fix on main
e9be746(with #1231), using uv 0.5.31 and 0.12.24. For the single-script shape in this issue,vendor --revert,scan --prune,removeandrollbacknow finish afteruv remove --script.The two-script shape from my earlier comment, where only one script drops six, still reproduces on main. I filed it separately as #1285.
Generated by Claude Code
[agent] Found by the scheduled uv bug-hunt routine (ledger #310).
Summary
#1147 fixed #1140 for uv projects: after
uv remove six,revert_uvnow reportsvendor_lock_entry_removedwhen neitherpyproject.tomlnoruv.locknames the entry's uuid, and the revert finishes. The same removal in a PEP 723 script lock isn't covered. Script locks go throughrevert_python_locks(pypi_lock.rs), which still has only the drift arm.After
uv remove --script s.py six, uv deletes six from the script block, thetool.uv.sources.sixline and thes.py.lockpackage. Nosocketreference is left in either file. Then:vendor --checkexits 1: "dependency removed … runsocket-patch scan --mode vendored --pruneto revert the vendored entry".scan --pruneexits 0 and prints "GC: kept 1 drifted vendored entry … undo the drift and re-runvendor --revert". Check stays red.vendor --revert --jsonexits 0success, withvendor_lock_entry_drifted+vendor_artifact_kept+vendor_revert_kept. The wheel and ledger entry stay.remove pkg:pypi/six@1.16.0exits 1vendor_revert_kept.rollbackexits 1partial_failure(vendor_lock_entry_drifted).scan --mode hostedexits 0 withvendor_ledger_entry_unwiredand leaves the entry too.There's nothing to undo, so no command can ever clear the entry. Check's own remedy (
scan --prune) is a no-op that exits 0. I reported this shape on #1140 before #1147 merged (#1140 (comment)). #1140 is now closed, and the project and upgrade shapes from that comment pass onb76d7ab, so I'm filing the script lane separately.Impact
A CI gate on
vendor --checkstays red for good after a routine dependency removal from a uv script. Every remedy the tool names exits 0 or loops, and the dead wheel and ledger entry stay committed. Nothing installs unpatched (six is gone from the script), so this is a stuck state, not a silent unpatch.Repro (Linux, uv 0.12.24 or 0.5.31, main
b76d7ab)Patch data came from a local mock of the patch API (
six@1.16.0), the same one as earlier uv issues.Expected vs actual
python_script_metadata/python_lock_documentrecord warnsvendor_lock_entry_removed, the revert finishes and deletes the wheel and ledger entry, andvendor --checkturns green. CLI_CONTRACT.md hasscan --prunerevert vendored entries whose dependency is gone, and that's the remedyvendor --checknames.Matrix (Linux, real
uv lock --script/uv remove --script; fresh fixture per cell, all run twice)uv remove --scriptvendor --checkafterscan --prunevendor --revertvendor_lock_entry_drifted)remove pkg:pypi/six@1.16.0vendor_revert_keptrollbackpartial_failurescan --mode hostedvendor_ledger_entry_unwireduv remove six→scan --pruneuv remove six && uv add six==1.17.0→scan --pruneNot bisected: this is a gap left by #1147, which only touched
pypi_uv.rs. No probe branch: there's no OS-specific logic involved.Suspect code
crates/socket-patch-core/src/vendor/pypi_lock.rs:723(revert_python_locks): the script-metadata and script-lock records only map a missing original tovendor_lock_entry_drifted(lines ~733 / 746 / 774). They need the same "nothing names the uuid any more →vendor_lock_entry_removed" arm that Fix vendored revert reading a removed dependency as drift (#1132, #1140, #1142) #1147 added atcrates/socket-patch-core/src/vendor/pypi_uv.rs:825.