Skip to content

Fix vendored Pipenv sibling requirements.txt (#612) - #1309

Merged
Mikola Lysenko (mikolalysenko) merged 10 commits into
mainfrom
agent/v5-pipenv-vendor-sibling-reqs
Oct 10, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 10 commits into
mainfrom
agent/v5-pipenv-vendor-sibling-reqs

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #612 (the requirements.txt lanes). The Pipenv pylock.toml and uv-export lanes from the issue comments are split out to #1368.

Summary

A Pipenv project often installs through a pipenv requirements > requirements.txt export, for Docker or plain pip. Before this PR:

  • Vendored mode wired only Pipfile.lock, so that path kept installing the unpatched release. Decide which lockfile governs installs in one table #1044 made this loud, but it was still unpatched.
  • The hosted → vendored takeover turned the export's hosted pin back into a plain PyPI pin.
  • Re-running vendor answered already_vendored, so vendor --check and vex (whose remedy says "re-run vendor") stayed red.

Root cause

The vendored flavor router picks one flavor (pipenv), and only that flavor's file is wired. The exported requirements pin was only ever named as a pypi_multiple_lockfiles loser.

Fix (core vendor/pypi.rs, vendor/pypi_requirements.rs)

  • sibling_pin_wirable checks whether the requirements set (root requirements.txt and in-root -r includes) pins the package exactly from the registry, in a shape the requirements wiring rewrites in place. It never appends a line. When it does, the Pipenv plan also rewrites that pin to the same committed wheel (hashed or not, following the file), and the records go into the same ledger entry. If the requirements write fails after the lock was written, Pipfile.lock is put back.
  • Routing no longer names such a pin a loser beside Pipfile.lock. A pin the wiring can't rewrite (a range, extras, an include outside the root) stays loud.
  • Revert (vendor --revert, remove, rollback, the takeover): records are split by kind. Pipfile.lock records go through revert_pipenv and requirements_line records through revert_requirements, so both files come back.
  • Superseding re-vendor: a superseded entry's recorded requirements lines are re-wired in place to the new uuid.
  • In-sync re-run (a project vendored before this change, or an export made since): the export is wired to the committed wheel and the ledger entry is extended (pypi_requirements_sibling_wired). Without a ledger entry it stays a named loser.
  • CLI_CONTRACT.md (pypi_multiple_lockfiles row) and docs/testing/pipenv-compatibility.md are updated.

Coordination: another session pushed a parallel attempt to this branch (872c692, c17e5d8) while this one was finishing. d3f6c30 merges it: it keeps this branch's implementation, which also covers the CLI e2e, the in-sync re-run, supersede and docs items that attempt listed as remaining, and carries over its core test. Pipfile.lock writing is untouched apart from making LOCK_FILE pub(super), so this shouldn't conflict with #1188.

Tests (per issue)

Red→green: before the fix the CLI test failed on the vendor envelope's "requirements.txt will still install the UNPATCHED" warning.

Commands run

  • cargo test -p socket-patch-core --lib: all pass. vendor::pypi is 415 tests.
  • cargo test -p socket-patch-cli --all-features --no-fail-fast: all pass except two e2e_vendor_cargo_build old-toolchain cells. Those fail locally with Bad CPU type in executable (an x86 rustup toolchain on arm64), a host issue.
  • cargo clippy --workspace --all-features -- -D warnings and cargo fmt --check: clean for the changed files.

🤖 Generated with Claude Code


Note

Medium Risk
Touches PyPI vendored wiring, revert, and ledger semantics for Pipenv; mistakes could leave mixed patched/unpatched install paths or partial reverts.

Overview
Vendored Pipenv now patches the common pipenv requirements > requirements.txt install path alongside Pipfile.lock, matching hosted mode. Exact registry pins in the root file or in-root -r includes are rewritten to the same .socket/vendor/pypi/<uuid>/ wheel, recorded on one ledger entry, and restored together on vendor --revert. Pins that cannot be rewritten (ranges, etc.) still trigger pypi_multiple_lockfiles.

Behavior changes: hosted→vendored takeover no longer leaves the export on plain PyPI; in-sync re-runs extend the ledger and wire a late-added export (pypi_requirements_sibling_wired); supersede re-vendors re-wire prior requirements lines; failed sibling wiring rolls back Pipfile.lock.

Collateral: production e2e/backtest harnesses pin a new free minimist@1.2.2 patch UUID and updated patched hash; vlt backtest holds() resolves patch file paths with or without a package/ prefix. Docs (CLI_CONTRACT.md, pipenv-compatibility.md) and tests cover the new contract.

Reviewed by Cursor Bugbot for commit d3f6c30. Configure here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A Pipenv project often installs through a `pipenv requirements >
requirements.txt` export (Docker, plain pip). Vendored mode wired only
Pipfile.lock, so that path kept installing the unpatched release, and
the hosted -> vendored takeover turned the export's hosted pin back
into a plain PyPI pin. Re-running vendor answered `already_vendored`,
so `vendor --check` and `vex` stayed red.

Vendoring a Pipenv entry now also rewrites an exact registry pin of
the package in requirements.txt (or an in-root `-r` include) to the
same committed wheel, the way hosted mode rewrites both files. The
ledger entry records both, every revert restores both, a superseding
patch re-wires both, and a re-run over an already wired Pipfile.lock
wires a newly made export. Pins the requirements wiring cannot
rewrite stay named by `pypi_multiple_lockfiles`.

Fixes #612

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A Pipenv project often keeps a requirements.txt exported by `pipenv
requirements` for Docker or plain pip installs. Vendored mode wired
only Pipfile.lock, so `pip install -r requirements.txt` kept
installing the unpatched release, and a hosted to vendored switch
turned that file's patched pin back into a registry pin.

A fresh Pipenv vendor now wires the root requirements.txt (and its -r
includes) along with Pipfile.lock when it pins the package, and
revert restores both. If the lock is wired but the requirements file
can't be, the vendor fails as a whole and the lock is put back. A
requirements file that can't be co-wired, or a project vendored
before this change, is still named in the loud
pypi_multiple_lockfiles warning.

Refs #612

Assisted-by: Claude Code:claude-opus-5-5
`vendor --check` and `vex` read lockfile discovery. With Pipfile.lock
and requirements.txt both pointing at the same vendored wheel, the
regression test now checks that discovery finds the patch in both
files and reports no contest between them.

Refs #612

Assisted-by: Claude Code:claude-opus-5-5
The hosted -> vendored takeover test asserted the old warning that
requirements.txt stays UNPATCHED; it now asserts that the export's
pin is wired to the vendored wheel too.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Another session pushed a co-wiring implementation to this branch while
this one was finishing its own. Keep this branch's implementation
(which also covers the CLI e2e, the in-sync re-run, the superseding
re-vendor and the docs) and carry over that attempt's core test, which
also checks that discovery finds both files with nothing contested.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] Merged the parallel attempt (872c692, c17e5d8) instead of force-pushing. This branch's implementation covers the items that attempt listed as remaining, and its core test is kept. The pylock and uv lanes moved to #1368.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review

