Repository navigation
Span widened decisions across same-deps runs - #592
Merged
Merged
Conversation
notatallshaw
force-pushed
the
perf/span-decided-runs
branch
from
July 28, 2026 08:57
b8202be to
0cfa638
Compare
This was referenced Jul 29, 2026
Documentation build overview
4 files changed± how-to/workspaces.html± reference/build-policy.html± reference/cli.html± reference/configuration.html |
notatallshaw
marked this pull request as ready for review
July 29, 2026 23:48
charliermarsh
pushed a commit
to astral-sh/uv
that referenced
this pull request
Aug 8, 2026
This is a partial port of a technique I am adopting in nab, I have been following @konstin's lead in astral-sh/pubgrub#75 and extending the approach into more places (notatallshaw/nab#357, notatallshaw/nab#590, notatallshaw/nab#592, notatallshaw/nab#604). This speeds up `uv lock` with `requires-python >= 3.8` over boto3 + awscli by ~20% wall time, and the largest accumulated range in the run drops from 287 segments to 2. `add_unavailable_version` records one singleton incompatibility per rejected version, so consecutive rejections never coalesce and the accumulated range grows a hole per version. This widens each singleton to the gap between its neighbors in the known versions, the same interval decided-version dependencies use. The win needs long runs of rejected versions. The main source is a Python floor below the ecosystem's support boundary: boto3 and awscli dropped 3.8 in April 2025 and now require >= 3.10, so a 3.8 floor rejects hundreds of releases in one run, while a 3.10 floor rejects almost nothing (14 rounds, 2 segments either way) and the change is a no-op. The first commit keys the pre-release hint on the requesting requirement instead of the derived set's bounds: widened bounds land on whatever the registry lists next, and a pre-release neighbor used to read as a pre-release marker nobody wrote. Rejection widening makes that routine, so the fix leads the series. The second commit merges unavailable versions that are causes of the same derivation, and the third is the widening itself. The fourth keeps the subsequent-index hint, which was suppressed whenever the set covered all versions; after widening that also covers "the index listed versions and none of them worked", which is the case the hint is for. The last two commits are #20809, merged in here so the error messages land as one change. With the widening, uv no longer asks for a version in a gap it created, so the `no_versions` incompatibility behind "only the following versions of X are available" is no longer created there, and steps that cross a gap stop following from the premises next to them. The fifth commit adds that clause back while the tree is reduced, on whichever cause rules the package out, or on the step itself when neither does. The sixth reports the one version a package has as that version rather than as a range over it, so a rejected `sphinx 7.2.6` reads `sphinx==7.2.6` and not `sphinx>=7.2.6`. Neither touches the solver. <details> <summary>MRE</summary> ```toml [project] name = "mre" version = "0.1.0" requires-python = ">=3.8" dependencies = ["boto3", "awscli"] ``` Max accumulated segments (287 on main, 2 with this PR; `uv.lock` identical): ```console $ uv lock --exclude-newer 2026-07-01 -v 2>&1 | grep 'Searching for a compatible version' | awk -F'|' '{print NF}' | sort -n | tail -1 ``` Wall (run without `-v`, which prints the accumulated ranges and dominates the time): ```console $ hyperfine --warmup 3 --min-runs 20 --prepare 'rm -f uv.lock' 'uv lock --exclude-newer 2026-07-01' ``` </details>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A decided version's widened parent term now extends across adjacent listed versions whose cached dependencies are identical, so a single dependency clause rejects a whole run instead of one version per backjump. That is the contract Dart's pub already ships and astral's pubgrub documents: every selectable version inside the range has exactly the dependencies being recorded. The span reads cached metadata only and fences at the first neighbor that is unfetched or differs, while extras proxies and look-ahead terms keep pure neighbor-gap widening, which the tests pin.
On the conflict-heavy uv-issue-10344 scenario this drops about a quarter of the decisions and a third of the conflicts with identical pins, and one scenario that ran out its wall-clock budget on main now resolves deterministically. Under a lowest preference the span is capped to the preference direction, since the solution sits near the floor and an upward span only carries the search away from it, so those scenarios keep their baseline trajectories.
Stacked on #590, so the diff here is only this delta.