Skip to content

fix(package-manager): stop pnpr install re-downloading prefetched tarballs#12245

Merged
zkochan merged 1 commit into
mainfrom
fix-pnpr-duplicate-tarball-downloads
Jun 6, 2026
Merged

fix(package-manager): stop pnpr install re-downloading prefetched tarballs#12245
zkochan merged 1 commit into
mainfrom
fix-pnpr-duplicate-tarball-downloads

Conversation

@zkochan

@zkochan zkochan commented Jun 6, 2026

Copy link
Copy Markdown
Member

Problem

On the pnpr client path the resolve-time TarballPrefetcher fires a background download for every package frame into the shared MemCache, but the frozen materialization install (InstallPackageBySnapshot) fetched each registry/tarball through run_without_mem_cache — so it never consulted that cache. The two fan-outs ran concurrently with no in-flight coordination: the materializer only avoided a second download when the prefetch had already finished writing the tarball to the store before the materializer reached it.

On a fresh install of a ~1300-package fixture this re-downloaded ~48% of tarballs:

downloads transfer download phase
before 1933 (625 dups) 107 MB dribbled to ~15s
after 1308 (0 dups) 66 MB saturates the link, ~2-5s

The redundant fetches also thrashed the network/extract slots, so the download phase never saturated the link.

Fix

Thread the install-scoped tarball_mem_cache down through InstallFrozenLockfileCreateVirtualStoreInstallPackageBySnapshot, and route the registry/tarball branch through run_with_mem_cache when a cache is provided. The frozen path passes Some (materializer parks on / reuses the prefetcher's in-flight download); the fresh-lockfile path passes None and keeps run_without_mem_cache (its downloads already resolve through the resolve-time prefetcher into the store and dedup against on-disk state).

Scope / caveat

This removes redundant work; it does not by itself make pnpr faster than a local install on a fast/low-latency registry. There the dominant cost is the remote resolve round-trip plus the serial resolve → write-lockfile → materialize barrier, not the tarball bytes. Measured wall-clock on a fast CDN: interleaved pnpr-on ~16.2s vs off ~14.4s (the gap narrowed ~1-2s but did not close). The bigger lever — letting materialization start before the full resolve stream lands — is a separate change.

Known follow-up: progress label

Because the materializer now consumes the prefetcher's downloads and the prefetcher reports through SilentReporter, a fresh pnpr install emits pnpm:progress found_in_store for the prefetched packages instead of fetched (it labels freshly-downloaded tarballs as "reused"). Label-only — no double-count, no missing event — but it should be corrected so the summary line is accurate. Two viable fixes, both more invasive than this PR:

  1. Share one SharedReportedProgressKeys between the prefetcher (emitting fetched via the real reporter) and the materializer, so the cache-hit found_in_store is deduped away. Requires plumbing the set from the CLI through Install, whose struct literal has ~70 construction sites.
  2. Carry a network_fetched flag on CacheValue::Available (set by the owner when run_without_mem_cache actually hit the network) so the waiting cache-hit reports fetched vs found_in_store correctly. Requires changing run_without_mem_cache's return type (~16 call sites).

Tests

All 51 frozen/snapshot + install_package_by_snapshot tests pass, plus both pnpr_install integration tests (install_via_pnpr_links_node_modules exercises the changed path). cargo clippy clean.


Written by an agent (Claude Code, claude-opus-4-8).

Summary by CodeRabbit

  • Performance
    • Installation process optimized with shared tarball download caching, reducing redundant network requests by reusing previously-fetched packages across different installation workflows.

…balls

On the pnpr client path the resolve-time `TarballPrefetcher` fires a
background download for every `package` frame into the shared `MemCache`,
but the frozen materialization install (`InstallPackageBySnapshot`) fetched
each registry/tarball through `run_without_mem_cache`, so it never consulted
that cache. The two fan-outs ran concurrently with no in-flight
coordination: the materializer only avoided a second download when the
prefetch had already finished writing the tarball to the store before the
materializer reached it. On a fresh install of a ~1300-package fixture this
re-downloaded ~48% of tarballs — 1933 downloads for 1308 packages, 107 MB
transferred instead of 66 MB — and the redundant fetches thrashed the
network/extract slots so the download phase dribbled out to ~15s instead of
saturating the link.

Thread the install-scoped `tarball_mem_cache` down through
`InstallFrozenLockfile` -> `CreateVirtualStore` -> `InstallPackageBySnapshot`
and route the registry/tarball branch through `run_with_mem_cache` when a
cache is provided. The frozen path passes `Some` so the materializer parks
on (or reuses) the prefetcher's in-flight download; the fresh-lockfile path
passes `None` and keeps the standalone `run_without_mem_cache` (its
downloads already resolve through the resolve-time prefetcher into the store
and dedup against on-disk state). After the change the same install does
1308 downloads (0 duplicates) and the download phase saturates the link and
completes in ~2-5s.

Note: this only removes redundant work; it does not by itself make pnpr
faster than a local install on a fast/low-latency registry, where the
dominant cost is the remote resolve round-trip plus the serial
resolve -> write-lockfile -> materialize barrier rather than the tarball
bytes.

Known follow-up (reporting label): because the materializer now consumes the
prefetcher's downloads and the prefetcher reports through `SilentReporter`,
a fresh pnpr install now emits `pnpm:progress found_in_store` for the
prefetched packages instead of `fetched` (it labels freshly-downloaded
tarballs as "reused"). It is a label-only issue — no double-count, no
missing event — but it should be corrected so the summary line is accurate.
Two viable fixes, both more invasive than this change:
  1. Share one `SharedReportedProgressKeys` between the prefetcher (emitting
     `fetched` via the real reporter) and the materializer so the cache-hit
     `found_in_store` is deduped away. Requires plumbing the set from the
     CLI through `Install`, whose struct literal has ~70 construction sites.
  2. Carry a `network_fetched` flag on `CacheValue::Available` (set by the
     owner when `run_without_mem_cache` actually hit the network) so the
     waiting cache-hit reports `fetched` vs `found_in_store` correctly.
     Requires changing `run_without_mem_cache`'s return type (~16 call
     sites).

---
Written by an agent (Claude Code, claude-opus-4-8).
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8bbf690d-b15d-44a5-b9bf-b47b87253037

📥 Commits

Reviewing files that changed from the base of the PR and between c199198 and 8afcabd.

📒 Files selected for processing (5)
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (1)
pacquet/**/*.rs

📄 CodeRabbit inference engine (pacquet/AGENTS.md)

pacquet/**/*.rs: Log emissions are part of matching pnpm — when porting a function that fires pnpm:<channel> events through globalLogger, logger.debug(...), or streamParser.write(...), mirror the call site, payload, and ordering so @pnpm/cli.default-reporter parses pacquet's NDJSON the same way
Declare a newtype wrapper for branded string types instead of collapsing the brand into a plain String or &str in Rust
If upstream TypeScript always validates before construction of a branded string, validate in the Rust wrapper too via TryFrom<String> and/or FromStr and do not provide an infallible public constructor
If upstream TypeScript never validates a branded string, just brand for type-safety in Rust by exposing an infallible From<String> constructor
If upstream TypeScript occasionally constructs a branded string without validation, expose from_str_unchecked in Rust as an escape hatch alongside the validating constructor
Match upstream serde behavior for branded strings crossing JSON, YAML, or INI boundaries by using #[serde(try_from = "String")] for deserialization and #[serde(into = "String")] for serialization
Derive simple conversions for branded strings using #[derive(derive_more::From)] and #[derive(derive_more::Into)] instead of handwriting impl blocks; use manual impl only when conversion needs custom logic
Model TypeScript string literal unions (like 'auto' | 'always' | 'never') as Rust enums instead of newtype wrappers, since the set of valid values is closed
Treat TypeScript string template literal types (like `${string}@${string}`) the same as branded string types in Rust, using a newtype wrapper with validation
Follow the code style guide in CODE_STYLE_GUIDE.md — imports, modules, naming, ownership and borrowing, parameter type selection, trait bounds, pattern matching, pipe-trait, error handling, test layout, and cloning of Arc and Rc
Choose owned vs. borrowed parameters to minimize copies; widen to t...

Files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
🧠 Learnings (23)
📓 Common learnings
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12189
File: pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs:435-439
Timestamp: 2026-06-04T14:40:29.444Z
Learning: In `pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs` (pnpm/pnpm repo), the pnpr install accelerator always invokes `Install` with `lockfile_only: true` (hard-coded in `pnpr/crates/pnpr/src/install_accelerator/resolve.rs`). Under `lockfile_only: true`:
1. The `PrefetchingResolver` wrapper is skipped — the bare `inner_resolver` is used instead, so `PrefetchContext { config }` is never constructed.
2. The function returns before `CreateVirtualStore` is reached, so `install_package_by_snapshot` and its `config.auth_headers` fetch path are never hit.
pnpr's tarball fetch is handled separately in `resolve::fetch_uncached`, which independently receives the request-scoped `auth_headers`. Therefore, `auth_override` only needs to be threaded into the resolver-side components (NpmResolver, TarballResolver, NamedRegistryResolver) — not into PrefetchingResolver or CreateVirtualStore — on the pnpr path. For local installs (`lockfile_only: false`), `auth_override` is always `None` a...
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11915
File: pacquet/crates/resolving-deps-resolver/src/resolve_dependency_tree.rs:553-617
Timestamp: 2026-05-24T21:11:04.272Z
Learning: In the pacquet Rust port (pnpm/pnpm repo), the `ResolvedPackage.optional` AND-folding on revisit intentionally mirrors pnpm's `resolveDependencies.ts:1627-1648` behavior: only the directly-revisited package's `optional` flag is updated; transitive descendants are not re-walked. pnpm CLI corrects stale optional flags downstream via `copyDependencySubGraph` BFS in `lockfile/pruner/src/index.ts:160-205`, which tracks a `nonOptional` set and re-stamps any package reachable by an all-non-optional path. Pacquet does not yet have this pruner equivalent, so the stale flags flow directly through `dependencies_graph_to_lockfile.rs:409` → `create_virtual_store.rs:762` → `installability.rs:394`. A follow-up to port `copyDependencySubGraph` is planned; until then, do not flag the resolver-layer optional propagation gap as a bug in pacquet PRs — it is intentional parity with pnpm's resolver layer.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11915
File: pacquet/crates/resolving-deps-resolver/src/resolve_dependency_tree.rs:553-617
Timestamp: 2026-05-24T21:11:04.272Z
Learning: In pacquet (pnpm/pnpm repo), `ResolvedPackage.optional` AND-folding intentionally mirrors pnpm's resolveDependencies.ts:1627-1648 revisit behavior: only the directly-visited package's `optional` flag is updated on revisit, not transitive descendants. pnpm CLI corrects stale optional flags via `copyDependencySubGraph` BFS in `lockfile/pruner/src/index.ts:160-205`. Pacquet does not yet have this pruner equivalent, so raw `node.optional` flows directly into snapshot/virtual-store via `dependencies_graph_to_lockfile.rs:409` → `create_virtual_store.rs:762` → `installability.rs:394`. A follow-up issue to port `copyDependencySubGraph` is planned.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12181
File: worker/src/start.ts:504-520
Timestamp: 2026-06-04T06:04:05.107Z
Learning: In pnpm/pnpm's pnpr install accelerator, the `/v1/install` response has a two-level framing structure:
1. **Outer layer** (full HTTP body): `[u32 outer header length][outer header JSON][files payload]` — `fetchFromPnpmRegistry` (pnpr/client/src/fetchFromPnpmRegistry.ts) strips the outer layer with `body.subarray(4 + headerLength)` and passes the remaining bytes to `writeCafsFiles`.
2. **Inner layer** (files payload): the files payload itself starts with its own `[u32 inner json length][inner header JSON]` prefix (built by the server's `build_files_payload` / `empty_files_payload_prefix`), followed by `[64-byte digest][u32 size][1-byte exec][content]` frames and a 64-zero-byte end marker.

`writeCafsFiles` in `worker/src/start.ts` is correct to read `jsonLen = payload.readUInt32BE(0)` and start frames at `offset = 4 + jsonLen` — this skips the inner header. The same two-level structure is mirrored in the Rust reference client (`parse_inline_response` + `write_files_payload`). Do not fla...
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-25T12:36:42.202Z
Learning: User-visible changes (CLI flags, defaults, environment variables, lockfile/manifest/state-file formats, error codes/messages, log emissions, store layout, hook semantics) in pnpm must be mirrored to pacquet in the same PR
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11867
File: pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs:726-730
Timestamp: 2026-05-23T09:14:43.635Z
Learning: In `pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs`, the fresh-lockfile path intentionally does not invoke `BuildModules` and discards `side_effects_maps_by_snapshot` from `CreateVirtualStoreOutput`. This is pre-existing, documented behavior (mirroring upstream `link.ts:167-170`): `importing_done` fires once extraction and symlink linking are complete, and the fresh-lockfile path does not run lifecycle scripts. The frozen-lockfile path wires `BuildModules` end-to-end as normal. Do not flag this omission as a bug; wiring lifecycle scripts into the fresh-lockfile path is tracked as future work separate from perf refactors.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11784
File: pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs:120-133
Timestamp: 2026-05-20T23:08:06.093Z
Learning: Pacquet (pnpm's Rust port) has a cardinal rule: "match pnpm exactly — do not fix pnpm quirks unless the same fix has landed in pnpm first." Review comments should not suggest behavioral deviations from upstream pnpm, even when the upstream behavior appears buggy. If a real bug is identified, it must be fixed upstream first.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12189
File: pacquet/crates/cli/src/cli_args/install.rs:0-0
Timestamp: 2026-06-04T14:55:52.163Z
Learning: In `pacquet/crates/cli/src/cli_args/install.rs` (pnpm/pnpm repo), the `install_via_pnpr` function intentionally forwards the **full** `state.config.auth_headers` map to the pnpr server (not filtered to only the declared default/named registries). This is required for correctness: transitive dependencies can be scope-routed to registries not in the explicit registry list, or pinned to tarball URLs on hosts present in `.npmrc` but not a declared registry. Filtering to the declared registries silently drops tokens those sub-dependencies need, causing 401s on the server. pnpr uses the forwarded map to attach the right token per fetched URL exactly as a local install does (`AuthHeaders::for_url`). The pnpr-server's own credential is sent separately in the `Authorization` header and is excluded from the body map. Do NOT flag this as a credential-leakage issue — the rationale is documented in a comment at both call sites.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11867
File: pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs:726-730
Timestamp: 2026-05-23T09:14:43.635Z
Learning: In `pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs`, the fresh-lockfile path intentionally does not run lifecycle scripts (`BuildModules` is not invoked, and `side_effects_maps_by_snapshot` from `CreateVirtualStoreOutput` is discarded). This is pre-existing behavior documented by an in-code comment mirroring upstream `link.ts:167-170`. The frozen-lockfile path wires `BuildModules` end-to-end as normal. Wiring lifecycle scripts into the fresh-lockfile path is tracked as future work, separate from this file's concern.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11784
File: pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs:120-133
Timestamp: 2026-05-20T23:08:06.093Z
Learning: In `pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs`, the `else` branch that calls `max_satisfying_any` is intentional and matches upstream pnpm's `hoistPeers.ts` (lines 45-59). When `is_exact_version && !auto_install_peers`, pnpm still runs `semver.maxSatisfying(versions, '*', { includePrerelease: true })` and picks the closest available preferred version; any version mismatch is reported downstream as a `bad` peer issue rather than dropping the edge. Do NOT suggest changing this branch to skip `max_satisfying_any` for exact ranges — it would diverge from pnpm.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11931
File: pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs:560-589
Timestamp: 2026-05-25T14:58:11.105Z
Learning: In `pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs`, all per-`(registry, name[, version])` caches in `NpmResolutionVerifier` (`published_at`, `full_meta`, `full_meta_for_trust`, `abbreviated_meta`, `local_meta`) intentionally use the same pattern: lock → miss-check → release lock → await fetch/load → re-acquire lock → insert. This uniform pattern is deliberate; do not flag individual caches for using it. The known follow-up improvement (replacing the pattern with `tokio::sync::OnceCell` per key inside a `Mutex<HashMap<…>>`) is tracked as a future structural change to cover all five caches simultaneously.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11452
File: exec/commands/src/dlx.ts:298-305
Timestamp: 2026-05-04T17:01:30.322Z
Learning: In `exec/commands/src/dlx.ts`, when `promptApproveDlxBuilds` exits early (no `approve-builds` command or non-interactive stdin), the `cachedDir` is intentionally still linked into the shared dlx cache even if some build scripts were skipped. This is by design: (1) it mirrors `pnpm add -g` behavior which also commits the install with skipped builds in non-interactive mode; (2) the cache key already encodes `allowBuild`, so users can recover by re-invoking with `--allow-build=<pkg>` which generates a fresh cache entry; (3) re-installing on every non-interactive invocation would be a perf regression for CI. Do not suggest preventing the symlink in this code path.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12144
File: pnpr/crates/pnpr/src/install_accelerator/verdict_cache.rs:57-61
Timestamp: 2026-06-02T16:13:39.456Z
Learning: In `pnpr/crates/pnpr/src/install_accelerator/verdict_cache.rs`, the `lockfile_verdicts` SQLite table intentionally uses `hash` alone (not a composite `(hash, policy)` key) as the primary key — last-write-wins per hash. This mirrors the local `lockfile-verified.jsonl` cache design in pnpm. A looser current policy can trust a stricter cached pass via `can_trust_past_check`; alternating-policy re-verification is an accepted trade-off. A composite key was explicitly rejected to maintain parity with the local cache model.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11878
File: resolving/npm-resolver/src/createNpmResolutionVerifier.ts:381-418
Timestamp: 2026-05-23T17:30:06.849Z
Learning: In `resolving/npm-resolver/src/pickPackage.ts` (pnpm/pnpm), the resolver's `PackageMetaCache` keys by `name` (abbreviated) and `name:full` (full metadata) only — no registry component is included. This is a pre-existing limitation meaning that if two different registries serve packages of the same name in one install, the cache will only hold the first fetched entry. The `createNpmResolutionVerifier.ts` shares this same cache and inherits the limitation; a `validateSharedMeta` name-check guards against cross-package contamination but cannot distinguish same-named packages from different registries. Tightening to a registry-qualified key would require a coordinated change to the resolver's cache key shape. The Pacquet/Rust side is already registry-qualified (`{registry}\x00{name}:full`).
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12134
File: pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs:311-325
Timestamp: 2026-06-02T13:18:30.659Z
Learning: In pacquet's lockfile resolution verifier (`pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs`), URL-keyed tarball dependencies do NOT need a separate `non_semver_version` field in `VerifyCtx`. Unlike the TypeScript side (which derives `version` from `snapshot.version` and threads `nonSemverVersion` separately), pacquet's `collect_candidates` takes `version` from the lockfile key suffix. For a URL-keyed dep the key is `name@<url>`, so `ctx.version` is the URL string, which fails `node_semver::Version::parse(ctx.version)` and the existing guard `if node_semver::Version::parse(ctx.version).is_err() { return ResolutionVerification::Ok; }` already skips the registry lookup correctly. Adding a `non_semver_version` field to `VerifyCtx` for this purpose would be inert.
📚 Learning: 2026-05-23T09:14:43.635Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11867
File: pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs:726-730
Timestamp: 2026-05-23T09:14:43.635Z
Learning: In `pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs`, the fresh-lockfile path intentionally does not run lifecycle scripts (`BuildModules` is not invoked, and `side_effects_maps_by_snapshot` from `CreateVirtualStoreOutput` is discarded). This is pre-existing behavior documented by an in-code comment mirroring upstream `link.ts:167-170`. The frozen-lockfile path wires `BuildModules` end-to-end as normal. Wiring lifecycle scripts into the fresh-lockfile path is tracked as future work, separate from this file's concern.

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
📚 Learning: 2026-06-04T14:40:29.444Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12189
File: pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs:435-439
Timestamp: 2026-06-04T14:40:29.444Z
Learning: In `pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs` (pnpm/pnpm repo), the pnpr install accelerator always invokes `Install` with `lockfile_only: true` (hard-coded in `pnpr/crates/pnpr/src/install_accelerator/resolve.rs`). Under `lockfile_only: true`:
1. The `PrefetchingResolver` wrapper is skipped — the bare `inner_resolver` is used instead, so `PrefetchContext { config }` is never constructed.
2. The function returns before `CreateVirtualStore` is reached, so `install_package_by_snapshot` and its `config.auth_headers` fetch path are never hit.
pnpr's tarball fetch is handled separately in `resolve::fetch_uncached`, which independently receives the request-scoped `auth_headers`. Therefore, `auth_override` only needs to be threaded into the resolver-side components (NpmResolver, TarballResolver, NamedRegistryResolver) — not into PrefetchingResolver or CreateVirtualStore — on the pnpr path. For local installs (`lockfile_only: false`), `auth_override` is always `None` a...

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-23T09:14:43.635Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11867
File: pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs:726-730
Timestamp: 2026-05-23T09:14:43.635Z
Learning: In `pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs`, the fresh-lockfile path intentionally does not invoke `BuildModules` and discards `side_effects_maps_by_snapshot` from `CreateVirtualStoreOutput`. This is pre-existing, documented behavior (mirroring upstream `link.ts:167-170`): `importing_done` fires once extraction and symlink linking are complete, and the fresh-lockfile path does not run lifecycle scripts. The frozen-lockfile path wires `BuildModules` end-to-end as normal. Do not flag this omission as a bug; wiring lifecycle scripts into the fresh-lockfile path is tracked as future work separate from perf refactors.

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-25T14:58:11.105Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11931
File: pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs:560-589
Timestamp: 2026-05-25T14:58:11.105Z
Learning: In `pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs`, all per-`(registry, name[, version])` caches in `NpmResolutionVerifier` (`published_at`, `full_meta`, `full_meta_for_trust`, `abbreviated_meta`, `local_meta`) intentionally use the same pattern: lock → miss-check → release lock → await fetch/load → re-acquire lock → insert. This uniform pattern is deliberate; do not flag individual caches for using it. The known follow-up improvement (replacing the pattern with `tokio::sync::OnceCell` per key inside a `Mutex<HashMap<…>>`) is tracked as a future structural change to cover all five caches simultaneously.

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Use snapshot tests with `insta` and carefully review diffs when intentional changes alter snapshots; accept with `cargo insta review` only after careful review

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-23T16:55:36.507Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11878
File: pacquet/crates/cli/tests/lockfile_verification.rs:158-162
Timestamp: 2026-05-23T16:55:36.507Z
Learning: In `pacquet/crates/cli/tests/lockfile_verification.rs`, the `trust_lockfile_skips_verification` and `trust_lockfile_cli_flag_skips_verification` tests intentionally do NOT assert `output.status.success()`. The hand-rolled fixture lockfile uses a placeholder integrity hash (`sha512-AAA…`), so the install always fails the downstream tarball integrity check regardless of the supply-chain gate. The contract being tested is "gate-skipped, not install-succeeded"; asserting success would require generating a real lockfile via the `generate_lockfile` pattern (see `hoist.rs`) which is considered not worth the extra wiring for an opt-out smoke test.

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
📚 Learning: 2026-06-04T14:55:52.163Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12189
File: pacquet/crates/cli/src/cli_args/install.rs:0-0
Timestamp: 2026-06-04T14:55:52.163Z
Learning: In `pacquet/crates/cli/src/cli_args/install.rs` (pnpm/pnpm repo), the `install_via_pnpr` function intentionally forwards the **full** `state.config.auth_headers` map to the pnpr server (not filtered to only the declared default/named registries). This is required for correctness: transitive dependencies can be scope-routed to registries not in the explicit registry list, or pinned to tarball URLs on hosts present in `.npmrc` but not a declared registry. Filtering to the declared registries silently drops tokens those sub-dependencies need, causing 401s on the server. pnpr uses the forwarded map to attach the right token per fetched URL exactly as a local install does (`AuthHeaders::for_url`). The pnpr-server's own credential is sent separately in the `Authorization` header and is excluded from the body map. Do NOT flag this as a credential-leakage issue — the rationale is documented in a comment at both call sites.

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/Cargo.toml : Keep dependencies at the right level — add a new dependency to the specific crate that needs it, not to the workspace root or shared crate unless multiple crates depend on it

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-20T19:40:55.051Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11774
File: pacquet/crates/resolving-deps-resolver/src/resolve_peers.rs:0-0
Timestamp: 2026-05-20T19:40:55.051Z
Learning: In the pacquet Rust code, ensure the semver implementation uses the `node-semver` crate (not `nodejs-semver`). `node-semver`’s public API does not include a `satisfies_with_prerelease`-style method; prerelease-tolerant matching should be implemented inline by first calling `Range::satisfies`, and when it rejects a prerelease version, retry matching against a stripped `MAJOR.MINOR.PATCH` base of the prerelease version.

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-22T00:08:44.646Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11837
File: pacquet/crates/resolving-npm-resolver/src/pick_package.rs:33-51
Timestamp: 2026-05-22T00:08:44.646Z
Learning: In the pnpm/pnpm repo’s pacquet Rust crates, do not flag Unicode ellipsis characters (U+2026, `…`) in Rust doc comments (`///` / `/** */`) as a lint violation. The pacquet crate’s `dylint.toml` only enables `perfectionist::derive_ordering`, and the Dylint `unicode-ellipsis` rule is not enabled for this project—so `…` in doc comments is an intentional, repo-consistent style.

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-20T23:07:58.444Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11784
File: pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs:120-133
Timestamp: 2026-05-20T23:07:58.444Z
Learning: When reviewing code in this pacquet Rust port, follow the upstream pnpm compatibility rule: only match pnpm’s behavior exactly. Do not propose review changes that intentionally deviate from pnpm’s documented/observed behavior, even if pnpm appears buggy. If you identify a real bug in pnpm behavior, the review should prioritize fixing it upstream in pnpm first, and avoid implementing a pnpm-behavior workaround here unless the same fix has already landed upstream.

Applied to files:

  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Prefer existing pacquet-* crates over writing new code; check pacquet-tarball, pacquet-crypto-hash, pacquet-crypto-shasums-file, pacquet-package-manifest, pacquet-network, pacquet-registry, pacquet-fs, and pacquet-diagnostics before implementing non-trivial functionality

Applied to files:

  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-24T16:07:54.784Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11904
File: pacquet/crates/package-manager/src/install.rs:556-560
Timestamp: 2026-05-24T16:07:54.784Z
Learning: In pacquet's `is_modules_yaml_consistent` (pacquet/crates/package-manager/src/install.rs), `enableGlobalVirtualStore` is intentionally NOT checked as a separate field. Upstream pnpm's `validateModules.ts` does not persist or check `enableGlobalVirtualStore` in `.modules.yaml` either. Drift on this setting is caught indirectly: toggling `enableGlobalVirtualStore` changes `config.effective_virtual_store_dir()` (GVS-on → `<store>/v11/links`, GVS-off → `<project>/node_modules/.pnpm`), so the existing `modules.virtual_store_dir == config.effective_virtual_store_dir()` comparison in `is_modules_yaml_consistent` already detects the mismatch and prevents the short-circuit. Do not flag the absence of an explicit `enableGlobalVirtualStore` field as a bug.

Applied to files:

  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
📚 Learning: 2026-06-02T13:18:30.659Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12134
File: pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs:311-325
Timestamp: 2026-06-02T13:18:30.659Z
Learning: In pacquet's lockfile resolution verifier (`pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs`), URL-keyed tarball dependencies do NOT need a separate `non_semver_version` field in `VerifyCtx`. Unlike the TypeScript side (which derives `version` from `snapshot.version` and threads `nonSemverVersion` separately), pacquet's `collect_candidates` takes `version` from the lockfile key suffix. For a URL-keyed dep the key is `name@<url>`, so `ctx.version` is the URL string, which fails `node_semver::Version::parse(ctx.version)` and the existing guard `if node_semver::Version::parse(ctx.version).is_err() { return ResolutionVerification::Ok; }` already skips the registry lookup correctly. Adding a `non_semver_version` field to `VerifyCtx` for this purpose would be inert.

Applied to files:

  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-24T21:11:04.272Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11915
File: pacquet/crates/resolving-deps-resolver/src/resolve_dependency_tree.rs:553-617
Timestamp: 2026-05-24T21:11:04.272Z
Learning: In pacquet (pnpm/pnpm repo), `ResolvedPackage.optional` AND-folding intentionally mirrors pnpm's resolveDependencies.ts:1627-1648 revisit behavior: only the directly-visited package's `optional` flag is updated on revisit, not transitive descendants. pnpm CLI corrects stale optional flags via `copyDependencySubGraph` BFS in `lockfile/pruner/src/index.ts:160-205`. Pacquet does not yet have this pruner equivalent, so raw `node.optional` flows directly into snapshot/virtual-store via `dependencies_graph_to_lockfile.rs:409` → `create_virtual_store.rs:762` → `installability.rs:394`. A follow-up issue to port `copyDependencySubGraph` is planned.

Applied to files:

  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-24T21:11:04.272Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11915
File: pacquet/crates/resolving-deps-resolver/src/resolve_dependency_tree.rs:553-617
Timestamp: 2026-05-24T21:11:04.272Z
Learning: In the pacquet Rust port (pnpm/pnpm repo), the `ResolvedPackage.optional` AND-folding on revisit intentionally mirrors pnpm's `resolveDependencies.ts:1627-1648` behavior: only the directly-revisited package's `optional` flag is updated; transitive descendants are not re-walked. pnpm CLI corrects stale optional flags downstream via `copyDependencySubGraph` BFS in `lockfile/pruner/src/index.ts:160-205`, which tracks a `nonOptional` set and re-stamps any package reachable by an all-non-optional path. Pacquet does not yet have this pruner equivalent, so the stale flags flow directly through `dependencies_graph_to_lockfile.rs:409` → `create_virtual_store.rs:762` → `installability.rs:394`. A follow-up to port `copyDependencySubGraph` is planned; until then, do not flag the resolver-layer optional propagation gap as a bug in pacquet PRs — it is intentional parity with pnpm's resolver layer.

Applied to files:

  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/*.rs : Search for existing shared helpers before writing new code; shared helpers tend to live in `crates/fs`, `crates/testing-utils`, and `crates/diagnostics`

Applied to files:

  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-06-04T20:24:32.096Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12198
File: pnpr/crates/pnpr/src/storage.rs:469-477
Timestamp: 2026-06-04T20:24:32.096Z
Learning: In `pnpr/crates/pnpr/src/storage.rs` (pnpm/pnpm repo, Rust), `Store::list_package_names` intentionally uses `fs::try_exists(...).await.unwrap_or(false)` and `if let Ok(mut inner) = fs::read_dir(...)` — NOT `?`-propagation — for per-entry checks. This is deliberate best-effort / verdaccio-style search behavior: (1) `try_exists(stray_file/package.json)` returns `ENOTDIR` (not `NotFound`) for a stray non-package file in the store root, so `?` would fail the entire search; (2) the `@`-scope `read_dir` would fail on a non-directory `@`-named entry; (3) switching to `DirEntry::file_type()` would stop following symlinked package dirs. Failures that DO propagate are preserved: opening the store root itself, and `next_entry()` during the walk. Do not suggest blanket `?`-propagation for these per-entry checks.

Applied to files:

  • pacquet/crates/package-manager/src/create_virtual_store.rs
  • pacquet/crates/package-manager/src/install_package_by_snapshot.rs
📚 Learning: 2026-05-20T10:06:55.749Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11760
File: pacquet/crates/resolving-deps-resolver/src/resolved_tree.rs:15-18
Timestamp: 2026-05-20T10:06:55.749Z
Learning: In `pacquet/crates/resolving-deps-resolver/src/resolved_tree.rs`, the `DirectDep.id`, `ResolvedPackage.id`, and `ResolvedTree.packages` HashMap keys are intentionally plain `String` for now. The natural branded type would be `pacquet_lockfile::PkgNameVer`, but it cannot be used as a HashMap key because `node_semver::Version` does not derive `Hash`. The upstream parity type is `PkgResolutionId` (which carries an optional peer-dep suffix), and the branded type should be introduced alongside peer-dep resolution and lockfile generation work to avoid locking the seam too early.

Applied to files:

  • pacquet/crates/package-manager/src/create_virtual_store.rs
📚 Learning: 2026-05-19T19:23:00.981Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11752
File: pacquet/crates/config/src/lib.rs:1062-1073
Timestamp: 2026-05-19T19:23:00.981Z
Learning: In `pacquet/crates/config/src/lib.rs`, `modules_dir` does not need a `!virtual_store_dir_explicit` guard on its workspace re-anchor because `modules_dir` is in pnpm's `excludedPnpmKeys` (filtered out by `WorkspaceSettings::clear_workspace_only_fields`) and therefore can only be set by workspace yaml (applied immediately after) or env vars (applied later in the cascade) — not by global `config.yaml`. `virtual_store_dir`, by contrast, IS settable from global config and requires the `if !virtual_store_dir_explicit` guard to survive the workspace-root re-anchor.

Applied to files:

  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
📚 Learning: 2026-06-02T16:13:39.456Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12144
File: pnpr/crates/pnpr/src/install_accelerator/verdict_cache.rs:57-61
Timestamp: 2026-06-02T16:13:39.456Z
Learning: In `pnpr/crates/pnpr/src/install_accelerator/verdict_cache.rs`, the `lockfile_verdicts` SQLite table intentionally uses `hash` alone (not a composite `(hash, policy)` key) as the primary key — last-write-wins per hash. This mirrors the local `lockfile-verified.jsonl` cache design in pnpm. A looser current policy can trust a stricter cached pass via `can_trust_past_check`; alternating-policy re-verification is an accepted trade-off. A composite key was explicitly rejected to maintain parity with the local cache model.

Applied to files:

  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
📚 Learning: 2026-05-20T20:41:50.322Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11773
File: pacquet/crates/package-manager/src/install_package_from_registry.rs:111-114
Timestamp: 2026-05-20T20:41:50.322Z
Learning: In pacquet (pnpm/pnpm repo, Rust codebase), `install_package_from_registry` is the npm-only install path. The npm resolver always stamps `ResolveResult.id` (a `PkgResolutionId`) as `nameversion`. Parsing it back through `PkgNameVer` with `.expect()` is intentional — a parse failure means a mis-dispatch bug, not malformed external input. Per pacquet's CLAUDE.md: "Don't add error handling, fallbacks, or validation for scenarios that can't happen. Trust internal code and framework guarantees." Do not suggest replacing such `.expect()` calls with graceful error handling.

Applied to files:

  • pacquet/crates/package-manager/src/install_frozen_lockfile.rs
🔇 Additional comments (7)
pacquet/crates/package-manager/src/install.rs (1)

875-875: LGTM!

pacquet/crates/package-manager/src/install_frozen_lockfile.rs (1)

29-29: LGTM!

Also applies to: 34-34, 145-151, 288-288, 614-614

pacquet/crates/package-manager/src/create_virtual_store.rs (1)

23-23: LGTM!

Also applies to: 166-170, 216-216, 776-776

pacquet/crates/package-manager/src/install_package_by_snapshot.rs (3)

23-24: LGTM!


52-62: LGTM!


237-237: LGTM!

Also applies to: 278-309

pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs (1)

1294-1298: LGTM!


📝 Walkthrough

Walkthrough

The PR threads a shared in-memory tarball cache (tarball_mem_cache) through the frozen-lockfile install pipeline, enabling cold-batch snapshot downloads to reuse prefetched tarballs from the resolver instead of re-downloading them. The fresh-lockfile path explicitly excludes the cache with explanatory comments.

Changes

Tarball memory cache threading

Layer / File(s) Summary
Frozen-lockfile cache plumbing
pacquet/crates/package-manager/src/install.rs, pacquet/crates/package-manager/src/install_frozen_lockfile.rs
Install::run passes the shared tarball_mem_cache into InstallFrozenLockfile struct initialization. InstallFrozenLockfile imports MemCache, adds the cache field, destructures it in run, and forwards it into CreateVirtualStore.
Virtual store cache forwarding
pacquet/crates/package-manager/src/create_virtual_store.rs
CreateVirtualStore imports MemCache, adds the tarball_mem_cache field, destructures it in run, and passes it into each InstallPackageBySnapshot instance used by the cold-batch download path.
Per-snapshot cache-aware download routing
pacquet/crates/package-manager/src/install_package_by_snapshot.rs
InstallPackageBySnapshot imports MemCache, adds the tarball_mem_cache field, destructures it in run, and refactors the tarball download logic to construct a DownloadTarballToStore instance and conditionally call run_with_mem_cache (when cache is provided) or run_without_mem_cache, enabling deduplication of in-flight downloads.
Fresh-lockfile cache policy
pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
The fresh-lockfile path explicitly sets tarball_mem_cache: None in the CreateVirtualStore invocation with comments explaining that prefetching already populates the store and cold-batch deduplication makes the shared in-flight cache unnecessary.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • pnpm/pnpm#12241: This PR directly implements the fix for the prefetch vs cold-batch race condition by threading the shared tarball cache through CreateVirtualStore and InstallPackageBySnapshot to switch cold-batch downloads to run_with_mem_cache.

Possibly related PRs

  • pnpm/pnpm#11856: Introduces the MemCache and run_with_mem_cache infrastructure in the resolver; this PR threads that shared cache into the install-side cold-batch downloads to reuse prefetched results.
  • pnpm/pnpm#11867: Both PRs modify the install_with_fresh_lockfile.rs path and the CreateVirtualStore callsite; the main PR additionally wires tarball_mem_cache: None into that invocation.
  • pnpm/pnpm#12076: Warms the in-memory tarball cache during remote tarball resolution; this PR threads that shared cache into the install/snapshot cold-batch download path to reuse those prefetched in-flight tarballs.

Poem

🐇 A cache flows through frozen paths so bright,
From snapshot to snapshot, downloads take flight!
Cold batches now reuse what prefetch has found,
No redundant downloads spin round and around.
Fresh lockfiles stand still, their prefetch complete—
Sweet deduplication makes installs more fleet! 🌟

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: threading a tarball memory cache through the install pipeline to prevent re-downloading prefetched tarballs on the pnpr client path.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-pnpr-duplicate-tarball-downloads

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.00      7.9±0.28ms   550.0 KB/sec    1.00      7.9±0.10ms   551.3 KB/sec

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Each scenario has pacquet rows (direct install) and pnpr rows (the same client through the pnpr install accelerator), so pnpr@HEAD vs pacquet@HEAD is the pnpr-vs-direct ratio. Cold-store scenarios wipe the client store between runs (warm server); hot-store scenarios keep it warm. The pacquet@HEAD rows feed the pacquet Bencher testbed; the pnpr@HEAD rows feed the pnpr testbed.

Scenario: Isolated linker: fresh restore, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 9.976 ± 0.177 9.834 10.452 2.01 ± 0.06
pacquet@main 10.044 ± 0.210 9.863 10.428 2.02 ± 0.07
pnpr@HEAD 4.991 ± 0.136 4.861 5.302 1.01 ± 0.04
pnpr@main 4.961 ± 0.126 4.850 5.210 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 9.976332235700001,
      "stddev": 0.17666419189957885,
      "median": 9.9313940981,
      "user": 3.4983488599999992,
      "system": 2.7236304399999995,
      "min": 9.8338984851,
      "max": 10.4518794111,
      "times": [
        10.0125223861,
        9.992676285100002,
        9.917582276100001,
        9.8598999281,
        10.4518794111,
        9.9323609221,
        9.8338984851,
        9.8682719081,
        9.930427274100001,
        9.963803481100001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 10.043622227,
      "stddev": 0.20972996987073758,
      "median": 9.976091083100002,
      "user": 3.45489176,
      "system": 2.7816032399999995,
      "min": 9.863337576100001,
      "max": 10.428059649100001,
      "times": [
        9.8642694371,
        10.0770491301,
        9.884249286100001,
        10.428059649100001,
        10.027184375100001,
        9.863337576100001,
        10.108382760100001,
        10.3780102411,
        9.924997791100001,
        9.8806820241
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 4.9914931869,
      "stddev": 0.13593902258364335,
      "median": 4.9470517261,
      "user": 2.5210640599999996,
      "system": 2.4521815399999998,
      "min": 4.8613399121,
      "max": 5.3023598381,
      "times": [
        5.1556012921,
        4.9526372511,
        4.8613399121,
        5.3023598381,
        4.9961597571,
        4.9414662011,
        4.9306087821,
        4.9729588621,
        4.9264576961,
        4.8753422771
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 4.960569936000001,
      "stddev": 0.1259227377219873,
      "median": 4.9071291531,
      "user": 2.5205619599999993,
      "system": 2.4209554399999997,
      "min": 4.8502153301,
      "max": 5.2104599611,
      "times": [
        5.2104599611,
        4.8712999651,
        4.8833086241,
        4.9296748151,
        5.1644120791,
        4.9095048541,
        4.9918030151,
        4.8502153301,
        4.8902672641,
        4.9047534521000005
      ]
    }
  ]
}

Scenario: Isolated linker: fresh restore, hot cache + hot store

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 506.5 ± 31.1 485.3 591.8 1.01 ± 0.06
pacquet@main 499.8 ± 8.2 491.6 521.1 1.00
pnpr@HEAD 617.4 ± 26.9 589.4 679.9 1.24 ± 0.06
pnpr@main 651.6 ± 94.7 589.9 905.8 1.30 ± 0.19
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.5064935650800001,
      "stddev": 0.031120830554653707,
      "median": 0.49742577728000004,
      "user": 0.38426522,
      "system": 0.8033639599999999,
      "min": 0.48531513128000003,
      "max": 0.59178103428,
      "times": [
        0.59178103428,
        0.51346389228,
        0.50417347328,
        0.49786142728000005,
        0.48820101528000004,
        0.49393778128000004,
        0.50321956028,
        0.48531513128000003,
        0.49699012728,
        0.48999220828000006
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.49980125078000004,
      "stddev": 0.008204428031389283,
      "median": 0.49868174978,
      "user": 0.38853731999999996,
      "system": 0.80038386,
      "min": 0.49164504628000005,
      "max": 0.52113858328,
      "times": [
        0.52113858328,
        0.49794244328000004,
        0.50119815828,
        0.49641630828000005,
        0.50036135128,
        0.49942105628000005,
        0.49164504628000005,
        0.49669602628000004,
        0.50086911228,
        0.49232442228000006
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.6173668904800002,
      "stddev": 0.026864353841048374,
      "median": 0.61156101078,
      "user": 0.39931651999999995,
      "system": 0.81074006,
      "min": 0.58938044628,
      "max": 0.6799440732800001,
      "times": [
        0.6799440732800001,
        0.62398740628,
        0.61112640428,
        0.61199561728,
        0.60614313028,
        0.58938044628,
        0.59224759028,
        0.64298511928,
        0.61475228128,
        0.6011068362800001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.6515821297800001,
      "stddev": 0.0947076080265515,
      "median": 0.6114931797800001,
      "user": 0.39271692,
      "system": 0.8189499599999998,
      "min": 0.58985799428,
      "max": 0.9057812562800001,
      "times": [
        0.69161852228,
        0.61543555228,
        0.60503502828,
        0.65995954228,
        0.58985799428,
        0.60755080728,
        0.59815452628,
        0.60517183628,
        0.9057812562800001,
        0.6372562322800001
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 5.167 ± 0.058 5.091 5.298 3.07 ± 0.07
pacquet@main 5.143 ± 0.058 5.063 5.272 3.06 ± 0.07
pnpr@HEAD 1.683 ± 0.035 1.629 1.736 1.00
pnpr@main 1.693 ± 0.057 1.601 1.783 1.01 ± 0.04
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 5.167117290919999,
      "stddev": 0.058402750885731984,
      "median": 5.156676325020001,
      "user": 3.9166654999999997,
      "system": 2.0842009599999995,
      "min": 5.09098846952,
      "max": 5.29770129152,
      "times": [
        5.167026137520001,
        5.29770129152,
        5.12006428752,
        5.2185132985200005,
        5.09098846952,
        5.169854321520001,
        5.18930449952,
        5.1423350585200005,
        5.146326512520001,
        5.129059032520001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 5.14284741242,
      "stddev": 0.05839915577141343,
      "median": 5.13084404502,
      "user": 3.8650611999999995,
      "system": 2.0623847599999996,
      "min": 5.063181230520001,
      "max": 5.272376754520001,
      "times": [
        5.11044046652,
        5.13147792052,
        5.13086582052,
        5.121779749520001,
        5.13082226952,
        5.272376754520001,
        5.14049264752,
        5.063181230520001,
        5.1145391805200004,
        5.212498084520001
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 1.68264532882,
      "stddev": 0.03474871442743423,
      "median": 1.68764721452,
      "user": 2.6333425,
      "system": 1.9245152599999997,
      "min": 1.6291404145200001,
      "max": 1.73593873652,
      "times": [
        1.63534707952,
        1.6925070985200001,
        1.68207885952,
        1.70596832852,
        1.6291404145200001,
        1.69698832952,
        1.6506010075200002,
        1.68278733052,
        1.73593873652,
        1.71509610352
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 1.69318142662,
      "stddev": 0.056936378535371285,
      "median": 1.68604865602,
      "user": 2.6286283,
      "system": 1.9724707599999998,
      "min": 1.6012787615200001,
      "max": 1.78262499352,
      "times": [
        1.78262499352,
        1.6012787615200001,
        1.7355737385199999,
        1.63842215152,
        1.73640304452,
        1.68155807452,
        1.6709132175199999,
        1.74918626752,
        1.64531477952,
        1.69053923752
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, hot cache + hot store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 1.253 ± 0.015 1.233 1.282 2.47 ± 0.05
pacquet@main 1.283 ± 0.067 1.231 1.460 2.53 ± 0.14
pnpr@HEAD 0.522 ± 0.054 0.487 0.671 1.03 ± 0.11
pnpr@main 0.507 ± 0.008 0.492 0.517 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 1.25285844718,
      "stddev": 0.015075952954788948,
      "median": 1.25038394058,
      "user": 1.59288284,
      "system": 1.10989096,
      "min": 1.23292559508,
      "max": 1.28215570508,
      "times": [
        1.23659377708,
        1.2452845400800001,
        1.26663183308,
        1.25429451308,
        1.23292559508,
        1.28215570508,
        1.25180334508,
        1.24376072208,
        1.24896453608,
        1.26616990508
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.28262580688,
      "stddev": 0.06718525284220123,
      "median": 1.26027393058,
      "user": 1.6148672400000001,
      "system": 1.1018432599999997,
      "min": 1.23097245808,
      "max": 1.45977287908,
      "times": [
        1.26463835608,
        1.25448195608,
        1.23570689308,
        1.27666572308,
        1.45977287908,
        1.3196041090800001,
        1.27953003208,
        1.24897615708,
        1.25590950508,
        1.23097245808
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.52157912498,
      "stddev": 0.053938835324674944,
      "median": 0.50363808308,
      "user": 0.33747314,
      "system": 0.75728246,
      "min": 0.48705369808000004,
      "max": 0.6707499130800001,
      "times": [
        0.49926782608000003,
        0.50530648508,
        0.51076178908,
        0.5019696810800001,
        0.5086871740800001,
        0.50090700808,
        0.49541765608000005,
        0.48705369808000004,
        0.6707499130800001,
        0.53567001908
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.5065021159800001,
      "stddev": 0.008489111748034931,
      "median": 0.50683951708,
      "user": 0.33593884,
      "system": 0.7677413599999999,
      "min": 0.49193544808,
      "max": 0.51713133508,
      "times": [
        0.51713133508,
        0.5166256450800001,
        0.49747675708000005,
        0.49193544808,
        0.50156451508,
        0.50495534208,
        0.50108399208,
        0.5128897100800001,
        0.50872369208,
        0.51263472308
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + hot store

Resolution-only: cold packument cache (full re-resolve over the registry link) with a hot store (no tarball download), so this isolates pnpr offloading the client resolution to its warm server.

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 4.939 ± 0.056 4.870 5.067 9.53 ± 0.19
pacquet@main 4.942 ± 0.034 4.887 5.004 9.53 ± 0.17
pnpr@HEAD 0.518 ± 0.008 0.507 0.538 1.00
pnpr@main 0.518 ± 0.006 0.512 0.532 1.00 ± 0.02
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 4.9385919974800006,
      "stddev": 0.05597386995902876,
      "median": 4.94110802598,
      "user": 1.8946239200000001,
      "system": 1.26454108,
      "min": 4.87023677598,
      "max": 5.06711869998,
      "times": [
        4.96466058098,
        4.87939957398,
        4.87023677598,
        4.93671084998,
        4.94550520198,
        5.06711869998,
        4.95441468898,
        4.945972966979999,
        4.88928800998,
        4.93261262598
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 4.94217820938,
      "stddev": 0.034347822509429055,
      "median": 4.94103661648,
      "user": 1.89510522,
      "system": 1.2672648800000001,
      "min": 4.88727593498,
      "max": 5.00365121598,
      "times": [
        4.88727593498,
        4.93135496598,
        4.94921558998,
        4.91386009898,
        4.90944117898,
        4.93285764298,
        4.97460705598,
        4.95603199398,
        4.96348641598,
        5.00365121598
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.5183429866800001,
      "stddev": 0.00841767306127987,
      "median": 0.51729428748,
      "user": 0.34274612000000004,
      "system": 0.7843087799999999,
      "min": 0.50707910898,
      "max": 0.53758219998,
      "times": [
        0.51736658098,
        0.51112800698,
        0.51885485798,
        0.51722199398,
        0.53758219998,
        0.52558788498,
        0.50707910898,
        0.51502044498,
        0.51978108598,
        0.51380770198
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.5184197432800002,
      "stddev": 0.005555037502617592,
      "median": 0.51697366498,
      "user": 0.34945152,
      "system": 0.7769385799999998,
      "min": 0.51235982098,
      "max": 0.53183294998,
      "times": [
        0.52156776698,
        0.51235982098,
        0.52009982098,
        0.51547717898,
        0.51726813598,
        0.51971291598,
        0.53183294998,
        0.51667919398,
        0.51310211998,
        0.51609752898
      ]
    }
  ]
}

@github-actions

github-actions Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12245
Testbedpacquet

🚨 2 Alerts

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
isolated-linker.fresh-install.cold-cache.cold-storeLatency
seconds (s)
📈 plot
🚷 threshold
🚨 alert (🔔)
5.17 s
(+124.71%)Baseline: 2.30 s
2.76 s
(187.26%)

isolated-linker.fresh-restore.cold-cache.cold-storeLatency
seconds (s)
📈 plot
🚷 threshold
🚨 alert (🔔)
9.98 s
(+122.66%)Baseline: 4.48 s
5.38 s
(185.55%)

Click to view all benchmark results
BenchmarkLatencyBenchmark Result
milliseconds (ms)
(Result Δ%)
Upper Boundary
milliseconds (ms)
(Limit %)
isolated-linker.fresh-install.cold-cache.cold-store📈 view plot
🚷 view threshold
🚨 view alert (🔔)
5,167.12 ms
(+124.71%)Baseline: 2,299.43 ms
2,759.32 ms
(187.26%)

isolated-linker.fresh-install.cold-cache.hot-store📈 view plot
🚷 view threshold
4,938.59 ms
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
🚷 view threshold
1,252.86 ms
(-5.75%)Baseline: 1,329.33 ms
1,595.19 ms
(78.54%)
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
🚷 view threshold
🚨 view alert (🔔)
9,976.33 ms
(+122.66%)Baseline: 4,480.61 ms
5,376.73 ms
(185.55%)

isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
🚷 view threshold
506.49 ms
(-25.52%)Baseline: 680.04 ms
816.05 ms
(62.07%)
🐰 View full continuous benchmarking report in Bencher

@zkochan zkochan marked this pull request as ready for review June 6, 2026 17:45
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Eliminate duplicate tarball downloads in pnpr frozen materialization

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Thread install-scoped tarball cache through frozen lockfile materialization
• Reuse prefetcher's in-flight downloads instead of re-fetching tarballs
• Eliminate ~48% duplicate downloads on pnpr fresh installs (~625 redundant fetches)
• Saturate network link during download phase, reducing time from ~15s to ~2-5s
Diagram
flowchart LR
  A["TarballPrefetcher<br/>background downloads"] -->|"shared MemCache"| B["InstallFrozenLockfile"]
  B -->|"tarball_mem_cache: Some"| C["CreateVirtualStore"]
  C -->|"tarball_mem_cache"| D["InstallPackageBySnapshot"]
  D -->|"run_with_mem_cache"| E["DownloadTarballToStore<br/>reuses in-flight downloads"]
  F["InstallWithFreshLockfile"] -->|"tarball_mem_cache: None"| C
  F -->|"resolve-time prefetch"| E

Loading

Grey Divider

File Changes

1. pacquet/crates/package-manager/src/install.rs ✨ Enhancement +1/-0

Thread tarball cache to frozen store creation

• Pass tarball_mem_cache: Some(&tarball_mem_cache) to CreateVirtualStore on frozen lockfile path
• Enables materialization to reuse prefetcher's in-flight downloads

pacquet/crates/package-manager/src/install.rs


2. pacquet/crates/package-manager/src/install_frozen_lockfile.rs ✨ Enhancement +12/-2

Add tarball cache field to frozen lockfile installer

• Add tarball_mem_cache: Option<&'a Arc> field to InstallFrozenLockfile
• Import MemCache and Arc types
• Thread cache through to CreateVirtualStore invocation

pacquet/crates/package-manager/src/install_frozen_lockfile.rs


3. pacquet/crates/package-manager/src/create_virtual_store.rs ✨ Enhancement +8/-1

Add tarball cache field to virtual store creator

• Add tarball_mem_cache: Option<&'a std::sync::Arc> field to CreateVirtualStore
• Import MemCache type from pacquet_tarball
• Thread cache through to InstallPackageBySnapshot invocation

pacquet/crates/package-manager/src/create_virtual_store.rs


View more (2)
4. pacquet/crates/package-manager/src/install_package_by_snapshot.rs 🐞 Bug fix +28/-5

Route downloads through shared cache when available

• Add tarball_mem_cache: Option<&'a Arc> field to InstallPackageBySnapshot
• Import MemCache type from pacquet_tarball
• Route tarball downloads through run_with_mem_cache when cache is provided, else use
 run_without_mem_cache
• Clone HashMap from shared Arc to maintain by-value contract

pacquet/crates/package-manager/src/install_package_by_snapshot.rs


5. pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs ✨ Enhancement +5/-0

Disable shared cache for fresh lockfile path

• Pass tarball_mem_cache: None to CreateVirtualStore on fresh lockfile path
• Preserves existing behavior where downloads already deduplicate through resolve-time prefetcher

pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs


Grey Divider

Qodo Logo

@zkochan zkochan merged commit 5f7f747 into main Jun 6, 2026
27 of 28 checks passed
@zkochan zkochan deleted the fix-pnpr-duplicate-tarball-downloads branch June 6, 2026 17:54
zkochan added a commit that referenced this pull request Jun 6, 2026
…e prefetcher

On the fresh-resolve install path the same tarball could be downloaded
twice: once by the resolve-time `PrefetchingResolver` and again by
`CreateVirtualStore`'s cold batch. The shared `tarball_mem_cache`
infrastructure already exists (added in #12245 for the pnpr/frozen
path), but the fresh-lockfile call site threaded `None`, so the cold
batch went through `run_without_mem_cache` and never observed the
in-flight prefetch — its only on-disk dedup is the store-index row,
which the prefetcher's writer commits asynchronously, so a snapshot
whose row hasn't committed yet re-downloaded the same bytes.

Thread `Some(&tarball_mem_cache)` from the fresh-lockfile path so the
cold batch reuses a finished prefetch immediately (`CacheValue::Available`)
or briefly parks on the per-URL `Notify` for an in-flight one. Installs
with no prefetcher keep passing `None`.

Closes #12241
zkochan added a commit that referenced this pull request Jun 6, 2026
…e prefetcher

On the fresh-resolve install path the same registry tarball could be
downloaded twice: once by the resolve-time `PrefetchingResolver` and
again by `CreateVirtualStore`'s cold batch. The shared `tarball_mem_cache`
infrastructure already exists (added in #12245 for the pnpr/frozen path),
but the fresh-lockfile call site threaded `None`, so the cold batch went
through `run_without_mem_cache` and never observed the in-flight prefetch
— its only on-disk dedup is the store-index row, which the prefetcher's
writer commits asynchronously, so a snapshot whose row hasn't committed
yet re-downloaded the same bytes.

Thread `Some(&tarball_mem_cache)` from the fresh-lockfile path so the
cold batch reuses a finished prefetch (`CacheValue::Available`) or
briefly parks on the per-URL `Notify` for an in-flight one.

Two refinements keep this safe:

- Coordinate only registry resolutions. The `PrefetchingResolver` skips
  remote tarballs (they resolve with no `name_ver`); their only mem-cache
  entry comes from the resolver's download-to-resolve, keyed by
  `name@version`, while the lockfile and this pass address them by
  `name@<url>`. Reusing that entry would skip writing the `name@<url>`
  store-index row a later re-resolve needs to reuse the warm store
  (regressed `remote_tarball_reresolves_from_warm_store_without_refetch`).

- Fall back to a standalone retried download when the best-effort
  prefetch failed (`SiblingFetchFailed`) instead of inheriting the
  failure, so a transient prefetch error no longer fails the install.

Closes #12241
zkochan added a commit that referenced this pull request Jun 6, 2026
…ce fix) (#12243)

* fix(package-manager): coordinate the fresh-resolve cold batch with the prefetcher

On the fresh-resolve install path the same registry tarball could be
downloaded twice: once by the resolve-time `PrefetchingResolver` and
again by `CreateVirtualStore`'s cold batch. The shared `tarball_mem_cache`
infrastructure already exists (added in #12245 for the pnpr/frozen path),
but the fresh-lockfile call site threaded `None`, so the cold batch went
through `run_without_mem_cache` and never observed the in-flight prefetch
— its only on-disk dedup is the store-index row, which the prefetcher's
writer commits asynchronously, so a snapshot whose row hasn't committed
yet re-downloaded the same bytes.

Thread `Some(&tarball_mem_cache)` from the fresh-lockfile path so the
cold batch reuses a finished prefetch (`CacheValue::Available`) or
briefly parks on the per-URL `Notify` for an in-flight one.

Two refinements keep this safe:

- Coordinate only registry resolutions. The `PrefetchingResolver` skips
  remote tarballs (they resolve with no `name_ver`); their only mem-cache
  entry comes from the resolver's download-to-resolve, keyed by
  `name@version`, while the lockfile and this pass address them by
  `name@<url>`. Reusing that entry would skip writing the `name@<url>`
  store-index row a later re-resolve needs to reuse the warm store
  (regressed `remote_tarball_reresolves_from_warm_store_without_refetch`).

- Fall back to a standalone retried download when the best-effort
  prefetch failed (`SiblingFetchFailed`) instead of inheriting the
  failure, so a transient prefetch error no longer fails the install.

Closes #12241

* refactor(package-manager): match resolution by reference in mem-cache guard

Borrow `metadata.resolution` in the registry-only mem-cache guard so the
non-binding `matches!` reads through the shared reference explicitly,
addressing a review comment on #12243. No behavior change.
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.

1 participant