Skip to content

Read recovered uv/pdm wheel pins through the shared lock model (#1079) - #1121

Merged
Mikola Lysenko (mikolalysenko) merged 3 commits into
mainfrom
arch-refactor/1079-recover-uv-wheel
Oct 8, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 3 commits into
mainfrom
arch-refactor/1079-recover-uv-wheel

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #1079 (slice 1: ledger recovery)

Summary

repair and re-vendor rebuild a missing PyPI artifact from the uv / pdm [[package]] unit recorded in the vendor ledger. That unit was read by a third uv.lock reader, a string scanner (pure_wheel_from_uv_unit). It paired a pure wheel's URL with the first hash = "sha256: after it, even when that hash belonged to a later platform wheel. It also kept its own -none-any.whl suffix rule, which drifted from the shared wheel classifier once #1053 (#1048) landed. Recovery now reads the unit through the shared lock model and the shared classifier.

Why (leverage)

What changed

  • vendor/pypi_distribution.rs: new is_portable_wheel_url(url). It strips ?/#, takes the last path segment, requires .whl, and asks wheel_platform_from_filename, the rule vendored (vendor_platform_locked) and hosted (redirect_pypi_platform_wheel) mode already use.
  • vendor/lock_inventory/recover.rs: pure_wheel_from_uv_unit parses the unit as TOML ([[package]] unit, or a bare artifact-array fragment). It reads artifacts through utils::python_lock::package_artifacts (archive, wheels, wheel, files), so each URL keeps its own hash, and keeps the http(s) gate (http_url).
  • .github/workflows/ci.yml: the setup-php pin comment # v2 → # 2.37.2, ported from Label the setup-php pin in ci.yml with its real tag #1118 because zizmor fails every PR on main without it. It no-ops once Label the setup-php pin in ci.yml with its real tag #1118 merges.

Deleted

  • The string scanner body (≈25 lines) and recovery's private -none-any.whl suffix rule.
  • git diff --stat: production +36 / −24 (recover.rs, pypi_distribution.rs), tests +88 (recover_tests.rs), CI +1 / −1.

Remaining (slice 2, after #1058 / #1009 / #1045 / #768 land)

  • lock_inventory/pypi.rs python_package_archive and the poetry site still use ends_with("-none-any.whl"). Both move onto is_portable_wheel_url, and the inventory and recovery selectors become one function.
  • Rename pure_wheel_from_uv_unit and move its old test out of lock_inventory/{mod,tests}.rs.
    These files are changed by open PRs, so they're left alone here.

Behavior

Recovery only (repair / re-vendor of a missing vendored PyPI artifact from a uv or pdm static_urls fragment):

Test evidence

  • New tests in recover_tests.rs:
  • Red→green: with main's recover.rs, all 3 fail. On the branch, all pass. The existing composer_gem_uv_fragments_recover, recover_pypi_pdm_static_urls_recovers_pure_wheel, recover_pypi_urlless_locks_report_no_fetchable_url and pure_wheel_rejects_short_hash_missing_hash_and_non_http_url pass unchanged.
  • cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-core --lib: 5742 passed, 4 failed. The 4 failures fail on main too because the sandbox runs as root (copy_tree::relax_loop_must_not_traverse_symlinked_root, vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry, pypi_poetry::wire_write_failure_maps_error_and_leaves_lock_untouched, pypi_requirements::wire_failure_rolls_back_already_written_files).
  • cargo test -p socket-patch-cli --all-features --test repair: 125 passed, 2 failed. Both are the known root-only chmod tests.

Risk

Low. The change is confined to the ledger-recovery path, which is rare and fail-closed: the fetch layer still verifies every digest. Recovery now parses the unit with toml_edit, which costs ≈80 µs per call; it runs once per missing artifact.

🤖 Generated with Claude Code


Note

Low Risk
Changes are limited to rare ledger-recovery code; fetches still verify digests, and unpinned or ambiguous cases remain fail-closed.

Overview
Fixes #1079 in the vendor-ledger recovery path (repair / re-vendor when a PyPI artifact is missing): uv and pdm [[package]] units are no longer read with a string scanner that could bind a portable wheel URL to another wheel’s sha256.

Recovery now parses the unit as TOML and walks artifacts through package_artifacts, so each URL keeps its own hash. Portable wheel selection uses a new is_portable_wheel_url helper (same wheel_platform_from_filename rule as vendored/hosted mode) instead of a -none-any.whl suffix check—so interpreter-tagged “any” wheels are excluded and query/fragment URLs classify correctly. Unpinned or non-portable wheels still fail closed with the existing “no fetchable registry URL” behavior.

CI only updates the setup-php pin comment (# v2 → # 2.37.2) for zizmor. New tests cover the mis-pairing repro, portability matrix, and per-artifact hashing.

Reviewed by Cursor Bugbot for commit fd8b7e6. Configure here.


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko Mikola Lysenko (mikolalysenko) added refactor Structural change: duplicated code or logic, missing abstraction, layering, dead code arch-refactor PR opened by the scheduled architecture refactor routine labels Oct 8, 2026
repair and re-vendor rebuild a missing PyPI artifact from the uv or
pdm [[package]] unit recorded in the vendor ledger. That unit was read
by a string scanner that paired a pure wheel's URL with the first
sha256 after it, even when that hash belonged to a later platform
wheel, so a hashless pure wheel failed with a confusing digest
mismatch instead of the honest "no fetchable registry URL" message.

Recovery now parses the unit as TOML through the shared
utils::python_lock::package_artifacts, so each URL keeps its own hash,
and decides portability through the shared wheel classifier vendored
and hosted mode use (#1048): cp311-none-any, pp310-none-any and
py2-none-any wheels are no longer picked, and #sha256= / ?query URLs
are classified by their file name. The string scanner and its private
-none-any.whl suffix rule are deleted.

Refs #1079

Assisted-by: Claude Code:claude-opus-5-5
zizmor's ref-version-mismatch audit fails every PR on main's ci.yml
because the setup-php hash pin is labelled `# v2`. Same one-line
change as #1118, ported so this PR's audit goes green; it no-ops when
#1118 lands.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] Audit GitHub Actions failed on the first commit with zizmor ref-version-mismatch on .github/workflows/ci.yml:1400 (the setup-php pin labelled # v2). This PR doesn't cause it; main's ci.yml does. Open PR #1118 fixes it, so I ported the same one-line change in fd8b7e6. It no-ops once #1118 merges.


Generated by Claude Code

@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 8, 2026 09:11
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

Mikola Lysenko (mikolalysenko) pushed a commit that referenced this pull request Oct 8, 2026
Assisted-by: Claude Code:claude-opus-5-5

@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 fd8b7e6. Configure here.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] e2e (ubuntu-latest, e2e_vendor_maven_build, maven, 3.8.9) failed during fixture warm-up, before any test body ran. Maven Central didn't serve maven-dependency-plugin:3.6.1 on all 3 tries ("Could not find artifact … in central"). This PR only changes PyPI ledger recovery and doesn't touch Maven or the e2e harness, so the failure isn't this PR's and there's no fix to port. I'll re-run the failed jobs once when the run completes.


Generated by Claude Code

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 8, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Ready for review (burn-down agent).

  • Head: fd8b7e6060eb8c7b58854c0b91de08246522eccb
  • CI: 472/472 check runs green (success/skipped/neutral) on this head, mergeable, no conflicts.
  • Bugbot: reviewed this head (Cursor Bugbot check: success), no unresolved review threads.
  • Changelog: untouched.

Nothing specific flagged for the reviewer beyond the PR description.


Generated by Claude Code

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

Labels

arch-refactor PR opened by the scheduled architecture refactor routine Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review refactor Structural change: duplicated code or logic, missing abstraction, layering, dead code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Vendored uv repair pairs a hashless pure wheel with another wheel's hash, because ledger recovery re-parses uv.lock with its own scanner

3 participants