Skip to content

feat(pnpr): gzip-compress package metadata over the wire#12170

Merged
zkochan merged 1 commit into
mainfrom
gzip-metadata
Jun 3, 2026
Merged

feat(pnpr): gzip-compress package metadata over the wire#12170
zkochan merged 1 commit into
mainfrom
gzip-metadata

Conversation

@zkochan

@zkochan zkochan commented Jun 3, 2026

Copy link
Copy Markdown
Member

Closes #12169.

What

Package metadata (packuments) now travels gzip-compressed between pacquet and pnpr — matching how a real, CDN-fronted registry serves it. Previously neither side used gzip for metadata: pacquet fetched packuments uncompressed from every registry (unlike pnpm-TS, which gets gzip transparently via undici), and pnpr served them uncompressed. Packuments are the largest payloads pulled during resolution and gzip ~5–10×, so this was a real resolution-time cost — and it's especially visible on the frozen-install lockfile-verification path, which fetches full packuments.

Both halves are needed and land together (server-only would be a no-op for pacquet, which never asked for gzip):

Client (pacquet)

Enable reqwest's gzip feature → it sends Accept-Encoding: gzip and transparently decompresses.

  • Tarballs unaffected: served as application/octet-stream with no Content-Encoding, so reqwest leaves them alone — store-integrity verification is unchanged.
  • /v1/files unaffected: that stream is already gzipped with an explicit Content-Encoding: gzip; reqwest now auto-decompresses it, and the pnpr-client's existing gzip-magic-byte check already handles the decompressed case.

Server (pnpr)

Add a tower-http CompressionLayer, scoped to JSON via NotForContentType so it compresses packuments / version manifests / dist-tags / search but never re-gzips an already-compressed payload — tarballs (application/octet-stream), the file stream (application/x-pnpm-install), or the resolve NDJSON (application/x-ndjson).

On the architecture question of why in the app vs. a CDN/nginx: pnpr's common shape is a warm server hit directly over a LAN/CI network with no proxy in front — there the application is the only layer that can compress. Where a CDN/nginx is present, the Content-Encoding: gzip is simply passed through (no double compression), or origin compression is disabled by config.

Tests

