Skip to content

perf(pacquet): speed up lockfile verification repeats#12260

Merged
zkochan merged 2 commits into
mainfrom
codex/pacquet-verification-fast-path
Jun 7, 2026
Merged

perf(pacquet): speed up lockfile verification repeats#12260
zkochan merged 2 commits into
mainfrom
codex/pacquet-verification-fast-path

Conversation

@zkochan

@zkochan zkochan commented Jun 7, 2026

Copy link
Copy Markdown
Member

Summary

  • record successful fresh lockfile verification results so mtime-bypassed no-op installs can reuse the verification cache
  • add a synchronous verifier interest check before lockfile-verification fan-out allocates async work
  • skip npm metadata verification for ordinary registry entries when no tarball URL, age policy, or trust policy applies

Testing

  • cargo test -p pacquet-lockfile-verification verify_lockfile_resolutions::tests::
  • cargo test -p pacquet-resolving-npm-resolver create_npm_resolution_verifier::tests::
  • cargo test -p pacquet-package-manager install::tests::
  • push hooks: pnpm compile/lint, cargo fmt --all -- --check, Rust docs, dylint, taplo format check

Did not rerun the external vlt benchmark harness locally.


Written by an agent (Codex, GPT-5).

Summary by CodeRabbit

  • New Features

    • Fresh installs now record lockfile verification status so subsequent installs can skip redundant verification.
  • Performance

    • Verification pre-filters applicable checks to avoid unnecessary verifier work and metadata lookups, skipping irrelevant candidates.
  • Tests

    • New tests validate that uninterested verifiers are skipped and that lockfile verification is bypassed when cached/no-op conditions apply.

@coderabbitai

coderabbitai Bot commented Jun 7, 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: 9bda1427-a3e1-457d-9b0c-7511560080da

📥 Commits

Reviewing files that changed from the base of the PR and between bef3ac7 and 403edae.

📒 Files selected for processing (1)
  • pacquet/crates/package-manager/src/install/tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • pacquet/crates/package-manager/src/install/tests.rs
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Lint and Test (macos-latest)
  • GitHub Check: Lint and Test (ubuntu-latest)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Dylint
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Code Coverage
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Compile & Lint

📝 Walkthrough

Walkthrough

Adds a synchronous might_verify pre-check to ResolutionVerifier, pre-filters verifiers per-candidate in the runner (skipping candidates with no matches), implements gating in the NPM verifier, and threads a can_record_lockfile_verification flag so fresh installs can record verification results when the written lockfile is unchanged by hooks.

Changes

Lockfile Verification Optimization with Result Recording

Layer / File(s) Summary
Resolution Verifier pre-check protocol
pacquet/crates/resolving-resolver-base/src/verifier.rs
ResolutionVerifier gains might_verify(&self, resolution: &LockfileResolution, ctx: VerifyCtx) -> bool (default true) for synchronous pre-filtering.
Verifier runner pre-filtering
pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs, pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
run_fan_out now filters verifiers per-candidate via might_verify(...) and skips candidates without matching verifiers; new test ensures uninterested verifiers are not invoked.
NPM verifier gating and early-exit tightening
pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs, pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
NpmResolutionVerifier implements might_verify (true for tarball URLs or when policy/age checks apply and entry not excluded); verify_impl moves checks earlier and only early-exits when no tarball URL and no checks apply; tests validate gating and avoided metadata lookups.
Recording lockfile verification results
pacquet/crates/package-manager/src/install.rs
Build resolution_verifiers via build_resolution_verifiers(...), pass into verify_lockfile_resolutions, and call record_lockfile_verified after fresh installs when fresh_result.can_record_lockfile_verification is true and wanted_lockfile exists.
Lockfile verification readiness flag threading
pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
Add can_record_lockfile_verification: bool to InstallWithFreshLockfileResult; change save_wanted_lockfile to return (Option<WantedLockfile>, bool) and propagate the flag through both --lockfile-only and normal fresh-install flows.
Verification caching integration tests
pacquet/crates/package-manager/src/install/tests.rs
Add fresh_install_records_lockfile_verification_for_mtime_bypassed_noop to assert a second install with mtime bump takes the no-op path and emits no lockfile verification events (cache hit).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

Possibly related PRs

Poem

A rabbit inspects each lockfile with cheer,
Skips what’s not needed, keeps the needed near,
Fresh installs remember what passed the test,
Fewer wasted checks — now that’s progress! 🐇✨

🚥 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 'perf(pacquet): speed up lockfile verification repeats' directly describes the main change—optimizing repeated lockfile verification by caching and adding pre-checks to skip unnecessary work.
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 codex/pacquet-verification-fast-path

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 7, 2026

Copy link
Copy Markdown
Contributor

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.00      7.6±0.14ms   573.2 KB/sec    1.00      7.6±0.31ms   573.7 KB/sec

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

Copy link
Copy Markdown

Review Summary by Qodo

Speed up lockfile verification with synchronous filtering and cache recording

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add synchronous might_verify filter to skip unnecessary async verification work
• Record successful lockfile verification results for mtime-bypassed no-op installs
• Skip npm metadata verification when no tarball URL, age policy, or trust policy applies
• Optimize verification cache reuse across repeated installs
Diagram
flowchart LR
  A["Fresh Lockfile Resolution"] --> B["Build Verifiers"]
  B --> C["Save Lockfile"]
  C --> D["Record Verification Cache"]
  E["Repeat Install"] --> F["Load Cached Lockfile"]
  F --> G["might_verify Filter"]
  G --> H["Skip Async Work"]
  H --> I["No-op Install"]
  D -.->|cache hit| I

Loading

Grey Divider

File Changes

1. pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs ✨ Enhancement +11/-2

Add synchronous verifier interest check before fan-out

• Filter verifiers using might_verify before allocating async work in fan-out
• Skip candidates with no interested verifiers to avoid unnecessary futures
• Reduce concurrency overhead by pre-filtering uninterested verifiers

pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs


2. pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs 🧪 Tests +47/-0

Test uninterested verifier candidate skipping

• Add test verifying uninterested verifiers skip candidate processing
• Confirm verify is never called when might_verify returns false
• Validate zero async calls for filtered-out candidates

pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs


3. pacquet/crates/package-manager/src/install.rs ✨ Enhancement +23/-10

Record verification cache after fresh lockfile resolution

• Move verifier construction before lockfile verification to enable cache recording
• Call record_lockfile_verified after fresh lockfile resolution completes
• Pass verifiers to cache recording for policy-based verification tracking

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


View more (5)
4. pacquet/crates/package-manager/src/install/tests.rs 🧪 Tests +129/-0

Test mtime-bypassed no-op install verification cache

• Add end-to-end test for verification cache reuse on mtime-bypassed no-op installs
• Verify second install skips lockfile verification when cache is valid
• Confirm no registry contact occurs when verification cache hits

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


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

Track lockfile verification recordability status

• Add can_record_lockfile_verification flag to result struct
• Track whether afterAllResolved hook mutated the lockfile
• Return verification recordability status from save_wanted_lockfile
• Only record cache when typed lockfile matches persisted lockfile

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


6. pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs ✨ Enhancement +21/-4

Implement might_verify for npm resolution verifier

• Implement might_verify to check tarball URL, age policy, and trust policy applicability
• Return false for non-semver versions and excluded packages
• Move policy applicability checks to might_verify for early filtering
• Skip metadata lookup when no policies apply in verify_impl

pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs


7. pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs 🧪 Tests +18/-3

Test npm verifier interest filtering

• Add test confirming might_verify returns true for tarball URL resolutions
• Add test verifying registry resolutions skip metadata lookup when no policy active
• Validate zero metadata requests when might_verify returns false

pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs


8. pacquet/crates/resolving-resolver-base/src/verifier.rs ✨ Enhancement +8/-0

Add might_verify trait method to ResolutionVerifier

• Add might_verify trait method with default true implementation
• Document synchronous filter semantics and equivalence to verify returning Ok
• Enable verifier implementations to provide cheap pre-checks

pacquet/crates/resolving-resolver-base/src/verifier.rs


Grey Divider

Qodo Logo

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pacquet/crates/package-manager/src/install/tests.rs`:
- Around line 6041-6044: The 20ms sleep before re-reading the manifest is too
short for coarse mtime filesystems and causes flaky fast-path selection; replace
the std::thread::sleep(Duration::from_millis(20)) approach with a deterministic
mtime bump: either sleep for a safe floor (e.g., >= 1s) or, better, set the file
mtime explicitly (e.g., using the filetime crate) on manifest_path and then call
std::fs::write and PackageManifest::from_path to reload; ensure the test updates
manifest_path's mtime deterministically so the fast path is reliably bypassed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8a57bf0e-0cb5-411d-9e3e-2dd1b049ecdd

📥 Commits

Reviewing files that changed from the base of the PR and between 6b5d91a and bef3ac7.

📒 Files selected for processing (8)
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/resolving-resolver-base/src/verifier.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run benchmark on ubuntu-latest
🧰 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/resolving-resolver-base/src/verifier.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
🧠 Learnings (33)
📓 Common learnings
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: 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: 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.
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: CR
Repo: pnpm/pnpm PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-06-06T22:48:27.363Z
Learning: Keep pnpm and pacquet in sync — any user-visible change (CLI flags, defaults, environment-variable handling, lockfile/manifest/state-file format, error codes and messages, log emissions, store layout, hook semantics) must land in both the TypeScript pnpm CLI and the Rust pacquet port in the same PR
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: 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: 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: 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: 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: 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.
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.
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.
📚 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/resolving-resolver-base/src/verifier.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.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/resolving-resolver-base/src/verifier.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.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/resolving-resolver-base/src/verifier.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.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/resolving-resolver-base/src/verifier.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.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/resolving-resolver-base/src/verifier.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
📚 Learning: 2026-06-06T18:58:37.156Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 12243
File: pacquet/crates/package-manager/src/install_package_by_snapshot.rs:319-322
Timestamp: 2026-06-06T18:58:37.156Z
Learning: When reviewing Rust code, do not assume `matches!(expr, Pattern(_))` will move out of `expr` if `Pattern(_)` contains no by-value bindings. `matches!` desugars to a `match` that auto-borrows the scrutinee for discrimination, so even if `expr` is a non-`Copy` value behind a shared reference (e.g., `&T`), the macro should not move-out of the borrowed data purely due to `matches!`. Treat `matches!(&expr, Pattern(_))` as a readability/clarity improvement, not a correctness requirement. Only flag potential move-out-of-borrow risks when the pattern includes by-value bindings that would require moving the matched value.

Applied to files:

  • pacquet/crates/resolving-resolver-base/src/verifier.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.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/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
📚 Learning: 2026-05-20T21:18:56.391Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11778
File: pacquet/crates/resolving-local-resolver/tests/resolve.rs:365-372
Timestamp: 2026-05-20T21:18:56.391Z
Learning: In `pacquet/crates/resolving-local-resolver/tests/resolve.rs`, the test `fail_when_resolving_from_not_existing_directory_an_injected_dependency` intentionally uses `injected: false`. The test is a verbatim port of the upstream pnpm TypeScript test (resolving/local-resolver/test/index.ts at ef87f3ccff). The `injected` flag only affects the file/link protocol choice for plain directory paths; when the `file:` scheme is explicit in the bare specifier, the flag has no effect on the resolution code path. The misleading test name is inherited from upstream.

Applied to files:

  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install/tests.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/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.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 : Prefer `#[cfg_attr(target_os = "windows", ignore = "...")]` (or matching `#[cfg(unix)]` gates) over runtime probe-and-skip helpers for platform-locked tools

Applied to files:

  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.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 : Tests are documentation — do not duplicate test scenarios, edge cases, failure modes, or worked examples in prose when they are already captured by tests

Applied to files:

  • pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/package-manager/src/install/tests.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/lockfile-verification/src/verify_lockfile_resolutions/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
📚 Learning: 2026-05-23T17:30:06.849Z
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`).

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
📚 Learning: 2026-05-18T20:35:22.917Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11729
File: pacquet/crates/resolving-npm-resolver/src/fetch_attestation_published_at.rs:55-57
Timestamp: 2026-05-18T20:35:22.917Z
Learning: In `pacquet/crates/resolving-npm-resolver/src/fetch_attestation_published_at.rs`, the npm attestation endpoint (`/-/npm/v1/attestations/{pkg_name}@{version}`) intentionally does NOT percent-encode the package name — the endpoint accepts literal `/` in scoped package names (e.g. `scope/pkg`). This matches upstream pnpm's `fetchAttestationPublishedAt.ts` behavior. Do not flag missing URL encoding here. By contrast, the full-metadata fetch paths (`fetch_full_metadata`, `fetch_full_metadata_cached`) DO percent-encode via the `registry_url::to_registry_url` helper, matching upstream's `toUri` behavior.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.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 : Tests that need the mocked registry should start `pnpr` through `pacquet-testing-utils`; `cargo test` / `cargo nextest run` should not require a separate `just registry-mock launch` step

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install/tests.rs
📚 Learning: 2026-05-20T10:51:16.296Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11760
File: pacquet/crates/resolving-npm-resolver/src/named_registry.rs:109-127
Timestamp: 2026-05-20T10:51:16.296Z
Learning: In `pacquet/crates/resolving-npm-resolver/src/named_registry.rs`, the `pick_registry_for_package` function's logic `scope_from_bare_specifier(bare_specifier).or_else(|| scope_of(pkg_name))` is intentionally correct and matches upstream pnpm's `getScope` in `config/pick-registry-for-package/src/index.ts`. When bare_specifier is an npm: alias for an unscoped package (e.g., `npm:lodash@^1`), `scope_from_bare_specifier` returns `None`, and the fallthrough to `scope_of(pkg_name)` is correct behavior — allowing a scoped local name like `private/foo` to still route through the `private` registry. Do NOT suggest changing this to an early-return on `npm:` prefix, as that would break pnpm compatibility.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
📚 Learning: 2026-05-24T08:18:06.019Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11895
File: pnpm/test/deploy.ts:91-95
Timestamp: 2026-05-24T08:18:06.019Z
Learning: In the pnpm/pnpm repository, integration tests that hit the real `registry.npmjs.org` (e.g., for `pacquet` or `pnpm/pacquet`) do NOT use a runtime env-var gate (such as `PNPM_RUN_PUBLIC_REGISTRY_TESTS`). They simply pass `--config.registry=https://registry.npmjs.org/` directly to `execPnpm` and set a higher timeout. This is the established pattern, as seen in `pnpm/test/install/pacquet.ts` and `pnpm/test/deploy.ts`. Do not suggest adding env-var guards for these tests.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.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/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
📚 Learning: 2026-05-20T01:42:22.599Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11755
File: pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs:187-194
Timestamp: 2026-05-20T01:42:22.599Z
Learning: In `pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs`, the package-level `modified` shortcut for the maturity/minimumReleaseAge filter intentionally uses strict `<` (not `<=`) when comparing `modified_date < cutoff`. This mirrors pnpm's upstream behavior in `pickPackage.ts#L372` and `pickPackageFromMeta.ts#L47`. The reasoning: per-version `time[ver]` uses `<=` (a version published exactly at the cutoff is mature), but the package-level `modified` shortcut uses `<` because `modified == cutoff` means a version *might* have been published at that exact instant and the abbreviated metadata can't confirm it, so the safe path is to fall through to a full metadata fetch / MissingTime error. Do not suggest changing this to `<=`.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
📚 Learning: 2026-05-14T07:57:23.823Z
Learnt from: mandarini
Repo: pnpm/pnpm PR: 11622
File: resolving/npm-resolver/src/pickPackage.ts:183-221
Timestamp: 2026-05-14T07:57:23.823Z
Learning: In `resolving/npm-resolver/src/pickPackage.ts`, the error-fallback `catch` block (the `loadMeta(pkgMirror)` path that fires when the primary network fetch throws) intentionally does NOT call `maybeUpgradeAbbreviatedMetaForReleaseAge` or retry with `fullMetadata: true`. This is by design: the network is already known-iffy at that point, so an extra fetch would risk compounding the failure. The `ignoreMissingTimeField` warn-and-skip path is the accepted graceful degradation here.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.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/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs
  • pacquet/crates/package-manager/src/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.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 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/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.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/install.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/install.rs
  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.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/install.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/tests.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 : Prefer real fixtures over dependency-injection seams — use `tempfile::TempDir`, the mocked registry, or integration tests spawning the actual binary for happy paths and most error paths; use the DI seam only for filesystem error kinds, deterministic time, shared process-global state, or external-service happy paths

Applied to files:

  • pacquet/crates/package-manager/src/install/tests.rs
📚 Learning: 2026-05-20T01:52:55.764Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11755
File: pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs:193-200
Timestamp: 2026-05-20T01:52:55.764Z
Learning: In `pacquet/crates/resolving-npm-resolver/src/pick_package_from_meta.rs`, the package-level `modified` shortcut for the maturity/minimumReleaseAge filter uses inclusive `<=` (not strict `<`) when comparing `modified_date <= cutoff`. This mirrors the corrected behavior in pnpm (fixed in ab4c96ead5). The reasoning: `modified` is "last modification time," which is an upper bound on every version's `time[v]`. The per-version maturity filter uses `<=` (a version published exactly at the cutoff is mature). Since `modified == cutoff` means every version satisfies the per-version filter, the abbreviated-metadata fast path should accept this case rather than forcing a full-metadata re-fetch or raising `MissingTime`. The same fix was applied to pnpm TS: `pickPackage.ts` (×2) and `pickPackageFromMeta.ts`.

Applied to files:

  • pacquet/crates/package-manager/src/install/tests.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.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/install/tests.rs
  • pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs
  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.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/install_with_fresh_lockfile.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-05-20T23:07:40.413Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11783
File: pacquet/crates/engine-runtime-node-resolver/src/node_resolver.rs:167-191
Timestamp: 2026-05-20T23:07:40.413Z
Learning: In `pacquet/crates/engine-runtime-node-resolver/src/node_resolver.rs`, the offline guard in `resolve_impl` (NodeResolver) is intentionally absent from `resolve_latest_impl`. This mirrors upstream pnpm's behavior: `resolveNodeRuntime` checks offline, but `resolveLatestNodeRuntime` does not carry `offline` in its context and never checks it. The asymmetry is required so `pnpm outdated` / `pnpm update --latest` can still query for newer runtime versions even in offline mode.

Applied to files:

  • pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs
🔇 Additional comments (15)
pacquet/crates/package-manager/src/install_with_fresh_lockfile.rs (6)

389-395: LGTM!


1091-1102: LGTM!


1127-1132: LGTM!


1570-1582: LGTM!


1595-1600: LGTM!


1693-1718: LGTM!

pacquet/crates/package-manager/src/install.rs (4)

22-24: LGTM!


635-642: LGTM!


647-658: LGTM!


989-1000: LGTM!

pacquet/crates/resolving-resolver-base/src/verifier.rs (1)

92-98: LGTM!

pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions.rs (1)

248-257: LGTM!

pacquet/crates/lockfile-verification/src/verify_lockfile_resolutions/tests.rs (1)

405-450: LGTM!

pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier.rs (1)

230-241: LGTM!

Also applies to: 330-336

pacquet/crates/resolving-npm-resolver/src/create_npm_resolution_verifier/tests.rs (1)

202-204: LGTM!

Also applies to: 211-224

Comment thread pacquet/crates/package-manager/src/install/tests.rs Outdated
@github-actions

github-actions Bot commented Jun 7, 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 10.044 ± 0.131 9.933 10.313 1.85 ± 0.06
pacquet@main 9.972 ± 0.110 9.894 10.258 1.83 ± 0.05
pnpr@HEAD 5.450 ± 0.173 5.281 5.816 1.00 ± 0.04
pnpr@main 5.437 ± 0.149 5.315 5.833 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 10.04443392342,
      "stddev": 0.13057371701925558,
      "median": 9.99879675772,
      "user": 3.2285095399999997,
      "system": 3.34666126,
      "min": 9.933124399719999,
      "max": 10.31329441972,
      "times": [
        10.21513038072,
        10.080186871719999,
        9.97080260472,
        9.94776334672,
        10.07862344072,
        9.933124399719999,
        9.93762590972,
        9.940996949719999,
        10.31329441972,
        10.026790910719999
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 9.972022980819998,
      "stddev": 0.11005091182142002,
      "median": 9.94035644672,
      "user": 3.2141148399999997,
      "system": 3.27889256,
      "min": 9.89424418172,
      "max": 10.25750811072,
      "times": [
        10.25750811072,
        9.94734782172,
        9.933365071719999,
        9.96223047472,
        9.89424418172,
        9.95455191972,
        9.906693430719999,
        9.90060150972,
        9.913348272719999,
        10.050339014719999
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 5.44963923482,
      "stddev": 0.17317025747431025,
      "median": 5.372943659720001,
      "user": 2.6015327399999997,
      "system": 2.9199592599999997,
      "min": 5.281200413720001,
      "max": 5.81642322172,
      "times": [
        5.3837872327200005,
        5.81642322172,
        5.667680299720001,
        5.33679881072,
        5.47980616072,
        5.281200413720001,
        5.33837505372,
        5.36210008672,
        5.512682644720001,
        5.31753842372
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 5.43714026912,
      "stddev": 0.14937117728279198,
      "median": 5.39259740572,
      "user": 2.59320664,
      "system": 2.9693428600000003,
      "min": 5.31514858472,
      "max": 5.832777812720001,
      "times": [
        5.413382401720001,
        5.4325269377200005,
        5.32899620372,
        5.44847684372,
        5.3645806377200005,
        5.832777812720001,
        5.31514858472,
        5.37103624372,
        5.37181240972,
        5.492664615720001
      ]
    }
  ]
}

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

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 689.6 ± 9.9 677.4 704.6 1.00
pacquet@main 708.9 ± 78.7 657.3 916.8 1.03 ± 0.12
pnpr@HEAD 808.5 ± 71.7 768.9 1010.9 1.17 ± 0.11
pnpr@main 823.5 ± 68.4 778.0 1005.1 1.19 ± 0.10
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.6896054739800002,
      "stddev": 0.00989969313260735,
      "median": 0.68917746528,
      "user": 0.41477006000000005,
      "system": 1.33007896,
      "min": 0.6774443692800001,
      "max": 0.70456377128,
      "times": [
        0.69556018628,
        0.69733935828,
        0.68088480328,
        0.68784046928,
        0.68167357028,
        0.67846160028,
        0.7017721502800001,
        0.69051446128,
        0.70456377128,
        0.6774443692800001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.70885816098,
      "stddev": 0.07868342901127981,
      "median": 0.68087154928,
      "user": 0.38766016000000003,
      "system": 1.3442196599999998,
      "min": 0.6573197402800001,
      "max": 0.9168097202800001,
      "times": [
        0.67724707228,
        0.75670699428,
        0.6844960262800001,
        0.66850599828,
        0.6573197402800001,
        0.9168097202800001,
        0.70999060028,
        0.66651606628,
        0.68750966028,
        0.66347973128
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.8085306148800001,
      "stddev": 0.07169921366028294,
      "median": 0.78759441078,
      "user": 0.43152096,
      "system": 1.3378887599999998,
      "min": 0.7688898322800001,
      "max": 1.01088944328,
      "times": [
        0.7688898322800001,
        0.77416443128,
        1.01088944328,
        0.79388457828,
        0.78322973828,
        0.79387376928,
        0.78734602328,
        0.78513599228,
        0.80004954228,
        0.78784279828
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.8234825774799999,
      "stddev": 0.06840804387520827,
      "median": 0.80511067678,
      "user": 0.42590075999999993,
      "system": 1.3461081599999998,
      "min": 0.77803741228,
      "max": 1.00511847828,
      "times": [
        0.78164473028,
        0.80180803428,
        0.81327286428,
        1.00511847828,
        0.8272390202800001,
        0.77803741228,
        0.77962989928,
        0.85550125128,
        0.80841331928,
        0.78416076528
      ]
    }
  ]
}

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 9.391 ± 0.069 9.314 9.507 1.82 ± 0.05
pacquet@main 9.364 ± 0.038 9.299 9.420 1.82 ± 0.05
pnpr@HEAD 5.148 ± 0.135 5.037 5.474 1.00
pnpr@main 5.164 ± 0.156 5.043 5.550 1.00 ± 0.04
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 9.39142125326,
      "stddev": 0.06908615598191693,
      "median": 9.37850578926,
      "user": 3.8813801799999994,
      "system": 3.3388374799999996,
      "min": 9.313770483759999,
      "max": 9.506557900759999,
      "times": [
        9.506557900759999,
        9.42757307176,
        9.33273869276,
        9.410651379759999,
        9.460355822759999,
        9.34636019876,
        9.313770483759999,
        9.33448830976,
        9.32557004876,
        9.456146623759999
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 9.36383496736,
      "stddev": 0.03752016699771038,
      "median": 9.366790016259998,
      "user": 3.824329979999999,
      "system": 3.359758179999999,
      "min": 9.29929466776,
      "max": 9.41968622676,
      "times": [
        9.411820101759998,
        9.39047864576,
        9.41968622676,
        9.34276177976,
        9.29929466776,
        9.371477280759999,
        9.362102751759998,
        9.33238941676,
        9.33557584776,
        9.372762954759999
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 5.1482070578600005,
      "stddev": 0.13450297163055613,
      "median": 5.097471071759999,
      "user": 2.46200268,
      "system": 2.8098034800000002,
      "min": 5.03652660976,
      "max": 5.47432630676,
      "times": [
        5.07163599576,
        5.03652660976,
        5.07543898776,
        5.04517157976,
        5.08343419776,
        5.19458308876,
        5.12331568476,
        5.47432630676,
        5.26613018176,
        5.11150794576
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 5.16426474486,
      "stddev": 0.1564801101781496,
      "median": 5.09328403076,
      "user": 2.42520158,
      "system": 2.83605008,
      "min": 5.04328569376,
      "max": 5.55023737876,
      "times": [
        5.55023737876,
        5.08681260476,
        5.13659179476,
        5.08383510976,
        5.20624588176,
        5.04328569376,
        5.09975545676,
        5.30133839976,
        5.06631093476,
        5.06823419376
      ]
    }
  ]
}

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 1.486 ± 0.019 1.450 1.511 2.15 ± 0.06
pacquet@main 1.506 ± 0.026 1.468 1.551 2.18 ± 0.07
pnpr@HEAD 0.690 ± 0.018 0.666 0.729 1.00
pnpr@main 0.691 ± 0.008 0.682 0.706 1.00 ± 0.03
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 1.48567161044,
      "stddev": 0.019070977473760395,
      "median": 1.4913622314400001,
      "user": 1.6381340199999996,
      "system": 1.82601958,
      "min": 1.4496041384400002,
      "max": 1.5105789954400002,
      "times": [
        1.4701056644400001,
        1.4903302424400002,
        1.48547869544,
        1.5038228984400002,
        1.49300071644,
        1.49239422044,
        1.5105789954400002,
        1.46323267544,
        1.4496041384400002,
        1.4981678574400001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.50577320344,
      "stddev": 0.026417520363064887,
      "median": 1.50693700694,
      "user": 1.6491840199999999,
      "system": 1.81350878,
      "min": 1.46795798044,
      "max": 1.5511064544400002,
      "times": [
        1.5511064544400002,
        1.51204289044,
        1.47915634844,
        1.46795798044,
        1.5018311234400001,
        1.49464617344,
        1.5126686354400003,
        1.5311140574400002,
        1.5281972924400002,
        1.4790110784400001
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.68952086934,
      "stddev": 0.017854429434961735,
      "median": 0.68687961344,
      "user": 0.3633045199999999,
      "system": 1.27853418,
      "min": 0.66600160744,
      "max": 0.7292551984400001,
      "times": [
        0.68348484844,
        0.6902743784400001,
        0.66600160744,
        0.7292551984400001,
        0.68316773344,
        0.7054035174400001,
        0.67511150344,
        0.67647881144,
        0.69139067144,
        0.69464042344
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.6905289719400001,
      "stddev": 0.0075671317588099155,
      "median": 0.68966992794,
      "user": 0.3476141199999999,
      "system": 1.2929448799999999,
      "min": 0.6817696604400001,
      "max": 0.7055342384400001,
      "times": [
        0.6817696604400001,
        0.69115069244,
        0.68818916344,
        0.68261461444,
        0.6976466654400001,
        0.68733701944,
        0.69299502544,
        0.6829631514400001,
        0.7055342384400001,
        0.6950894884400001
      ]
    }
  ]
}

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 5.101 ± 0.030 5.044 5.137 7.52 ± 0.12
pacquet@main 5.100 ± 0.042 5.051 5.182 7.52 ± 0.13
pnpr@HEAD 0.678 ± 0.010 0.665 0.694 1.00
pnpr@main 0.709 ± 0.096 0.656 0.978 1.05 ± 0.14
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 5.10072105492,
      "stddev": 0.030019966196925506,
      "median": 5.10256794012,
      "user": 1.87275634,
      "system": 1.9562323400000001,
      "min": 5.0435198231200005,
      "max": 5.13728852812,
      "times": [
        5.07476162412,
        5.09973738812,
        5.1344958301200005,
        5.11246019812,
        5.09108042412,
        5.13728852812,
        5.13077388612,
        5.07769435512,
        5.0435198231200005,
        5.10539849212
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 5.100172701020001,
      "stddev": 0.04232462041248157,
      "median": 5.09998210062,
      "user": 1.8355810399999999,
      "system": 1.97773474,
      "min": 5.05094026512,
      "max": 5.18215121112,
      "times": [
        5.1279070001200004,
        5.06646029012,
        5.05182581812,
        5.05094026512,
        5.10434419012,
        5.18215121112,
        5.09562001112,
        5.06851649012,
        5.115638161120001,
        5.13832357312
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.6781437292200001,
      "stddev": 0.009799021249327963,
      "median": 0.6769756711200001,
      "user": 0.35339924,
      "system": 1.2826433400000004,
      "min": 0.6645628911200001,
      "max": 0.6940651251200001,
      "times": [
        0.6855584831200001,
        0.6695733651200001,
        0.6794382121200001,
        0.6684426371200001,
        0.67451313012,
        0.6851155391200001,
        0.6719376541200001,
        0.6940651251200001,
        0.6882302551200001,
        0.6645628911200001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.7091766822200001,
      "stddev": 0.09574876369979379,
      "median": 0.6800681926200001,
      "user": 0.34744983999999995,
      "system": 1.26904494,
      "min": 0.6557479311200001,
      "max": 0.9783973211200001,
      "times": [
        0.6557479311200001,
        0.6828460261200001,
        0.6772903591200001,
        0.7077028201200001,
        0.67246361212,
        0.6668197951200001,
        0.6893138091200001,
        0.9783973211200001,
        0.6927013101200001,
        0.6684838381200001
      ]
    }
  ]
}

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12260
Testbedpacquet

