Skip to content

Support hosted and legacy Poetry patches - #241

Merged
Mikola Lysenko (mikolalysenko) merged 19 commits into
mainfrom
codex/poetry-patch-compat
Sep 17, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 19 commits into
mainfrom
codex/poetry-patch-compat

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

LLM Description written by Codex:gpt-6-astra

Poetry projects can now install hosted patches on Poetry 1.x/2.x and vendored patches across Poetry 0.12/1.x/2.x. Hosted scans previously missed poetry.lock, and vendoring refused legacy lock formats and CRLF files.

The shared rewriter preserves dependency metadata and the pyproject content hash, supports legacy hashes/files and modern package files, and records independent rollback fragments. Either of two patches can be removed first while unrelated edits survive. Source and integrity edits stay together when rollback encounters drift; re-scanning after Poetry relocks rebases the rollback fragments.

The Python crawler also discovers Poetry's out-of-tree virtualenvs. Lock-only vendoring uses the recorded pure-Python wheel digest to find and verify the upstream artifact. Unsupported formats, ambiguous package forks, foreign sources, and mismatched wheels are refused.

Hosted redirects now probe installed Python file hashes. Readable upstream or modified bytes produce redirect_pypi_stale_install and are excluded from same-run VEX, including with --vex-no-verify or a healthy copy in another interpreter. The check is read-only, repeats on re-scans, and falls back to persisted records if fetching fresh records fails. Lock-only checkouts retain their lock-based redirect attestations.

Compatibility boundaries

  • Poetry 0.12 ignores URL sources and installs the upstream registry artifact. Hosted mode refuses this case; vendored mode installs the patched wheel.
  • Poetry before 1.4 may keep same-version upstream packages in a warm virtualenv and does not enforce local wheel hashes. The CLI warns about these installer limitations. Recreate the virtualenv or uninstall the affected package before installing, then verify with socket-patch vex.
  • Poetry 1.0 needs a source reference and a SHA-256 URL fragment compatible with its pip invocation. Pip 22.3 and 23.0 refuse that spelling; the compatibility documentation records the supported pip versions.

Validation

  • 6 CLI Poetry tests passed, including stale/healthy installs, re-scans, record-fetch fallback, multiple interpreters, VEX exclusion, dry runs, and explicit LF/CRLF relock/rollback cases. Preserving the simulator's line endings fixes the Windows CI failure.
  • 28 hosted-flow unit tests passed, including existing gem probes and Python artifact-variant/custom-prefix coverage.
  • 11 core Poetry hosted tests passed.
  • cargo clippy --workspace --all-features -- -D warnings passed.
  • The committed live Poetry matrix contains 108 successful cases across Poetry 0.12.17 through 2.4.3. Those installer captures predate the final stale-install guard; the new guard is covered by the CLI regressions above.
  • The Windows apply-lock regression now retries the documented delete-pending OS error within its existing bound and still requires a clean mutual-exclusion result. All 14 local apply-lock tests passed; production locking is unchanged.
  • All 94 GitHub checks passed on 106645c41c687823719a40c9eaba90a8f2dd156b, including Linux/macOS/Windows, release tests, coverage, and the dependent installer suites (CI run).

Native lock fixtures, the live backtest harness, captured results, and compatibility documentation are included. The depscan stack is SocketDev/depscan#26287 → core Poetry support #26348tests and fixtures #26358.


Note

Medium Risk
Changes how poetry.lock is rewritten for installs (URLs, hashes, integrity tables); mistakes could break Poetry installs, though inputs are validated and rollback is fragment-based with drift guards.

Overview
Hosted PyPI patches now rewrite poetry.lock (included in hosted scans) to point patched wheels at Socket patch URLs, with recorded redirect_poetry_lock_package fragments that roll back with other PyPI redirect edits. Poetry 0.12 URL redirects are refused because that installer ignores URL sources.

A shared poetry_lock rewriter drives both hosted URL wiring and vendored local file sources across legacy (metadata.hashes / metadata.files) and modern lock formats, preserves pyproject content-hash, handles CRLF locks, and refuses ambiguous forks, foreign sources, and bad wheels/SHA-256.

Vendored Poetry expands beyond 2.x-only to 0.x/1.x/2.x (with integrity warnings before Poetry 1.4). Legacy and CRLF paths use the shared rewriter; atomic revert skips partial writes when lock fragments have drifted so source and hash splices stay consistent.

Fixtures and tests cover many Poetry versions, idempotent redirect, independent multi-patch rollback, and updated docs.

Reviewed by Cursor Bugbot for commit 2ac2436. Configure here.

Wire hosted and vendored wheels across native Poetry lock formats.
Preserve independent rollback and verify installer compatibility.

Assisted-by: Codex:gpt-6-astra
Preserve the lock when a legacy patch fragment has drifted, so rollback
does not restore upstream hashes while retaining a patched source.

Assisted-by: Codex:gpt-6-astra

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

Comment thread crates/socket-patch-core/src/patch/redirect/poetry.rs
Comment thread crates/socket-patch-core/src/utils/poetry_lock.rs
Normalize checked-out fixtures before explicitly exercising LF and
CRLF, so Windows auto-conversion cannot double carriage returns.

Assisted-by: Codex:gpt-6-astra
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Claude (@claude) review

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

✅ Bugbot reviewed your changes and found no new issues!

1 issue from previous review remains unresolved.

Fix All in Cursor

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

Reviewed by Cursor Bugbot for commit 2ac2436. Configure here.

…s with uv

- Never panic on a user-editable lock: a `[metadata.files]` / `[metadata.hashes]`
  value that is not a table (array of tables, scalar, `[[metadata]]`) used to hit
  toml_edit's IndexMut and abort `scan --mode hosted|vendored` with exit 101 and
  no JSON; every table access is now guarded and refuses with a warning.
- Accept any `lock-version = "2.<n>"` in the shared rewriter (the vendored loader
  already accepted newer minors with an advisory), so the same lock no longer
  succeeds LF-vendored, hard-fails CRLF-vendored and silently no-ops hosted.
- Supersede an earlier Socket hosted URL for the same wheel in place (same origin
  + filename, fragment ignored) instead of refusing it as a foreign source, so a
  grant-token rotation or republished patch does not strand the pin — the bun /
  requirements / cargo rewriters make the same call. Foreign sources and vendored
  file sources are still refused.
- Hosted rewriter: gate the missing-SHA-256 warning once per dep (not per lock),
  warn `redirect_poetry_entry_not_found` when a lock has no entry at the granted
  version (uv parity), and emit `redirect_poetry_stale_install_risk` when the
  lock was written by Poetry < 1.4 — measured on real 0.12.17–2.4.3: those
  releases never replace an already-installed same-version package after the
  redirect, 1.4+ do.
- Write the SHA-256 lowercase (Poetry compares hexdigest strings) and anchor the
  legacy integrity fragment at its line break so a suffix-named sibling entry
  with the same value cannot make the splice ambiguous.
- Unit tests for the shared rewriter (it had none) and hosted integration tests
  for the new warnings, the 2.x minor, and token rotation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`pypi_poetry_integrity_unverified` fired for every lock-version 2.0 project,
telling Poetry 1.4–1.8 users their installer verifies nothing. Lock 2.0 is
written by 1.3 through 1.8; releases from 1.4 stamp `@generated by Poetry
X.Y.Z`, so a stamped 2.0 lock is no longer flagged. The advisory now also names
the second pre-1.4 behaviour measured on real releases: an already-installed
same-version package is not replaced after the lock is rewired.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
scripts/backtest-poetry.py mirrors backtest-uv.py: it bootstraps every Poetry
release (0.12.17 … 2.4.3) with uv, generates a native lock for a one-dependency
project with a public free-tier patch, and drives the real CLI through hosted,
vendored, agent and out-of-tree-venv agent mode plus `setup`, checking applied
counts, idempotent re-scans, lock-driven installs into an emptied virtualenv,
fresh-clone installs, `poetry check --lock`, `vex`, tampered-hash rejection,
warm-virtualenv reinstall, Poetry's own relock, and `rollback` restoring every
byte. 108 cases pass on the PR head; the results file feeds the docs table.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd the matrix

