Skip to content

Fix uv sources unwind on dotted/sub-table spellings (#544, #524) - #545

Open
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
agent/fix-uv-sources-table-spelling
Open

Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
agent/fix-uv-sources-table-spelling

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 2, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #544
Fixes #524

Summary

After vendoring or a hosted scan, uv projects whose existing [tool.uv] sources aren't written as a plain [tool.uv.sources] table now unwind cleanly:

Root cause

The uv wiring assumed sources live under an explicit [tool.uv.sources] header as name = {…} lines. toml_edit, though, writes a new key in the spelling its parent already has:

  • Vendored mode recorded a hard-coded six = { path = … } in the ledger, while the file held sources.six = { … }. Revert's exact-line splice missed it, and the fragment was treated as user drift.
  • A parent that exists only implicitly (implied by [tool.uv.sources.<pkg>] sub-tables) prints its header once a key is added. Vendored mode decided "we didn't create the table" because the table existed, and the hosted restore left it explicit.

Changes

Known trade-off: a user who wrote an explicit, key-less [tool.uv.sources] header with only sub-tables beneath it gets that header dropped by a hosted rollback. The hosted path has no ledger, so it can't tell that header apart from one the scan made explicit. The result still parses identically, and that shape is unusual.

No wrapper changes are needed (npm/, pypi/, gem/ only dispatch to the binary).

Test evidence

Each regression test was run red on the pre-fix code and green with the fix:

Issue Test Without fix With fix
#544 vendor::pypi_uv::tests::revert_round_trips_dotted_sources_under_tool_uv drift warning ok
#544 …revert_round_trips_dotted_sources_path_key drift ok
#544 …revert_round_trips_dotted_uv_sources_under_tool (follow-up comment's [tool] + uv.sources) drift ok
#544 …revert_round_trips_root_dotted_tool_uv_sources drift ok
#544 …revert_round_trips_dotted_sources_crlf drift ok
#544 …revert_round_trips_dotted_override_under_tool (transitive) drift ×2 ok
#544 e2e e2e_vendor_pypi_build::uv_vendor_revert_dotted_sources_key, …_dotted_sources_url_key (real uv 0.8.17, plus uv lock --check after revert) vendor_lock_entry_drifted ok
#524 …revert_drops_header_made_explicit_over_sub_tables (+ _override, _crlf) header residue ok
#524 patch::redirect::upstream::uv::tests::restore_drops_sources_header_made_explicit_over_sub_tables (+ _transitive, _crlf) header residue ok
#524 e2e e2e_vendor_pypi_build::uv_vendor_revert_sub_table_sources (real uv 0.8.17) [tool.uv.sources]\n\n residue ok
control revert_keeps_user_authored_sources_header, restore_keeps_user_sources_spellings – ok

Commands run locally on bec2311:

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo test --workspace --all-features --no-fail-fast: all pass except 12 permission-injection tests (chmod/set_permissions read-only fixtures in covgap_commands_vendor, in_process_redirect, repair, and core copy_tree/vlt_heal/pypi_poetry/pypi_requirements). Those can't fail as intended because the sandbox runs as root. None of them is in a file this PR touches, and CI runs as non-root.
  • cargo test -p socket-patch-cli --all-features --test e2e_vendor_pypi_build -- --include-ignored (uv 0.8.17): every uv test passes, including the 3 new ones. Two pip/requirements tests (pip_requirements_vendor_fresh_checkout_no_index_and_revert, pip_vendored_requirements_evaluate_environment_markers) panic in the harness's copy_tree in this sandbox. They exercise code this PR doesn't touch, so CI is authoritative.
  • cargo test -p socket-patch-cli --all-features --test e2e_redirect_uv_build -- --include-ignored (uv 0.8.17): 16/16 pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_013Lodu4CMs7Cfqq8pEzPXpb


Note

Medium Risk
Changes how vendor and hosted flows edit pyproject.toml and uv.lock for uv projects; mistakes could break lock consistency or mis-remove user TOML, though scope is limited to unwind/restore paths with new regression tests.

Overview
Fixes uv vendor revert and hosted unwind when pyproject.toml already expresses [tool.uv] sources with dotted keys or sub-table-only layouts (#544, #524), so vendor --revert / rollback no longer leave false vendor_lock_entry_drifted warnings or stray [tool.uv.sources] headers and the project returns byte-identical pyproject.toml / uv.lock that uv lock --check accepts.

Core work records the exact line toml_edit emitted when wiring (rendered_key_line), treats implicit parent tables as owned so revert can drop headers the scan made explicit (header_is_ours), tightens TOML removal spacing in toml_surgery, and mirrors the same cleanup on the hosted restore path (hide_header_over_sub_tables).

This diff also adds real-uv e2e capstone tests for three source spellings and applies rustfmt across socket-patch-cli (formatting only).

Reviewed by Cursor Bugbot for commit bec2311. Configure here.


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
Vendored uv revert misreads its own sources line as drift when the
project spells sources as dotted keys (#544), and leaves behind the
[tool.uv.sources] header it made explicit over sub-tables (#524).

Assisted-by: Claude Code:claude-opus-5-5
Vendored revert and remove now find the sources and override lines
they wrote even when the project spells [tool.uv] sources as dotted
keys, so a revert no longer reports its own line as drift and leaves
pyproject.toml routed to the vendored wheel while uv.lock is restored
(which broke uv sync --locked). (#544)

When a project only has [tool.uv.sources.<pkg>] sub-tables, the scan
has to print an explicit [tool.uv.sources] header. Vendored revert and
hosted rollback/remove now drop that header again, so an unwind leaves
pyproject.toml byte-identical. (#524)

Assisted-by: Claude Code:claude-opus-5-5
Vendors and reverts six on real uv projects whose existing sources use
a dotted key, a dotted .url key, or [tool.uv.sources.<pkg>] sub-tables,
and checks the unwind is byte-identical and passes uv lock --check.
(#544, #524)

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 2, 2026 10:08
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for 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 bec2311. Configure here.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] Ready for review at bec2311. CI is green (484 checks passed, 6 skipped by design) and Bugbot found no issues. Two legs failed on first run for reasons outside this change, and each passed when re-run once: native (macos-latest, 1.1.15) (Poetry populated/hosted appliedExactlyOne; the same leg is green on #543's run off the same main) and e2e (macos-latest, e2e_vex_build, pipenv::) (a DNS failure fetching pipenv from files.pythonhosted.org before any test body ran).


Generated by Claude Code

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants