groundy
developer tools

CHRONO-RESOLUTION: npm, PyPI, and crates.io lockfile drift measured at release points

CHRONO-RESOLUTION measures resolution drift across npm, PyPI, and crates.io at release points. Lockfiles are snapshots, not contracts. Teams must adopt per-ecosystem.

11 min···6 sources ↓

A lockfile regenerated six weeks apart from an unchanged manifest can resolve to different transitive dependency versions, and the CHRONO-RESOLUTION dataset (arXiv:2607.15315), accepted to ICSME 2026’s Tool Demonstration and Data Showcase Track, is the first public attempt to measure that drift across npm, PyPI, and crates.io at release points. The practical consequence: lockfiles are point-in-time snapshots, not reproducibility contracts, and the burden moves to release-cadence policy.

What does “reproducible” actually mean for a lockfile?

Reproducibility for a lockfile means one specific thing: deleting the lockfile and re-resolving the same manifest, at any later date, produces the same transitive dependency tree. By that definition, no mainstream package manager offers reproducibility from the manifest alone, because permissive version ranges legitimately admit multiple valid resolutions.

The mechanism is semver itself. npm follows the semantic versioning standard, under which a range like ^4.17.0 matches any 4.x release at or above 4.17.0. That range is a set of valid answers, and the resolver picks one based on what the registry contains at resolution time. When a dependency publishes 4.18.0 on Tuesday, a Wednesday re-resolve of your unchanged manifest returns a different tree than a Monday re-resolve. This is intended behavior. The drift is not a bug in the resolver; it is the design working as specified, and it is exactly the quantity a release-point dataset can measure.

The confusion persists because teams conflate three distinct properties. Integrity is whether the artifact you downloaded is the artifact the publisher shipped. Availability is whether the registry serves it at all. Reproducibility is whether resolution is deterministic over time. The first two have seen real investment: CPython release artifacts have been signed with Sigstore since Python 3.11.0, 3.10.7, and 3.9.14, and PyPI has been served by the modern Warehouse platform since 16 April 2018. Neither does anything for the third. A signed, highly available package that resolves to a different version next month is still a different version next month.

So when someone says “we have a lockfile, we’re reproducible,” the precise claim is narrower: we can reinstall the tree we recorded. The moment anyone regenerates that lockfile, during an upgrade, a security patch, or a fresh npm install on a branch that predates the lockfile’s last refresh, the guarantee is gone and drift enters.

How does CHRONO-RESOLUTION measure resolution drift?

CHRONO-RESOLUTION is a dependency-resolution dataset measured at release points across npm, PyPI, and crates.io packages, according to its arXiv abstract, and it was accepted to ICSME 2026 in the Tool Demonstration and Data Showcase Track. The method implied by the title is the right one for this problem: take real manifests, re-resolve them each time a relevant dependency releases a new version, and record how often the resolved tree changes.

That design matters more than it might appear. Most reproducibility discussion is anecdotal: a postmortem where CI broke because a transitive minor release landed mid-sprint. Anecdotes cannot rank ecosystems. A dataset that fixes the manifest and varies only time can, because it isolates registry churn from every other variable. If ecosystem A’s manifests re-resolve to new trees twice as often as ecosystem B’s at comparable release cadences, that is a property of the ecosystem’s release culture and range conventions, not of any one team’s hygiene.

One honesty constraint applies to everything quantitative about this dataset. The abstract page establishes scope (npm, PyPI, crates.io) and the ICSME 2026 acceptance, but it does not publish the per-ecosystem drift figures in the form available to this article. Any specific ranking of which ecosystem drifts most, and any percentage attached to that ranking, has to come from the full paper’s tables, and those numbers should be quoted from the paper directly rather than paraphrased secondhand. What can be stated now: the measurement exists, it spans the three largest language-specific registries in common use, and it was vetted through a peer-reviewed tool track.

How do npm, PyPI, and crates.io differ on the axes that matter?

The three ecosystems differ on four axes that determine how much reproducibility pain a team feels: range semantics and resolver defaults, lockfile behavior, registry governance and integrity infrastructure, and release cadence culture. Only some of these are documented in the sources at hand; the rest are stable, pre-2026 mechanics that the CHRONO-RESOLUTION paper’s tables would quantify.

AxisnpmPyPIcrates.io
Version range conventionsemver caret/tilde ranges per Node.js documentationPEP 440 specifiers; >= pins common in librariessemver caret-style ranges by default
Default registryregistry.npmjs.org, configured by defaultPyPI, operated by the Python Software Foundation, a charitycrates.io, Cargo’s default registry
Registry scale2M+ packages; 2.1M reported in September 2022Large; exact current count not in sourced materialSmaller; exact count not in sourced material
Integrity infrastructureRegistry-level; not detailed in sourced materialSigstore signing for CPython artifacts since 3.11.0; Warehouse since April 2018Not detailed in sourced material
Resolution drift rateMeasured by CHRONO-RESOLUTION; figure requires the full paperMeasured by CHRONO-RESOLUTION; figure requires the full paperMeasured by CHRONO-RESOLUTION; figure requires the full paper

Two rows deserve expansion because they drive the tradeoffs.

Registry defaults shape resolution surfaces. npm is configured by default to use the npm Public Registry at registry.npmjs.org, which means every resolver in the ecosystem resolves against the same mutable package set. PyPI’s situation is similar in practice, but its governance differs: it is run by the Python Software Foundation, a charity, and its operational history includes events that remind you the registry is run by humans under jurisdiction. In May 2023 the PSF reported that the U.S. Department of Justice had subpoenaed user data of five PyPI contributors. Governance does not change resolution math, but it changes who answers when something goes wrong with the index your reproducibility depends on.

Integrity investment is not reproducibility investment. Python’s packaging story is the clearest example. CPython artifacts carry Sigstore signatures, and as of 14 October 2024 the certificate authority for PSF Windows installers is the Microsoft Identity Verification Root Certificate Authority. That is a real supply-chain improvement. It tells you the bits are authentic. It says nothing about whether pip install -r requirements.txt with unpinned ranges resolves to the same versions in August that it did in June. Teams that read “we signed everything” as “we fixed reproducibility” are solving a different problem than the one that breaks their CI.

Why don’t one package manager’s guarantees transfer in a monorepo?

Cross-ecosystem monorepos fail on reproducibility because each package manager encodes different assumptions about ranges, lockfiles, and registry behavior, and none of those assumptions compose. A repo with a TypeScript frontend, a Python inference service, and a Rust edge component runs three resolvers with three drift profiles, and the team’s reproducibility posture is only as strong as the worst of the three.

The failure mode is usually asymmetric in a way that surprises people. Teams port habits, not guarantees. An engineer who learned that package-lock.json plus npm ci gives deterministic installs will reach for the equivalent incantation in pip and find the historical default tooling thinner, or will apply npm’s range-permissiveness instincts to a Cargo.toml where the release cadence culture differs. The tooling surface has converged somewhat over the years, but the ecosystems underneath have not: npm’s two-million-plus package registry generates a release-event volume that a smaller registry does not, and drift opportunities scale with that volume.

This is where a per-ecosystem drift measurement earns its keep. Without one, the monorepo reproducibility discussion is pure folk wisdom: “npm is chaos, cargo is fine,” repeated until believed. If CHRONO-RESOLUTION’s tables show the ranking differs from the folk ranking, or that the gap is smaller than assumed, that changes where a platform team spends its hardening budget. If the folk ranking holds with numbers attached, that is also useful: it converts a vibes-based argument into a budget line. Either way, the correct move is to stop assuming one lockfile discipline covers all three ecosystems and to set policy per ecosystem, informed by measured drift rather than by whichever language the loudest engineer on the team writes.

What should your release-cadence policy look like?

The operational answer is to treat the lockfile as a snapshot and govern the regeneration schedule deliberately: pair permissive semver ranges with a disciplined, scheduled re-lock, and accept that pinning and patching are a tradeoff you manage on a calendar rather than a problem you solve once.

