Skip to content

Backports various fixes and tests from Berry - #327

Merged
arcanis merged 4 commits into
mainfrom
berry-backports
Aug 15, 2026
Merged

Backports various fixes and tests from Berry#327
arcanis merged 4 commits into
mainfrom
berry-backports

Conversation

@arcanis

@arcanis arcanis commented Aug 14, 2026

Copy link
Copy Markdown
Member

What's the problem this PR addresses?

A review of recent Berry PRs identified several fixes and regression tests that also apply to zpm. This PR backports them in one batch.

How did I fix it?

Bug fixes (the ported regression tests reproduced each of these before the fix):

Feature:

Tests only (zpm's behavior was already correct):

Artifact sync:

Checklist

  • I have read the Contributing Guide.
  • I have checked that all the impacted tests pass: the touched acceptance suites (npmMinimalAgeGate, prunedNativeDeps, protocols/npm, npm/audit, info, publish, node-modules, packageExtensions, checkResolutions, add) pass 215/218 (3 skipped), plus cargo test for zpm-config (7) and zpm-semver (108). The only remaining local failures reproduce identically on a pristine main build (venv/Python environment, one live-Algolia-data test, path_iterators and two lazyInstalls focus-coverage tests).

Note

Medium Risk
Touches core install resolution, architecture filtering, and audit traversal; behavior changes are intentional but affect many installs and multi-arch fetches.

Overview
Backports a batch of Berry fixes and tests into zpm, covering install resolution, CLI behavior, configuration, and artifact sync.

Resolution & install: Literal * ranges can resolve to prereleases when no stable versions exist, with matching --check-resolutions acceptance. Algolia auto-@types lookup is capped at 10s, warns instead of failing yarn add, and respects enableAutoTypes. HTTP requests gain a per-request .timeout() bounded by httpTimeout.

Commands & linkers: npm publish errors with a --otp hint when not on an interactive TTY. Recursive production npm audit skips nested workspaces’ devDependencies. yarn info --virtuals shows physical descriptors with virtual locators. Node-modules bin symlinks prefer direct dependencies over hoisted aliases.

supportedArchitectures: Schema becomes a oneOrMany list of entries with ArchitectureFilter fields (null = any). Legacy single-object YAML still works; project config replaces (not merges) user entries. Matching uses SystemSet / supported_systems() with per-entry validation instead of a flat cross-product of all systems.

Artifacts: builtin-extensions.json gains Volar, Vite devtools, and Parcel peer entries; package manager pin updated.

Reviewed by Cursor Bugbot for commit 4aaf6a1. Bugbot is set up for automated code reviews on this repo. Configure here.

- yarnpkg/berry#7205: resolve `*` to prereleases when no stable version exists
- yarnpkg/berry#7216: prefer direct dependency binaries in the nm linker
- yarnpkg/berry#7209: fail instead of prompting for an OTP in non-TTY mode
- yarnpkg/berry#7243: support explicit supportedArchitectures combinations
- yarnpkg/berry#7255: exclude nested workspace dev dependencies from production audits
- yarnpkg/berry#7253: report virtual dependency locators in yarn info
- yarnpkg/berry#7206: degrade gracefully when the Algolia auto-types lookup fails
- yarnpkg/berry#7250 / #7257 / #7214: npmMinimalAgeGate regression tests
- yarnpkg/berry#7232 / #7228: re-imported artifacts (package extensions, PnP hooks, patches)
@netlify

netlify Bot commented Aug 14, 2026

Copy link
Copy Markdown

Deploy Preview for yarn-v6 ready!

Name Link
🔨 Latest commit 4aaf6a1
🔍 Latest deploy log https://app.netlify.com/projects/yarn-v6/deploys/6a804fc0b20d3f000829a874
😎 Deploy Preview https://deploy-preview-327--yarn-v6.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Algolia test overwrites auto-types config
    • Added tsEnableAutoTypes: true to the .yarnrc.yml file written by the test to preserve the configuration setting alongside the network settings.
  • ✅ Fixed: Architecture configs concatenate across layers
    • Modified config preprocessing to remove user-level fields that are overridden by project-level fields (unless onConflict: extend is explicitly set), fixing the incorrect concatenation behavior for array configs like supportedArchitectures.

Create PR

Or push these changes by commenting:

@cursor push 77be7c13a5
Preview (77be7c13a5)
diff --git a/packages/zpm-config/src/lib.rs b/packages/zpm-config/src/lib.rs
--- a/packages/zpm-config/src/lib.rs
+++ b/packages/zpm-config/src/lib.rs
@@ -1202,6 +1202,30 @@
         retain_user_conflict_fields(user_value, project_root_mode, &project_field_modes);
     }
 
+    // Remove user fields that are present in project config, unless they have extend mode
+    // This ensures project config overrides user config by default (not concatenates)
+    if let (Some(user_value), Some(project_value)) = (user_value.as_mut(), project_value.as_ref()) {
+        if let (serde_yaml::Value::Mapping(user_map), serde_yaml::Value::Mapping(project_map)) = (user_value, project_value) {
+            let extended_fields: BTreeSet<&str> = project_field_modes
+                .iter()
+                .filter_map(|(key, mode)| (*mode == ConflictMode::Extend).then_some(key.as_str()))
+                .collect();
+            
+            let mut fields_to_remove = Vec::new();
+            for key in project_map.keys() {
+                if let serde_yaml::Value::String(key_str) = key {
+                    if !extended_fields.contains(key_str.as_str()) {
+                        fields_to_remove.push(key.clone());
+                    }
+                }
+            }
+            
+            for key in fields_to_remove {
+                user_map.remove(&key);
+            }
+        }
+    }
+
     let (user, _user_config_requires_trust)
         = deserialize_intermediate_settings(user_value)?;
     let (project, requires_trust)

diff --git a/tests/acceptance-tests/pkg-tests-specs/sources/plugins/plugin-typescript.test.ts b/tests/acceptance-tests/pkg-tests-specs/sources/plugins/plugin-typescript.test.ts
--- a/tests/acceptance-tests/pkg-tests-specs/sources/plugins/plugin-typescript.test.ts
+++ b/tests/acceptance-tests/pkg-tests-specs/sources/plugins/plugin-typescript.test.ts
@@ -53,6 +53,8 @@
           // instance a corporate proxy silently dropping the request); the
           // registry is configured through the environment and stays reachable
           await xfs.writeFilePromise(ppath.join(path, `.yarnrc.yml`), [
+            `tsEnableAutoTypes: true`,
+            ``,
             `networkSettings:`,
             `  "*.algolia.net":`,
             `    enableNetwork: false`,

You can send follow-ups to the cloud agent here.

Comment thread packages/zpm-config/schema.json
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown

⏱️ Benchmark Results

gatsby install-full-cold

Metric Base Head Difference
Mean 3.958s 3.972s +0.34% ⚠️
Median 3.937s 3.972s +0.88% ⚠️
Min 3.896s 3.906s
Max 4.176s 4.063s
Std Dev 0.061s 0.041s
📊 Raw benchmark data (gatsby install-full-cold)

Base times: 3.905s, 3.957s, 3.920s, 3.962s, 3.953s, 4.072s, 3.928s, 3.908s, 4.015s, 3.903s, 3.935s, 3.944s, 3.957s, 3.918s, 3.934s, 3.910s, 4.050s, 3.896s, 3.975s, 3.926s, 3.915s, 3.963s, 3.931s, 3.939s, 4.049s, 4.176s, 3.979s, 3.930s, 3.981s, 3.923s

Head times: 3.944s, 3.906s, 3.918s, 3.945s, 3.987s, 3.967s, 4.002s, 3.914s, 3.926s, 4.001s, 4.048s, 4.012s, 4.063s, 3.960s, 3.914s, 3.928s, 3.990s, 3.941s, 4.001s, 4.026s, 3.979s, 4.002s, 3.975s, 3.947s, 3.962s, 3.940s, 3.972s, 4.039s, 3.976s, 3.971s


gatsby install-cache-only

Metric Base Head Difference
Mean 1.338s 1.341s +0.21% ⚠️
Median 1.334s 1.333s -0.09% ✅
Min 1.306s 1.310s
Max 1.403s 1.557s
Std Dev 0.019s 0.043s
📊 Raw benchmark data (gatsby install-cache-only)

Base times: 1.330s, 1.334s, 1.324s, 1.334s, 1.330s, 1.338s, 1.326s, 1.334s, 1.331s, 1.364s, 1.339s, 1.344s, 1.338s, 1.332s, 1.306s, 1.336s, 1.346s, 1.319s, 1.340s, 1.370s, 1.403s, 1.343s, 1.340s, 1.332s, 1.324s, 1.333s, 1.373s, 1.332s, 1.327s, 1.323s

Head times: 1.318s, 1.327s, 1.329s, 1.357s, 1.324s, 1.337s, 1.374s, 1.342s, 1.329s, 1.331s, 1.326s, 1.340s, 1.311s, 1.327s, 1.361s, 1.339s, 1.338s, 1.557s, 1.350s, 1.321s, 1.315s, 1.332s, 1.331s, 1.342s, 1.335s, 1.337s, 1.333s, 1.310s, 1.334s, 1.325s


gatsby install-cache-and-lock (warm, with lockfile)

Metric Base Head Difference
Mean 0.364s 0.367s +0.84% ⚠️
Median 0.361s 0.358s -0.92% ✅
Min 0.353s 0.351s
Max 0.392s 0.612s
Std Dev 0.009s 0.046s
📊 Raw benchmark data (gatsby install-cache-and-lock (warm, with lockfile))

Base times: 0.363s, 0.358s, 0.365s, 0.381s, 0.385s, 0.392s, 0.382s, 0.355s, 0.356s, 0.359s, 0.353s, 0.360s, 0.372s, 0.359s, 0.362s, 0.360s, 0.365s, 0.364s, 0.362s, 0.357s, 0.359s, 0.362s, 0.359s, 0.360s, 0.363s, 0.360s, 0.361s, 0.361s, 0.361s, 0.359s

Head times: 0.368s, 0.362s, 0.357s, 0.355s, 0.358s, 0.365s, 0.360s, 0.351s, 0.612s, 0.356s, 0.357s, 0.359s, 0.357s, 0.360s, 0.365s, 0.361s, 0.356s, 0.358s, 0.356s, 0.355s, 0.360s, 0.356s, 0.358s, 0.356s, 0.357s, 0.355s, 0.359s, 0.361s, 0.356s, 0.360s

… one

One-or-many settings are a single logical value, so the project
configuration must replace the user one rather than extend it like
regular list settings do; otherwise a project couldn't narrow down a
user-level architecture set.

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Lockfile drops node-gyp resolution
    • Restored node-gyp@npm:* resolution and all its transitive dependencies to the lockfile, making it portable across operating systems again.

Create PR

Or push these changes by commenting:

@cursor push 02927edf6a
Preview (02927edf6a)
diff --git a/yarn.lock b/yarn.lock
--- a/yarn.lock
+++ b/yarn.lock
@@ -7357,6 +7357,13 @@
         }
       }
     },
+    "abbrev@npm:^5.0.0": {
+      "checksum": "dc16af5283e27efa4cb6e97d4a3ffa496e3c59c6ec02dc94a8e262da5c5f88b6c4840039dd89b3dc8dc8e0de46feebc5e57d2c25a2e0c1e8241c565a64daf79e",
+      "resolution": {
+        "resolution": "abbrev@npm:5.0.0",
+        "version": "5.0.0"
+      }
+    },
     "acorn@npm:^8.15.0": {
       "checksum": "ed7053eb83a8c131ffce1abb573ca45431ceb5ec684cedc7ef44523475157b8d96edd0a69d198ff8dbbbb9cbbd38c0d0584c77f553f6ad7b1cc62a825cd7f937",
       "resolution": {
@@ -9908,6 +9915,13 @@
         "version": "6.0.1"
       }
     },
+    "env-paths@npm:^2.2.0": {
+      "checksum": "f1740c5cfa1f277cb8f0c9751eec990828d430a524f70f770757cfdf569257a8ffbc43e1e6a724bda5fd96680f2a19ba02a647ea69364785804960e03ded0cdd",
+      "resolution": {
+        "resolution": "env-paths@npm:2.2.1",
+        "version": "2.2.1"
+      }
+    },
     "env-paths@npm:^2.2.1": {
       "checksum": "f1740c5cfa1f277cb8f0c9751eec990828d430a524f70f770757cfdf569257a8ffbc43e1e6a724bda5fd96680f2a19ba02a647ea69364785804960e03ded0cdd",
       "resolution": {
@@ -10588,6 +10602,13 @@
         }
       }
     },
+    "exponential-backoff@npm:^3.1.1": {
+      "checksum": "dc5e89d20fa6c44bc1c8b7e9e7d8e4bf2dbb3e797556917c1b0e78d9c612302db1e22d0bd4fcca9dc9c4e8c0e58508f8c084b11d5b47e93c2c2d59ea33afa8e8",
+      "resolution": {
+        "resolution": "exponential-backoff@npm:3.1.1",
+        "version": "3.1.1"
+      }
+    },
     "exit@npm:^0.1.2": {
       "checksum": "9195c9636dff6139e79950984213d1a52844633919987165a961709c26e4309675cee6744b2dbe19477d73c2d223cf6e8c4ac3c2d2f10f02d7eef227ec037b10",
       "resolution": {
@@ -12225,6 +12246,20 @@
         "version": "2.0.0"
       }
     },
+    "isexe@npm:^3.1.1": {
+      "checksum": "355e1c6bacf0f58b3af8a8c24aa59e5664fb7932e84ddde4e7fcc3e81c45af5b66427630e2b676b4d77ca1f33b3ecafe9b1c03ee5f3e0a955c51af369a8a9ac0",
+      "resolution": {
+        "resolution": "isexe@npm:3.1.1",
+        "version": "3.1.1"
+      }
+    },
+    "isexe@npm:^4.0.0": {
+      "checksum": "9be54001e72ff2efbca8e02ee5552b79d81c126ac47ee6e334506c7da8ffa987dc51aad879edc834c79bc2fd0ef53a8e3725dfbadb52031c3fe2f1ab0fa9cad6",
+      "resolution": {
+        "resolution": "isexe@npm:4.0.0",
+        "version": "4.0.0"
+      }
+    },
     "istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": {
       "checksum": "4c56545b6239f470bd1d542fae163ef8545e209537990b22271733a97e0d8e8ed875e225553f8611fc628ff816f57b58dae0d9e213fccc4f87b76bf6f41fa55c",
       "resolution": {
@@ -14612,6 +14647,25 @@
         "version": "1.6.7"
       }
     },
+    "node-gyp@npm:*": {
+      "checksum": "fd48a6b4775e3615654c16be20a8a812e32b117c9d12a43b5ac1c3506d3e3fb2e4e8a9eb677104bfb918a873c433e11695f9eee7d2733ac0564cb719c90626aa",
+      "resolution": {
+        "resolution": "node-gyp@npm:13.0.1",
+        "version": "13.0.1",
+        "dependencies": {
+          "env-paths": "^2.2.0",
+          "exponential-backoff": "^3.1.1",
+          "graceful-fs": "^4.2.6",
+          "nopt": "^10.0.0",
+          "proc-log": "^7.0.0",
+          "semver": "^7.3.5",
+          "tar": "^7.5.4",
+          "tinyglobby": "^0.2.12",
+          "undici": "^8.4.1",
+          "which": "^7.0.0"
+        }
+      }
+    },
     "node-int64@npm:^0.4.0": {
       "checksum": "163620e2657781fecff525af63868bbf9cb00a99c935a5e2e4408b99a0c9e8d4b3ac4432eb6c776daf92b6c04e326de2c40e8bde643a55fdf6ea219932d8e0d7",
       "resolution": {
@@ -14640,6 +14694,16 @@
         "version": "0.7.3"
       }
     },
+    "nopt@npm:^10.0.0": {
+      "checksum": "02d56c4870f8f0442243ff22877a980b77cce28648b909228147c630bc534aa7dec9de132994538691d41a8e221a74191836c51bda73684f6605109efe671918",
+      "resolution": {
+        "resolution": "nopt@npm:10.0.1",
+        "version": "10.0.1",
+        "dependencies": {
+          "abbrev": "^5.0.0"
+        }
+      }
+    },
     "normalize-path@npm:^3.0.0": {
       "checksum": "93eb4091b194a8ab8041976df5d77d9f7729f1613fdb88dd685e809757302ab1d038f9da077191aa25283db4a9362b986d48c4302e6966dbfb507ae702930a04",
       "resolution": {
@@ -15332,6 +15396,13 @@
         "version": "6.1.0"
       }
     },
+    "proc-log@npm:^7.0.0": {
+      "checksum": "8a31a22ebcdefc81cbcfac1b757211489eb9c33199938c378a0845fa3c76fedd5c9da89fe5ac64998cca8f3b855c937b09afa0f19c04d43621baf00726607ca3",
+      "resolution": {
+        "resolution": "proc-log@npm:7.0.0",
+        "version": "7.0.0"
+      }
+    },
     "process-nextick-args@npm:~2.0.0": {
       "checksum": "c88845576a932ce4ab1e22e079533258a85c79f10074cb03ae8ed2da64401b41259a6289e340c0b97216c262c2188de69bfdb802dfbca05f7cdf4865b6aaef0d",
       "resolution": {
@@ -17279,6 +17350,20 @@
         }
       }
     },
+    "tar@npm:^7.5.4": {
+      "checksum": "602985e860dec206f42c582076e088f4fd65e89adf2237ebf019c7060d604ec38e3d86883056703d3e80447e7d478561ef8888c72369cb6015369bb7254d63bc",
+      "resolution": {
+        "resolution": "tar@npm:7.5.20",
+        "version": "7.5.20",
+        "dependencies": {
+          "@isaacs/fs-minipass": "^4.0.0",
+          "chownr": "^3.0.0",
+          "minipass": "^7.1.2",
+          "minizlib": "^3.1.0",
+          "yallist": "^5.0.0"
+        }
+      }
+    },
     "tar-fs@npm:^1.16.0": {
       "checksum": "18ebfa1788a40ef3761a756d62adc328bda194916895f996d82fec210dd84b3a83497b0b88a969e671f82d9a852de38b73e8bd3754b64f18528bbc0d87b035c7",
       "resolution": {
@@ -17409,6 +17494,17 @@
         "version": "1.1.2"
       }
     },
+    "tinyglobby@npm:^0.2.12": {
+      "checksum": "5a5f0e648836fbe413ba31d29204fdfc4f206a4878868cc926e528413637e27ab73997b7e4939444918b11c45e604ce706e39fee335474185b7b014ea7010733",
+      "resolution": {
+        "resolution": "tinyglobby@npm:0.2.17",
+        "version": "0.2.17",
+        "dependencies": {
+          "fdir": "^6.5.0",
+          "picomatch": "^4.0.4"
+        }
+      }
+    },
     "tinyglobby@npm:^0.2.13, tinyglobby@npm:^0.2.15": {
       "checksum": "57467da2137c5d1ae705ef8efee6edbe0558142d5d87bc35d09edde2325aa607e3a3f98c625bf7ab05de7e2f7f5bcd058178d5896232fa0525e47a3e499a8466",
       "resolution": {
@@ -17727,6 +17823,13 @@
         "version": "0.1.3"
       }
     },
+    "undici@npm:^8.4.1": {
+      "checksum": "fae70318a7ec30b40d168fdc034547777d3897578dd60a4cdbbc3c4f6be61533c7e3a665960d4dd3ea5949f34c860444905bd19a4c19cc9c904e968d4e0ce8dd",
+      "resolution": {
+        "resolution": "undici@npm:8.7.0",
+        "version": "8.7.0"
+      }
+    },
     "undici-types@npm:~7.16.0": {
       "checksum": "c219e5594a58875faa9bb7d661accffdea7fd4152ecc6dbbd984907e03661ca28d290d8b4c2771d26001b44210524e2756eb05a3741c88b4ca478b587a31c738",
       "resolution": {
@@ -18329,6 +18432,16 @@
         }
       }
     },
+    "which@npm:^7.0.0": {
+      "checksum": "a51c8b81c57af84c8a94aac0d27faa2b4fef8c2fd72976a00c68ad5adf3de2e8011a53cdc34224a68338a41d82caa6559b7f325f31c76fff0c5c26cae4c310a9",
+      "resolution": {
+        "resolution": "which@npm:7.0.0",
+        "version": "7.0.0",
+        "dependencies": {
+          "isexe": "^4.0.0"
+        }
+      }
+    },
     "which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": {
       "checksum": "1c97b81248da1d6297889c5748971882810fbaea7200220911a4599df480d84caa4f59c3d3dfadb62c7b47fa4c3abd1bd52f1b334868d6fe0660fbfd1c69388b",
       "resolution": {

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit a629836. Configure here.

Comment thread yarn.lock
The published 6.0.0-rc.19 release derives cached packages' dependencies
from the zip manifests rather than from the resolver output, so on warm
caches it loses the injected node-gyp dependency and prunes its subtree
from the lockfile (while newer builds regenerate it, making the two
fight). Pinning packageManager to a per-commit build from master avoids
the stale-release behavior; the lockfile is regenerated with the branch
binary, restoring the node-gyp entries and refreshing the workspace
hashes affected by the imported package extensions.
@arcanis
arcanis merged commit 8be5add into main Aug 15, 2026
25 checks passed
@arcanis
arcanis deleted the berry-backports branch August 15, 2026 12:18
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