- CHANGELOG [Unreleased] entry for hosted + legacy Poetry support (the uv
  precedent had one; this PR did not).
- poetry-compatibility.md rewritten around the measured matrix: per-generation
  rewrite shapes, the Poetry < 1.4 warm-virtualenv and hash-verification
  boundaries, which Poetry commands drop the patch source (with content-hash
  unchanged, so `poetry check --lock` cannot tell), the 0.12/1.0 cwd-relative
  file-source caveat, agent-mode discovery of Poetry's out-of-tree virtualenv,
  the lock-only vendored limitation, the harness recipe and the generated
  results table.
- CLI_CONTRACT: poetry.lock joins the hosted candidate files; the vendored rows
  cover every lock generation; the new `redirect_poetry_*` and
  `pypi_poetry_integrity_unverified` codes are listed.
- hosted-production-e2e.md no longer says Poetry locks are not rewritten by
  hosted mode; README no longer says hosted mode has no CLI revert (`rollback`
  unwinds it since the scan↔rollback duality change).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Poetry keeps a project's virtualenv OUTSIDE the project by default
(`{cache-dir}/virtualenvs/<name>-<hash>-py<X.Y>`), so after a plain `poetry
install` the crawler found no VIRTUAL_ENV / .venv / venv and fell through to
the global interpreter's site-packages: `scan --mode agent` patched nothing
for the project's dependencies (or the wrong interpreter) and reported
success, and a bare `rollback` pruned the manifest while the venv stayed
patched — measured on real Poetry 1.1.15, 1.8.5 and 2.4.3.

The crawler now reproduces Poetry's own placement without running Poetry:
`virtualenvs.create` / `in-project` / `path` and `cache-dir` from the
`POETRY_*` environment, the project's `poetry.toml` and the user
`config.toml` (Poetry's precedence), the platform default cache dir, the
`{cache-dir}` / `{project-dir}` / `~` placeholders, and
`EnvManager.generate_env_name` (lowercased sanitized name, 42-char cap,
first 8 chars of url-safe base64 sha256 of normcase(realpath(cwd))) —
unchanged from Poetry 1.0 through 2.x and pinned by known-answer vectors.
Every `-py<X.Y>` sibling is scanned. A project-local venv still wins; a
project that opted into in-project venvs or disabled creation is left to the
existing paths.

The matrix harness's out-of-tree leg now applies and rolls back BARE when the
crawler sees the venv (falling back to `poetry run` otherwise) and records
which path it took.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`scan --mode vendored` on a fresh clone (pyproject + poetry.lock, nothing
installed) was skipped with `vendor_fetch_unverifiable` + `package_not_installed`
although the lock records the wheel's sha256 — the poetry.lock inventory was
discovery-only (`LockIntegrity::None`), so the fetch gate refused before the
vendor engine ever ran, while the identical uv.lock scenario vendored fine.
That broke the CI story for Poetry: the machine that vendors had to have the
package installed.

The inventory now carries the pure-Python (`-none-any.whl`) wheel's sha256 from
`files` (lock 2.x) or `[metadata.files]` (lock 1.0/1.1), lowercased, and the
pypi fetcher resolves a hash-only entry through PyPI's JSON API
(`urls[].digests.sha256`, `SOCKET_PYPI_JSON_API` overrides the endpoint) and
verifies the download against the same digest, exactly like uv's lock-only
path. Poetry 0.12's bare `[metadata.hashes]` names no wheel, and platform-only
wheels offer no platform-independent choice, so those stay discovery-only.

Measured on the fixed CLI: lock-only vendoring now applies on Poetry 1.0
(populated lock), 1.2, 1.8 and 2.4 fixtures (`vendor_fetched_missing` +
`vendor_prebuilt_downloaded`), and the resulting checkout installs the patched
wheel with every release.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…endoring

CHANGELOG Fixed bullets for the two pre-existing gaps the Poetry matrix
surfaced (out-of-tree venv discovery, lock-only vendoring), the contract's
pypi discovery-root sentence and `vendor_fetched_missing` row, and the
compatibility doc's mode notes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the pip window

- A lock-version 1.0 hosted rewrite only carried the patched hash in
  `[metadata.files]` and the URL fragment. Poetry >= 1.2 (which still reads
  1.0 locks) verifies url sources against the package's own `files` and
  ignores `metadata.files` hashes, so it installed the hosted wheel with no
  hash check at all (measured on 1.2.2: every hash tampered, install exit 0).
  Write the package `files` entry for 1.0 too — Poetry 1.0.10 ignores the
  extra key (measured), 1.2.2 then rejects a tampered hash.
- Poetry 1.0 installs url sources through pip, reading the hash from the URL
  fragment that Poetry suffixes with `#egg=<name>`. Sweeping pip 20.3–25.0
  with real Poetry 1.0.10: the `#sha256=<hex>&` spelling installs and
  verifies on pip <= 22.2 and >= 23.1; pip 22.3 and 23.0 (what Python 3.8's
  ensurepip seeds) take the rest of the fragment as part of the digest and
  refuse (fail-closed); without the `&` every pip >= 22.3 refuses. The
  spelling stays; the lock-1.0 hosted advisory now names the pip window and
  the compatibility doc records the sweep.
- Pin each generation's hosted shape in `poetry_hosted` (1.0 fragment +
  reference + dual files, 1.1 dual files, 2.x metadata untouched) and drop
  duplicated lines from a vendored test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…a qualifier

