Skip to content

Fix vendored Pipenv re-vendor to a newer patch (#769) - #825

Open
Mikola Lysenko (mikolalysenko) wants to merge 9 commits into
mainfrom
agent/fix-pipenv-vendored-revendor
Open

Mikola Lysenko (mikolalysenko) wants to merge 9 commits into
mainfrom
agent/fix-pipenv-vendored-revendor

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #769

Summary

Before this change, a Pipenv project vendored at patch A could never move
to a newer patch B for the same package. scan --mode vendored and
get <B> --mode vendored downloaded B, reported it as replacing A, and
then exited 1, while --dry-run previewed would_revendor:

  • lock-only checkout: failed pypi_pipenv_source_already_exists
  • venv installed from A's vendored wheel (pipenv sync): skipped package_not_installed ("no installed package found on disk"), which
    is false

Now both shapes re-vendor to B: Pipfile.lock is rewired to B's wheel, A's
artifact is swept (vendor_stale_artifact_removed), the ledger moves to
B, and vendor --revert of B restores the original registry pin.

Root cause

Two gaps, both about socket-patch's own wiring at an older patch uuid:

  1. Core, Pipfile.lock guard. check_target_guards in
    vendor/pypi_pipenv.rs refused the "ours, but a stale patch
    generation" entry outright, because wiring over it would lose the only
    recorded registry original. The original is not lost: the ledger entry
    for the older uuid holds it.
  2. CLI, installed-variant probe. In commands/vendor.rs, a PyPI
    install is hashed against the new record's beforeHash. A venv
    installed from A's wheel holds A's patched bytes, so the probe dropped
    the package, and it fell through to package_not_installed.

Fix

  • pypi_prelude looks up the ledger entry that vendored this package at
    another uuid and passes it to the new
    check_target_guards_superseding / wire_pipenv_superseding. An entry
    routed through that older uuid's wheel is rewired in place only when the
    ledger records that exact entry (section:key, unchanged since
    vendoring) with a pre-vendor original, and the wheel names the same
    release. The new record carries that original forward. With no ledger
    record, after an edit, or for another release it still refuses, and
    the message now says which.
  • superseded_install in the vendor loop (and the service download plan,
    which mirrors the loop): when the probe fails but the ledger holds exactly
    this package at an older uuid, the candidate gets the same pristine source
    path a lock-only checkout uses, instead of being skipped. This is limited
    to a sole candidate, or a ledger key equal to the candidate, so it never
    picks among sibling release variants.

This is the Pipenv lane of the #765 family (requirements.txt: #766;
uv/Hatch hosted: #743). It is kept separate so #766, which is ready for
review, doesn't grow. Follow-up (not in scope): pypi_poetry.rs and
pypi_pdm.rs have the same "STALE patch generation" refusal arm. No issue
has been filed for those yet.

No wrapper changes: npm/, pypi/ and gem/ only dispatch to the binary.

Tests (red → green)

Issue case Test Without fix With fix
#769 lock-only re-vendor vendor::pypi::tests::pipenv_superseding_uuid_revendors_in_place (core) FAIL (Refused) pass
#769 lock-only, end to end mode_migration_pypi::pipenv_revendors_to_a_superseding_patch (lock-only lane) FAIL pass
#769 venv installed from A mode_migration_pypi::pipenv_revendors_to_a_superseding_patch (venv lane) FAIL (package_not_installed, as reported) pass
Guard: no ledger record still refuses pipenv_superseding_uuid_without_ledger_refuses (new wording) pass
Guard: drifted entry still refuses pipenv_superseding_uuid_drifted_entry_refuses (new wording) pass

The red runs were done by applying the tests to the pre-fix sources: the
three core tests failed on main code, and the venv lane failed with
only the core half applied.

Commands run locally (Linux, root):

  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo test -p socket-patch-core --all-features --lib: 4845 passed.
    4 failed, all chmod/permission simulations that can't fail as root, and
    none in touched code (copy_tree, vlt_heal, poetry/requirements
    write-failure tests).
  • cargo test -p socket-patch-cli --all-features --lib: 834 passed
  • CLI suites mode_migration_pypi, in_process_vendor,
    in_process_redirect_pipenv, in_process_python_envs,
    e2e_vendor_pypi_build, e2e_vendored_production, e2e_vex_vendor,
    vendor_group_commit_e2e, vendor_ledger_schema_e2e,
    scan_requirements_lock_only, covgap_commands_get: all pass.
    covgap_commands_vendor has 3 failures, the state-write-failure tests,
    which also need a non-root chmod.
  • Real Pipenv: SOCKET_PATCH_PIPENV_E2E_REQUIRED=1 SOCKET_PATCH_PIPENV_E2E_VERSIONS=2026.8.0 cargo test -p socket-patch-cli --all-features --test e2e_vex_build -- pipenv:: --ignored: pass
  • The full cargo test --workspace ran out of this session's disk
    allowance while building every test binary, so CI is the full run.
  • cargo fmt: the touched code is formatted. main itself isn't
    rustfmt-clean under 1.93.1, so the unrelated reformat churn was left out.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VSXCFoPbraq7rNKJpXEP2n


Note

Medium Risk
Changes Pipenv lock wiring and vendor planning logic that affects ledger originals and revert correctness; behavior is gated on strict ledger/lock checks but touches a critical dependency path.

Overview
Fixes #769 so Pipenv projects vendored at patch A can re-vendor in place to a superseding patch B (same release), matching would_revendor / CLI behavior for both lock-only checkouts and venvs installed from A’s wheel.

Pipfile.lock path: check_target_guards_superseding / wire_pipenv_superseding treat an older .socket/vendor/pypi/<uuid> wheel as re-wirable when the vendor ledger still has that uuid’s entry (unchanged section:key, same wheel identity) and a pre-vendor registry original to carry forward; revert of B then restores the registry pin. Missing ledger, drifted lock entries, or wrong release still refuse with clearer errors.

CLI vendor loop: superseded_install plus lookup_entry_kv detect when the installed-variant probe fails because the venv holds A’s patched bytes, not B’s pristine baseline; those packages are sourced like lock-only (.socket/vendor/.uninstalled) instead of being skipped as not installed. The service download planner mirrors the same logic.

Tests cover lock-only and venv lanes (CLI), plus core guard/refusal cases. Unrelated: JVM/Gradle checksum code routes SHA-1/SHA-256 through shared utils::digest helpers.

Reviewed by Cursor Bugbot for commit ff5fb6c. Configure here.


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
A Pipenv project vendored at one patch never moved to a newer patch
for the same package: the re-vendor refused with
pypi_pipenv_source_already_exists and the run exited 1, although the
dry run previewed would_revendor.

When the vendor ledger records the Pipfile.lock entry the older patch
wrote, and that entry is unchanged, it is now rewired in place to the
new wheel. The record carries the older entry's pre-vendor registry
original forward, so vendor --revert still restores the user's pin.
Without that record, or after an edit, it still refuses as before.

Refs #769

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) force-pushed the agent/fix-pipenv-vendored-revendor branch from 6483c64 to 4fc3896 Compare October 5, 2026 04:45
When a venv was installed from the vendored wheel of an older patch
(pipenv sync after vendoring), re-vendoring to a newer patch skipped
the package as package_not_installed and exited 1: the installed
files are the old patch's bytes, so they failed the new patch's
installed-variant check.

