Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.

feat(package-manager): wire nodeLinker=hoisted into install pipeline (#438 slice 6)#518

Merged
zkochan merged 2 commits into
mainfrom
feat/438-slice-6
May 14, 2026
Merged

feat(package-manager): wire nodeLinker=hoisted into install pipeline (#438 slice 6)#518
zkochan merged 2 commits into
mainfrom
feat/438-slice-6

Conversation

@zkochan

@zkochan zkochan commented May 14, 2026

Copy link
Copy Markdown
Member

Summary

Slice 6 of #438. Plugs the existing slice 3-5 building blocks
(real-hoist, lockfile_to_hoisted_dep_graph, link_hoisted_modules)
into Install::run / InstallFrozenLockfile::run behind a branch on
config.node_linker == Hoisted. With this PR, pacquet install --frozen-lockfile --node-linker hoisted produces a real-directory
`node_modules/` tree rooted at the project (no symlinks, no virtual
store), and .modules.yaml.hoistedLocations is persisted so a
follow-up install or rebuild can locate every package.

Pipeline changes under hoisted

  • CreateVirtualStore skips CreateVirtualDirBySnapshot for both warm
    and cold batches, collects each snapshot's CAS file index keyed by
    PkgIdWithPatchHash into a new cas_paths_by_pkg_id output field.
  • InstallPackageBySnapshot::run now returns the per-package CAS map
    unconditionally and skips the virtual-store-slot write when its new
    node_linker field is Hoisted.
  • InstallFrozenLockfile::run skips SymlinkDirectDependencies,
    LinkVirtualStoreBins, the isolated hoist pass, and BuildModules
    under hoisted; runs lockfile_to_hoisted_dep_graph +
    link_hoisted_modules in their place. Folds the walker's augmented
    skip set back into the install-time SkippedSnapshots so
    .modules.yaml.skipped reflects the union of both passes.
  • Install::run's build_modules_manifest now takes the walker's
    hoisted_locations and writes it through
    Modules.hoisted_locations (only when non-empty so the isolated
    path doesn't produce a hoisted-only key).

Mirrors upstream's hoisted branch in headlessInstall at
https://github.com/pnpm/pnpm/blob/94240bc046/installing/deps-restorer/src/index.ts#L369-L425.

Out of scope (deferred to later slices)

  • Build phase under hoisted (slice 7). Rebuild over
    `hoistedLocations` directories with `extraBinPaths` gathered from
    every ancestor `node_modules/.bin`. `MISSING_HOISTED_LOCATIONS`
    also lives there. Today's PR skips `BuildModules` under hoisted so
    the install completes without trying to walk a virtual store that
    was never written.
  • Workspace-aware hoisting (slice 9). Single-importer only today —
    the walker rejects multi-importer lockfiles with
    `HoistError::UnsupportedWorkspace`.
  • `hoistingLimits` / `externalDependencies` (slice 10). Walker
    inputs default to empty.
  • `hoistedDependencies` (the alias-to-public/private adapter
    field).
    Left empty under hoisted because upstream's
    `linkHoistedModules` uses `hoistedLocations` directly; the
    isolated-mode adapter shape is unused under `nodeLinker: hoisted`
    and pacquet matches that.

Test plan

  • `just ready` (1211 tests pass; lint, fmt, typos clean)
  • `just dylint` (perfectionist) clean
  • `taplo format --check` clean
  • New wiring tests in `crates/package-manager/src/install/tests.rs`:
    • `hoisted_node_linker_empty_lockfile_writes_modules_yaml` — pins
      `Install::run` → `InstallFrozenLockfile::run` → walker → linker
      composition against an empty lockfile, asserts
      `.modules.yaml.nodeLinker == hoisted` and
      `hoisted_locations is None` (the field drops to `None` when empty).
    • `hoisted_node_linker_does_not_create_virtual_store_root` — pins
      that `/node_modules/.pacquet` is never created under
      hoisted.
  • Real-package end-to-end coverage against the registry-mock —
    `@pnpm.e2e/foo@100.0.0` style fixture with hand-written lockfile.
    Tracked as a follow-up; the existing slice 4 / slice 5 unit tests
    already cover the underlying components and the slice 7 build-phase
    retargeting will benefit from the same fixture.

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

Summary by CodeRabbit

  • New Features

    • Hoisted-mode install path supported with conditional link-time behavior and CAS path capture.
    • Persist hoisted installation location data into the modules manifest when applicable.
  • Refactor

    • Virtual-store materialization and build-step execution now vary by selected linker mode.
  • Tests

    • Added end-to-end tests for hoisted installs and unit tests ensuring manifest omits empty hoisted locations.

Review Change Stack

…#438 slice 6)

Branches `Install::run` / `InstallFrozenLockfile::run` on
`config.node_linker == Hoisted`. Threads the slice 4
`lockfile_to_hoisted_dep_graph` walker output and the per-package CAS
index produced by `CreateVirtualStore` (slot writes skipped under
hoisted) into the slice 5 `link_hoisted_modules` linker. Persists the
walker's `hoisted_locations` into `.modules.yaml` for rebuild and
follow-up installs to consume.

Pipeline changes under hoisted:
- `CreateVirtualStore` skips `CreateVirtualDirBySnapshot` for both warm
  and cold batches, collects each snapshot's CAS file index keyed by
  `PkgIdWithPatchHash` into a new `cas_paths_by_pkg_id` output field.
- `InstallPackageBySnapshot::run` returns the per-package CAS map
  unconditionally and skips the virtual-store-slot write when its new
  `node_linker` field is `Hoisted`.
- `InstallFrozenLockfile::run` skips `SymlinkDirectDependencies`,
  `LinkVirtualStoreBins`, the isolated hoist pass, and `BuildModules`
  under hoisted; runs `lockfile_to_hoisted_dep_graph` +
  `link_hoisted_modules` in their place. Folds the walker's augmented
  skip set back into the install-time `SkippedSnapshots` so
  `.modules.yaml.skipped` reflects the union.
- `Install::run`'s `build_modules_manifest` now takes the walker's
  `hoisted_locations` and writes it through `Modules.hoisted_locations`
  (only when non-empty so the isolated path doesn't produce a
  hoisted-only key).

The build phase under hoisted (rebuild over `hoistedLocations` with
ancestor-`.bin` lookup, `MISSING_HOISTED_LOCATIONS`) is slice 7's
scope and is intentionally left as a no-op here. Workspace and
`hoistingLimits` / `externalDependencies` knobs are slices 9-10.

Mirrors upstream's hoisted branch in `headlessInstall` at
https://github.com/pnpm/pnpm/blob/94240bc046/installing/deps-restorer/src/index.ts#L369-L425.

---
Written by an agent (Claude Code, claude-opus-4-7).
Copilot AI review requested due to automatic review settings May 14, 2026 05:22
@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown

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: dac356ba-6e54-40ac-937a-45abef6e1baf

📥 Commits

Reviewing files that changed from the base of the PR and between 8a58a81 and 87efe16.

📒 Files selected for processing (4)
  • crates/package-manager/src/create_virtual_store.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/install_frozen_lockfile.rs
  • crates/package-manager/src/install_package_by_snapshot.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/package-manager/src/install_package_by_snapshot.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/install_frozen_lockfile.rs
  • crates/package-manager/src/create_virtual_store.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). (5)
  • GitHub Check: Code Coverage
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Lint and Test (ubuntu-latest)

📝 Walkthrough

Walkthrough

The PR threads NodeLinker configuration (hoisted vs isolated) through the frozen-lockfile install pipeline, enabling hoisted-mode installs to build and return a CAS paths index instead of materializing virtual-store slots, while isolated mode retains existing slot-driven behavior. Hoisted-mode installs branch to run hoisted linker workflows and persist hoisted_locations to .modules.yaml.

Changes

Hoisted node-linker install flow

Layer / File(s) Summary
CAS paths index creation in CreateVirtualStore
crates/package-manager/src/create_virtual_store.rs
CreateVirtualStore now accepts node_linker and conditionally builds a hoisted-only CAS paths index from warm and cold snapshots' CAS-write results, returning it in CreateVirtualStoreOutput::cas_paths_by_pkg_id. Isolated mode leaves it None. Warm batch skips slot materialization in hoisted mode but still emits progress events.
InstallPackageBySnapshot CAS paths return type
crates/package-manager/src/install_package_by_snapshot.rs
InstallPackageBySnapshot now accepts node_linker and changes its return type from () to HashMap<String, PathBuf> of CAS paths. For isolated/Pnp modes it materializes virtual directory then returns CAS paths; for hoisted mode it skips virtual-dir creation and returns CAS paths directly.
InstallFrozenLockfile hoisted and isolated linker paths
crates/package-manager/src/install_frozen_lockfile.rs
InstallFrozenLockfile now accepts node_linker, lockfile, and current_lockfile. During run, it branches between hoisted-linker flow (materializes hoisted dep-graph, links hoisted modules, records hoisted_locations, skips BuildModules) and isolated-linker flow (runs symlink/bin-linking and BuildModules as before). Hoisted path consumes cas_paths_by_pkg_id from CreateVirtualStore.
Modules manifest persistence with hoisted_locations
crates/package-manager/src/install.rs
Frozen-lockfile install dispatch returns hoisted_locations alongside hoisted_dependencies and skipped; non-frozen path initializes empty hoisted_locations. build_modules_manifest signature accepts hoisted_locations parameter and persists it to Modules only when non-empty. Documentation updated for new field meaning and persistence behavior.
Unit and end-to-end test updates
crates/package-manager/src/install/tests.rs
Updated build_modules_manifest call sites with new parameter signature. Expanded empty-skipped test to assert hoisted_locations is None. Added two new hoisted-mode e2e tests validating .modules.yaml contains node_linker: Hoisted with correct hoisted fields and verifying hoisted installs do not materialize node_modules/.pacquet virtual-store root.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • pnpm/pacquet#505: Related hoisted-mode CAS-path plumbing and link_hoisted_modules integration.
  • pnpm/pacquet#491: Changes to lockfile_to_hoisted_dep_graph options/skipped behavior used by this PR.
  • pnpm/pacquet#423: Related edits to CreateVirtualStore outputs and build/hoist interactions.

Poem

🐰 I hopped through snapshots, CAS in paw,
Threaded linkers without a flaw,
Hoisted paths gathered, slots left light,
Manifests updated, tidy and bright.
A little rabbit did the install dance—hip hip hooray!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: wiring the hoisted node linker mode into the install pipeline, with appropriate context (slice 6 of #438).
Description check ✅ Passed The PR description comprehensively covers the summary, upstream reference, scope/deferral, test plan, and implementation details, following the template structure.
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 feat/438-slice-6

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@codecov

codecov Bot commented May 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.67797% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.54%. Comparing base (8fa7251) to head (87efe16).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
crates/package-manager/src/create_virtual_store.rs 72.97% 10 Missing ⚠️
crates/package-manager/src/install.rs 90.42% 9 Missing ⚠️
...tes/package-manager/src/install_frozen_lockfile.rs 96.62% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #518      +/-   ##
==========================================
- Coverage   88.63%   88.54%   -0.10%     
==========================================
  Files         125      125              
  Lines       13688    13821     +133     
==========================================
+ Hits        12133    12238     +105     
- Misses       1555     1583      +28     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented May 14, 2026

Copy link
Copy Markdown

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.00      5.0±0.33ms   865.4 KB/sec    1.06      5.3±0.14ms   813.2 KB/sec

@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 `@crates/package-manager/src/install_frozen_lockfile.rs`:
- Around line 659-665: The current merge builds walker_skipped from the input
skipped set and then later treats walker_result.skipped as authoritative, which
can cause transient reasons (e.g., "optional_excluded", "fetch_failed") from
walker_result.skipped to be persisted into .modules.yaml.skipped; fix by
filtering out transient skip reasons before merging/constructing the BTreeSet
used for LockfileToHoistedDepGraphOptions (the variable walker_skipped) or
before writing persisted skips so only permanent skip reasons remain;
specifically, when using walker_result.skipped and when creating
LockfileToHoistedDepGraphOptions::skipped, exclude entries whose reason is
optional_excluded or fetch_failed so they are not converted into installability
skips.
🪄 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: a5b2869e-ea22-449a-8c92-caaf71fe8f91

📥 Commits

Reviewing files that changed from the base of the PR and between 2e39c13 and 8a58a81.

📒 Files selected for processing (5)
  • crates/package-manager/src/create_virtual_store.rs
  • crates/package-manager/src/install.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/install_frozen_lockfile.rs
  • crates/package-manager/src/install_package_by_snapshot.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). (6)
  • GitHub Check: copilot-pull-request-reviewer
  • GitHub Check: Code Coverage
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Lint and Test (ubuntu-latest)
  • GitHub Check: Run benchmark on ubuntu-latest
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Preserve existing method chains and pipe-trait chains; do not break them into intermediate let bindings unless there is a concrete justification such as a compilation failure, borrow checker rejection, meaningful performance improvement, or other technical necessity. Refactoring for style alone is not sufficient justification.
Choose owned vs. borrowed parameters to minimize copies; prefer borrowed types (&Path over &PathBuf, &str over &String) when it does not force extra copies.
Prefer Arc::clone(&x) and Rc::clone(&x) over x.clone() for reference-counted types to make the cost visible at the call site.
Do not use star imports inside module bodies. Write use super::{Foo, bar} instead of use super::*; for any glob whose target is a module you control. External-crate preludes (e.g., use rayon::prelude::*;) and root-of-module re-exports (e.g., pub use submodule::*; in lib.rs) are exceptions.
Follow Rust API Guidelines for naming, as documented in https://rust-lang.github.io/api-guidelines/naming.html.
Declare a newtype wrapper for any branded string type being ported from TypeScript pnpm. Do not collapse the brand into a plain String or &str; give the type its own struct so misuse is a type error.
When porting branded string types where upstream TypeScript always validates before construction, validate in the Rust port too. Construct the wrapper only via TryFrom<String> and/or FromStr; do not provide an infallible public constructor that takes an arbitrary string.
For branded string types where upstream TypeScript never validates (used purely for type-safety to prevent confusion between string slots), expose an infallible From<String> and From<&str> constructor in the Rust wrapper.
When upstream TypeScript occasionally constructs a branded type without validation (via bare as assertion), add a from_str_unchecked (or similarly named) constructor on the Rust side. Keep the validating constructor as well; `from_str_u...

Files:

  • crates/package-manager/src/install_package_by_snapshot.rs
  • crates/package-manager/src/install.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/create_virtual_store.rs
  • crates/package-manager/src/install_frozen_lockfile.rs
🧠 Learnings (5)
📚 Learning: 2026-05-07T23:19:08.272Z
Learnt from: KSXGitHub
Repo: pnpm/pacquet PR: 401
File: tasks/integrated-benchmark/src/work_env.rs:343-344
Timestamp: 2026-05-07T23:19:08.272Z
Learning: When reviewing Rust code in pnpm/pacquet for deprecated API usage, do not automatically treat `serde_saphyr::to_string` as deprecated. In `serde-saphyr` v0.0.25, `serde_saphyr::to_string` has no `#[deprecated]` attribute (the `#[deprecated]` later in `serde-saphyr-0.0.25/src/lib.rs` applies to a different function). Only flag `serde_saphyr::to_string` as deprecated if the resolved dependency version’s source shows `#[deprecated]` on that specific function.

Applied to files:

  • crates/package-manager/src/install_package_by_snapshot.rs
  • crates/package-manager/src/install.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/create_virtual_store.rs
  • crates/package-manager/src/install_frozen_lockfile.rs
📚 Learning: 2026-05-13T22:52:32.579Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 506
File: crates/package-manager/src/link_bins.rs:238-241
Timestamp: 2026-05-13T22:52:32.579Z
Learning: In Rust code using `matches!` (or `match`) on a borrowed value (e.g., `meta: &PackageMetadata` and a field access like `meta.resolution`), it is safe to use wildcard/OR patterns such as `LockfileResolution::Binary(_) | LockfileResolution::Variations(_)` when the pattern does not bind the inner payload by value. `_` wildcard patterns (and similar discriminant-only patterns) should not move non-`Copy` data; they only test the variant and avoid ownership transfer. Do not flag these patterns as move-out-of-borrow/ownership compile errors. Only patterns that bind the inner value by value (e.g., `LockfileResolution::Binary(b)`) would require ownership and may trigger move errors when matching on data behind a borrow.

Applied to files:

  • crates/package-manager/src/install_package_by_snapshot.rs
  • crates/package-manager/src/install.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/create_virtual_store.rs
  • crates/package-manager/src/install_frozen_lockfile.rs
📚 Learning: 2026-05-13T19:22:48.951Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 478
File: crates/package-manager/src/hoisted_dep_graph.rs:51-55
Timestamp: 2026-05-13T19:22:48.951Z
Learning: When reviewing this Rust codebase, avoid introducing/using a newtype like `PkgIdWithPatchHash` in only one module (e.g., `hoisted_dep_graph.rs`) if other related pacquet modules still represent the upstream pnpm “pkg id with patch hash” as a plain `String` (e.g., `virtual_store_layout`). For type consistency, either keep `pkg_id_with_patch_hash` as `String` here, or require a workspace-wide sweep that defines/extracts the `PkgIdWithPatchHash` newtype once and updates all call sites together (otherwise defer the refactor to a coordinated follow-up PR).

Applied to files:

  • crates/package-manager/src/install_package_by_snapshot.rs
  • crates/package-manager/src/install.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/create_virtual_store.rs
  • crates/package-manager/src/install_frozen_lockfile.rs
📚 Learning: 2026-05-13T20:09:22.171Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 486
File: crates/package-manager/src/hoisted_dep_graph.rs:472-476
Timestamp: 2026-05-13T20:09:22.171Z
Learning: In pnpm/pacquet, when generating serialized `hoisted_locations` strings (used for `.modules.yaml`), normalize path separators to forward slashes (e.g., replace `\\` with `/`). This preserves cross-platform portability: the output must not use OS-native separators because upstream pnpm’s `path.relative` can return platform-specific separators, which would break consistency with pnpm/pacquet’s other serialized formats on Windows.

Applied to files:

  • crates/package-manager/src/install_package_by_snapshot.rs
  • crates/package-manager/src/install.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/create_virtual_store.rs
  • crates/package-manager/src/install_frozen_lockfile.rs
📚 Learning: 2026-05-01T10:01:33.766Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 349
File: crates/reporter/src/tests.rs:121-121
Timestamp: 2026-05-01T10:01:33.766Z
Learning: In Rust test code, follow the repo’s CODE_STYLE_GUIDE test-logging rule: add logging (e.g., `eprintln!`/`eprintln!(...)`) so that useful diagnostic values are printed when a test fails, unless the assertion is `assert_eq!` (where the differing values are already included). Concretely, if you use assertions like `assert!`, `assert_ne!`, etc., ensure the test logs the relevant actual/expected values (or context) before/around the assertion so failures can be diagnosed without rerunning.

Applied to files:

  • crates/package-manager/src/install/tests.rs
🔇 Additional comments (4)
crates/package-manager/src/install_package_by_snapshot.rs (1)

7-7: LGTM!

Also applies to: 71-83, 172-189, 417-442

crates/package-manager/src/install/tests.rs (1)

1619-1620: LGTM!

Also applies to: 1655-1662, 2236-2395

crates/package-manager/src/install.rs (1)

272-286: LGTM!

Also applies to: 416-441, 467-468, 537-583

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

2-2: LGTM!

Also applies to: 8-12, 83-96, 142-153, 195-209, 595-610, 613-675, 680-704, 728-738, 780-828

Comment thread crates/package-manager/src/install_frozen_lockfile.rs
@github-actions

github-actions Bot commented May 14, 2026

Copy link
Copy Markdown

Integrated-Benchmark Report (Linux)

Scenario: Frozen Lockfile

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.676 ± 0.104 2.544 2.820 1.03 ± 0.05
pacquet@main 2.586 ± 0.058 2.493 2.655 1.00
pnpm 6.107 ± 0.068 6.018 6.197 2.36 ± 0.06
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.6757123685199997,
      "stddev": 0.10439504425899129,
      "median": 2.6660590469199996,
      "user": 2.51531108,
      "system": 3.68613202,
      "min": 2.5440634159199997,
      "max": 2.82026797292,
      "times": [
        2.82026797292,
        2.61920904592,
        2.6210863279199996,
        2.55359198692,
        2.7110317659199996,
        2.5800648949199996,
        2.8067744279199998,
        2.5440634159199997,
        2.7516428029199997,
        2.7493910439199998
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.58594273882,
      "stddev": 0.05800137490785645,
      "median": 2.6068402754199997,
      "user": 2.5034626799999997,
      "system": 3.6997058200000006,
      "min": 2.4928675719199997,
      "max": 2.65535602692,
      "times": [
        2.55336780792,
        2.60399407292,
        2.6113303549199998,
        2.4928675719199997,
        2.60968647792,
        2.5069560429199997,
        2.6277988779199997,
        2.5448718149199996,
        2.65535602692,
        2.65319833992
      ]
    },
    {
      "command": "pnpm",
      "mean": 6.10738941072,
      "stddev": 0.06790402252270009,
      "median": 6.11768931942,
      "user": 8.968919679999997,
      "system": 4.50621452,
      "min": 6.0180670869199995,
      "max": 6.19736492792,
      "times": [
        6.1358553879199995,
        6.03067586192,
        6.05841268692,
        6.18757311492,
        6.09952325092,
        6.15811457592,
        6.0180670869199995,
        6.03534962292,
        6.15295759092,
        6.19736492792
      ]
    }
  ]
}

Scenario: Frozen Lockfile (Hot Cache)

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 738.3 ± 92.0 679.2 996.6 1.00
pacquet@main 778.4 ± 83.2 698.8 966.8 1.05 ± 0.17
pnpm 2631.1 ± 84.0 2514.2 2759.7 3.56 ± 0.46
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.73829334236,
      "stddev": 0.09203601723973015,
      "median": 0.7182277557600001,
      "user": 0.36683547999999994,
      "system": 1.5799856,
      "min": 0.67921881176,
      "max": 0.99660775576,
      "times": [
        0.99660775576,
        0.7220001837600001,
        0.70625644176,
        0.7235919617600001,
        0.72502995776,
        0.7164458477600001,
        0.6899956017600001,
        0.67921881176,
        0.70377719776,
        0.7200096637600001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.7784179336600001,
      "stddev": 0.0831737183982484,
      "median": 0.7580507487600001,
      "user": 0.37433668,
      "system": 1.6249027999999999,
      "min": 0.6987573917600001,
      "max": 0.9667860907600001,
      "times": [
        0.8562771987600001,
        0.74642342776,
        0.7092579317600001,
        0.81140169376,
        0.71760870676,
        0.71857880576,
        0.6987573917600001,
        0.9667860907600001,
        0.78941001976,
        0.7696780697600001
      ]
    },
    {
      "command": "pnpm",
      "mean": 2.63113542766,
      "stddev": 0.08401649749469109,
      "median": 2.64256537876,
      "user": 3.1752179799999993,
      "system": 2.240551,
      "min": 2.51419482976,
      "max": 2.75972548476,
      "times": [
        2.51419482976,
        2.66505559576,
        2.66106119676,
        2.75972548476,
        2.55877919976,
        2.57929591376,
        2.70831184076,
        2.5279256557600003,
        2.62406956076,
        2.71293499876
      ]
    }
  ]
}

… fix (#438 slice 6)

Docs CI was failing because `[`crate::link_hoisted_modules`]` is
ambiguous between the function and the module of the same name.
Disambiguate by switching to the function form
`[`crate::link_hoisted_modules()`]` everywhere.

Slice 6's hoisted-walker skip-set merge previously folded every entry
in `walker_result.skipped` into `SkippedSnapshots::insert_installability`,
which would promote pre-existing transient skips
(`fetch_failed` / `optional_excluded`) into the persisted-on-disk
`.modules.yaml.skipped` set. Diff against the input `walker_skipped`
so only walker-discovered (genuinely-new) installability skips flow
into the persisted subset.
@zkochan zkochan merged commit fe27251 into main May 14, 2026
14 of 16 checks passed
@zkochan zkochan deleted the feat/438-slice-6 branch May 14, 2026 06:16
@zkochan zkochan mentioned this pull request May 14, 2026
59 tasks
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants