[agent] Found by the scheduled uv bug-hunt routine (ledger #310).
Summary
A standalone PEP 751 lock made by uv pip compile --format pylock.toml is a supported hosted lane (docs/testing/uv-compatibility.md, "standalone PEP 751 compilation"). scan --mode hosted wires it, and uv pip sync pylock.toml installs the patch. But on main the hosted pin can't be unwound by anything:
rollback → partial_failure: cannot restore pkg:pypi/six@1.16.0 to its upstream registry entry: pylock.toml: no sibling registry package shows the registry and artifact fields this uv release records; restore it from version control instead (git checkout -- pylock.toml)
remove pkg:pypi/six@1.16.0 → hosted_revert_failed (same message)
scan --mode vendored (hosted → vendored takeover) → failed redirect_revert_failed
The cause: uv pip compile never writes an index key on [[packages]] (only uv export --format pylock.toml does). The v5 upstream restore takes a pylock entry's registry only from a sibling's index (crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:314-321). With no sibling carrying one, registries is empty and the restore refuses, however many plain PyPI siblings the lock has. Every sibling here is a files.pythonhosted.org artifact with the full url / upload-time / size / hashes shape.
Impact
Any project that uses uv pip compile --format pylock.toml and adopts hosted mode can't roll back, remove or switch to vendored mode afterwards. The only remedy is the git checkout the error suggests, which also throws away any unrelated lock changes made since. A rollback meant to unpatch everything leaves the patch wired and installable.
Repro (Linux)
Mock patch API as in #379 / #381 (now also returning integrity.sha512), --patch-server-url for the mock origin, PyPI JSON API reachable.
SP="socket-patch --api-url http://127.0.0.1:18080 --api-token t --org test-org --patch-server-url http://127.0.0.1:18080"
mkdir p && cd p
printf 'six==1.16.0\nidna==3.7\ncertifi==2024.2.2\n' > req.in
uv pip compile --format pylock.toml req.in -o pylock.toml
grep -c '^index' pylock.toml # 0: uv pip compile records no index
$SP scan --mode hosted --json --yes # redirected 1, rewrittenFiles [pylock.toml]
uv venv v && VIRTUAL_ENV=v uv pip sync pylock.toml # installs the patched six.py
$SP rollback --json --yes # exit 1, partial_failure, hosted.failed[0] = "...no sibling registry package shows the registry..."
$SP remove pkg:pypi/six@1.16.0 --json --yes # exit 1, hosted_revert_failed
$SP scan --mode vendored --json --yes # exit 1, failed redirect_revert_failed
grep -c 127.0.0.1:18080 pylock.toml # 1: still wired
Control: the same packages exported with uv lock && uv export --format pylock.toml (which writes index = "https://pypi.org/simple") roll back successfully.
Expected vs actual
- Expected: CLI_CONTRACT.md, "Hosted unwind coverage", pypi:
rollback / remove restore PEP 751 pylock*.toml pins, with hashes re-derived from PyPI's JSON API. The listed refusals for pylock are only "a release with a wheel that is not pure Python 3". The "other registry packages name no registry" refusal is stated for uv locks, where every registry package records its source. For a uv pip compile pylock the missing index is normal, so the restore should follow the siblings' shape (no index key) when their artifacts are PyPI files. At minimum, the refusal should be documented, and hosted mode should warn before it wires a lock it can never unwind.
- Actual: rollback, remove and the vendored takeover all refuse on every
uv pip compile pylock, and the hosted pin stays.
OS × uv matrix (main 2463257)
| OS |
uv 0.8.17 |
uv 0.12.21 |
| Linux |
fail (rollback / remove / takeover) |
fail (rollback / remove / takeover; reproduced 2×) |
macOS and Windows weren't probed. The refusal is in platform-independent TOML inspection.
First bad
2463257 (#277, the v5 upstream restore; v4's ledger-based revert didn't depend on sibling entries).
Suspect code
crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:314-321: for pep751, the registry comes only from package.get("index"), and siblings without it are skipped.
crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:345-351: the "no sibling registry package" refusal.
Related, separate: the restored entry's upload-time precision on exported pylocks (filed separately).
[agent] Found by the scheduled uv bug-hunt routine (ledger #310).
Summary
A standalone PEP 751 lock made by
uv pip compile --format pylock.tomlis a supported hosted lane (docs/testing/uv-compatibility.md, "standalone PEP 751 compilation").scan --mode hostedwires it, anduv pip sync pylock.tomlinstalls the patch. But on main the hosted pin can't be unwound by anything:rollback→partial_failure:cannot restore pkg:pypi/six@1.16.0 to its upstream registry entry: pylock.toml: no sibling registry package shows the registry and artifact fields this uv release records; restore it from version control instead (git checkout -- pylock.toml)remove pkg:pypi/six@1.16.0→hosted_revert_failed(same message)scan --mode vendored(hosted → vendored takeover) →failed redirect_revert_failedThe cause:
uv pip compilenever writes anindexkey on[[packages]](onlyuv export --format pylock.tomldoes). The v5 upstream restore takes a pylock entry's registry only from a sibling'sindex(crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:314-321). With no sibling carrying one,registriesis empty and the restore refuses, however many plain PyPI siblings the lock has. Every sibling here is afiles.pythonhosted.orgartifact with the fullurl/upload-time/size/hashesshape.Impact
Any project that uses
uv pip compile --format pylock.tomland adopts hosted mode can't roll back, remove or switch to vendored mode afterwards. The only remedy is thegit checkoutthe error suggests, which also throws away any unrelated lock changes made since. Arollbackmeant to unpatch everything leaves the patch wired and installable.Repro (Linux)
Mock patch API as in #379 / #381 (now also returning
integrity.sha512),--patch-server-urlfor the mock origin, PyPI JSON API reachable.Control: the same packages exported with
uv lock && uv export --format pylock.toml(which writesindex = "https://pypi.org/simple") roll back successfully.Expected vs actual
rollback/removerestore PEP 751pylock*.tomlpins, with hashes re-derived from PyPI's JSON API. The listed refusals for pylock are only "a release with a wheel that is not pure Python 3". The "other registry packages name no registry" refusal is stated for uv locks, where every registry package records its source. For auv pip compilepylock the missingindexis normal, so the restore should follow the siblings' shape (noindexkey) when their artifacts are PyPI files. At minimum, the refusal should be documented, and hosted mode should warn before it wires a lock it can never unwind.uv pip compilepylock, and the hosted pin stays.OS × uv matrix (main
2463257)macOS and Windows weren't probed. The refusal is in platform-independent TOML inspection.
First bad
2463257(#277, the v5 upstream restore; v4's ledger-based revert didn't depend on sibling entries).Suspect code
crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:314-321: forpep751, the registry comes only frompackage.get("index"), and siblings without it are skipped.crates/socket-patch-core/src/patch/redirect/upstream/uv.rs:345-351: the "no sibling registry package" refusal.Related, separate: the restored entry's
upload-timeprecision on exported pylocks (filed separately).