pnpr/crates/pnpr/tests/server.rs asserts a packument is gzipped when Accept-Encoding: gzip is sent, served plain otherwise, and a tarball is never re-gzipped. End-to-end coverage comes for free from the existing suites: the pnpr-client integration tests (the pnpr server's own resolver fetches gzipped packuments) and the pacquet add e2e tests (direct-client resolution) both pass with the feature on.

Notes

  • Enabling the gzip features pulls async-compression (+ compression-codecs/-core) transitively via reqwest/tower-http — standard, MIT/Apache crates.
  • A future optimization (not here): cache the compressed packument bytes so a hot server doesn't re-gzip the same metadata per request.

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

Summary by CodeRabbit

  • New Features

    • Responses now support gzip compression to reduce bandwidth; compression is skipped for already-compressed package tarballs and similar payloads.
    • Client requests properly advertise gzip handling so compressed metadata is served when supported.
  • Tests

    • Added tests verifying gzip behavior: metadata is compressed when requested, uncompressed when not, and tarballs are never double-compressed.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ab40b4ef-3258-4678-9507-2211c3355708

📥 Commits

Reviewing files that changed from the base of the PR and between a84792d and cd1c384.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • Cargo.toml
  • pacquet/crates/network/src/lib.rs
  • pnpr/crates/pnpr/src/server.rs
  • pnpr/crates/pnpr/tests/server.rs
✅ Files skipped from review due to trivial changes (2)
  • pacquet/crates/network/src/lib.rs
  • Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (2)
  • pnpr/crates/pnpr/src/server.rs
  • pnpr/crates/pnpr/tests/server.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: ubuntu-latest / Node.js 24 / Test
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Lint and Test (ubuntu-latest)
  • GitHub Check: Lint and Test (macos-latest)
  • GitHub Check: Code Coverage
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Run benchmark on ubuntu-latest

📝 Walkthrough

Walkthrough

Gzip for packument metadata is enabled: workspace dependencies updated, the reqwest client now requests gzip, pnpr adds a CompressionLayer that excludes binary/NDJSON/install types, and tests verify gzip behavior for packuments and tarballs.

Changes

Gzip metadata compression

Layer / File(s) Summary
Compression dependencies
Cargo.toml
reqwest gains the "gzip" feature; tower-http gains "compression-gzip" alongside "trace".
Reqwest client gzip enablement
pacquet/crates/network/src/lib.rs
default_client_builder sets .gzip(true) so packument fetches include Accept-Encoding: gzip and are transparently decoded.
CompressionLayer middleware
pnpr/crates/pnpr/src/server.rs
Imports updated to include CompressionLayer and predicate helpers; the axum Router inserts a CompressionLayer that skips application/octet-stream, application/x-pnpm-install, and application/x-ndjson.
Compression behavior tests
pnpr/crates/pnpr/tests/server.rs
Adds GzDecoder support, a foo_packument test helper, and tests asserting packuments compress when requested, remain uncompressed otherwise, and tarballs are never re-gzipped.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit nudges bytes to sleep,
Wrapping packuments in gzip deep.
Tarballs intact, untouched and neat,
Metadata shrinks — a lighter feat.
Hooray for swifter fetches, hop and leap! 🐇✨

🚥 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 clearly and concisely describes the main change: adding gzip compression for package metadata in pnpr.
Linked Issues check ✅ Passed The PR successfully implements all coding objectives from issue #12169: enables reqwest gzip [pacquet/crates/network/src/lib.rs], adds CompressionLayer to pnpr [pnpr/crates/pnpr/src/server.rs], skips already-compressed types, and includes comprehensive tests [pnpr/crates/pnpr/tests/server.rs].
Out of Scope Changes check ✅ Passed All changes are directly scoped to the gzip compression objective: Cargo.toml dependencies, pacquet client gzip enablement, pnpr server CompressionLayer, and corresponding tests.
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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch gzip-metadata

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

Enable gzip compression for package metadata over the wire

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Enable gzip compression for package metadata responses in pnpr server
• Add gzip decompression support to pacquet client via reqwest feature
• Scope compression to JSON endpoints, excluding binary payloads
• Add comprehensive tests for gzip compression behavior
Diagram
flowchart LR
  A["Client Request<br/>Accept-Encoding: gzip"] -->|reqwest gzip feature| B["Pacquet Client"]
  B -->|HTTP Request| C["pnpr Server"]
  C -->|CompressionLayer<br/>JSON only| D["Gzip Compress<br/>Packuments"]
  D -->|Content-Encoding: gzip| E["Client Receives<br/>Compressed Metadata"]
  E -->|Auto-decompress| F["Transparent to App"]
  G["Binary Payloads<br/>Tarballs, Streams"] -->|Excluded| C

Loading

Grey Divider

File Changes

1. Cargo.toml Dependencies +2/-1

Add gzip compression dependencies

• Enable gzip feature for reqwest to support gzip compression on client side
• Add compression-gzip feature to tower-http for server-side compression

Cargo.toml


2. pnpr/crates/pnpr/Cargo.toml Dependencies +1/-0

Add flate2 test dependency

• Add flate2 as dev dependency for gzip decompression in tests

pnpr/crates/pnpr/Cargo.toml


3. pnpr/crates/pnpr/src/server.rs ✨ Enhancement +26/-1

Add gzip compression middleware to server

• Import CompressionLayer and predicate types from tower-http
• Add CompressionLayer middleware scoped to JSON content types
• Exclude binary endpoints (tarballs, install streams, NDJSON) from compression
• Include detailed comments explaining compression strategy and architecture

pnpr/crates/pnpr/src/server.rs


View more (1)
4. pnpr/crates/pnpr/tests/server.rs 🧪 Tests +124/-0

Add comprehensive gzip compression tests

• Add flate2 GzDecoder import for decompression testing
• Create helper function foo_packument() to generate test packument JSON
• Add test verifying packuments are gzipped when client sends Accept-Encoding header
• Add test verifying packuments are uncompressed without Accept-Encoding header
• Add test verifying tarballs are never re-gzipped even with gzip acceptance

pnpr/crates/pnpr/tests/server.rs


Grey Divider

Qodo Logo

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@pnpr/crates/pnpr/Cargo.toml`:
- Line 63: Remove the redundant dev-dependency entry for flate2 in Cargo.toml:
delete the line "flate2 = { workspace = true }" from the [dev-dependencies]
section because flate2 is already declared under [dependencies] (used by
install_accelerator.rs via flate2::write::GzEncoder) and runtime dependencies
are available to tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ab68b007-bd1a-4c03-a2ae-0614d914820e

📥 Commits

Reviewing files that changed from the base of the PR and between 65c9bef and a1b77fd.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • Cargo.toml
  • pnpr/crates/pnpr/Cargo.toml
  • pnpr/crates/pnpr/src/server.rs
  • pnpr/crates/pnpr/tests/server.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Code Coverage
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Dylint
  • 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: Analyze (javascript)
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (2)
pnpr/**/pnpr/**/*.rs

📄 CodeRabbit inference engine (pnpr/AGENTS.md)

pnpr/**/pnpr/**/*.rs: Follow the pacquet code-style guide (../pacquet/CODE_STYLE_GUIDE.md) for Rust-level conventions including imports, naming, ownership, and error handling
Follow the pacquet contributing guide (../pacquet/CONTRIBUTING.md) for test layout and Rust conventions

Files:

  • pnpr/crates/pnpr/src/server.rs
  • pnpr/crates/pnpr/tests/server.rs
pnpr/**/pnpr/**/Cargo.toml

📄 CodeRabbit inference engine (pnpr/AGENTS.md)

Declare new shared dependencies in the root [workspace.dependencies] and use { workspace = true } in pnpr crate's Cargo.toml

Files:

  • pnpr/crates/pnpr/Cargo.toml
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-25T12:36:42.202Z
Learning: User-visible changes (CLI flags, defaults, environment variables, lockfile/manifest/state-file formats, error codes/messages, log emissions, store layout, hook semantics) in pnpm must be mirrored to pacquet in the same PR
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Match how the same feature is implemented in the TypeScript pnpm CLI — any change in pacquet must match pnpm's behavior, logic, edge cases, config resolution, error messages, file/lockfile formats, and existing tests
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11773
File: pacquet/crates/resolving-tarball-resolver/src/tarball_resolver.rs:115-117
Timestamp: 2026-05-20T20:41:30.632Z
Learning: In the pacquet Rust port of pnpm, the `is_http_url` helper in `pacquet/crates/resolving-tarball-resolver/src/tarball_resolver.rs` intentionally uses `bare.starts_with("http:") || bare.starts_with("https:")` (not `"http://"` / `"https://"`) to match upstream pnpm's `startsWith('http:')` / `startsWith('https:')` check byte-for-byte. Pacquet's cardinal rule (pacquet/AGENTS.md) requires matching pnpm even on quirks; malformed non-URL inputs are rejected downstream by `reqwest::Url::parse` as a `ResolveError`.
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Prefer existing pacquet-* crates over writing new code; check pacquet-tarball, pacquet-crypto-hash, pacquet-crypto-shasums-file, pacquet-package-manifest, pacquet-network, pacquet-registry, pacquet-fs, and pacquet-diagnostics before implementing non-trivial functionality
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11784
File: pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs:120-133
Timestamp: 2026-05-20T23:08:06.093Z
Learning: Pacquet (pnpm's Rust port) has a cardinal rule: "match pnpm exactly — do not fix pnpm quirks unless the same fix has landed in pnpm first." Review comments should not suggest behavioral deviations from upstream pnpm, even when the upstream behavior appears buggy. If a real bug is identified, it must be fixed upstream first.
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11915
File: pacquet/crates/resolving-deps-resolver/src/resolve_dependency_tree.rs:553-617
Timestamp: 2026-05-24T21:11:04.272Z
Learning: In the pacquet Rust port (pnpm/pnpm repo), the `ResolvedPackage.optional` AND-folding on revisit intentionally mirrors pnpm's `resolveDependencies.ts:1627-1648` behavior: only the directly-revisited package's `optional` flag is updated; transitive descendants are not re-walked. pnpm CLI corrects stale optional flags downstream via `copyDependencySubGraph` BFS in `lockfile/pruner/src/index.ts:160-205`, which tracks a `nonOptional` set and re-stamps any package reachable by an all-non-optional path. Pacquet does not yet have this pruner equivalent, so the stale flags flow directly through `dependencies_graph_to_lockfile.rs:409` → `create_virtual_store.rs:762` → `installability.rs:394`. A follow-up to port `copyDependencySubGraph` is planned; until then, do not flag the resolver-layer optional propagation gap as a bug in pacquet PRs — it is intentional parity with pnpm's resolver layer.
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Do not add a dependency not already declared in `[workspace.dependencies]` without explicit human request; ask for approval and request addition to the workspace root `Cargo.toml`

Applied to files:

  • Cargo.toml
  • pnpr/crates/pnpr/Cargo.toml
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Applies to pnpr/**/pnpr/**/Cargo.toml : Declare new shared dependencies in the root [workspace.dependencies] and use { workspace = true } in pnpr crate's Cargo.toml

Applied to files:

  • Cargo.toml
  • pnpr/crates/pnpr/Cargo.toml
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/Cargo.toml : Keep dependencies at the right level — add a new dependency to the specific crate that needs it, not to the workspace root or shared crate unless multiple crates depend on it

Applied to files:

  • Cargo.toml
  • pnpr/crates/pnpr/Cargo.toml
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/Cargo.toml : Check whether the workspace already depends on something suitable in `[workspace.dependencies]` in the root `Cargo.toml` before adding a new dependency

Applied to files:

  • Cargo.toml
  • pnpr/crates/pnpr/Cargo.toml
📚 Learning: 2026-05-20T19:41:03.063Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11774
File: pacquet/crates/resolving-deps-resolver/src/resolve_peers.rs:0-0
Timestamp: 2026-05-20T19:41:03.063Z
Learning: In the pacquet project (Rust), the semver crate used is `node-semver` (version ~2.2.0), NOT `nodejs-semver`. These are two distinct crates. `node-semver` only exposes `Range::satisfies` as its public satisfaction API — there is no separate `satisfies_with_prerelease` method. Prerelease-tolerant matching is handled inline by retrying against the stripped `MAJOR.MINOR.PATCH` base when `Range::satisfies` rejects a prerelease version.

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Prefer existing pacquet-* crates over writing new code; check pacquet-tarball, pacquet-crypto-hash, pacquet-crypto-shasums-file, pacquet-package-manifest, pacquet-network, pacquet-registry, pacquet-fs, and pacquet-diagnostics before implementing non-trivial functionality

Applied to files:

  • Cargo.toml
  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Port relevant pnpm tests to Rust tests whenever they translate when porting behavior from pnpm

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Applies to pnpr/**/pnpr/**/*.rs : Follow the pacquet contributing guide (../pacquet/CONTRIBUTING.md) for test layout and Rust conventions

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
  • pnpr/crates/pnpr/Cargo.toml
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/*.rs : Tests are documentation — do not duplicate test scenarios, edge cases, failure modes, or worked examples in prose when they are already captured by tests

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Applies to pnpr/**/pnpr/**/*.rs : Follow the pacquet code-style guide (../pacquet/CODE_STYLE_GUIDE.md) for Rust-level conventions including imports, naming, ownership, and error handling

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
  • pnpr/crates/pnpr/Cargo.toml
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Use snapshot tests with `insta` and carefully review diffs when intentional changes alter snapshots; accept with `cargo insta review` only after careful review

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Tests that need the mocked registry should start `pnpr` through `pacquet-testing-utils`; `cargo test` / `cargo nextest run` should not require a separate `just registry-mock launch` step

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-20T20:41:30.632Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11773
File: pacquet/crates/resolving-tarball-resolver/src/tarball_resolver.rs:115-117
Timestamp: 2026-05-20T20:41:30.632Z
Learning: In the pacquet Rust port of pnpm, the `is_http_url` helper in `pacquet/crates/resolving-tarball-resolver/src/tarball_resolver.rs` intentionally uses `bare.starts_with("http:") || bare.starts_with("https:")` (not `"http://"` / `"https://"`) to match upstream pnpm's `startsWith('http:')` / `startsWith('https:')` check byte-for-byte. Pacquet's cardinal rule (pacquet/AGENTS.md) requires matching pnpm even on quirks; malformed non-URL inputs are rejected downstream by `reqwest::Url::parse` as a `ResolveError`.

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Prefer real fixtures over dependency-injection seams — use `tempfile::TempDir`, the mocked registry, or integration tests spawning the actual binary for happy paths and most error paths; use the DI seam only for filesystem error kinds, deterministic time, shared process-global state, or external-service happy paths

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
  • pnpr/crates/pnpr/Cargo.toml
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Applies to pnpr/**/pnpr/crates/**/Cargo.toml : Cargo.toml files for new registry-only crates must use the pnpr- prefix for the package name

Applied to files:

  • pnpr/crates/pnpr/Cargo.toml
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Applies to pnpr/**/pnpr/crates/**/Cargo.toml : New registry-only crates must be placed under pnpr/crates/<short-name>/ and named pnpr-<short-name> in Cargo.toml, never using the pacquet- prefix

Applied to files:

  • pnpr/crates/pnpr/Cargo.toml
🔇 Additional comments (9)
Cargo.toml (2)

117-124: LGTM!


145-145: LGTM!

pnpr/crates/pnpr/src/server.rs (2)

30-36: LGTM!


130-148: LGTM!

pnpr/crates/pnpr/tests/server.rs (5)

5-5: LGTM!

Also applies to: 9-9


571-586: LGTM!


588-627: LGTM!


629-654: LGTM!


656-691: LGTM!

Comment thread pnpr/crates/pnpr/Cargo.toml Outdated
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.02      7.8±0.23ms   555.2 KB/sec    1.00      7.7±0.13ms   566.0 KB/sec

Neither side used gzip for package metadata: pacquet fetched packuments
uncompressed from every registry (unlike pnpm-TS, which gets gzip via
undici), and pnpr served them uncompressed. Packuments are the largest
payloads pulled during resolution and gzip ~5-10x, so this was a real
resolution-time cost and a divergence from how a CDN-fronted registry
behaves. Closes #12169.

Both halves are needed and land together:

- Client (pacquet): enable reqwest`s `gzip` feature and set `.gzip(true)`
  explicitly on the network client builder, so it sends
  `Accept-Encoding: gzip` and transparently decompresses. Tarballs are
  unaffected (served as `application/octet-stream` with no
  `Content-Encoding`, so reqwest leaves them alone and store-integrity
  verification is unchanged). It also transparently handles the install
  accelerator's already-gzipped `/v1/files` stream — the client's
  existing magic-byte check covers the now-auto-decompressed case.

- Server (pnpr): add a `tower-http` `CompressionLayer`, scoped to JSON
  via `NotForContentType` so it compresses packuments / version
  manifests / dist-tags / search but never re-gzips an already-compressed
  payload: tarballs (`application/octet-stream`), the file stream
  (`application/x-pnpm-install`), or the resolve NDJSON
  (`application/x-ndjson`). pnpr is commonly hit directly with no CDN or
  nginx in front, so the application is the only layer that can compress;
  where a proxy/CDN is present, the `Content-Encoding: gzip` is passed
  through (no double compression).

Tests assert a packument is gzipped when `Accept-Encoding: gzip` is sent,
served plain otherwise, and a tarball is never re-gzipped.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
Cargo.toml (1)

117-124: ⚡ Quick win

Scope reqwest’s gzip feature to the crates that actually need it

  • reqwest 0.13’s gzip feature is the right knob for transparent gzip decompression of response bodies.
  • Adding gzip in [workspace.dependencies] makes every workspace crate that uses reqwest pull in gzip-related transitive dependencies even if they don’t need it.
  • Keep the workspace reqwest features minimal and enable gzip only where required (e.g., in the specific crate’s Cargo.toml: reqwest = { workspace = true, features = ["gzip"] }).
🤖 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 `@Cargo.toml` around lines 117 - 124, The workspace Cargo.toml currently
enables reqwest's "gzip" feature globally which forces all workspace crates that
depend on reqwest to pull in gzip-related transitive deps; update the workspace
dependency declaration for reqwest to remove "gzip" from the features list, keep
only minimal features needed workspace-wide (e.g., "json","rustls",etc.), and
then enable "gzip" selectively in the individual crate Cargo.toml files that
actually need transparent gzip decompression by adding reqwest = { workspace =
true, features = ["gzip"] } there; look for the workspace dependency entry named
"reqwest" and the crate-level Cargo.toml files that declare reqwest to make this
change.
pnpr/crates/pnpr/tests/server.rs (1)

659-659: 💤 Low value

Potentially misleading comment in test body.

The comment references "compression-size-floor," but tower-http's CompressionLayer is configured to exclude application/octet-stream via NotForContentType (see context snippet 1), so the body size is irrelevant—tarballs are never compressed regardless of size. The longer body doesn't hurt, but the comment might confuse future readers.

Simplify the test body or clarify the comment

Option 1: Remove the comment and use a simpler body:

-    let bytes = b"fake-tarball-bytes-long-enough-to-clear-the-compression-size-floor";
+    let bytes = b"fake-tarball-bytes";

Option 2: Clarify the comment to reference content-type exclusion:

-    let bytes = b"fake-tarball-bytes-long-enough-to-clear-the-compression-size-floor";
+    // Body size doesn't matter; the middleware excludes application/octet-stream entirely.
+    let bytes = b"fake-tarball-bytes";
🤖 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/tests/server.rs` at line 659, The test's comment about
"compression-size-floor" is misleading because tower-http's CompressionLayer is
configured with NotForContentType to exclude application/octet-stream, so body
length doesn't affect compression; update the test around the bytes variable
(let bytes =
b"fake-tarball-bytes-long-enough-to-clear-the-compression-size-floor") to either
(a) simplify the body to a shorter representative payload, or (b) replace the
comment to explicitly state that CompressionLayer + NotForContentType excludes
application/octet-stream so tarballs are never compressed regardless of size
(reference CompressionLayer and NotForContentType and the bytes variable to
locate the code).
🤖 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 `@Cargo.toml`:
- Around line 117-124: The workspace Cargo.toml currently enables reqwest's
"gzip" feature globally which forces all workspace crates that depend on reqwest
to pull in gzip-related transitive deps; update the workspace dependency
declaration for reqwest to remove "gzip" from the features list, keep only
minimal features needed workspace-wide (e.g., "json","rustls",etc.), and then
enable "gzip" selectively in the individual crate Cargo.toml files that actually
need transparent gzip decompression by adding reqwest = { workspace = true,
features = ["gzip"] } there; look for the workspace dependency entry named
"reqwest" and the crate-level Cargo.toml files that declare reqwest to make this
change.

In `@pnpr/crates/pnpr/tests/server.rs`:
- Line 659: The test's comment about "compression-size-floor" is misleading
because tower-http's CompressionLayer is configured with NotForContentType to
exclude application/octet-stream, so body length doesn't affect compression;
update the test around the bytes variable (let bytes =
b"fake-tarball-bytes-long-enough-to-clear-the-compression-size-floor") to either
(a) simplify the body to a shorter representative payload, or (b) replace the
comment to explicitly state that CompressionLayer + NotForContentType excludes
application/octet-stream so tarballs are never compressed regardless of size
(reference CompressionLayer and NotForContentType and the bytes variable to
locate the code).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1f6d399e-8031-43a5-8a77-d8ee86ccc858

📥 Commits

Reviewing files that changed from the base of the PR and between a1b77fd and a84792d.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • Cargo.toml
  • pnpr/crates/pnpr/src/server.rs
  • pnpr/crates/pnpr/tests/server.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • pnpr/crates/pnpr/src/server.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Lint and Test (ubuntu-latest)
  • GitHub Check: Lint and Test (macos-latest)
  • GitHub Check: Dylint
  • GitHub Check: Doc
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Code Coverage
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (1)
pnpr/**/pnpr/**/*.rs

📄 CodeRabbit inference engine (pnpr/AGENTS.md)

pnpr/**/pnpr/**/*.rs: Follow the pacquet code-style guide (../pacquet/CODE_STYLE_GUIDE.md) for Rust-level conventions including imports, naming, ownership, and error handling
Follow the pacquet contributing guide (../pacquet/CONTRIBUTING.md) for test layout and Rust conventions

Files:

  • pnpr/crates/pnpr/tests/server.rs
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-05-25T12:36:42.202Z
Learning: User-visible changes (CLI flags, defaults, environment variables, lockfile/manifest/state-file formats, error codes/messages, log emissions, store layout, hook semantics) in pnpm must be mirrored to pacquet in the same PR
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Match how the same feature is implemented in the TypeScript pnpm CLI — any change in pacquet must match pnpm's behavior, logic, edge cases, config resolution, error messages, file/lockfile formats, and existing tests
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11784
File: pacquet/crates/resolving-deps-resolver/src/hoist_peers.rs:120-133
Timestamp: 2026-05-20T23:08:06.093Z
Learning: Pacquet (pnpm's Rust port) has a cardinal rule: "match pnpm exactly — do not fix pnpm quirks unless the same fix has landed in pnpm first." Review comments should not suggest behavioral deviations from upstream pnpm, even when the upstream behavior appears buggy. If a real bug is identified, it must be fixed upstream first.
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Reference the upstream pnpm commit/PR when porting code from pnpm in commit messages
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Do not add a dependency not already declared in `[workspace.dependencies]` without explicit human request; ask for approval and request addition to the workspace root `Cargo.toml`

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/Cargo.toml : Keep dependencies at the right level — add a new dependency to the specific crate that needs it, not to the workspace root or shared crate unless multiple crates depend on it

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Applies to pnpr/**/pnpr/**/Cargo.toml : Declare new shared dependencies in the root [workspace.dependencies] and use { workspace = true } in pnpr crate's Cargo.toml

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/Cargo.toml : Check whether the workspace already depends on something suitable in `[workspace.dependencies]` in the root `Cargo.toml` before adding a new dependency

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-20T19:41:03.063Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11774
File: pacquet/crates/resolving-deps-resolver/src/resolve_peers.rs:0-0
Timestamp: 2026-05-20T19:41:03.063Z
Learning: In the pacquet project (Rust), the semver crate used is `node-semver` (version ~2.2.0), NOT `nodejs-semver`. These are two distinct crates. `node-semver` only exposes `Range::satisfies` as its public satisfaction API — there is no separate `satisfies_with_prerelease` method. Prerelease-tolerant matching is handled inline by retrying against the stripped `MAJOR.MINOR.PATCH` base when `Range::satisfies` rejects a prerelease version.

Applied to files:

  • Cargo.toml
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Prefer existing pacquet-* crates over writing new code; check pacquet-tarball, pacquet-crypto-hash, pacquet-crypto-shasums-file, pacquet-package-manifest, pacquet-network, pacquet-registry, pacquet-fs, and pacquet-diagnostics before implementing non-trivial functionality

Applied to files:

  • Cargo.toml
  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Port relevant pnpm tests to Rust tests whenever they translate when porting behavior from pnpm

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/*.rs : Tests are documentation — do not duplicate test scenarios, edge cases, failure modes, or worked examples in prose when they are already captured by tests

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Applies to pnpr/**/pnpr/**/*.rs : Follow the pacquet contributing guide (../pacquet/CONTRIBUTING.md) for test layout and Rust conventions

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Use snapshot tests with `insta` and carefully review diffs when intentional changes alter snapshots; accept with `cargo insta review` only after careful review

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Tests that need the mocked registry should start `pnpr` through `pacquet-testing-utils`; `cargo test` / `cargo nextest run` should not require a separate `just registry-mock launch` step

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:24.797Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pnpr/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:24.797Z
Learning: Applies to pnpr/**/pnpr/**/*.rs : Follow the pacquet code-style guide (../pacquet/CODE_STYLE_GUIDE.md) for Rust-level conventions including imports, naming, ownership, and error handling

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-29T18:03:15.372Z
Learnt from: CR
Repo: pnpm/pnpm PR: 0
File: pacquet/AGENTS.md:0-0
Timestamp: 2026-05-29T18:03:15.372Z
Learning: Applies to pacquet/**/tests/**/*.rs : Prefer real fixtures over dependency-injection seams — use `tempfile::TempDir`, the mocked registry, or integration tests spawning the actual binary for happy paths and most error paths; use the DI seam only for filesystem error kinds, deterministic time, shared process-global state, or external-service happy paths

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
📚 Learning: 2026-05-20T20:41:30.632Z
Learnt from: zkochan
Repo: pnpm/pnpm PR: 11773
File: pacquet/crates/resolving-tarball-resolver/src/tarball_resolver.rs:115-117
Timestamp: 2026-05-20T20:41:30.632Z
Learning: In the pacquet Rust port of pnpm, the `is_http_url` helper in `pacquet/crates/resolving-tarball-resolver/src/tarball_resolver.rs` intentionally uses `bare.starts_with("http:") || bare.starts_with("https:")` (not `"http://"` / `"https://"`) to match upstream pnpm's `startsWith('http:')` / `startsWith('https:')` check byte-for-byte. Pacquet's cardinal rule (pacquet/AGENTS.md) requires matching pnpm even on quirks; malformed non-URL inputs are rejected downstream by `reqwest::Url::parse` as a `ResolveError`.

Applied to files:

  • pnpr/crates/pnpr/tests/server.rs
🔇 Additional comments (6)
Cargo.toml (1)

145-145: ⚡ Quick win

Use tower-http’s compression-gzip feature where it’s actually needed
tower-http v0.6.11 supports the compression-gzip feature (used by CompressionLayer for gzip responses). Keep the feature scoped to the specific crate(s) that use CompressionLayer (if more than pnpr consumes tower-http via workspace dependencies); otherwise the current workspace-level enablement is fine.

# workspace Cargo.toml
tower-http = { version = "0.6.11", features = ["trace"] }

# pnpr/crates/pnpr/Cargo.toml
[dependencies]
tower-http = { workspace = true, features = ["compression-gzip"] }
pnpr/crates/pnpr/tests/server.rs (5)

5-5: LGTM!

Also applies to: 9-9


571-586: LGTM!


588-627: LGTM!


629-654: LGTM!


656-691: LGTM!

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.58%. Comparing base (65c9bef) to head (cd1c384).

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12170      +/-   ##
==========================================
- Coverage   87.58%   87.58%   -0.01%     
==========================================
  Files         269      269              
  Lines       30807    30814       +7     
==========================================
+ Hits        26982    26988       +6     
- Misses       3825     3826       +1     

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

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

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Each scenario has pacquet rows (direct install) and pnpr rows (the same client through the pnpr install accelerator), so pnpr@HEAD vs pacquet@HEAD is the pnpr-vs-direct ratio. Cold-store scenarios wipe the client store between runs (warm server); hot-store scenarios keep it warm. The pacquet@HEAD rows feed the pacquet Bencher testbed; the pnpr@HEAD rows feed the pnpr testbed.

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 4.807 ± 0.085 4.746 5.025 2.39 ± 0.08
pacquet@main 4.799 ± 0.030 4.766 4.853 2.39 ± 0.07
pnpr@HEAD 2.009 ± 0.055 1.921 2.082 1.00
pnpr@main 2.064 ± 0.098 1.991 2.293 1.03 ± 0.06
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 4.80701957108,
      "stddev": 0.08538669815009696,
      "median": 4.772740564479999,
      "user": 2.49091934,
      "system": 3.7323969800000008,
      "min": 4.74630576548,
      "max": 5.02543070548,
      "times": [
        4.78497789548,
        4.7629250694800005,
        4.82215673948,
        4.77584326548,
        4.76963786348,
        4.87048953948,
        4.75409372948,
        4.7583351374800005,
        5.02543070548,
        4.74630576548
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 4.799306362579999,
      "stddev": 0.03004846241487064,
      "median": 4.7865031169800005,
      "user": 2.50235984,
      "system": 3.72430078,
      "min": 4.76588108348,
      "max": 4.85269175748,
      "times": [
        4.78011671548,
        4.78080083948,
        4.82823280548,
        4.7760069634799995,
        4.82862274948,
        4.85269175748,
        4.79220539448,
        4.76588108348,
        4.77071875748,
        4.81778655948
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 2.0085962152800003,
      "stddev": 0.05527478553207941,
      "median": 2.02231790198,
      "user": 2.70550474,
      "system": 3.23022208,
      "min": 1.92142312948,
      "max": 2.08243758948,
      "times": [
        1.9570593224800001,
        2.02986526148,
        1.92142312948,
        2.03022588348,
        2.02124465648,
        2.08243758948,
        2.01164653548,
        2.07660204648,
        2.02339114748,
        1.93206658048
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 2.06365564508,
      "stddev": 0.0981522044439346,
      "median": 2.00831398848,
      "user": 2.65967504,
      "system": 3.27441988,
      "min": 1.99105302748,
      "max": 2.29285537848,
      "times": [
        2.29285537848,
        2.07179604748,
        2.10593956448,
        1.9979577424800001,
        1.99105302748,
        2.00484418748,
        2.15752842748,
        2.00434095648,
        1.9984573294799999,
        2.01178378948
      ]
    }
  ]
}

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

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 687.7 ± 21.2 665.4 738.4 1.00
pacquet@main 688.4 ± 16.4 661.2 716.8 1.00 ± 0.04
pnpr@HEAD 698.3 ± 34.7 670.6 786.4 1.02 ± 0.06
pnpr@main 727.7 ± 37.0 677.7 789.1 1.06 ± 0.06
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.6877080606800001,
      "stddev": 0.021200945301639185,
      "median": 0.6821600184800001,
      "user": 0.39473642,
      "system": 1.3290748799999998,
      "min": 0.66537931098,
      "max": 0.73841654398,
      "times": [
        0.73841654398,
        0.6952708039800001,
        0.6822270609800001,
        0.70442012998,
        0.66783124598,
        0.6820929759800001,
        0.66537931098,
        0.67652656298,
        0.68143370798,
        0.68348226398
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.6884318269799999,
      "stddev": 0.01637260347982969,
      "median": 0.68484677598,
      "user": 0.39261401999999995,
      "system": 1.3517216799999998,
      "min": 0.6611917539800001,
      "max": 0.71677048598,
      "times": [
        0.71677048598,
        0.68303469198,
        0.68138303398,
        0.67778750698,
        0.6611917539800001,
        0.6776228589800001,
        0.7097498719800001,
        0.6925051009800001,
        0.69761410498,
        0.68665885998
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.69834662128,
      "stddev": 0.03465244615066035,
      "median": 0.68666501698,
      "user": 0.38802941999999996,
      "system": 1.36033958,
      "min": 0.67063064798,
      "max": 0.78639533898,
      "times": [
        0.72555109298,
        0.68582516098,
        0.69875863998,
        0.69449668298,
        0.67388819598,
        0.67960702198,
        0.6808085579800001,
        0.67063064798,
        0.6875048729800001,
        0.78639533898
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.72769094798,
      "stddev": 0.03695797311832049,
      "median": 0.72990901048,
      "user": 0.39318672,
      "system": 1.3527690799999998,
      "min": 0.67774306698,
      "max": 0.7891103849800001,
      "times": [
        0.74659826098,
        0.7512350439800001,
        0.7469708269800001,
        0.67896285498,
        0.7613645329800001,
        0.67774306698,
        0.71180064998,
        0.71321975998,
        0.6999040979800001,
        0.7891103849800001
      ]
    }
  ]
}

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.222 ± 0.048 2.185 2.349 1.01 ± 0.03
pacquet@main 2.209 ± 0.028 2.169 2.258 1.00
pnpr@HEAD 2.209 ± 0.019 2.188 2.251 1.00 ± 0.02
pnpr@main 2.212 ± 0.030 2.173 2.269 1.00 ± 0.02
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.22204073766,
      "stddev": 0.04833327267142016,
      "median": 2.20667436086,
      "user": 3.5708206,
      "system": 3.0266350999999996,
      "min": 2.18473396236,
      "max": 2.34914926336,
      "times": [
        2.20667306636,
        2.18473396236,
        2.20988585636,
        2.1953331043600004,
        2.34914926336,
        2.1888956363600003,
        2.23126849036,
        2.24572104336,
        2.2020712983600004,
        2.20667565536
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.20894545426,
      "stddev": 0.028315035054633682,
      "median": 2.2063308793600003,
      "user": 3.5594250999999995,
      "system": 2.9918217,
      "min": 2.16916022436,
      "max": 2.25833905736,
      "times": [
        2.18403558536,
        2.25833905736,
        2.20173295736,
        2.21258593636,
        2.18412522736,
        2.19737593936,
        2.2226606553600003,
        2.16916022436,
        2.21092880136,
        2.2485101583600002
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 2.2091435147600005,
      "stddev": 0.01893134486423863,
      "median": 2.20887171636,
      "user": 3.542442299999999,
      "system": 2.9970532,
      "min": 2.1883365983600003,
      "max": 2.25120392636,
      "times": [
        2.2133554273600002,
        2.19384606736,
        2.21265959636,
        2.2132397693600003,
        2.2253265143600003,
        2.1883365983600003,
        2.25120392636,
        2.19712244736,
        2.20508383636,
        2.19126096436
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 2.211546146460001,
      "stddev": 0.030244074128081767,
      "median": 2.20938211786,
      "user": 3.5761952999999997,
      "system": 2.9938182999999996,
      "min": 2.17298140736,
      "max": 2.2686363053600003,
      "times": [
        2.18507727236,
        2.2187132533600002,
        2.1849214093600002,
        2.24295966336,
        2.20936112436,
        2.2343836823600003,
        2.2094031113600003,
        2.1890242353600002,
        2.17298140736,
        2.2686363053600003
      ]
    }
  ]
}

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

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 1.424 ± 0.019 1.384 1.459 1.02 ± 0.03
pacquet@main 1.457 ± 0.042 1.417 1.551 1.04 ± 0.04
pnpr@HEAD 1.402 ± 0.043 1.363 1.496 1.00
pnpr@main 1.461 ± 0.071 1.364 1.591 1.04 ± 0.06
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 1.4239389454600002,
      "stddev": 0.019314553174934537,
      "median": 1.4209462579600003,
      "user": 1.5293084999999997,
      "system": 1.8053105999999999,
      "min": 1.38420911846,
      "max": 1.45913740446,
      "times": [
        1.4377992424600001,
        1.42958658246,
        1.41721014146,
        1.41999589046,
        1.45913740446,
        1.4200511474600002,
        1.4356033674600002,
        1.38420911846,
        1.4218413684600002,
        1.4139551914600001
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.4572398962600004,
      "stddev": 0.04246245310762424,
      "median": 1.4460615959600003,
      "user": 1.5705858,
      "system": 1.7981643000000003,
      "min": 1.41667931746,
      "max": 1.5506282984600002,
      "times": [
        1.41667931746,
        1.5506282984600002,
        1.44188319946,
        1.4210452584600002,
        1.45314642146,
        1.44242000346,
        1.43108970046,
        1.45111327246,
        1.4497031884600002,
        1.5146903024600002
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 1.40157110796,
      "stddev": 0.042984497404747364,
      "median": 1.3852319029600002,
      "user": 1.5351025,
      "system": 1.7435771999999996,
      "min": 1.36313831546,
      "max": 1.49649366246,
      "times": [
        1.39111327346,
        1.37456255546,
        1.36313831546,
        1.49649366246,
        1.3749448664600001,
        1.3798765614600002,
        1.36896365046,
        1.4261218074600002,
        1.4499091424600001,
        1.39058724446
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 1.4612571035600002,
      "stddev": 0.07083349027852179,
      "median": 1.44706706796,
      "user": 1.5594819,
      "system": 1.7736645,
      "min": 1.36386049346,
      "max": 1.59106739246,
      "times": [
        1.3949307424600002,
        1.36386049346,
        1.52665533146,
        1.42622657746,
        1.59106739246,
        1.5391952954600001,
        1.46437931346,
        1.44430297746,
        1.4121217534600001,
        1.44983115846
      ]
    }
  ]
}

@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12170
Testbedpacquet

🚨 1 Alert

BenchmarkMeasure
Units
ViewBenchmark Result
(Result Δ%)
Upper Boundary
(Limit %)
isolated-linker.fresh-restore.cold-cache.cold-storeLatency
seconds (s)
📈 plot
🚷 threshold
🚨 alert (🔔)
4.81 s
(+125.10%)Baseline: 2.14 s
2.56 s
(187.58%)

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
2,222.04 ms
(-4.21%)Baseline: 2,319.59 ms
2,783.51 ms
(79.83%)
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
🚷 view threshold
1,423.94 ms
(-4.76%)Baseline: 1,495.14 ms
1,794.17 ms
(79.36%)
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
🚷 view threshold
🚨 view alert (🔔)
4,807.02 ms
(+125.10%)Baseline: 2,135.50 ms
2,562.60 ms
(187.58%)

isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
🚷 view threshold
687.71 ms
(+5.79%)Baseline: 650.08 ms
780.10 ms
(88.16%)
🐰 View full continuous benchmarking report in Bencher

@zkochan zkochan merged commit 3492bb8 into main Jun 3, 2026
28 checks passed
@zkochan zkochan deleted the gzip-metadata branch June 3, 2026 15:11
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.

pnpr + pacquet: gzip package metadata (packuments) — client requests it, server honors it

2 participants