When the vendor ledger holds exactly this package at an older patch
uuid, such an install is now treated like a lock-only checkout: the
pristine wheel comes from the lock, registry or patch service, and the
package is re-vendored. The service download plan makes the same call.

Fixes #769

Assisted-by: Claude Code:claude-opus-5-5
check_target_guards and wire_pipenv now have no production caller
(the vendor flow passes the ledger through the _superseding
variants), so clippy flagged them as dead code. Compile them for
tests only and point the docs at the variants production uses.

Refs #769

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 5, 2026 05:02
@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.

Stale Bugbot comment from a previous run.

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

Copy link
Copy Markdown
Collaborator Author

Burn-down agent: labeled Ready for review.

  • Head: 41dcd4258284c3e0c59e67e9223236bd4a633caa
  • CI: 485/485 green (6 skipped) on this head; branch not behind its base, no conflicts
  • Bugbot: reviewed 41dcd42, no new issues; all review threads resolved
  • Reviewer note: Nothing special; branch is current with main.

Generated by Claude Code

@mikolalysenko Mikola Lysenko (mikolalysenko) removed the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 5, 2026
Resolve the stage_manifest_with doc comment conflict in
mode_migration_pypi.rs: #766 added the same helper on main, so keep
main's wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VSXCFoPbraq7rNKJpXEP2n
Main has been red since 4646693 (#605): two
commands::vex_consumed tests built for #738 assume the name-keyed
resolver never returns npm-aliased copies, which #605 changed. This is
the same test-only change as #851 and becomes a no-op once that lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VSXCFoPbraq7rNKJpXEP2n
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

coverage was red on b72b4a6. The failure is in socket-patch-cli --lib: commands::vex_consumed::tests::hosted_expands_alias_only_copies and hosted_reuses_expanded_npm_copies_and_merges_alias_variants. These tests are not touched by this PR, and they fail the same way on main (coverage is red on 4646693). Main broke when #605 and #738 were combined; #851 fixes it.

I ported #851's test-only change into this PR as 3fade63. It becomes a no-op once #851 merges. Locally, cargo test -p socket-patch-cli --lib now passes (840 tests), with and without --all-features.

The earlier install-proof (macos-latest, 0.0.0-16) failure on cbcd6aa happened before any test ran: an artifact download failed after 5 retries. That commit has been replaced and the check re-runs on the new head.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


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.

Stale Bugbot comment from a previous run.

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

Copy link
Copy Markdown
Collaborator Author

Burn-down agent: labeled Ready for review.


Generated by Claude Code

@mikolalysenko Mikola Lysenko (mikolalysenko) removed the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 5, 2026
Resolved conflict in crates/socket-patch-cli/tests/mode_migration_pypi.rs:
main (#725) renamed the Pipenv fixture helper to stage_pipenv (returning
its wiring files); this branch had added write_pipenv_project for the
new #769 re-vendor test. Kept main's stage_pipenv and pointed the
branch's pipenv_revendors_to_a_superseding_patch test at it.

Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


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.

Stale Bugbot comment from a previous run.

Main is red since 1714299 (#865): its
production_digests_go_through_the_helpers guard flags the inline
digests that #646 added in gradle_cache.rs, jvm_jar.rs and
sidecars/maven.rs. This is the same change as #878 and becomes a
no-op once that lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VSXCFoPbraq7rNKJpXEP2n
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

test (windows-latest) was red on c079379. One test failed: socket-patch-core --lib → utils::digest::tests::production_digests_go_through_the_helpers. It flags inline digests in crawlers/gradle_cache.rs, patch/jvm_jar.rs and patch/sidecars/maven.rs. This PR doesn't touch any of those files, and the test fails the same way on Linux and on main. Main broke when the Gradle support from #646 was combined with the digest-helper check from #865. #878 fixes it.

I ported #878's change into this PR as ff5fb6c. It becomes a no-op once #878 merges. Locally, the digest test now passes and clippy is clean.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Several workflows show red on ff5fb6c, but no test failed. Every red job was cancelled between about 20:31 and 20:34 UTC, before finishing and with no failed step: CI (clippy, coverage, test-release, dispatch-tests, lint-ecosystems, e2e-build (ubuntu-latest), coverage-docker (deno)), the Gradle, PDM and vlt build jobs, and CodeQL Analyze. vlt's lock-diff then failed only because its upstream builds produced no locks ("locks from no OS"). All of these hit several workflows at the same moment, which points to a runner outage, not this PR.

I re-ran the failed jobs once for the CI, Gradle, PDM and vlt runs. The CodeQL run on this PR can't be retried through the API ("cannot be retried"); it will run again on the next push.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


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 ff5fb6c. Configure here.

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

Copy link
Copy Markdown
Collaborator Author

Burn-down agent: labeled Ready for review at ff5fb6c (ff5fb6c5cbb73063737edc241e39040f4e38ef2b).

  • CI: 536/536 workflow checks green on the head commit (6 skipped by matrix rule), after one re-run of jobs the GitHub Actions runner outage cancelled. No test failed. The only non-green entries are 4 CodeQL default-setup Analyze jobs that GitHub cancelled during the outage, and GitHub doesn't allow re-running them ("This workflow run cannot be retried").
  • Bugbot: reviewed ff5fb6c (re-requested this run) with no new issues, and no review threads are open.
  • Mergeable against main, with no conflicts.

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

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

3 participants