GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Fix uv revert restoring a stale specifier (#840) by mikolalysenko · Pull Request #841 · SocketDev/socket-patch Conversation
|
| Test | Covers | Without fix (58ef065) |
With fix |
|---|---|---|---|
pypi_uv::tests::revert_respells_an_edited_requires_dist_specifier |
#840, dependencies (>=1.15) |
fail (stale ==1.16.0) |
pass |
pypi_uv::tests::revert_respells_an_edited_requires_dev_specifier |
#840, PEP 735 dev group (==1.16.*) |
fail | pass |
pypi_uv::tests::revert_drops_the_specifier_of_an_unconstrained_declaration |
#840, bare six |
fail | pass |
pypi_uv::tests::revert_respells_an_edited_manifest_constraint |
#840, constraint-dependencies |
fail | pass |
pypi_uv::tests::revert_respells_only_the_edited_extra_element |
#840, package in deps plus an extra | fail | pass |
pypi_uv::tests::revert_keeps_the_pair_when_an_edited_specifier_is_not_derivable |
#840, multi-clause edit: drift, both files kept | fail (stale specifier, success) | pass |
pypi_uv::tests::revert_keeps_the_pair_on_a_multi_clause_edit_despite_sibling_evidence |
same, with a multi-clause sibling in the lock | fail | pass |
pypi_uv::tests::revert_respells_the_entry_whose_marker_mirrors_the_edit |
Bugbot: marker-split pair, only one edited | fail on 005404c (stale pin kept) |
pass |
pypi_uv::tests::revert_keeps_the_pair_when_group_declarations_disagree |
Bugbot: include-group still carries the old pin: drift |
fail on 005404c |
pass |
pypi_uv::tests::revert_respells_past_an_unreadable_sibling_declaration |
Bugbot: === extra beside an edited pin |
fail on 9983ac8 |
pass |
pypi_uv::tests::revert_does_not_converge_on_a_lookalike_dependency_entry |
Bugbot: a { name = "six" } lookalike fakes convergence |
fail on 9983ac8 |
pass |
pypi_uv::tests::revert_keeps_the_recorded_specifier_when_the_declaration_agrees |
control: re-spaced and marker-only edit stays byte-exact | pass | pass |
e2e_vendor_pypi_build::uv_vendor_revert_after_declaration_edit (real uv: vendor → uv add "six>=1.16" → vendor --revert → uv lock --check) |
#840 | fail (The lockfile at uv.lock needs to be updated) |
pass |
e2e_vendor_pypi_build::uv_vendor_revert_after_dev_group_declaration_edit (same, uv add --dev) |
#840, dev group | fail (same) | pass |
The red e2e runs used 58ef065's pypi_uv.rs (pre-fix revert plus the new tests).
767d6e9, rust 1.93.1 per rust-toolchain.toml)cargo clippy --workspace --all-features -- -D warnings: clean.cargo fmt: my hunks are fmt-clean. This rustfmt also reformats about 130 untouched files on main; those reformats were reverted rather than included.cargo test -p socket-patch-core --lib vendor::pypi_uv: 106/106 pass.SOCKET_PATCH_UV_E2E_REQUIRED=1 cargo test -p socket-patch-cli --all-features --test e2e_vendor_pypi_build -- --include-ignored (uv 0.8.17): 27/27 pass, with no skips.cargo test -p socket-patch-core --all-features:
copy_tree, vlt_heal, pypi_poetry, pypi_requirements). They expect a read-only path to refuse a write, which can't happen as root, and this sandbox runs as root. Fix uv vendored revert half-reverting after a relock (#806, #821) #822 documented the same four.--test '*'): 550/550 pass.uv sync --locked fails (vendor --revert / remove / rollback exit 0) #840: vendor --revert after uv add, dependencies: unit revert_respells_an_edited_requires_dist_specifier + e2e uv_vendor_revert_after_declaration_edituv sync --locked fails (vendor --revert / remove / rollback exit 0) #840: dev group: unit revert_respells_an_edited_requires_dev_specifier + e2e uv_vendor_revert_after_dev_group_declaration_edituv sync --locked fails (vendor --revert / remove / rollback exit 0) #840: other specifier shapes (>=1.15, ==1.16.*, unconstrained): unit tests aboveuv sync --locked fails (vendor --revert / remove / rollback exit 0) #840: remove / rollback / GC prune: same revert_pypi → revert_uv pathuv sync --locked fails (vendor --revert / remove / rollback exit 0) #840: multi-clause (six>=1.16,<1.17, the issue's main repro): the revert now keeps both files with vendor_lock_entry_drifted instead of breaking --locked. This is one of the two outcomes the issue accepts. Re-deriving it would need uv's per-release clause order (see follow-ups).02735f5 ports Fix vex alias tests broken by store-copy merge #851 unchanged: a tests-only fix for two commands::vex_consumed tests that are red on main since Fix npm store copies missed by agent apply and vex (#601, #603) #605 (4646693). It no-ops once Fix vex alias tests broken by store-copy merge #851 merges.restore_requirement_array) learns multi-clause spelling from SpecStyle's lexicographic or declaration-order candidates. uv 0.8.17 orders clauses by version, so a learned style can be wrong when the declaration order happens to agree with version order. That's not changed here.🤖 Generated with Claude Code
Note
Medium Risk
Changes uv vendor revert lockfile surgery and specifier derivation; incorrect respelling could break --locked sync, but ambiguous cases fail closed with warnings.
Overview
Fixes #840: after vendoring a uv dependency, editing its requirement in pyproject.toml (e.g. uv add "six>=1.16") leaves uv.lock unchanged because path sources drop specifiers. Revert used to write the stale recorded specifier back, so revert looked successful but uv sync --locked failed.
Revert now re-derives requires-dist, requires-dev, and [manifest] constraints entries from current declarations via new respell_lock_specifier / respell_original, matching entries by marker/extra like hosted unwind. Unchanged declarations still revert byte-for-byte; unconstrained deps drop the specifier; multi-clause or ambiguous edits fail closed (keep wired pair, vendor_lock_entry_drifted). requires-dist convergence no longer treats a lookalike { name = "six" } elsewhere in the lock as already restored.
Adds unit and e2e coverage plus docs in uv-compatibility.md. vex_consumed npm hosted tests are adjusted for post-#605 resolver behavior (alias expansion still exercised on an alias-free installed set).
Reviewed by Cursor Bugbot for commit 02735f5. Configure here.
Generated by Claude Code
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Assisted-by: Claude Code:claude-opus-5-5
After vendoring, an ordinary uv relock (`uv add --dev x`, `uv add y`) re-serializes the lock arrays that hold our element: the dev group's requires-dev line and `[manifest] overrides`. Revert matched those arrays by their exact recorded text, so it saw drift and kept uv.lock wired, but still reverted pyproject.toml. The pair then failed `uv sync --locked` while `vendor --revert` reported success. Revert now finds our unchanged element inside the live array under the same key and restores or removes just that element, rendering the array the way uv writes it. A pair gate also writes neither file when any record is genuinely drift-kept, so pyproject.toml and uv.lock always stay consistent. Fixes #806, #821. Assisted-by: Claude Code:claude-opus-5-5
Vendor six, run the uv command that re-serializes the lock array around our element (`uv add --dev zipp` for a dev group, `uv add idna` beside user overrides), then revert. Both files must be unwired with no drift warning, and `uv lock --check` must pass. Refs #806, #821. Assisted-by: Claude Code:claude-opus-5-5
A [manifest] overrides record holds the bare array, and the old convergence shortcut searched the whole lock for it. When the root requires-dist happened to match the user's overrides array, revert treated our element as already gone, left it in uv.lock and deleted the artifact it points at. Every whole-array record now reverts through its own key: an untouched array is restored verbatim, otherwise just our element is. Refs #806. Assisted-by: Claude Code:claude-opus-5-5
Revert treated any miss locating a whole-array record as convergence, including a key spelled differently or an unbalanced array. A lock that still routed through the vendored wheel could then lose the wheel. Only a key or section that is provably absent now counts as converged. Anything unreadable is drift, which keeps both files and the artifact. Refs #806, #821. Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
A vendored uv revert writes back the lock specifier it recorded when vendoring. If the user changed the package's requirement in pyproject.toml in the meantime, the lock no longer matches and `uv sync --locked` fails. These tests pin the expected behaviour for requires-dist, requires-dev groups and [manifest] constraints. Refs #840 Assisted-by: Claude Code:claude-opus-5-5
When six is vendored, uv.lock records it as a path source with no version specifier. If the user then changes six's requirement in pyproject.toml (uv add "six>=1.16"), the lock stays byte-identical, and vendor --revert, remove and rollback wrote back the specifier recorded at vendoring time. The revert reported success, but `uv sync --locked` then failed. The revert now writes the specifier pyproject.toml declares now, using the same derivation the hosted unwind uses. This covers requires-dist (each extra separately), requires-dev groups and [manifest] constraints. An unchanged declaration still restores byte-for-byte. When uv's spelling can't be derived, such as a multi-clause range whose clause order varies between uv releases, the revert keeps both files and warns vendor_lock_entry_drifted instead of breaking the lock. Fixes #840 Assisted-by: Claude Code:claude-opus-5-5
Refs #840 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
[agent] Labeled Ready for review.
Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
[burn-down agent] Labeled Ready for review (label from the 10:22 run was missing).
Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
#625 on main changed the uv declaration reader to report each optional-dependencies member's extra. The merge of main into this branch no longer compiled. Use that reader for requires-dist instead of the local extras walk. Dev groups now also pick up main's group-name normalization and include-group expansion. Refs #840 Assisted-by: Claude Code:claude-opus-5-5
|
[agent] The merge of Re-verified locally on
Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
When a package is declared twice, for example under two environment markers, or directly and through an include-group, the revert kept the recorded specifier whenever any one declaration still matched it. Edit just one of them and the stale pin came back, with the same broken `uv sync --locked` as #840. The revert now picks the declaration by the entry's own marker, as the hosted unwind does. Declarations that still disagree after that are treated as drift, and both files are kept. Refs #840 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Two cases Bugbot found on the vendored uv revert:
- A same-name declaration that isn't a plain version range, such as an
extra pinned with ===, stopped every entry from following its edited
declaration. Now only the entry whose own declaration is unreadable
keeps its recorded spelling.
- After a bound was dropped, the restored { name = "six" } element
also matched another dependency entry in uv.lock, so a drifted wiring
could pass as already reverted. The check now looks only in the root
unit's requires-dist array.
Refs #840
Assisted-by: Claude Code:claude-opus-5-5
Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Stale Bugbot comment from a previous run.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
main has been red since #605 (4646693). Two vex_consumed tests from #738 assumed the name-keyed copy resolver never returns npm-aliased copies, and #605 taught it to. This ports #851's tests-only fix unchanged so this PR's coverage and macOS test jobs can go green; it no-ops once #851 lands on main. Assisted-by: Claude Code:claude-opus-5-5
|
[agent] Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
✅ 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 02735f5. Configure here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Vendored uv revert writes the pre-vendor specifier back into uv.lock after the user changes the vendored package's version spec, souv sync --locked fails (vendor --revert / remove / rollback exit 0)
There was an error while loading. Please reload this page.