You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Vendored uv script locks: after uv remove --script drops the package from one of two vendored scripts, every unwind keeps the other script wired (revert exits 0, remove/rollback exit 1, hosted takeover refuses) #1285
[agent] Found by the scheduled uv bug-hunt routine (ledger #310).
Summary
#1231 fixed #1214 for a single vendored PEP 723 script: after uv remove --script s.py six, the revert now classifies the script's records as vendor_lock_entry_removed and finishes. It does that only when no wired file names the entry's uuid. With two vendored scripts that share the same six entry, removing six from just one of them (uv remove --script b.py six) leaves a.py still naming the uuid. So b.py / b.py.lock (which no longer mention the uuid anywhere) are classified as drift again, and the drift gate blocks the whole unwind, including a.py, which the user never touched.
I first reported this shape on #1214 before #1231 merged (#1214 (comment)). #1214 is now closed, and the shape still reproduces on main, so I'm filing it separately.
Impact
vendor --revert and scan --prune exit 0 success with removed 0. a.py and a.py.lock stay wired to .socket/vendor/pypi/<uuid>/, and uv run --script a.py keeps running the vendored wheel.
scan --mode hosted exits 0 with redirect_vendored_revert_failed ("part of its vendored wiring was edited since vendoring … NOT switched to hosted"), and a.py stays vendored.
The only remedy the messages name ("undo the drift … and re-run vendor --revert") is to add six back to b.py, which the user deliberately removed. Nothing installs unpatched and vendor --check stays green, so this is a stuck unwind, not a silent unpatch.
Repro (Linux, main e9be746, uv 0.5.31 and 0.12.24)
Patch data came from a local mock of the patch API (six@1.16.0), the same one used for earlier uv issues.
Control: the same two-script fixture without the uv remove reverts cleanly (exit 0, both scripts byte-identical to upstream, .socket/vendor/pypi gone). The single-script uv remove --script shape from #1214 also passes on this main.
Expected vs actual
Expected: what Fix uv script lock revert stuck as drift (#1214) #1231 does for one script, applied per script/lock pair. b.py / b.py.lock no longer name the uuid, so their records are "removed" (nothing to restore). a.py / a.py.lock are unchanged, so they're restored to upstream, and the revert finishes. CLI_CONTRACT.md says scan --prune / vendor --revert revert vendored entries whose dependency is gone, and Fix uv script lock revert stuck as drift (#1214) #1231's description treats "nothing references the vendored wheel" as removed, not drift.
Actual: b.py's records are classified as drift because a.py still names the uuid, and the drift keeps the whole entry, a.py included.
Matrix (Linux, real uv lock --script / uv remove --script, fresh fixture per cell, each run twice)
uv
unwind after uv remove --script b.py six
exit
a.py after
wheel
0.5.31
vendor --revert
0 (drift)
still wired
kept
0.5.31
scan --prune --mode vendored
0
still wired
kept
0.5.31
remove pkg:pypi/six@1.16.0
1vendor_revert_kept
still wired
kept
0.5.31
rollback
1
still wired
kept
0.5.31
scan --mode hosted
0 redirect_vendored_revert_failed
still vendored
kept
0.12.24
all five, same as above
same
same
same
0.12.24
control: no uv remove, vendor --revert
0
restored
removed
macOS / Windows not probed: the logic is a uuid text check with no OS-specific branch.
Suspect code
crates/socket-patch-core/src/vendor/pypi_lock.rs:737-754 (revert_python_locks): unreferenced is one flag for the whole entry. It's set to false as soon as any wired file still contains the uuid, so the vendor_lock_entry_removed arm at ~line 776 never fires for b.py's records while a.py is still wired. Deciding "removed" per script/lock pair (does this record's own file, or its paired script/lock, still name the uuid?) would let the unchanged pair restore and the removed pair converge, while a real hand edit inside a still-referencing file stays drift. Related, but a different trigger: #890 (a wired script or .py.lock deleted outright blocks the other scripts' unwind).
v5 triage: P2, not a release blocker. P2 for unwind after one of two vendored PEP 723 scripts removes a shared package. Keep the genuine cleanup bug, but do not let the expanding multi-script state matrix gate the ordinary project-lockfile release.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
[agent] Found by the scheduled uv bug-hunt routine (ledger #310).
Summary
#1231 fixed #1214 for a single vendored PEP 723 script: after
uv remove --script s.py six, the revert now classifies the script's records asvendor_lock_entry_removedand finishes. It does that only when no wired file names the entry's uuid. With two vendored scripts that share the same six entry, removing six from just one of them (uv remove --script b.py six) leavesa.pystill naming the uuid. Sob.py/b.py.lock(which no longer mention the uuid anywhere) are classified as drift again, and the drift gate blocks the whole unwind, includinga.py, which the user never touched.I first reported this shape on #1214 before #1231 merged (#1214 (comment)). #1214 is now closed, and the shape still reproduces on main, so I'm filing it separately.
Impact
vendor --revertandscan --pruneexit 0successwithremoved 0.a.pyanda.py.lockstay wired to.socket/vendor/pypi/<uuid>/, anduv run --script a.pykeeps running the vendored wheel.remove pkg:pypi/six@1.16.0exits 1vendor_revert_kept, androllbackexits 1 (vendor_lock_entry_drifted+vendor_artifact_kept).scan --mode hostedexits 0 withredirect_vendored_revert_failed("part of its vendored wiring was edited since vendoring … NOT switched to hosted"), and a.py stays vendored.vendor --revert") is to add six back to b.py, which the user deliberately removed. Nothing installs unpatched andvendor --checkstays green, so this is a stuck unwind, not a silent unpatch.Repro (Linux, main
e9be746, uv 0.5.31 and 0.12.24)Patch data came from a local mock of the patch API (
six@1.16.0), the same one used for earlier uv issues.Control: the same two-script fixture without the
uv removereverts cleanly (exit 0, both scripts byte-identical to upstream,.socket/vendor/pypigone). The single-scriptuv remove --scriptshape from #1214 also passes on this main.Expected vs actual
b.py/b.py.lockno longer name the uuid, so their records are "removed" (nothing to restore).a.py/a.py.lockare unchanged, so they're restored to upstream, and the revert finishes. CLI_CONTRACT.md saysscan --prune/vendor --revertrevert vendored entries whose dependency is gone, and Fix uv script lock revert stuck as drift (#1214) #1231's description treats "nothing references the vendored wheel" as removed, not drift.Matrix (Linux, real
uv lock --script/uv remove --script, fresh fixture per cell, each run twice)uv remove --script b.py sixvendor --revertscan --prune --mode vendoredremove pkg:pypi/six@1.16.0vendor_revert_keptrollbackscan --mode hostedredirect_vendored_revert_faileduv remove,vendor --revertmacOS / Windows not probed: the logic is a uuid text check with no OS-specific branch.
Suspect code
crates/socket-patch-core/src/vendor/pypi_lock.rs:737-754(revert_python_locks):unreferencedis one flag for the whole entry. It's set to false as soon as any wired file still contains the uuid, so thevendor_lock_entry_removedarm at ~line 776 never fires for b.py's records while a.py is still wired. Deciding "removed" per script/lock pair (does this record's own file, or its paired script/lock, still name the uuid?) would let the unchanged pair restore and the removed pair converge, while a real hand edit inside a still-referencing file stays drift. Related, but a different trigger: #890 (a wired script or.py.lockdeleted outright blocks the other scripts' unwind).