🚨 2 Alerts

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
isolated-linker.fresh-install.cold-cache.cold-storeLatency
seconds (s)
📈 plot
🚷 threshold
🚨 alert (🔔)
9.39 s
(+197.40%)Baseline: 3.16 s
3.79 s
(247.83%)

isolated-linker.fresh-restore.cold-cache.cold-storeLatency
seconds (s)
📈 plot
🚷 threshold
🚨 alert (🔔)
10.04 s
(+60.25%)Baseline: 6.27 s
7.52 s
(133.54%)

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 (🔔)
9,391.42 ms
(+197.40%)Baseline: 3,157.85 ms
3,789.42 ms
(247.83%)

isolated-linker.fresh-install.cold-cache.hot-store📈 view plot
🚷 view threshold
5,100.72 ms
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
🚷 view threshold
1,485.67 ms
(+11.43%)Baseline: 1,333.33 ms
1,599.99 ms
(92.85%)
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
🚷 view threshold
🚨 view alert (🔔)
10,044.43 ms
(+60.25%)Baseline: 6,267.90 ms
7,521.48 ms
(133.54%)

isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
🚷 view threshold
689.61 ms
(+0.45%)Baseline: 686.55 ms
823.86 ms
(83.70%)
🐰 View full continuous benchmarking report in Bencher

@zkochan zkochan merged commit 68ddaf9 into main Jun 7, 2026
26 of 28 checks passed
@zkochan zkochan deleted the codex/pacquet-verification-fast-path branch June 7, 2026 19:20
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