Skip to content

fix: detect enableGlobalVirtualStore toggle in workspace state check#12147

Merged
zkochan merged 3 commits into
pnpm:mainfrom
aqeelat:fix/issue-12142/gvs-toggle-detection
Jun 8, 2026
Merged

fix: detect enableGlobalVirtualStore toggle in workspace state check#12147
zkochan merged 3 commits into
pnpm:mainfrom
aqeelat:fix/issue-12142/gvs-toggle-detection

Conversation

@aqeelat

@aqeelat aqeelat commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Problem

Closes #12142

Toggling enableGlobalVirtualStore off in pnpm-workspace.yaml has no effect — pnpm install prints "Already up to date" without reinstalling dependencies in the new virtual store location (node_modules/.pnpm instead of <storeDir>/links).

Root cause

enableGlobalVirtualStore was missing from WORKSPACE_STATE_SETTING_KEYS in workspace/state/src/types.ts. The optimisticRepeatInstall fast path (checkDepsStatus) runs before mutateModules and compares stored workspace state settings against current config. Since the GVS toggle was never recorded, the comparison found nothing changed and short-circuited — bypassing validateModulescheckCompatibility which would have detected the virtualStoreDir mismatch.

Fix

  • Add 'enableGlobalVirtualStore' to WORKSPACE_STATE_SETTING_KEYS so checkDepsStatus records and compares it, returning upToDate: false when it changes and allowing the full mutateModules path (virtualStoreDir compatibility check + purge) to run.
  • Bidirectional settings comparison in checkDepsStatus: iterate the full WORKSPACE_STATE_SETTING_KEYS list instead of only the keys present in the recorded state. A key absent from an older state file (written before it was tracked) is now read as undefined and compared against the live config, so a toggle is detected even on legacy state files. This also folds the former allowBuilds null special-case into the loop via ?? {} coercion.

pacquet parity

The bidirectional comparison tightens the pnpm↔pacquet workspace-state contract. pacquet writes .pnpm-workspace-state-v1.json too; with the all-keys loop, pnpm now reads any key pacquet omits as undefined and compares it against pnpm's resolved config. Every key pnpm resolves to a concrete default that pacquet omitted therefore shows up as drift after a pacquet install, costing pnpm the optimistic fast path on every command (it falls through to a normal, idempotent install — a perf regression, not a destructive reinstall).

Verified against an isolated config-reader run (the dev machine's global pnpm config otherwise pollutes the defaults), the concrete-default keys pacquet was omitting are excludeLinksFromLockfile (false), minimumReleaseAge (1440), and minimumReleaseAgeIgnoreMissingTime (true). enableGlobalVirtualStore is undefined by default (concrete only under --global/CI). The rest (minimumReleaseAgeStrict/Exclude, trustPolicy*) stay undefined, so omitting them still matches.

Ported to pacquet (current_settings + settings_match in optimistic_repeat_install.rs, fields in workspace-state):

  • Write and compare excludeLinksFromLockfile, minimumReleaseAge (the raw config value, not the Some(0)-disabled resolution), and minimumReleaseAgeIgnoreMissingTime — pacquet already resolves all three to pnpm's exact defaults, and consumes them (lockfile content / resolution verifier), so comparing them is correct, not spurious.
  • Track enableGlobalVirtualStore: write Some(true) only when on and omit when off (matching pnpm's undefined default); settings_match coerces None/Some(false) as equal (same pattern as the existing allow_builds/package_extensions handling). This also fixes pacquet's own copy of the bug — the toggle was invisible to its freshness check.

Remaining narrow gaps (documented in the carve-out comment, not fixed here): workspacePackagePatterns is concrete for multi-package workspaces but lives in the workspace manifest rather than Config, so threading it into current_settings is a follow-up; minimumReleaseAgeStrict is only concrete when the user explicitly sets minimumReleaseAge.

Test plan

  • New checkDepsStatus unit tests: upToDate: false when enableGlobalVirtualStore is toggled off, and when toggled on from a legacy state file lacking the key
  • All existing checkDepsStatus tests pass (13/13); @pnpm/workspace.state tests pass (9/9)
  • New pacquet drift tests for excludeLinksFromLockfile, minimumReleaseAge, minimumReleaseAgeIgnoreMissingTime, and enableGlobalVirtualStore; plus a pnpm-CI-written false staying up-to-date against a pacquet off-install
  • pacquet optimistic_repeat_install + workspace-state tests pass (29 run); cargo check/clippy --deny warnings/fmt/doc clean
  • Lint and compile pass

Written by an agent (opencode, glm-5.1).

The bidirectional comparison and pacquet port were added by an agent (Claude Code, claude-opus-4-8).

Summary by CodeRabbit

  • Bug Fixes

    • Workspace-state checks now correctly respect the enableGlobalVirtualStore toggle, preventing false "out-of-date" reports.
  • Tests

    • Added tests covering enableGlobalVirtualStore present, absent, and mismatched saved state scenarios.
  • Documentation

    • Clarified workspace-state compatibility and how omitted vs. disabled settings are normalized during freshness checks.
  • Chores

    • Recorded release metadata and version bumps.

Copilot AI review requested due to automatic review settings June 2, 2026 16:53
@aqeelat aqeelat requested a review from zkochan as a code owner June 2, 2026 16:53
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: f7184bc7-08ed-4229-8a0d-f3fbb4ffc7dd

📥 Commits

Reviewing files that changed from the base of the PR and between bf4aa25 and 54ac9a3.

📒 Files selected for processing (3)
  • pacquet/crates/package-manager/src/optimistic_repeat_install.rs
  • pacquet/crates/package-manager/src/optimistic_repeat_install/tests.rs
  • pacquet/crates/workspace-state/src/lib.rs
✅ Files skipped from review due to trivial changes (1)
  • pacquet/crates/workspace-state/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • pacquet/crates/package-manager/src/optimistic_repeat_install.rs
  • pacquet/crates/package-manager/src/optimistic_repeat_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). (7)
  • GitHub Check: Compile & Lint
  • GitHub Check: Lint and Test (ubuntu-latest)
  • GitHub Check: Lint and Test (macos-latest)
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Code Coverage

📝 Walkthrough

Walkthrough

Adds 'enableGlobalVirtualStore' to workspace state keys, updates checkDepsStatus to compare declared workspace settings, normalizes the new key in pacquet optimistic-repeat-install (treating omitted and explicit false as equivalent), adds tests, and includes a changeset documenting the change.

Changes

Workspace State Setting Tracking

Layer / File(s) Summary
Workspace state setting contract
workspace/state/src/types.ts
WORKSPACE_STATE_SETTING_KEYS gains 'enableGlobalVirtualStore', extending persisted workspace settings.
Dependency-status comparison logic
deps/status/src/checkDepsStatus.ts
checkDepsStatus now iterates WORKSPACE_STATE_SETTING_KEYS, skips ignored keys, handles allowBuilds specially, and reports an issue when any tracked setting (including enableGlobalVirtualStore) differs.
Deps tests and changeset
deps/status/test/checkDepsStatus.test.ts, .changeset/gvs-toggle-detection.md
Adds tests covering toggling enableGlobalVirtualStore (including legacy missing-key case), updates a mocked patchedDependencies entry, and adds a changeset documenting the fix for #12142.
Pacquet optimistic-repeat-install normalization and tests
pacquet/crates/package-manager/src/optimistic_repeat_install.rs, pacquet/crates/package-manager/src/optimistic_repeat_install/tests.rs, pacquet/crates/workspace-state/src/lib.rs
Normalize enable_global_virtual_store in the fast-path settings matcher and writer (treat omitted and explicit false as equivalent), add tests for drift and explicit-false equivalence, and refine docs explaining omission semantics.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • pnpm/pnpm#11943: Prior changes to optimistic-repeat-install fast-path that this normalization builds upon.
  • pnpm/pnpm#12005: Modifies pacquet optimistic-repeat-install settings comparison logic in a similar area.
  • pnpm/pnpm#12032: Related optimistic-repeat-install workspace-state freshness adjustments for a different setting.

Suggested reviewers

  • zkochan

Poem

🐇 I found a hidden toggle in the hay,
I nudged the keys and tests awake today,
When GVS flips, reinstalls will start,
No more "up to date" that skips the part,
Hooray — dependency hops that play!

🚥 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 directly summarizes the main change: adding detection of the enableGlobalVirtualStore toggle to workspace state checking.
Linked Issues check ✅ Passed The PR fully addresses issue #12142 by adding enableGlobalVirtualStore to WORKSPACE_STATE_SETTING_KEYS, updating checkDepsStatus comparison logic, and ensuring the toggle is detected across pnpm and pacquet.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing enableGlobalVirtualStore toggle detection in workspace state. Documentation updates align with the implementation changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Detect enableGlobalVirtualStore toggle in workspace state check

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Add enableGlobalVirtualStore to workspace state settings detection
• Ensures toggle changes trigger full dependency validation
• Prevents "Already up to date" when virtual store location changes
• Includes unit test for toggle detection scenario
Diagram
flowchart LR
  A["enableGlobalVirtualStore toggle"] --> B["Added to WORKSPACE_STATE_SETTING_KEYS"]
  B --> C["checkDepsStatus detects change"]
  C --> D["upToDate returns false"]
  D --> E["Full mutateModules path runs"]
  E --> F["virtualStoreDir compatibility check executes"]

Loading

Grey Divider

File Changes

1. workspace/state/src/types.ts 🐞 Bug fix +1/-0

Add enableGlobalVirtualStore to state settings keys

• Added 'enableGlobalVirtualStore' to WORKSPACE_STATE_SETTING_KEYS array
• Enables workspace state comparison to detect toggle changes
• Placed first in the settings keys list for priority detection

workspace/state/src/types.ts


2. deps/status/test/checkDepsStatus.test.ts 🧪 Tests +30/-0

Add test for enableGlobalVirtualStore toggle detection

• Added new test case for enableGlobalVirtualStore toggle detection
• Tests scenario where toggle is changed from true to false
• Verifies upToDate returns false and correct issue message
• Validates that setting change is properly detected by checkDepsStatus

deps/status/test/checkDepsStatus.test.ts


3. .changeset/gvs-toggle-detection.md 📝 Documentation +7/-0

Add changeset for GVS toggle detection fix

• Created changeset entry documenting the bug fix
• Marks patches for @pnpm/workspace.state, @pnpm/deps.status, and pnpm
• References issue #12142 in changelog

.changeset/gvs-toggle-detection.md


Grey Divider

Qodo Logo

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.

Pull request overview

This PR fixes a missed workspace-state setting comparison so pnpm install doesn’t incorrectly take the optimisticRepeatInstall “Already up to date” fast path after toggling enableGlobalVirtualStore, ensuring the full install path runs and can validate/purge for the new virtual store location.

Changes:

  • Add enableGlobalVirtualStore to WORKSPACE_STATE_SETTING_KEYS so it’s persisted and compared during checkDepsStatus.
  • Add a unit test asserting checkDepsStatus returns upToDate: false when enableGlobalVirtualStore changes.
  • Add a changeset to ship patch releases for affected packages.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
workspace/state/src/types.ts Record enableGlobalVirtualStore in persisted workspace state settings so status checks can detect toggles.
deps/status/test/checkDepsStatus.test.ts Add coverage for checkDepsStatus detecting enableGlobalVirtualStore changes.
.changeset/gvs-toggle-detection.md Publish patch changes for workspace state + deps status + pnpm.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread workspace/state/src/types.ts
aqeelat added 2 commits June 8, 2026 15:05
…npm#12142)

The optimisticRepeatInstall fast path bypasses validateModules entirely,
so toggling enableGlobalVirtualStore off was not detected — pnpm printed
"Already up to date" without reinstalling deps in the new virtual store
location.

Add enableGlobalVirtualStore to WORKSPACE_STATE_SETTING_KEYS so
checkDepsStatus detects the change and falls through to the full
mutateModules path (which includes the virtualStoreDir compatibility
check and purge).
Iterate over WORKSPACE_STATE_SETTING_KEYS instead of
Object.entries(workspaceState.settings) so that settings absent from
legacy state files (e.g. enableGlobalVirtualStore) are still compared
against the current config. Removes the ad-hoc allowBuilds null-check
block since the main loop now covers it with the ?? {} coalescing.
@zkochan zkochan force-pushed the fix/issue-12142/gvs-toggle-detection branch from 1737198 to 20f9362 Compare June 8, 2026 13:09
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 8, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0)

Grey Divider


Remediation recommended

1. Pacquet omits workspace patterns 🐞 Bug ➹ Performance
Description
checkDepsStatus now compares every key in WORKSPACE_STATE_SETTING_KEYS, so any key missing from
the saved state is treated as undefined and compared against pnpm's live config. pacquet’s
workspace-state writer does not populate workspacePackagePatterns, so pnpm runs after a pacquet
install in a workspace will see drift (undefined vs a concrete patterns array) and skip the fast
path unnecessarily.
Code

deps/status/src/checkDepsStatus.ts[R138-146]

+    for (const settingName of WORKSPACE_STATE_SETTING_KEYS) {
     if (ignoredSettings.has(settingName as keyof WorkspaceStateSettings)) continue
-      const currentSettingValue = settingName === 'allowBuilds'
+      const storedValue = settingName === 'allowBuilds'
+        ? workspaceState.settings[settingName] ?? {}
+        : workspaceState.settings[settingName as keyof WorkspaceStateSettings]
+      const currentValue = settingName === 'allowBuilds'
       ? opts.allowBuilds ?? {}
       : opts[settingName as keyof WorkspaceStateSettings]
-      if (!equals(settingValue, currentSettingValue)) {
+      if (!equals(storedValue, currentValue)) {
Evidence
The PR changes pnpm to compare all workspace-state setting keys (not just those present in the
file). Since workspacePackagePatterns is among those keys and pnpm resolves it to a concrete array
for workspaces, a pacquet-written state that omits it will compare as undefined vs a concrete
array and be considered stale. pacquet’s writer uses current_settings, which does not set
workspace_package_patterns even though the wire type supports it.

deps/status/src/checkDepsStatus.ts[135-153]
workspace/state/src/types.ts[18-56]
config/reader/src/index.ts[420-424]
pacquet/crates/package-manager/src/install.rs[1629-1663]
pacquet/crates/package-manager/src/optimistic_repeat_install.rs[299-355]
pacquet/crates/workspace-state/src/lib.rs[160-168]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
pnpm now iterates the full `WORKSPACE_STATE_SETTING_KEYS` list during freshness checks, so pacquet must serialize any key that pnpm resolves to a concrete (non-`undefined`) value. `workspacePackagePatterns` is such a key in workspaces, but pacquet’s `current_settings` (and thus its workspace-state writer) does not populate it, causing pnpm to report drift after pacquet installs.
## Issue Context
- pnpm resolves `workspacePackagePatterns` for workspaces (from CLI override or `pnpm-workspace.yaml`, defaulting to `["."]`).
- pacquet already has a `workspace_package_patterns` field in its `WorkspaceStateSettings` wire type, but doesn’t set it when writing state.
## Fix Focus Areas
- pacquet/crates/package-manager/src/optimistic_repeat_install.rs[299-355]
- pacquet/crates/package-manager/src/install.rs[1629-1663]
Suggested implementation direction:
- Thread the workspace package patterns (the same list used for workspace project discovery) into `build_workspace_state` and/or `current_settings`.
- Set `workspace_package_patterns: Some(patterns.clone())` in the `WorkspaceStateSettings` struct so pnpm’s all-keys comparison sees equality.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Pacquet omits GVS=false state ✓ Resolved 🐞 Bug ➹ Performance
Description
pacquet serializes enableGlobalVirtualStore only when it is true, but pnpm now explicitly
compares this key when checking workspace-state freshness. When pnpm runs with a concrete
enableGlobalVirtualStore: false (e.g. CI or explicit config), a pacquet-written state file that
omits the key will be treated as stale, forcing pnpm off the optimisticRepeatInstall fast path.
Code

pacquet/crates/package-manager/src/optimistic_repeat_install.rs[R315-319]

+        // Mirror pnpm's writer, which omits the key for its `undefined`
+        // default and records a concrete value only when forced. pacquet
+        // has no `--global` flow, so the only "on" value it ever writes
+        // is `true`; an off store maps back to the omitted `None`.
+        enable_global_virtual_store: config.enable_global_virtual_store.then_some(true),
Evidence
pnpm’s new freshness check compares enableGlobalVirtualStore even when missing in recorded
settings, and pnpm can resolve the setting to a concrete false (CI). pacquet’s current_settings
omits the key when off, which makes pnpm see undefined vs false and treat the state as stale in
the pnpm-read/pacquet-write direction.

deps/status/src/checkDepsStatus.ts[135-153]
workspace/state/src/types.ts[18-56]
config/reader/src/index.ts[653-659]
pacquet/crates/package-manager/src/optimistic_repeat_install.rs[182-190]
pacquet/crates/package-manager/src/optimistic_repeat_install.rs[295-345]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
pacquet’s `current_settings` writes `enableGlobalVirtualStore` only when enabled (`true`). pnpm’s updated `checkDepsStatus` now compares `enableGlobalVirtualStore` from `WORKSPACE_STATE_SETTING_KEYS` even if it was omitted in the recorded state. This means **pnpm reading a pacquet-written workspace-state file** can decide the state is stale when pnpm’s current config resolves the setting to a concrete `false` (notably in CI, where pnpm forces `false`, or when the user explicitly sets `enableGlobalVirtualStore: false`).
## Issue Context
- pnpm now iterates `WORKSPACE_STATE_SETTING_KEYS` and compares each key’s stored value (missing → `undefined`) against the current config value.
- pnpm config resolution forces `enableGlobalVirtualStore = false` under CI when unset.
- pacquet currently omits the key for `false`, so pnpm sees `undefined` vs `false` and flags drift.
## Fix Focus Areas
Update pacquet’s state writer to record `enableGlobalVirtualStore: false` in the cases where pnpm will resolve it to a concrete `false` (or choose to always serialize the bool and accept the one-time cross-tool reinstall).
- pacquet/crates/package-manager/src/optimistic_repeat_install.rs[295-345]
- config/reader/src/index.ts[653-659]
- deps/status/src/checkDepsStatus.ts[135-153]
- workspace/state/src/types.ts[18-56]
### Concrete implementation options
- **Option A (simple, may cause one-time reinstall when switching tools):** always serialize `Some(config.enable_global_virtual_store)` instead of omitting `false`.
- **Option B (closer to pnpm):** serialize `Some(false)` when running under CI-like conditions (e.g. `CI=1` / `PNPM_CONFIG_CI=true`) and the setting is off; otherwise keep omitting the default-off value.
- If you want to also cover “explicit false in workspace yaml”, add an explicitness signal (store raw `Option<bool>` from workspace yaml / env overlay alongside the resolved bool) and serialize `false` when it was explicitly set.
### Tests
Add/adjust a test that simulates pnpm reading a pacquet-written state in the concrete-false environment (CI/explicit false) and ensures it remains up-to-date when no real drift occurred.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

zkochan added a commit to aqeelat/pnpm that referenced this pull request Jun 8, 2026
Port pnpm#12147 to pacquet. pnpm's checkDepsStatus now iterates the
full WORKSPACE_STATE_SETTING_KEYS list, so a key pacquet omits from
.pnpm-workspace-state-v1.json is read as `undefined` and compared
against pnpm's resolved config. `enableGlobalVirtualStore` resolves to a
concrete default (true, or false under CI), so omitting it would make
pnpm reinstall after a pacquet install — and pacquet itself never
detected the toggle (its own copy of pnpm#12142).

Add `enable_global_virtual_store` to WorkspaceStateSettings;
current_settings writes `then_some(true)` (omit when off, mirroring
pnpm omitting its undefined default); settings_match coerces
`None`/`Some(false)` as equal before comparing, matching the existing
allow_builds/package_extensions handling.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 8, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit bf4aa25

@aqeelat

aqeelat commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

@zkochan are you working on the parquet coverage or should I do it?

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Each scenario reports direct installs and pnpr installs. Bencher consumes pacquet@HEAD and pnpr@HEAD.

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 9.895 ± 0.097 9.770 10.067 1.85 ± 0.05
pacquet@main 9.920 ± 0.150 9.793 10.228 1.85 ± 0.06
pnpr@HEAD 5.360 ± 0.113 5.270 5.656 1.00 ± 0.03
pnpr@main 5.349 ± 0.139 5.253 5.734 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 9.89467198464,
      "stddev": 0.09694356885521525,
      "median": 9.858184751140001,
      "user": 3.0514643799999996,
      "system": 3.2071696199999997,
      "min": 9.77029832014,
      "max": 10.06726701014,
      "times": [
        9.940113891140001,
        9.85156299514,
        10.06726701014,
        9.857720719140001,
        9.97411202314,
        9.82124833514,
        9.77029832014,
        9.80064391014,
        10.00510385914,
        9.858648783140001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 9.920290644940001,
      "stddev": 0.1503967832578077,
      "median": 9.86484465664,
      "user": 3.03612708,
      "system": 3.21486392,
      "min": 9.792855471140001,
      "max": 10.227968457140001,
      "times": [
        9.869198372140001,
        9.792855471140001,
        10.227968457140001,
        9.83866504414,
        9.86952219014,
        10.16318253714,
        9.86049094114,
        9.92769059714,
        9.844812366140001,
        9.80852047314
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 5.36039155224,
      "stddev": 0.11251790345814933,
      "median": 5.32981622664,
      "user": 2.51671558,
      "system": 2.8766888200000005,
      "min": 5.26984656014,
      "max": 5.65583250714,
      "times": [
        5.347358472140001,
        5.393948429140001,
        5.32589116814,
        5.273390200140001,
        5.39564225414,
        5.26984656014,
        5.29637775714,
        5.33374128514,
        5.65583250714,
        5.31188688914
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 5.34908951534,
      "stddev": 0.13927334165122476,
      "median": 5.31235356264,
      "user": 2.5377687799999995,
      "system": 2.8460832199999997,
      "min": 5.253317867140001,
      "max": 5.734350095140001,
      "times": [
        5.31212747014,
        5.287867851140001,
        5.37237032114,
        5.33488029114,
        5.28129633314,
        5.253317867140001,
        5.31798630114,
        5.31257965514,
        5.734350095140001,
        5.2841189681400005
      ]
    }
  ]
}

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

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 642.7 ± 10.6 628.3 665.0 1.00
pacquet@main 675.6 ± 69.0 637.3 869.6 1.05 ± 0.11
pnpr@HEAD 776.0 ± 34.1 744.2 843.9 1.21 ± 0.06
pnpr@main 766.1 ± 36.7 739.2 859.0 1.19 ± 0.06
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.6426720350400001,
      "stddev": 0.010565047036562853,
      "median": 0.6406162431400001,
      "user": 0.37248748,
      "system": 1.3205697399999998,
      "min": 0.6283327716400001,
      "max": 0.6650135916400001,
      "times": [
        0.6514714986400001,
        0.6447665596400001,
        0.6650135916400001,
        0.64041128964,
        0.64037098964,
        0.6408211966400001,
        0.6484740196400001,
        0.6348191946400001,
        0.6322392386400001,
        0.6283327716400001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.67563501384,
      "stddev": 0.0689631690143954,
      "median": 0.6574014366400001,
      "user": 0.3660764799999999,
      "system": 1.3182450399999999,
      "min": 0.6372773776400001,
      "max": 0.8695769656400001,
      "times": [
        0.6605424686400001,
        0.6388188466400001,
        0.6372773776400001,
        0.8695769656400001,
        0.66830999564,
        0.6646624426400001,
        0.6542604046400001,
        0.66329310364,
        0.64684122464,
        0.6527673086400001
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.77597050874,
      "stddev": 0.03412677215191066,
      "median": 0.7655310321400002,
      "user": 0.38622188,
      "system": 1.3243700399999998,
      "min": 0.74417738064,
      "max": 0.8438679896400001,
      "times": [
        0.7730254596400001,
        0.7517336546400001,
        0.7473349876400001,
        0.8070800886400001,
        0.7602763896400001,
        0.74417738064,
        0.7707856746400001,
        0.8438679896400001,
        0.8135660656400001,
        0.7478573966400001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.7660885945400001,
      "stddev": 0.03669579120199429,
      "median": 0.7551041366400001,
      "user": 0.38714807999999995,
      "system": 1.33142174,
      "min": 0.7391695846400002,
      "max": 0.8590286156400001,
      "times": [
        0.7568444366400001,
        0.7391695846400002,
        0.7454085546400001,
        0.8590286156400001,
        0.7575678806400001,
        0.7529949606400002,
        0.7404636786400001,
        0.7991999606400001,
        0.7567273096400001,
        0.7534809636400001
      ]
    }
  ]
}

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 9.210 ± 0.053 9.150 9.326 1.81 ± 0.02
pacquet@main 9.210 ± 0.046 9.151 9.285 1.81 ± 0.02
pnpr@HEAD 5.108 ± 0.125 4.989 5.379 1.01 ± 0.03
pnpr@main 5.075 ± 0.056 5.015 5.211 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 9.21005511614,
      "stddev": 0.053432961516206454,
      "median": 9.21339928884,
      "user": 3.6303936,
      "system": 3.17487162,
      "min": 9.14968991584,
      "max": 9.32558188384,
      "times": [
        9.22859615784,
        9.22660242984,
        9.23494795584,
        9.162447475839999,
        9.32558188384,
        9.15729661484,
        9.20019614784,
        9.17361934284,
        9.241573236839999,
        9.14968991584
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 9.210407914040001,
      "stddev": 0.04556624776719224,
      "median": 9.19598073884,
      "user": 3.5894438,
      "system": 3.19535032,
      "min": 9.15094161784,
      "max": 9.28509104584,
      "times": [
        9.20330770584,
        9.28509104584,
        9.17624846384,
        9.24865784384,
        9.17420219684,
        9.18865377184,
        9.15094161784,
        9.17667734884,
        9.27029592684,
        9.23000321884
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 5.108432744939999,
      "stddev": 0.12452737732902637,
      "median": 5.05301497534,
      "user": 2.3630252,
      "system": 2.7313555199999997,
      "min": 4.98878048684,
      "max": 5.37940844084,
      "times": [
        5.03125225984,
        5.11355336984,
        4.98878048684,
        5.060215212839999,
        5.04581473784,
        5.283951397839999,
        5.095816107839999,
        5.37940844084,
        5.0423453478399995,
        5.043190087839999
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 5.074814851239999,
      "stddev": 0.05564529414171983,
      "median": 5.06439045734,
      "user": 2.3871464000000002,
      "system": 2.7079582199999996,
      "min": 5.014970441839999,
      "max": 5.21098059584,
      "times": [
        5.05006322584,
        5.074508970839999,
        5.04185602884,
        5.1199040578399995,
        5.21098059584,
        5.073327024839999,
        5.07173185984,
        5.014970441839999,
        5.057049054839999,
        5.03375725184
      ]
    }
  ]
}

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 1.409 ± 0.015 1.388 1.439 2.09 ± 0.07
pacquet@main 1.402 ± 0.022 1.383 1.458 2.08 ± 0.07
pnpr@HEAD 0.676 ± 0.021 0.659 0.724 1.00
pnpr@main 0.698 ± 0.082 0.655 0.929 1.03 ± 0.13
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 1.40937626708,
      "stddev": 0.015106653391288378,
      "median": 1.4103490867800001,
      "user": 1.51740684,
      "system": 1.7968388999999998,
      "min": 1.3882195637799999,
      "max": 1.43890105178,
      "times": [
        1.42391832878,
        1.41467898578,
        1.39959898578,
        1.39306426378,
        1.41312377678,
        1.40000194178,
        1.41468137578,
        1.43890105178,
        1.40757439678,
        1.3882195637799999
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.4023313662799999,
      "stddev": 0.022299078539003956,
      "median": 1.39653653278,
      "user": 1.51644234,
      "system": 1.7864566999999998,
      "min": 1.38332756578,
      "max": 1.45819420578,
      "times": [
        1.45819420578,
        1.40484521278,
        1.40269834278,
        1.4026332287799999,
        1.38866088178,
        1.4172969357799998,
        1.3868595607799998,
        1.38835789178,
        1.39043983678,
        1.38332756578
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.6755460030800001,
      "stddev": 0.021035673936795708,
      "median": 0.66915793978,
      "user": 0.33126034000000004,
      "system": 1.2763841999999999,
      "min": 0.6587076847800001,
      "max": 0.72449892278,
      "times": [
        0.7024432417800001,
        0.66109049878,
        0.66937212178,
        0.72449892278,
        0.6587076847800001,
        0.6702121567800001,
        0.66894375778,
        0.66706389878,
        0.6702173707800001,
        0.6629103767800001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.6975960978800001,
      "stddev": 0.08208711182526489,
      "median": 0.67251414478,
      "user": 0.32674874,
      "system": 1.2792863999999997,
      "min": 0.6551099567800001,
      "max": 0.92889950078,
      "times": [
        0.6721448777800001,
        0.6551099567800001,
        0.66892392178,
        0.92889950078,
        0.6653990207800001,
        0.6750758717800001,
        0.6624287817800001,
        0.67581654578,
        0.6992790897800001,
        0.6728834117800001
      ]
    }
  ]
}

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 5.035 ± 0.036 4.994 5.108 7.23 ± 0.52
pacquet@main 5.007 ± 0.038 4.941 5.077 7.19 ± 0.52
pnpr@HEAD 0.703 ± 0.015 0.683 0.732 1.01 ± 0.08
pnpr@main 0.697 ± 0.050 0.665 0.828 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 5.034724502120001,
      "stddev": 0.036011097695373216,
      "median": 5.0269384208200005,
      "user": 1.69280798,
      "system": 1.9921260999999997,
      "min": 4.99412428032,
      "max": 5.10790661232,
      "times": [
        4.99412428032,
        5.04865817632,
        4.99796688532,
        5.02808364832,
        5.07899846132,
        5.10790661232,
        5.04095387532,
        5.02579319332,
        5.01187636432,
        5.01288352432
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 5.00684980472,
      "stddev": 0.037654634277571535,
      "median": 5.00223070882,
      "user": 1.6848743799999997,
      "system": 1.967875,
      "min": 4.94075681832,
      "max": 5.07718568332,
      "times": [
        5.00105160932,
        5.03608591432,
        4.94075681832,
        4.99365049732,
        5.00340980832,
        5.00653653432,
        4.99417150632,
        5.04105330032,
        4.97459637532,
        5.07718568332
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.70268173432,
      "stddev": 0.015306057215695733,
      "median": 0.7036407628200001,
      "user": 0.33591457999999996,
      "system": 1.3226501000000002,
      "min": 0.6832233603200001,
      "max": 0.7323828023200001,
      "times": [
        0.7323828023200001,
        0.70417100832,
        0.70502893832,
        0.68390538532,
        0.72007984032,
        0.7073415433200001,
        0.6832233603200001,
        0.6922715783200001,
        0.69530236932,
        0.7031105173200001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.69681343102,
      "stddev": 0.049922783942111686,
      "median": 0.6793221513200001,
      "user": 0.33850238000000005,
      "system": 1.2869619,
      "min": 0.6646033543200001,
      "max": 0.8279659103200001,
      "times": [
        0.7334846673200001,
        0.6646033543200001,
        0.66910876332,
        0.6813935843200001,
        0.8279659103200001,
        0.68534942332,
        0.67015563332,
        0.6772507183200001,
        0.67700740232,
        0.68181485332
      ]
    }
  ]
}

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12147
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.21 s
(+112.93%)Baseline: 4.33 s
5.19 s
(177.44%)

isolated-linker.fresh-restore.cold-cache.cold-storeLatency
seconds (s)
📈 plot
🚷 threshold
🚨 alert (🔔)
9.89 s
(+39.15%)Baseline: 7.11 s
8.53 s
(115.96%)

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,210.06 ms
(+112.93%)Baseline: 4,325.32 ms
5,190.39 ms
(177.44%)

isolated-linker.fresh-install.cold-cache.hot-store📈 view plot
🚷 view threshold
5,034.72 ms
(+0.61%)Baseline: 5,004.02 ms
6,004.83 ms
(83.84%)
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
🚷 view threshold
1,409.38 ms
(+4.46%)Baseline: 1,349.21 ms
1,619.05 ms
(87.05%)
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
🚷 view threshold
🚨 view alert (🔔)
9,894.67 ms
(+39.15%)Baseline: 7,110.84 ms
8,533.01 ms
(115.96%)

isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
🚷 view threshold
642.67 ms
(-2.58%)Baseline: 659.72 ms
791.66 ms
(81.18%)
🐰 View full continuous benchmarking report in Bencher

Port pnpm#12147 to pacquet. pnpm's checkDepsStatus now iterates the
full WORKSPACE_STATE_SETTING_KEYS list, reading a key absent from the
recorded state as `undefined`. So after a pacquet install, any key pnpm
resolves to a concrete default that pacquet omits from
.pnpm-workspace-state-v1.json shows up as drift, and pnpm re-runs a
(no-op) install on every command instead of taking the optimistic
fast path.

Mirror the concrete-default keys pacquet was omitting so a
pacquet-written state matches what pnpm would compute:
- excludeLinksFromLockfile (pnpm default false)
- minimumReleaseAge (pnpm default 1440)
- minimumReleaseAgeIgnoreMissingTime (pnpm default true)

enableGlobalVirtualStore is also tracked: pnpm leaves it `undefined`
by default (concrete only under --global/CI), so pacquet writes
`Some(true)` only when on and omits when off, matching pnpm's encoding;
settings_match coerces `None`/`Some(false)` as equal (same pattern as
allow_builds/package_extensions). This also fixes pacquet's own copy of
pnpm#12142 (the toggle was invisible to its freshness check).

Keys pnpm leaves `undefined` by default (minimumReleaseAgeStrict/Exclude,
trustPolicy*) stay omitted — `undefined == undefined`. workspacePackage-
Patterns is concrete for multi-package workspaces but lives in the
workspace manifest, not Config; threading it into current_settings is a
follow-up.
@zkochan zkochan force-pushed the fix/issue-12142/gvs-toggle-detection branch from bf4aa25 to 54ac9a3 Compare June 8, 2026 15:01
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 8, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 54ac9a3

@zkochan zkochan merged commit 97e1982 into pnpm:main Jun 8, 2026
19 of 20 checks passed
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.

Toggling enableGlobalVirtualStore off is ignored — pnpm says "Already up to date" without reinstalling

3 participants