fix(pnpr): repair registry-mock routing and migrate tests off real-npm writes#12769
Conversation
PR Summary by QodoFix pnpr registry mock by mirroring upstream packages tests write to
AI Description
Diagram
High-Level Assessment
Files changed (10)
|
📝 WalkthroughWalkthroughThe PR tightens pnpr routing and ACL rules, adds new fixture packages, updates pnpm tests to use those fixtures, and changes registry-mock package metadata lookup to scan namespaced public cache paths. Changespnpr routing tightening and fixture-based test migration
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels: ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Pull request overview
Updates the pnpr-based registry mock to restore TypeScript test stability after the registry-mounts routing model change, by explicitly seeding (“mirroring”) specific real npm packages into the hosted storage and tightening routing to exact names (avoiding wildcard scope/prefix routes that accidentally capture real packages).
Changes:
- Add
pnpr-prepare --mirrorsupport that downloads real npm packuments/tarballs listed inpnpr/.fixtures/upstream-mirror.yamlinto hosted storage. - Update the bundled pnpr
config.yamlrouting to exact-name patterns (fixture packages, mirrored packages, and test-published names) and restore the**ACL rule to allow authenticated unpublish. - Wire the TS Jest “with-registry” harness to invoke
pnpr-preparewith the mirror manifest; adjust a lockfile fixture accordingly.
Reviewed changes
Copilot reviewed 9 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpr/crates/pnpr/src/config/tests.rs | Updates the bundled-config parsing test to assert the new “hosted vs upstream” routing expectations. |
| pnpr/crates/pnpr/config.yaml | Switches fixture/mirror/test-publish routing to exact-name patterns; restores ** ACL for unpublish/publish defaults. |
| pnpr/crates/pnpr-fixtures/src/upstream_mirror.rs | New implementation for downloading/caching upstream packuments + tarballs and writing them into hosted storage. |
| pnpr/crates/pnpr-fixtures/src/lib.rs | Exposes the mirror helper and adds an upstream-cache directory helper under target/. |
| pnpr/crates/pnpr-fixtures/src/bin/pnpr-prepare.rs | Adds --mirror flag and invokes the upstream mirror after building fixture storage. |
| pnpr/crates/pnpr-fixtures/Cargo.toml | Adds dependencies needed for mirroring (reqwest, tokio, serde-saphyr). |
| pnpr/.fixtures/upstream-mirror.yaml | New manifest enumerating real npm packages + “existence assertion” versions required by tests. |
| pnpm11/utils/jest-config/with-registry/globalSetup.js | Updates Jest global setup to run pnpr-prepare with --mirror using the new manifest. |
| pnpm11/fixtures/with-git-protocol-dep/pnpm-lock.yaml | Updates the fixture lockfile (adds is-number and updates git-hosted resolution shape). |
| pnpm11/fixtures/with-git-protocol-dep/cache/lockfile-verified.jsonl | Adds a lockfile verification cache file under the fixture (currently machine-specific / likely unintended). |
| Cargo.lock | Locks new Rust deps pulled in by pnpr-fixtures mirroring. |
Files not reviewed (1)
- pnpm11/fixtures/with-git-protocol-dep/pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Code Review by Qodo
Context used✅ Tickets:
🎫 Lockfile flickering and --filter 1. Proxy constructor scope misroute
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
pnpr/crates/pnpr-fixtures/src/upstream_mirror.rs (1)
118-122: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winLegacy (shasum-only) packages bypass integrity verification entirely.
When
dist.integrityhas nosha512-entry,integrity_matchesreturnstrueunconditionally, so packages with only a legacyshasumare never actually verified against anything — a corrupted/tampered download for these packages would silently pass. Since npm still always populatesshasum(SHA-1) even on legacy manifests, falling back to asha1comparison would close this gap cheaply.Based on path instructions ("validate integrity/hashes ... your mirror flow verifies
dist.integrity") — this flow should also verify theshasumfallback rather than skipping verification.Also applies to: 193-202
🤖 Prompt for 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. In `@pnpr/crates/pnpr-fixtures/src/upstream_mirror.rs` around lines 118 - 122, The integrity check in `integrity_matches` currently treats legacy `shasum`-only packuments as automatically valid, so add a fallback verification path instead of returning true when there is no `sha512-` entry. Use the existing `integrity`/packument data in `upstream_mirror.rs` to compare the downloaded bytes against the npm `shasum` (SHA-1) for legacy manifests, and keep the current `sha512` behavior for modern ones so the mirror flow still validates hashes consistently.Source: Path instructions
🤖 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 `@pnpr/crates/pnpr-fixtures/src/upstream_mirror.rs`:
- Around line 48-51: Add a timeout to the HTTP client built in
upstream_mirror::fetch by extending the reqwest::Client::builder() configuration
alongside the existing USER_AGENT setup. Use a reasonable bounded timeout for
registry requests so slow or hanging registry.npmjs.org responses cannot block
pnpr-prepare --mirror indefinitely on the current-thread runtime. Keep the
change localized to the client construction path and ensure any related request
code that relies on this client continues to use the same fetch flow and error
handling.
---
Nitpick comments:
In `@pnpr/crates/pnpr-fixtures/src/upstream_mirror.rs`:
- Around line 118-122: The integrity check in `integrity_matches` currently
treats legacy `shasum`-only packuments as automatically valid, so add a fallback
verification path instead of returning true when there is no `sha512-` entry.
Use the existing `integrity`/packument data in `upstream_mirror.rs` to compare
the downloaded bytes against the npm `shasum` (SHA-1) for legacy manifests, and
keep the current `sha512` behavior for modern ones so the mirror flow still
validates hashes consistently.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: e522e98c-2cc2-493e-b2f6-f0cf9f34a61b
⛔ Files ignored due to path filters (3)
Cargo.lockis excluded by!**/*.lock,!Cargo.lockpnpm11/__fixtures__/with-git-protocol-dep/cache/lockfile-verified.jsonlis excluded by!**/__fixtures__/**pnpm11/__fixtures__/with-git-protocol-dep/pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml,!**/__fixtures__/**
📒 Files selected for processing (8)
pnpm11/__utils__/jest-config/with-registry/globalSetup.jspnpr/.fixtures/upstream-mirror.yamlpnpr/crates/pnpr-fixtures/Cargo.tomlpnpr/crates/pnpr-fixtures/src/bin/pnpr-prepare.rspnpr/crates/pnpr-fixtures/src/lib.rspnpr/crates/pnpr-fixtures/src/upstream_mirror.rspnpr/crates/pnpr/config.yamlpnpr/crates/pnpr/src/config/tests.rs
Micro-Benchmark ResultsLinux |
|
Code review by qodo was updated up to the latest commit 42b6bc8 |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #12769 +/- ##
=======================================
Coverage 85.49% 85.49%
=======================================
Files 412 412
Lines 63758 63758
=======================================
+ Hits 54512 54513 +1
+ Misses 9246 9245 -1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
CI Feedback 🧐A test triggered by this PR failed. Here is an AI-generated analysis of the failure:
|
…e ACL The full-purity registry-mock config (#12747) broke the TypeScript test suite in ways TS CI never caught (it was path-filter-skipped on that pnpr-only merge): - The @zkochan/* and @pnpm/* routes claimed those entire REAL npm scopes with no fall-through, 404ing real packages that proxied dependency trees need (@zkochan/async-regex-replace, @pnpm/error). The fixture packages in those scopes are now routed individually; the rest of each scope proxies npm again. - Unscoped names tests publish to the mock (test-publish-*, batch-*, project-100, ...) routed to the npmjs upstream, where a write is rejected. They are enumerated exactly; @pnpmtest/* covers dynamically-suffixed publish tests. Deliberately no unscoped prefix wildcards: a test-* route would swallow real packages like test-exclude (istanbul's dependency tree). - The migration dropped the '**' ACL entry, and the built-in default admits no one to unpublish, so unpublish tests got 403. Restored: $all access, $authenticated publish and unpublish.
Under the mounts model a write to an upstream-routed name is rejected, and
the old materialize-on-write overlay is gone on purpose — so tests may only
write to packages the mock hosts. Migrate every real-npm write target to a
dedicated fixture:
- @pnpm.e2e/multi-version-{a,b,c} replace is-negative/is-positive/micromatch
in the update, overwrite, and interactive-update tests.
- @pnpm.e2e/circular-{iterator,ext,symbol} replace the
es6-iterator/es5-ext/es6-symbol circular trio; circular-ext requires
^2.0.1 so both circular-iterator versions land in the tree, which is the
point of the concurrency test.
- @pnpm.e2e/function-with-clone replaces lodash where the test executes the
installed code (module and module.clone are functions).
- @scoped/exports-function replaces @rstacruz/tap-spec in the scoped
devDependencies-save test.
- @pnpm.e2e/has-build-metadata{,-dep} replace @monorepolint/{core,cli}: the
dependency range carries build metadata (^0.5.0-alpha.51+f10fea0), which
is what #2928 is about; the hardcoded real-npm integrity becomes
getIntegrity().
- The search tests query a hosted fixture (search scans hosted stores only).
- Dynamically-suffixed publish names move into the @pnpmtest scope, since
exact routes cannot cover generated names.
- The vestigial addDistTag('foo') calls in the workspace-protocol tests are
dropped; those resolve via workspace:, never the registry.
Read-only usages of real npm packages are untouched — they keep proxying.
getIntegrity() in the registry-mock helper also learns the proxy cache's
post-mounts layout (.pnpr-cache/~public/<digest>/), which the patch tests
depend on for proxied is-positive.
42b6bc8 to
c101fef
Compare
|
Code review by qodo was updated up to the latest commit c101fef |
There was a problem hiding this comment.
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 `@pnpm11/testing/registry-mock/src/index.ts`:
- Around line 102-106: The retry logic in getIntegrity currently builds
candidatePaths once using listPublicProxyNamespaces, so later retries never see
namespaces that appear after the first read. Move the namespace enumeration
inside the retry loop in getIntegrity (and any related retry helpers used in the
same flow) so each attempt recomputes candidatePaths from the current state of
the ~public cache before checking package.json paths. This ensures newly created
namespace directories can be discovered during retries instead of being
permanently missed by a stale path list.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: eb18845a-74aa-4fb8-88aa-0f51c6dbe9a6
📒 Files selected for processing (37)
pnpm11/installing/commands/test/update/interactive.tspnpm11/installing/deps-installer/test/hoistedNodeLinker/install.tspnpm11/installing/deps-installer/test/install/misc.tspnpm11/installing/deps-installer/test/install/multipleImporters.tspnpm11/installing/deps-installer/test/install/updatingPkgJson.tspnpm11/installing/deps-installer/test/lockfile.tspnpm11/registry-access/commands/test/search.tspnpm11/releasing/commands/test/publish/batchPublish.test.tspnpm11/releasing/commands/test/publish/publish.tspnpm11/testing/registry-mock/src/index.tspnpr/.fixtures/packages/@pnpm.e2e/circular-ext/0.10.31/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/circular-iterator/2.0.0/index.jspnpr/.fixtures/packages/@pnpm.e2e/circular-iterator/2.0.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/circular-iterator/2.0.1/index.jspnpr/.fixtures/packages/@pnpm.e2e/circular-iterator/2.0.1/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/circular-symbol/3.1.1/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/function-with-clone/4.0.0/index.jspnpr/.fixtures/packages/@pnpm.e2e/function-with-clone/4.0.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/function-with-clone/4.1.0/index.jspnpr/.fixtures/packages/@pnpm.e2e/function-with-clone/4.1.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/has-build-metadata-dep/0.5.0-alpha.51/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/has-build-metadata/0.5.0-alpha.51/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-a/1.0.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-a/1.0.1/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-a/2.0.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-a/2.1.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-b/1.0.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-b/2.0.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-b/3.0.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-b/3.1.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-c/3.0.0/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-c/3.1.10/package.jsonpnpr/.fixtures/packages/@pnpm.e2e/multi-version-c/4.0.0/package.jsonpnpr/.fixtures/packages/@scoped/exports-function/4.1.1/index.jspnpr/.fixtures/packages/@scoped/exports-function/4.1.1/package.jsonpnpr/crates/pnpr/config.yamlpnpr/crates/pnpr/src/config/tests.rs
💤 Files with no reviewable changes (1)
- pnpm11/installing/deps-installer/test/install/multipleImporters.ts
✅ Files skipped from review due to trivial changes (20)
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-b/1.0.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-c/4.0.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-c/3.0.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/circular-symbol/3.1.1/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-a/1.0.1/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-a/2.1.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/has-build-metadata/0.5.0-alpha.51/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/has-build-metadata-dep/0.5.0-alpha.51/package.json
- pnpr/.fixtures/packages/@scoped/exports-function/4.1.1/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-b/3.1.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-a/2.0.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-b/3.0.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/function-with-clone/4.1.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-b/2.0.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/circular-ext/0.10.31/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/multi-version-c/3.1.10/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/function-with-clone/4.0.0/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/circular-iterator/2.0.1/package.json
- pnpr/.fixtures/packages/@pnpm.e2e/circular-iterator/2.0.0/package.json
- pnpm11/registry-access/commands/test/search.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- pnpr/crates/pnpr/config.yaml
|
Code review by qodo was updated up to the latest commit c101fef |
…ntegrity retry The ~public namespace directory is created lazily together with the first cached packument, so a candidate list built once before the retry loop could never discover a namespace that appears while the retries are running.
|
Code review by qodo was updated up to the latest commit f32cb92 |
1 similar comment
|
Code review by qodo was updated up to the latest commit f32cb92 |
… config Route the @pnpm and @zkochan fixture packages by exact name in REGISTRY_MOCK_LOCAL_PATTERNS too, so pacquet's in-process test registry proxies the rest of those real npm scopes exactly like the bundled config.yaml does. Also filter the getIntegrity() proxy-cache namespace enumeration to directories, so a stray file under ~public/ cannot turn a retryable miss into an ENOTDIR error.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
pnpr/crates/pnpr/src/config.rs (1)
1151-1175: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated allowlist between
config.yamland this Rust constant risks drift.
REGISTRY_MOCK_LOCAL_PATTERNSmirrors the router'slocalroute patterns inpnpr/crates/pnpr/config.yaml, but both lists are maintained by hand independently (and already differ in ordering, e.g.create-touch-file-one-binis positioned differently in each). Since this very PR exists because a stale/incomplete allowlist broke routing, consider deriving one list from the other (e.g. embedconfig.yaml's patterns via a build script or shared const) or add a test that asserts the two lists contain the same entries, to prevent future silent drift when new fixture packages are added.🤖 Prompt for 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. In `@pnpr/crates/pnpr/src/config.rs` around lines 1151 - 1175, The allowlist in REGISTRY_MOCK_LOCAL_PATTERNS is duplicated from the router patterns in config.yaml, so the two sources can drift and break fixture routing. Update the pnpr config path by either deriving REGISTRY_MOCK_LOCAL_PATTERNS from the YAML route list (ideally through a shared source or build-time generation) or adding a test that compares both sets for exact membership. Keep the list synchronized around the existing REGISTRY_MOCK_LOCAL_PATTERNS constant and the router’s local patterns so new fixture packages are only added in one place.Source: Path instructions
🤖 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.
Nitpick comments:
In `@pnpr/crates/pnpr/src/config.rs`:
- Around line 1151-1175: The allowlist in REGISTRY_MOCK_LOCAL_PATTERNS is
duplicated from the router patterns in config.yaml, so the two sources can drift
and break fixture routing. Update the pnpr config path by either deriving
REGISTRY_MOCK_LOCAL_PATTERNS from the YAML route list (ideally through a shared
source or build-time generation) or adding a test that compares both sets for
exact membership. Keep the list synchronized around the existing
REGISTRY_MOCK_LOCAL_PATTERNS constant and the router’s local patterns so new
fixture packages are only added in one place.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 822c7dbe-1cd5-4bac-adb3-fab6ea409169
📒 Files selected for processing (2)
pnpm11/testing/registry-mock/src/index.tspnpr/crates/pnpr/src/config.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- pnpm11/testing/registry-mock/src/index.ts
|
Code review by qodo was updated up to the latest commit 6e0186b |
1 similar comment
|
Code review by qodo was updated up to the latest commit 6e0186b |
Integrated-Benchmark Report (Linux)Commit: Each scenario reports direct installs and pnpr installs. Bencher consumes pacquet@HEAD and pnpr@HEAD. Scenario: Isolated linker: fresh restore, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 4.2161433621199995,
"stddev": 0.17173979587512875,
"median": 4.2189482925199995,
"user": 4.037404539999999,
"system": 3.41662968,
"min": 3.9888854465200003,
"max": 4.571850168519999,
"times": [
4.571850168519999,
3.9888854465200003,
4.0842999215199995,
4.15652416652,
4.27589887852,
4.189414859519999,
4.018962547519999,
4.27387168052,
4.24848172552,
4.353244226519999
]
},
{
"command": "pacquet@main",
"mean": 4.1115529650200004,
"stddev": 0.1581501444362238,
"median": 4.05722600602,
"user": 4.01219654,
"system": 3.40566348,
"min": 3.92031418452,
"max": 4.41034236052,
"times": [
4.41034236052,
3.92031418452,
3.9742064795200003,
4.19285826752,
4.01854794252,
4.095345851519999,
4.14001129252,
4.01910616052,
4.327492020519999,
4.01730509052
]
},
{
"command": "pnpr@HEAD",
"mean": 2.08202166342,
"stddev": 0.09857676324474796,
"median": 2.0640852070199998,
"user": 2.77256104,
"system": 2.9551270799999996,
"min": 1.98504339752,
"max": 2.24601554852,
"times": [
1.98648527852,
2.24601554852,
2.1233070185200003,
2.09416034252,
1.9925737025199999,
2.03961936852,
1.98504339752,
2.08855104552,
2.24469206852,
2.01976886352
]
},
{
"command": "pnpr@main",
"mean": 2.1258904965200003,
"stddev": 0.11471530336006532,
"median": 2.05297670602,
"user": 2.7554604399999993,
"system": 2.9447191799999994,
"min": 2.02846016752,
"max": 2.32978775652,
"times": [
2.2124219545200003,
2.0441292795200003,
2.0436802965200003,
2.05210820852,
2.2941950825200004,
2.32978775652,
2.02846016752,
2.0538452035200003,
2.04467940052,
2.15559761552
]
}
]
}Scenario: Isolated linker: fresh restore, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.6515781029200001,
"stddev": 0.014698803768933531,
"median": 0.65091480572,
"user": 0.3833444599999999,
"system": 1.3278065000000001,
"min": 0.6303939207200001,
"max": 0.67066640972,
"times": [
0.6303939207200001,
0.63987359572,
0.6638748827200001,
0.63379787472,
0.67066640972,
0.6532068067200001,
0.6486228047200001,
0.6435846617200001,
0.67049769272,
0.66126237972
]
},
{
"command": "pacquet@main",
"mean": 0.6779075359200002,
"stddev": 0.09675092357195805,
"median": 0.6448622392200001,
"user": 0.3884220599999999,
"system": 1.3298751,
"min": 0.6316648897200001,
"max": 0.9508086317200001,
"times": [
0.6370713157200001,
0.6316648897200001,
0.6363792137200001,
0.6610222497200001,
0.6738020797200001,
0.64204392172,
0.6422976397200001,
0.6474268387200001,
0.6565585787200001,
0.9508086317200001
]
},
{
"command": "pnpr@HEAD",
"mean": 0.7165576526199999,
"stddev": 0.08090827598844033,
"median": 0.6882970927200001,
"user": 0.3914276599999999,
"system": 1.3539146000000002,
"min": 0.67624804672,
"max": 0.9439082507200001,
"times": [
0.7081422337200001,
0.67624804672,
0.68008380272,
0.68691643672,
0.68484540772,
0.68090398772,
0.6985867087200001,
0.6896777487200001,
0.9439082507200001,
0.7162639027200001
]
},
{
"command": "pnpr@main",
"mean": 0.7215020099200001,
"stddev": 0.03545088192613261,
"median": 0.71896547372,
"user": 0.3921537599999999,
"system": 1.346754,
"min": 0.67734597072,
"max": 0.80830537272,
"times": [
0.72446016272,
0.72647286172,
0.7360872337200001,
0.7287849497200001,
0.70401623972,
0.69275962672,
0.7033168967200001,
0.80830537272,
0.67734597072,
0.71347078472
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + cold store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 4.36243193886,
"stddev": 0.04965497927533178,
"median": 4.36505972696,
"user": 3.907881259999999,
"system": 3.3608931000000006,
"min": 4.28756232746,
"max": 4.43864176646,
"times": [
4.43864176646,
4.36090700646,
4.36921244746,
4.37262628646,
4.28756232746,
4.43078707246,
4.33460888646,
4.3045865044600005,
4.39296030146,
4.33242678946
]
},
{
"command": "pacquet@main",
"mean": 4.363034064160001,
"stddev": 0.03480531007315911,
"median": 4.36078615746,
"user": 3.9005492600000005,
"system": 3.3726072,
"min": 4.30720115146,
"max": 4.40041418946,
"times": [
4.40041418946,
4.35773276746,
4.34826803346,
4.30720115146,
4.39815244746,
4.38936638146,
4.30890160146,
4.3602798934600004,
4.36129242146,
4.39873175446
]
},
{
"command": "pnpr@HEAD",
"mean": 2.2122564905600006,
"stddev": 0.10520417015922255,
"median": 2.17573637446,
"user": 2.55882906,
"system": 2.8532211000000003,
"min": 2.09148739946,
"max": 2.36085744546,
"times": [
2.14230357446,
2.24979660746,
2.13304729146,
2.19953899246,
2.34176800046,
2.36085744546,
2.34720094146,
2.10463089646,
2.15193375646,
2.09148739946
]
},
{
"command": "pnpr@main",
"mean": 2.2297263103600002,
"stddev": 0.14636470219203962,
"median": 2.2063743429600002,
"user": 2.61041556,
"system": 2.8510334999999998,
"min": 2.03927384746,
"max": 2.46542036546,
"times": [
2.23980743546,
2.03927384746,
2.08123886846,
2.17294125046,
2.35938838746,
2.42560862246,
2.13084636846,
2.46542036546,
2.25343010446,
2.12930785346
]
}
]
}Scenario: Isolated linker: fresh install, hot cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 1.45483915884,
"stddev": 0.025650730292413475,
"median": 1.4564400476400001,
"user": 1.38111308,
"system": 1.7805081,
"min": 1.40637304514,
"max": 1.50816908314,
"times": [
1.40637304514,
1.46530288814,
1.43688171314,
1.50816908314,
1.46231251214,
1.4470866991400002,
1.4631029891400003,
1.4605662831400001,
1.44628256314,
1.45231381214
]
},
{
"command": "pacquet@main",
"mean": 1.4219914627399999,
"stddev": 0.0550111937765213,
"median": 1.4047174201400001,
"user": 1.3652344800000003,
"system": 1.720702,
"min": 1.3921840791400002,
"max": 1.57542258914,
"times": [
1.4078040931400002,
1.3921840791400002,
1.57542258914,
1.3959137811400002,
1.40257447614,
1.3925779291400002,
1.41671433314,
1.4277085291400002,
1.40215445314,
1.4068603641400002
]
},
{
"command": "pnpr@HEAD",
"mean": 0.70676014354,
"stddev": 0.08263679091983525,
"median": 0.68046838014,
"user": 0.34916848,
"system": 1.3159437,
"min": 0.66472871514,
"max": 0.93943221314,
"times": [
0.67945433714,
0.93943221314,
0.66472871514,
0.6808354521400001,
0.68010130814,
0.7104840811400001,
0.68411697114,
0.6787593711400001,
0.68118437014,
0.66850461614
]
},
{
"command": "pnpr@main",
"mean": 0.6721618762400001,
"stddev": 0.027761796462025767,
"median": 0.66574533014,
"user": 0.34214468,
"system": 1.3003594,
"min": 0.64989098914,
"max": 0.7490307941400001,
"times": [
0.65945096214,
0.6694260791400001,
0.66256661914,
0.64989098914,
0.6618194151400001,
0.6601946911400001,
0.66892404114,
0.67111002814,
0.7490307941400001,
0.66920514314
]
}
]
}Scenario: Isolated linker: fresh install, cold cache + hot store
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 3.1386466684200003,
"stddev": 0.03363097323301493,
"median": 3.1270839070200003,
"user": 1.8529125200000003,
"system": 2.0259212399999997,
"min": 3.11142530652,
"max": 3.22465188752,
"times": [
3.12720552252,
3.12190582952,
3.1179978255200003,
3.13948591352,
3.11142530652,
3.1297968265200002,
3.16520806852,
3.22465188752,
3.12182721252,
3.12696229152
]
},
{
"command": "pacquet@main",
"mean": 3.10381860112,
"stddev": 0.04676559716327111,
"median": 3.09612432552,
"user": 1.84984702,
"system": 2.0055122399999994,
"min": 3.06843105652,
"max": 3.23078517252,
"times": [
3.0967186675200002,
3.10231317752,
3.06974447852,
3.08743635152,
3.07673296252,
3.10855523252,
3.09552998352,
3.23078517252,
3.10193892852,
3.06843105652
]
},
{
"command": "pnpr@HEAD",
"mean": 0.68288180812,
"stddev": 0.010056556397090494,
"median": 0.6819306735199999,
"user": 0.34734632,
"system": 1.32625764,
"min": 0.66560589852,
"max": 0.70121384852,
"times": [
0.70121384852,
0.68940063852,
0.66560589852,
0.68103427852,
0.67411539852,
0.67926006852,
0.69383828552,
0.68308209652,
0.67844049952,
0.68282706852
]
},
{
"command": "pnpr@main",
"mean": 0.66339585892,
"stddev": 0.009041491347776385,
"median": 0.66010387652,
"user": 0.33971132000000004,
"system": 1.2905994399999998,
"min": 0.65270066652,
"max": 0.68253772452,
"times": [
0.65836295052,
0.66032940452,
0.65987834852,
0.6576868515200001,
0.65270066652,
0.66604657252,
0.68253772452,
0.65538203852,
0.67165073152,
0.6693833005200001
]
}
]
}Scenario: Isolated linker: fresh restore, cold cache + cold store + cold pnpr
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 6.951952639220001,
"stddev": 0.17606810218578636,
"median": 6.90829544682,
"user": 4.21391164,
"system": 3.6710008199999997,
"min": 6.73664078132,
"max": 7.28497584032,
"times": [
6.83269770732,
6.73664078132,
7.01462555532,
6.98544596632,
6.82133161932,
6.91693971632,
6.89965117732,
6.82146520232,
7.20575282632,
7.28497584032
]
},
{
"command": "pacquet@main",
"mean": 6.988907087219999,
"stddev": 0.17205532890849878,
"median": 6.9431180683200004,
"user": 4.24378304,
"system": 3.7128138199999996,
"min": 6.77229762932,
"max": 7.39443164232,
"times": [
7.39443164232,
6.77229762932,
6.89638598332,
6.90829453432,
6.94928399632,
6.97565355632,
6.93695214032,
7.15749203832,
6.99369427032,
6.9045850813200005
]
},
{
"command": "pnpr@HEAD",
"mean": 5.01632204732,
"stddev": 0.07981845633963927,
"median": 4.98524249482,
"user": 2.92033634,
"system": 3.22123682,
"min": 4.91677001332,
"max": 5.17200103032,
"times": [
4.98227995132,
4.98693952132,
5.11993665932,
5.03824020132,
4.9345737753200005,
5.17200103032,
4.98354546832,
5.04755592032,
4.91677001332,
4.98137793232
]
},
{
"command": "pnpr@main",
"mean": 5.054585078819999,
"stddev": 0.13496538478550305,
"median": 5.04416383782,
"user": 2.89341964,
"system": 3.19034452,
"min": 4.90459994632,
"max": 5.24410274532,
"times": [
4.92092881932,
5.24225940832,
5.02028064232,
5.06804703332,
4.91984528132,
5.19007483832,
5.09490929332,
4.94080278032,
4.90459994632,
5.24410274532
]
}
]
} |
|
| Branch | pr/12769 |
| Testbed | pnpr |
⚠️ WARNING: No Threshold found!Without a Threshold, no Alerts will ever be generated.
Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the--ci-only-thresholdsflag.
Click to view all benchmark results
| Benchmark | Latency | milliseconds (ms) |
|---|---|---|
| isolated-linker.fresh-install.cold-cache.cold-store | 📈 view plot | 2,212.26 ms |
| isolated-linker.fresh-install.cold-cache.hot-store | 📈 view plot | 682.88 ms |
| isolated-linker.fresh-install.hot-cache.hot-store | 📈 view plot | 706.76 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store | 📈 view plot | 2,082.02 ms |
| isolated-linker.fresh-restore.cold-cache.cold-store.cold-pnpr | 📈 view plot | 5,016.32 ms |
| isolated-linker.fresh-restore.hot-cache.hot-store | 📈 view plot | 716.56 ms |
Summary
The registry-mounts merge (#12747) broke the TypeScript test suite, unnoticed because TS CI was path-filter-skipped on that pnpr-only merge (diagnosis on pnpm/pnpm#12698). Two contract breaks with the old verdaccio-style mock:
is-negative,is-positive,lodash,micromatch,es5-ext,es6-iterator,@rstacruz/tap-spec,@monorepolint/core) and published unscoped names; the old server materialized an overlay on first write, the mount model rejects the write by design.@zkochan/*→ local 404'd@zkochan/async-regex-replace;@pnpm/*→ local 404'd real@pnpm/error/@pnpm/git-resolverpulled by a huge-package test.The mount model and the mock stay exactly as they are — no overlay, no mirror feature, provenance stays declared. The fix is config + test migration:
pnpr config (first commit):
@pnpm,@zkochan) are routed by exact name; the rest of those scopes proxies npm again.@pnpmtest/*covers dynamically-suffixed publish names. Deliberately no unscoped prefix wildcards — atest-*route would swallow the realtest-excludefrom istanbul's dependency tree.'**'ACL entry the migration dropped is restored (the built-in default admits no one to unpublish, so unpublish tests got 403).Test migration (second commit): every test that writes to a real npm package now uses a dedicated in-repo fixture —
@pnpm.e2e/multi-version-{a,b,c}for the update/dist-tag flows,@pnpm.e2e/circular-{iterator,ext,symbol}for the concurrent-circular-deps test,@pnpm.e2e/function-with-clonewhere the test executes the installed code,@scoped/exports-functionfor the scoped devDeps-save test,@pnpm.e2e/has-build-metadata{,-dep}for the build-metadata lockfile test (hardcoded real-npm integrity →getIntegrity()), and dynamically-suffixed publish names move into@pnpmtest/. Read-only usages of real npm packages are untouched and keep proxying.getIntegrity()also learns the proxy cache's post-mounts layout (.pnpr-cache/~public/<digest>/), which the patch tests rely on.Verified locally against the real mock:
installing/commands31/31 suites (the two original CI failures pass),installing/deps-installer76/76 (787 tests, incl. patch, circular, catalogs),installing/deps-restorer,registry-access/commands9/9,releasing/commands23/23 (publish, recursive, batch),cache/commands3/3. pnpr: 568/568, clippy/fmt/dylint clean.Squash Commit Body
Checklist
pacquet/port, or the description notes what still needs porting. (Test infrastructure only: pnpr config + TS tests/fixtures. pacquet's in-process registry is unchanged — its tests never write to these packages.)Written by an agent (Claude Code, claude-fable-5).
Summary by CodeRabbit
New Features
Bug Fixes