@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.

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issues.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit d3f6c30. Configure here.

Comment thread crates/socket-patch-core/src/vendor/pypi.rs
Comment thread crates/socket-patch-core/src/vendor/pypi.rs Outdated
Comment thread crates/socket-patch-core/src/vendor/pypi.rs
Comment thread crates/socket-patch-core/src/vendor/pypi.rs
Resolve mode_migration_pypi.rs by keeping both sides: the #612
pipenv_vendor_wires_the_exported_requirements_too test and main's
#604 PEP 440 lock-only pin and #1138 uv workspace member tests.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Pick up #1336 (Hatch-derived pylock.toml lock-only rewrite); merges cleanly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- An in-sync re-run whose committed wheel is missing now rebuilds it and
  then wires the pending exported requirements pin, instead of returning
  after the rebuild with the export still on the registry.
- The in-sync sibling wiring pins only a committed wheel that
  verify_committed_artifact accepts (canonical path for this uuid, ledger
  sha256, afterHashes), and wire/rewire_requirements refuse a wheel path
  or digest that is not a single plain token (no CR/LF, whitespace or #).
- Re-wiring after a re-export replaces the entry's requirements_line
  records for that file instead of appending duplicates, so a later
  superseding patch can still re-wire the export.
- revert_pipenv_with_sibling reverts the export first and restores it if
  the Pipfile.lock revert then fails, so neither failure leaves the two
  files half reverted.
- Moves wire_requirements' doc comment back onto it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 10, 2026
Merged via the queue into main with commit 03d9237 Oct 10, 2026
53 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/v5-pipenv-vendor-sibling-reqs branch October 10, 2026 17:41
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