chore(deps): go-python-packaging v0.6.0, for the packed comparison key - #41
Merged
Conversation
Bumps the dependency only; no code in this repository changes. v0.6.0 compares versions through a packed 4xuint64 order-preserving key rather than a field-by-field walk, for the 97.3% of real versions that fit one. Against the production snapshot (932,861 packages), medians of five interleaved rounds: cold resolution is 2.0x to 13.4x faster and warm 1.2x to 1.9x. The asymmetry is the point. Building a package's sorted version order is comparison-bound and happens once per package per index, so it lands in cold -- wide-versions (botocore, >10k releases) drops 167.35 ms to 12.46 ms. Warm reuses that order through 0.5.0's memo, so the packed key only reaches the residual comparisons inside pep440set containment and candidate filtering. 1.2-1.9x warm says those were still material after #39 and #40; that it is not larger says #40 had already removed most. This does not compose multiplicatively with #39 or #40 and was not assumed to: #40 removed most comparisons and the packed key makes the remainder cheap, so they contend for the same cost. Measured against 276fe91, which contains both. candvers, metadata and the pin set are identical on every corpus entry. Equivalence checked across builds: 4,007 resolutions against the production snapshot (7 corpus entries plus 4,000 sampled names, seed 1) produce byte-identical transcripts -- identical pins, decision order, activated extras, and failure report text on the 1,607 that fail -- with 36 wall-clock-deadline cases excluded (35 both sides, 1 baseline only). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The bump entry asserted the packed key and #40 do not compose multiplicatively. That was reasoning, not a measurement. This records the 2x2 that establishes it, in one interleaved session, warm, medians of 3. The packed key is worth 1.99-5.93x BEFORE #40 and 1.23-1.88x after; #40 is worth 1.43-12.34x at gpp v0.5.0 and 1.07-2.95x at v0.6.0. Both directions shrink, so the two are substitutes: on app-set, multiplying the isolated headlines predicts 65.8x against a measured 15.7x end to end. That is the opposite sign to the #39/#40 interaction, where Contains became MORE valuable after the rank memo, so the interaction cannot be guessed. It also resolves an apparent conflict with go-python-packaging's own release notes, which claim 2.1-5.2x warm on this benchmark: those were measured at 73d820a, before #40 landed 46 minutes later. The pre-#40 column reproduces them (1.99-5.93x). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Found by review, not by me: go-python-packaging v0.6.0 also lands, under its own Fixed heading, "a parsed Version is now safe to share across goroutines" -- Compare pads into a fresh slice instead of appending into spare capacity a by-value copy shares. That restriction was documented on an EXPORTED API. PackageMetadata. SupportsPython told callers "DO NOT SHARE ONE PARSED target BETWEEN GOROUTINES ... give each goroutine its own version.Parse", and closed with "a fix is being filed upstream; until it lands there is nothing this method can do about it". This bump IS that fix landing, so the guidance now asks callers to do unnecessary work. Corrects that doc and the canonical account in RSFIndex.Versions, which also carried the trigger "when it is fixed upstream, memoizing the parsed values becomes available". The historical explanation is kept in both: it is still why several types memoize version KEYS rather than parsed values, and those choices remain correct -- they are now a choice rather than a requirement. Re-verified against both pins with the exact eight-goroutine repro the doc specifies (target 3.11.0, constraint >3.9.1): v0.5.0 reports WARNING: DATA RACE, v0.6.0 is clean. No behaviour changes. Taking the now-unblocked parsed-version memo is a performance change owing its own measurement and is left to a follow-up, along with the remaining internal rationales in provider, index/mock.go and resolver/bench_test.go. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 14, 2026
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.
Bumps
github.com/posit-dev/go-python-packagingfromv0.5.0tov0.6.0. No code in this repository changes — the diff isgo.mod,go.sumand a CHANGELOG entry.v0.6.0compares versions through a packed 4×uint64 order-preserving key rather than a field-by-field walk, for the 97.3% of real versions that fit one.Measured
Medians of five interleaved rounds, ten iterations, against the production snapshot (932,861 packages, dated 2026-08-04), Apple M4 Max. Interleaved round by round so ambient load lands on both sides.
single-no-depssmall-treeextrasapp-setwide-versionsbacktrackingunsatisfiableCold gains far exceed warm, and that asymmetry is the finding. Building a package's sorted version order is comparison-bound and happens once per package per index, so it lands entirely in cold. Warm reuses that order through 0.5.0's memo, so the packed key only reaches the residual comparisons inside
pep440setcontainment and candidate filtering.The interaction with #40 is measured, not asserted
The two contend — both attack version-comparison cost, so each is worth less once the other has landed. 2×2, one interleaved session, warm, medians of three:
single-no-depssmall-treeextrasapp-setwide-versionsbacktrackingunsatisfiableOn⚠️ Opposite sign to the #39/#40 interaction, where
app-set, multiplying the isolated headlines predicts 12.34 × 5.33 = 65.8x; measured end-to-end from73d820a+v0.5.0 to276fe91+v0.6.0 is 15.7x.Containsbecame more valuable after the rank memo — so these interactions cannot be guessed.This also resolves an apparent conflict with go-python-packaging's own release notes, which claim 2.1–5.2x warm on this benchmark: those were measured at
73d820a, before #40 landed 46 minutes later. The pre-#40 column reproduces them (1.99–5.93x).Not moved:
pypirsf.Open+NewRSFIndexis flat at ~220 ms (220.0 → 216.6, within noise) — it builds a name-to-offset table and parses no versions.Peak heap is flat to better (
wide-versions18.7 → 12.3 MB over baseline), with one exception kept rather than dropped:backtrackingretains slightly more (6.0 → 6.5 MB).Correctness
candvers,metadataand the pin set are identical on every corpus entry — this changes what a comparison costs, not what it answers.Cross-build equivalence, which is the check that matters for a comparison-key change: 4,007 resolutions against the production snapshot (the 7 corpus entries plus 4,000 sampled package names, seed 1) produce byte-identical transcripts before and after — identical pins, identical decision order, identical activated extras, and identical failure report text on the 1,607 that fail. 36 cases that hit an 8-second wall-clock deadline are excluded (35 both sides, 1 baseline only, 0 bumped only).
Suite:
go test ./...andgo test ./... -raceboth green against the production snapshot atGPR_SAMPLE=20000.provider's andcontiguity's differentials walk all 932,861 packages ("default 0 means all of them"), which is a multi-hour ~10 GB run. AtGPR_SAMPLE=2000TestCandidatesAgreeWithAnExactCountOnTheRealIndexfails its own anti-vacuity guard — identically onv0.5.0andv0.6.0(same 2000/1440/3/0 counts), so it is sample size, not this bump.🤖 Generated with Claude Code