Concretely, that policy has four moving parts:

  1. Commit the lockfile and install from it in CI. This is table stakes and worth stating because it is the only layer that is actually deterministic. The lockfile freezes one resolution; the policy governs everything after.
  2. Schedule re-locks instead of letting them happen incidentally. A weekly or biweekly dependency-refresh job that regenerates the lockfile, runs the full test suite, and opens a reviewable diff converts silent drift into visible, attributable change. The drift CHRONO-RESOLUTION measures still occurs; it just occurs inside a pull request with a changelog instead of inside a deploy.
  3. Scope pinning to what pinning protects. Hard pins on every transitive dependency maximize reproducibility and maximize security-patch latency, because every patch now requires a manual bump. Permissive ranges minimize patch latency and maximize drift. Neither extreme survives contact with a real production calendar. The defensible middle is permissive ranges on libraries you control the upgrade path for, tighter constraints on dependencies with a history of breaking minors, and a re-lock cadence fast enough that “permissive” never means “stale.”
  4. Set the cadence per ecosystem. If the full CHRONO-RESOLUTION paper shows one of your three ecosystems drifts substantially faster, that ecosystem gets the shorter re-lock interval and the tighter CI gate. This is the concrete way a dataset like this should change operations: not as trivia, but as the input to a scheduling decision.

What can’t the dataset tell us yet?

The honest limitation is that the publicly visible abstract confirms CHRONO-RESOLUTION’s existence, scope, and ICSME 2026 acceptance, but not its findings: the per-ecosystem drift rates, the rankings the title of this article promises, and the methodology’s edge cases all live in the full paper’s tables, which were not available in the material reviewed here.

That gap constrains what any responsible write-up can claim, this one included. Three specific things remain open. First, the rankings: which of npm, PyPI, and crates.io drifts most at release points is an empirical question the dataset answers, and quoting the answer requires the paper, not inference from registry size. Second, the counterfactual: drift measured at release points reflects release cadence as much as resolver semantics, so a fast-publishing ecosystem may score “worse” while delivering security patches faster. The dataset can show the tradeoff exists; it cannot tell you where your team should sit on it. Third, the shelf life: resolvers, registry defaults, and signing infrastructure all change, and measurements taken against 2026 registry behavior will age as the ecosystems do. The integrity side is already moving, as Python’s Sigstore adoption shows; resolution behavior can move just as fast.

The verdict, given all of that: stop treating any lockfile as a reproducibility guarantee, in any of the three ecosystems. Treat it as a snapshot with an expiration policy you choose. Pair permissive ranges with scheduled re-locks, set the schedule per ecosystem rather than per repo, and never assume npm’s resolution behavior transfers to pip or cargo inside a monorepo. When the full CHRONO-RESOLUTION tables are citable, use the per-ecosystem drift figures to tune those schedules with numbers instead of folk wisdom. Until then, the dataset’s most useful contribution is already visible in its premise: the drift is real, it is measurable, and it differs by ecosystem enough to be worth measuring at all.

Frequently Asked Questions

Does the CHRONO-RESOLUTION dataset account for private registry mirrors?

The arXiv abstract specifies measurement across npm, PyPI, and crates.io public registries. It does not mention private registries or self-hosted proxies like Artifactory or Nexus. Private mirrors often cache artifacts indefinitely or enforce stricter pinning, which would alter the drift profile. Teams using internal registries must validate whether their caching policy masks or amplifies the public registry drift measured by the dataset.

How does lockfile drift impact CI/CD pipeline costs?

Frequent lockfile regeneration triggers full dependency resolution, which is computationally expensive. npm resolution can consume significant CPU and memory, especially with large transitive trees. If a CI pipeline re-resolves on every commit without a lockfile, it incurs higher cloud compute costs and longer queue times compared to installing from a committed lockfile. Scheduled re-locks balance this cost by limiting heavy resolution to specific windows.

Can deterministic builds be achieved without a lockfile?

No. Deterministic builds require pinning every transitive dependency to a specific version and hash. Without a lockfile, the resolver must choose versions at install time, which varies based on registry state. Tools like pip-compile or npm shrinkwrap generate lockfiles to enforce this determinism. Relying solely on manifest files (package.json, requirements.txt) inherently allows drift as new versions are published.

What is the impact of security patches on reproducibility?

Security patches often bump patch versions (e.g., 1.2.3 to 1.2.4). If a manifest uses a permissive range like ^1.2.0, a re-resolve will pull the patched version, changing the lockfile. This breaks the reproducibility contract if the lockfile is regenerated after the patch release. Teams must decide whether to accept the drift for security or manually pin the version, which delays patch application until the next scheduled re-lock.

sources · 6 cited

  1. npm | Homenpmjs.comvendoraccessed 2026-07-26
  2. npmnpmjs.comvendoraccessed 2026-07-26
  3. Python Package Indexen.wikipedia.orgcommunityaccessed 2026-07-26
  4. Download Pythonpython.orgvendoraccessed 2026-07-26