Skip to content

Fix pylock projects dropping requirements.txt patch (#1758) - #1759

Merged
Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-pylock-requirements-sibling
Oct 28, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 4 commits into
mainfrom
agent/fix-pylock-requirements-sibling

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #1758

Summary

Take a pip project that installs from requirements.txt and from the pylock.toml that pip lock -r requirements.txt wrote. Vendored mode now wires both files to the vendored wheel. Before this change only the pylock was wired. After a hosted → vendored switch (plain vendor, the eject, or scan --mode vendored), requirements.txt had just been restored from its hosted pin to plain PyPI. So pip install -r requirements.txt went from patched to unpatched, the run exited 0, and its own vendor --check then failed with wiring contested.

Root cause

detect_pypi_flavor (crates/socket-patch-core/src/vendor/pypi.rs) sends a project whose pylock holds the target to the PythonLocks flavor. That flavor named requirements.txt as a loser that "retains its existing sources". The Pipfile.lock / uv.lock flavors already wire an exact registry pin in requirements.txt together with the lock (#612, #1368: sibling_pin_wirable, wire_sibling_requirements, wire_in_sync_sibling), but the PythonLocks flavor never got that co-wiring. A takeover's upstream restore covers every hosted file, so the restored requirements.txt was left unwired.

Change

  • WiringPlan::PythonLocks carries a sibling flag, set like the uv flavor's in the fresh plan, the supersede re-plan and the in-sync path (sibling_pending).
  • Routing: a wirable pin, or one already vendored, is no longer named in pypi_multiple_lockfiles. A pin the wiring can't rewrite (a range, extras, a package requirements.txt doesn't list) is still named as a loser.
  • sibling_lock gives the PythonLocks remedy as a re-lock, and the notes stop calling a pip-lock requirements.txt an "export".
  • CLI_CONTRACT.md: the pypi_multiple_lockfiles row names the pylock case.

Tests (red → green)

New tests in crates/socket-patch-cli/tests/mode_migration_pypi.rs use real pip lock output (pip 26.2.2):

Issue / case Test Without fix With fix
#1758 plain vendor wires both, dry run previews it, settled re-run is silent, revert restores both pip_lock_vendor_wires_requirements_with_the_pylock fails: requirements.txt not wired, retain their existing sources passes
#1758 hosted → vendored via plain vendor (eject) and scan --mode vendored, then vendor --check pip_lock_hosted_to_vendored_keeps_the_requirements_patched fails: requirements.txt back to six==1.16.0 from PyPI passes
#1758 in-sync re-run wires a pin added after the pylock was wired pip_lock_rerun_wires_a_requirements_pin_added_later n/a (path new) passes

The #1524 unit test requirements_then_pylock_entry_reverts_both_files now asserts that requirements.txt isn't named at all. Before, it expected the "keeps its vendored wiring" clause, which is dropped.

Local checks

  • cargo fmt --all -- --check: clean
  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo test --workspace --all-features --no-fail-fast: every pypi suite passes. 12 tests fail locally, and none touch this diff:
    • 9 rely on read-only directories or files, which root (uid 0) can still write in this sandbox: the repair lock/cleanup tests, in_process_redirect write-failure tests, copy_tree symlink-root perms, vlt_heal unremovable lock, and the pypi_poetry / pypi_requirements write-failure rollbacks, which never reach the changed code.
    • 3 e2e_bun_lockb tests reach patches-api.socket.dev, which this sandbox's proxy blocks.
    • CI on main is green for all of them.
  • /code-review high ran on the diff. Fixed: re-run warning noise, snapshot scope, remedy wording, stale docs, missing coverage. Not fixed:
    • Transitive packages that requirements.txt doesn't list stay named as losers. Hosted mode doesn't pin requirements.txt for those either, so a takeover never un-hosts them, and that warning is accurate.
    • sibling_pin_wirable runs again per stage, as in the uv and Pipenv lanes. It's a small read of requirements.txt and doesn't justify a new plumbing path.

https://claude.ai/code/session_011f9aeSBxGxNQ9baxh6k2cF


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
A pip project that installs from both requirements.txt and the
pylock.toml `pip lock` wrote from it had only the pylock wired to the
vendored wheel. requirements.txt was named as a file that "retains its
existing sources", but a hosted -> vendored switch (plain `vendor` or
`scan --mode vendored`) had just restored its hosted pin to plain PyPI,
so `pip install -r requirements.txt` silently went from patched to
unpatched while the run exited 0 and `vendor --check` then failed.

The Python-lock flavor now wires an exact registry pin in
requirements.txt (and in-root -r includes) to the same wheel, the way
the Pipenv and uv flavors already wire their exported requirements
(#612, #1368). The ledger entry records both files, so revert restores
both, and an already-wired lock re-run wires a pin added since.

Fixes #1758

Assisted-by: Claude Code:claude-opus-5-5
A settled re-run over a pip-lock project no longer names the wired
requirements.txt in a pypi_multiple_lockfiles note. The rollback
snapshot taken before wiring now skips symlinked files instead of
rewriting them, the notes no longer call requirements.txt an export
of the pylock, and the remedy shown when the ledger is missing names
a re-lock instead of a revert that cannot help. Adds coverage for the
dry run, the settled re-run, and a pin added after the pylock was
wired.

Refs #1758

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

If wiring requirements.txt fails after the pylock was wired, the
rollback put back every lock and script it had read, so a symlinked
uv script the run never rewrote was replaced by a regular copy. Now
only the files the pylock wiring actually rewrote are put back.

Refs #1758

Assisted-by: Claude Code:claude-opus-5-5
@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 09523b8. Configure here.

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

Copy link
Copy Markdown
Collaborator Author

Ready for review at 09523b8b833466a25c130e4f8a53e5d1bc421044 (burn-down agent label sweep).

  • CI: 50/50 check runs green or skipped on this head; mergeable, no conflicts.
  • Bugbot: reviewed 09523b8, no unresolved findings (the earlier pypi.rs thread is resolved).
  • Slack announcement not sent this run (Slack send unavailable); a later run will retry.

Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Final review brief

What it does — In a PEP 751 / script-lock project, a root requirements.txt whose exact pin can be rewritten is now wired to the same vendored wheel as the lock. Before, it was reported as an unpatched pypi_multiple_lockfiles loser. The new WiringPlan::PythonLocks(project, sibling) carries this through fresh vendor, in-sync re-runs, supersede/takeover and dry-run. If the requirements step refuses, only the lock and script files that were actually rewritten are restored.

Risk — low. It follows the existing Pipenv/uv sibling pattern (#612/#1368) and reuses sibling_pin_wirable, wire_sibling_requirements, restore_snapshot and the kind-based revert. Projects with only one of the two files, a range or extras pin, or an already-vendored requirements.txt behave as before.

Look here

  • pypi.rs:387-427: detection. A wirable requirements.txt is no longer counted as a loser.
  • pypi.rs:1145-1171: the prelude. It sets sibling_pending for an in-sync lock and builds the plan and dry-run notice for a fresh one.
  • pypi.rs:2282-2323: the apply step. It snapshots the files, wires the lock, uses retain to keep only the rewritten files, then wires the requirements pin with rollback.
  • pypi.rs:2893-2901: the supersede/takeover plan.
  • mode_migration_pypi.rs:3224: new end-to-end tests.

Verified

  • Read the full diff and traced rollback. The snapshot names match the WiringRecord.file values, so retain keeps exactly the files that were rewritten. If the lock wiring itself fails, it rolls back its own writes.
  • cargo test -p socket-patch-cli --test mode_migration_pypi: 74/74 pass. With pypi.rs/pypi_lock.rs reverted to main, all 3 new pip_lock_* tests fail, so they exercise the fix.
  • cargo test -p socket-patch-core --lib vendor::pypi: 506 pass. The 2 failures are untouched chmod-based tests that can't work when run as root locally; they pass in CI.
  • CI 31/31 green on head. Cursor Bugbot: no issues. CHANGELOG.md untouched.

Changes I made — none.

Open questions (non-blocking)

Auto-merge is armed: approving sends it straight to the merge queue.


Generated by Claude Code

Merged via the queue into main with commit 9a8baf7 Oct 28, 2026
50 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/fix-pylock-requirements-sibling branch October 28, 2026 14:02
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

4 participants