`scan --mode hosted --vex` exempts the purls the run just confirmed from
installed-tree verification and attests them from the redirect ledger
(`assume_applied`). The confirmed purls come from the grant reference
unqualified (`pkg:pypi/urllib3@1.26.18`) while the ledger records the API's
artifact-qualified purl (`…?artifact_id=py2-py3-none-any-whl`), so for pypi
redirects nothing matched: a lock-only Poetry (or uv) checkout redirected the
lock and then exited 1 with `no_applicable_patches`. Match on the
qualifier-stripped purl on both sides.

Adds the first CLI-level Poetry hosted test: a lock-only project is
redirected, attested in the same run, re-scanned idempotently, and rolled
back byte for byte against a mocked API.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`revert_lock_fragment_splice_atomic` held the write whenever ANY warning was
raised, so a record this build cannot replay (a newer ledger's unknown kind,
or a foreign file skipped by the allowlist) blocked restoring the fragments it
does understand — the lock stayed fully wired while the revert reported
success. Track drift separately: a drifted fragment still holds the whole
write (a half-restored legacy lock is uninstallable), forward-compat skips
only warn. Also documents that `poetry lock --no-update` on Poetry 1.1/1.2
reshapes a hosted entry and drops the package-level files Poetry >= 1.2
verifies against.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
108/108 cases pass on the fix-branch head. The rerun records the fixes'
effects: lock-only vendoring applies wherever the lock names a pure-Python
wheel hash (1.0/1.1 populated, 1.2+), the out-of-tree agent leg applies and
rolls back BARE on every 1.x/2.x release (the crawler finds Poetry's venv), and
the pre-1.4 hosted advisory fires for 1.0–1.3 locks only. The table renderer
reports the lock-only column per shape.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Two defects with one root cause — the recorded `[[package]]` fragment ended at
the unit's last line while the rewrite APPENDS `[package.source]` after it,
so the pristine fragment was a prefix of every rewritten (or relocked) unit:

- Replay's "already converged" check (`content.contains(original) &&
  !new.contains(original)`) fired when a relock (Poetry 1.1/1.2 `poetry lock
  --no-update`) or a hand edit dropped the inserted `files` line but kept the
  Socket source block: rollback reported success, deleted the ledger and
  restored `[metadata.files]` to upstream hashes while the lock still
  redirected — an inconsistent lock with no record left (lock 1.1 and 2.x).
  For lock 1.0 the guard's other arm meant a hand-restored pristine lock could
  never converge and rollback refused with a spurious drift.
- A re-scan after such a relock appended edits recorded against the RELOCKED
  text; replay inverted the newer links back to the relocked state and then
  found neither `new` nor `original` of the older ones, so `rollback` and
  `remove` refused forever — and the refusal's remedy ("re-run scan") was
  what lengthened the chain (reproduced with real Poetry 1.1.15 and 1.2.2).

The fragment now extends through the next top-level header (`[[package]]`,
`[metadata]`, …), so a unit that grew a source block never contains the
pristine fragment: the drifted shape is refused, the hand-restored lock
converges. The hosted ledger merge REBASES `redirect_poetry_lock_package`
edits whose (path, kind, key) already exists when the pre-run file no longer
carried their `new` fragments — keeping the oldest `original`, adopting the
fresh `new` — instead of appending, so one invertible link survives any
number of relock/re-scan rounds. Idempotent re-scans and token-rotation
supersedes still append as before.

Tests: fragment boundary property per generation and for adjacent units;
dropped-files-line-with-source-kept is refused not converged (1.1, 2.x);
lock-1.0 hand-restored lock converges; CLI relock → re-scan → rollback chain
lands on the pristine lock with a two-edit ledger.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
When Poetry's own relock keeps the patch source but re-lays the unit
(1.1/1.2), the harness now re-scans instead of restoring the CLI's lock and
lets the final rollback prove the rebased ledger still lands on pristine
bytes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… setup's Poetry

108/108 cases on the fix-branch head (0.12.17 … 2.4.3 × hosted / vendored /
agent / out-of-tree agent / setup × direct / populated / crlf / pep621),
including the live relock → re-scan → rollback chain on Poetry 1.1 and 1.2.
The `setup` leg now hands the CLI-spawned `poetry lock` the case-isolated
HOME as well (Poetry <= 1.1's shared HTTP-cache lock wedged one parallel run).

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

Copy link
Copy Markdown
Collaborator Author

Review follow-ups (2026-09-17)

Verified end-to-end against real Poetry 0.12.17, 1.0.10, 1.1.15, 1.2.2, 1.3.2, 1.4.2, 1.5.1, 1.6.1, 1.7.1, 1.8.5, 2.0.1, 2.1.4, 2.2.1, 2.3.4 and 2.4.3 with scripts/backtest-poetry.py (108 cases: hosted, vendored, agent, out-of-tree-venv agent and setup; direct, CRLF, populated-legacy and PEP 621 shapes) — results and the measured installer boundaries are in docs/testing/poetry-compatibility.md.

Fixes on top of the original three commits:

  • Rewriter hardening — a malformed [metadata.files]/[metadata.hashes] no longer panics the scan (exit 101, no JSON); any lock-version = "2.<n>" is accepted on every path (Bugbot Add new commands for patch remove, list and GC #2); an earlier Socket hosted URL for the same wheel is superseded in place (token rotation / republish) instead of refused; missing-SHA-256 warns once per dep; redirect_poetry_entry_not_found on absent entries (uv parity); SHA-256 written lowercase; legacy integrity fragments anchored at line breaks.
  • Measured installer boundaries surfaced as advisories — Poetry < 1.4 neither verifies local wheel hashes nor replaces an already-installed same-version package: redirect_poetry_stale_install_risk (hosted, Bugbot Remove tsc from npm prepare script #1) and pypi_poetry_integrity_unverified (vendored) fire only for locks written by those releases (formats 0/1.0/1.1, or a 2.0 lock without a @generated by Poetry X.Y.Z header), so 1.4–1.8 users are no longer told their installer verifies nothing.
  • Lock-1.0 hosted rewrites also write the package files entry — Poetry ≥ 1.2 consuming a 1.0 lock verified nothing otherwise. Poetry 1.0's pip window is documented: pip ≤ 22.2 and ≥ 23.1 install and verify the #sha256=…& spelling; pip 22.3/23.0 refuse it (fail-closed), and no spelling satisfies them.
  • Agent mode finds Poetry's out-of-tree virtualenv (pre-existing gap): the crawler reproduces Poetry's virtualenvs.path + env-name hash from POETRY_*, poetry.toml, config.toml and the platform default, so a bare socket-patch scan --mode agent / rollback in a default-configured checkout targets the right interpreter instead of falling through to the global one.
  • Vendored mode works from a lock-only checkout (pre-existing gap): the poetry.lock inventory carries the pure-Python wheel's sha256 and the fetcher resolves it through PyPI's JSON API by digest, like uv.
  • Same-run --vex attests pypi redirects (pre-existing gap): the confirmed purl and the ledger's artifact-qualified purl are now matched qualifier-insensitively; a lock-only Poetry scan --mode hosted --vex used to exit 1 with no_applicable_patches.
  • Atomic legacy revert holds only on fragment drift, not on forward-compat skips; CHANGELOG entry; CLI_CONTRACT/README/hosted-e2e docs updated; first CLI-level Poetry hosted test (in_process_redirect_poetry.rs).

Known, not changed here: setup on a Poetry project resolves socket-patch down to 3.3.0 because 4.0.0's hook extra needs the unpublished socket-patch-hook wheel (publishing gap); hosted↔vendored takeover stays cargo/npm-only; a lock-only agent scan of a non-Poetry pypi project still falls back to the global interpreter by design.

🤖 Generated with Claude Code

Preserve LF/CRLF in the relock simulator and exercise both newline forms. Probe installed Python package hashes after hosted redirects, warn on stale bytes, and exclude them from same-run VEX even when another interpreter is patched. Cover re-scans, ledger fallback, missing files, dry runs, variants, and custom prefixes.

Assisted-by: Codex:gpt-6-astra
Treat ERROR_ACCESS_DENIED from an open racing the deliberate lock-file deletion as a benign test interleaving on Windows. Retry within the existing bound and still require a clean mutually exclusive acquisition. Production lock acquisition and error handling are unchanged.

Assisted-by: Codex:gpt-6-astra
@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit ff6aaae into main Sep 17, 2026
94 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the codex/poetry-patch-compat branch September 17, 2026 22:19
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Sep 18, 2026
…a qualifier

`scan --mode hosted --vex` exempts the purls the run just confirmed from
installed-tree verification and attests them from the redirect ledger
(`assume_applied`). The confirmed purls come from the grant reference
unqualified (`pkg:pypi/urllib3@1.26.18`) while the ledger records the API's
artifact-qualified purl (`…?artifact_id=py2-py3-none-any-whl`), so for pypi
redirects nothing matched: a lock-only Pipenv checkout redirected the lock
and then exited 1 with `no_applicable_patches`. Match on the
qualifier-stripped purl on both sides. Measured on a lock-only Pipenv
2026.8.0 checkout: exit 1 / 0 statements before, exit 0 / 1 `not_affected`
statement after.

Same change as b7a4254 on fix/poetry-compat-review (PR #241); identical so
the two merge cleanly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko) added a commit that referenced this pull request Sep 18, 2026
Conflicts resolved: the crawler runs Poetry's then Pipenv's out-of-tree
venv discovery (both gated on nothing found above); replay keeps the
PipenvEntry inverse next to main's HatchDocument; the hosted confirmed-uuid
filter confirms Pipfile.lock rewrites through `confirmed_pipenv_uuids`
alongside main's python-lock / hatch / requirements sets and still vetoes
`refused_pipenv_uuids`; main's generic Python stale-install guard
(`redirect_pypi_stale_install`, `known_stale`) replaces the Pipenv-specific
hosted probe — it now judges only the project's own venvs (no global
interpreter fallback) and names the Pipenv-specific remedy (`pipenv run pip
uninstall -y <pkg> && pipenv sync`, never `pipenv uninstall`) for
Pipfile.lock redirects; the pypi fetcher keeps the digest-set resolver
(superset of main's single-hash one); the candidate-file list, the
ecosystem matrix row, the hosted-e2e note, CHANGELOG and CLI_CONTRACT carry
both sides once.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants