Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📜 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)
📝 WalkthroughWalkthroughAdds Binary and Variations resolution types to the lockfile system, extends LockfileResolution and serde integration to handle them, tests round-trip serialization with exact field ordering, and routes them through the install pipeline as unsupported-pending-fetcher-implementation. ChangesBinary and Variations resolution support
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #457 +/- ##
==========================================
- Coverage 87.35% 87.28% -0.08%
==========================================
Files 113 114 +1
Lines 9356 9451 +95
==========================================
+ Hits 8173 8249 +76
- Misses 1183 1202 +19 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Micro-Benchmark ResultsLinux |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (3)
crates/lockfile/src/resolution.rs (1)
70-71: ⚡ Quick winUse
pnpmblob/mainlinks in new porting references.Please replace newly added
.../blob/94240bc046/...links with.../blob/main/...so the references stay aligned with upstream tip.As per coding guidelines: "When porting features... open files from
https://github.com/pnpm/pnpm/blob/main/...rather than from a permalinked SHA."Also applies to: 89-90, 101-102, 117-118, 130-131, 148-149, 165-166, 232-233, 251-252
🤖 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 `@crates/lockfile/src/resolution.rs` around lines 70 - 71, Update the hardcoded permalinked GitHub references to point at the upstream tip by replacing any occurrences of "blob/94240bc046" with "blob/main" in the comment links (e.g., the comment referencing BinaryResolution.bin and the other inline links around the same area). Search for the exact URL substring "github.com/pnpm/pnpm/blob/94240bc046" in this file (crates/lockfile/src/resolution.rs) and update each to "github.com/pnpm/pnpm/blob/main" so all porting references follow the coding guideline.crates/workspace/src/manifest/tests.rs (1)
74-80: ⚡ Quick winLog the actual error before the
assert!(matches!(...))check.For this non-
assert_eq!assertion, print the error explicitly so failures are easier to diagnose from logs.💡 Suggested tweak
let err = read_workspace_manifest(tmp.path()).unwrap_err(); + eprintln!("workspace manifest parse error: {err:?}"); assert!( matches!( err, ReadWorkspaceManifestError::Invalid(InvalidWorkspaceManifestError::EmptyPackageEntry), ), "unexpected error: {err}", );Based on learnings: In Rust test code, when using assertions like
assert!, add logging so failures are diagnosable without reruns.🤖 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 `@crates/workspace/src/manifest/tests.rs` around lines 74 - 80, Print or log the actual error value (err) immediately before the assert so test failures show the concrete error; for example emit err with eprintln!, dbg!(err), or println! and then keep the existing assertion that checks for ReadWorkspaceManifestError::Invalid(InvalidWorkspaceManifestError::EmptyPackageEntry) so failure output includes the error value for easier diagnosis.crates/workspace/src/projects/tests.rs (1)
72-79: ⚡ Quick winAdd explicit diagnostic logging around non-
assert_eq!checks.These
assert!checks should lognamesexplicitly to aid failure triage in CI output.💡 Suggested tweak
+ eprintln!("workspace project names: {names:?}"); assert!( !names.contains(&"foo".to_string()), "node_modules contents must not surface as workspace projects: {names:?}", ); assert!( names.contains(&"real".to_string()), "expected the `real` project to be enumerated; got {names:?}", );Based on learnings: In Rust test code, when using assertions like
assert!, add logging so failures are diagnosable without reruns.🤖 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 `@crates/workspace/src/projects/tests.rs` around lines 72 - 79, Add explicit diagnostic output for the `names` variable around the two `assert!` checks so CI failures show the enumerated projects; before the `assert!( !names.contains(&"foo".to_string()) )` and before the `assert!( names.contains(&"real".to_string()) )` add an explicit log such as eprintln!("names: {:?}", names) (or dbg!(names) / tracing::debug if tests use tracing) so the actual `names` contents are printed when an assertion fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/lockfile/src/resolved_dependency/tests.rs`:
- Line 10: The bare assert! calls lack failure context; update each assertion
that checks parsed.as_link_target().is_none() (and the other plain assert!
occurrences in the same test file) to include a diagnostic message or replace
with an assertion macro that prints values (e.g., use assert!(cond, "parsed={:?}
expected none", parsed) or assert_eq!(parsed.as_link_target(), None,
"parsed={:?}", parsed)); alternatively add an eprintln! immediately before the
assertion to print the relevant variables (e.g., parsed and
parsed.as_link_target()) so failures show actual vs expected; target the
assertions using the identifier parsed and the method as_link_target (and the
other plain assert! lines noted) when making the edits.
In `@crates/package-manager/src/install.rs`:
- Line 267: The frozen-workspace preflight only validates the root importer via
satisfies_package_manifest with Lockfile::ROOT_IMPORTER_KEY, so other workspace
importers can be stale; update InstallFrozenLockfile to validate every
materialized importer before proceeding: either (a) when given workspace_root,
enumerate workspace manifests (all importer ids / package.json paths) and call
satisfies_package_manifest for each importer key found in the lockfile, or (b)
gate the existing check to run per-target importer when installing a single
importer. Specifically, modify the InstallFrozenLockfile path that currently
references workspace_root and Lockfile::ROOT_IMPORTER_KEY to iterate all
importer keys (or the actual importer being installed) and ensure
satisfies_package_manifest is invoked for each so the frozen install fails if
any importer is out of date (apply same fix to the analogous block around lines
325–330).
In `@crates/workspace/src/project_manifest.rs`:
- Around line 95-102: The code in read_exact_project_manifest lowercases the
file basename before matching, allowing case variants like "PACKAGE.JSON" to
match; change this to perform an exact match by removing the to_ascii_lowercase
call so basename remains the original file_name string (i.e., compute basename
with file_name().map(|n| n.to_string_lossy().to_string()).unwrap_or_default()),
then match basename.as_str() against "package.json" and return
PackageManifest::from_path(manifest_path.to_path_buf()).map_err(ReadProjectManifestError::Read)
or Err(ReadProjectManifestError::UnsupportedName { basename }) as before.
In `@crates/workspace/src/projects.rs`:
- Around line 149-171: The loop currently only accumulates matches into
manifest_paths and ignores negated patterns, so implement proper include vs
exclude handling: first iterate patterns and separate them into include_patterns
and exclude_patterns based on whether normalize_pattern(pattern) yields a
leading '!' (or pattern.starts_with('!'))—strip the '!' for exclude entries—then
for each include pattern use Glob::new/ glob.walk(...) to insert matches into
manifest_paths, and for each exclude pattern use Glob::new/ glob.walk(...) to
remove matching paths from manifest_paths (convert walk errors into the same
FindWorkspaceProjectsError variants as existing code). Apply the same change to
the other identical block (the one around the second occurrence) so exclusion
semantics mirror pnpm.
---
Nitpick comments:
In `@crates/lockfile/src/resolution.rs`:
- Around line 70-71: Update the hardcoded permalinked GitHub references to point
at the upstream tip by replacing any occurrences of "blob/94240bc046" with
"blob/main" in the comment links (e.g., the comment referencing
BinaryResolution.bin and the other inline links around the same area). Search
for the exact URL substring "github.com/pnpm/pnpm/blob/94240bc046" in this file
(crates/lockfile/src/resolution.rs) and update each to
"github.com/pnpm/pnpm/blob/main" so all porting references follow the coding
guideline.
In `@crates/workspace/src/manifest/tests.rs`:
- Around line 74-80: Print or log the actual error value (err) immediately
before the assert so test failures show the concrete error; for example emit err
with eprintln!, dbg!(err), or println! and then keep the existing assertion that
checks for
ReadWorkspaceManifestError::Invalid(InvalidWorkspaceManifestError::EmptyPackageEntry)
so failure output includes the error value for easier diagnosis.
In `@crates/workspace/src/projects/tests.rs`:
- Around line 72-79: Add explicit diagnostic output for the `names` variable
around the two `assert!` checks so CI failures show the enumerated projects;
before the `assert!( !names.contains(&"foo".to_string()) )` and before the
`assert!( names.contains(&"real".to_string()) )` add an explicit log such as
eprintln!("names: {:?}", names) (or dbg!(names) / tracing::debug if tests use
tracing) so the actual `names` contents are printed when an assertion fails.
🪄 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: c556779c-0b26-470c-b26b-98ba59fb3d75
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (30)
Cargo.tomlcrates/config/src/lib.rscrates/lockfile/src/resolution.rscrates/lockfile/src/resolution/tests.rscrates/lockfile/src/resolved_dependency.rscrates/lockfile/src/resolved_dependency/tests.rscrates/lockfile/src/save_lockfile/tests.rscrates/package-manager/Cargo.tomlcrates/package-manager/src/build_modules/tests.rscrates/package-manager/src/build_sequence.rscrates/package-manager/src/build_sequence/tests.rscrates/package-manager/src/create_virtual_store.rscrates/package-manager/src/install.rscrates/package-manager/src/install_frozen_lockfile.rscrates/package-manager/src/install_package_by_snapshot.rscrates/package-manager/src/installability/tests.rscrates/package-manager/src/symlink_direct_dependencies.rscrates/package-manager/src/symlink_direct_dependencies/tests.rscrates/real-hoist/src/lib.rscrates/real-hoist/src/tests.rscrates/workspace/Cargo.tomlcrates/workspace/src/lib.rscrates/workspace/src/manifest.rscrates/workspace/src/manifest/tests.rscrates/workspace/src/project_manifest.rscrates/workspace/src/project_manifest/tests.rscrates/workspace/src/projects.rscrates/workspace/src/projects/tests.rscrates/workspace/src/root_finder.rscrates/workspace/src/root_finder/tests.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). (5)
- GitHub Check: Run benchmark on ubuntu-latest
- GitHub Check: Lint and Test (macos-latest)
- GitHub Check: Code Coverage
- GitHub Check: Lint and Test (windows-latest)
- GitHub Check: Run benchmark on ubuntu-latest
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Preserve existing method chains andpipe-traitchains; do not break them into intermediateletbindings unless there is a concrete justification such as a compilation failure, borrow checker rejection, meaningful performance improvement, or other technical necessity. Refactoring for style alone is not sufficient justification.
Choose owned vs. borrowed parameters to minimize copies; prefer borrowed types (&Pathover&PathBuf,&strover&String) when it does not force extra copies.
PreferArc::clone(&x)andRc::clone(&x)overx.clone()for reference-counted types to make the cost visible at the call site.
Do not use star imports inside module bodies. Writeuse super::{Foo, bar}instead ofuse super::*;for any glob whose target is a module you control. External-crate preludes (e.g.,use rayon::prelude::*;) and root-of-module re-exports (e.g.,pub use submodule::*;inlib.rs) are exceptions.
Follow Rust API Guidelines for naming, as documented in https://rust-lang.github.io/api-guidelines/naming.html.
Declare a newtype wrapper for any branded string type being ported from TypeScript pnpm. Do not collapse the brand into a plainStringor&str; give the type its own struct so misuse is a type error.
When porting branded string types where upstream TypeScript always validates before construction, validate in the Rust port too. Construct the wrapper only viaTryFrom<String>and/orFromStr; do not provide an infallible public constructor that takes an arbitrary string.
For branded string types where upstream TypeScript never validates (used purely for type-safety to prevent confusion between string slots), expose an infallibleFrom<String>andFrom<&str>constructor in the Rust wrapper.
When upstream TypeScript occasionally constructs a branded type without validation (via bareasassertion), add afrom_str_unchecked(or similarly named) constructor on the Rust side. Keep the validating constructor as well; `from_str_u...
Files:
crates/package-manager/src/build_sequence.rscrates/real-hoist/src/tests.rscrates/package-manager/src/build_sequence/tests.rscrates/workspace/src/project_manifest/tests.rscrates/package-manager/src/install_package_by_snapshot.rscrates/workspace/src/manifest/tests.rscrates/workspace/src/lib.rscrates/lockfile/src/resolved_dependency/tests.rscrates/real-hoist/src/lib.rscrates/package-manager/src/installability/tests.rscrates/package-manager/src/create_virtual_store.rscrates/workspace/src/project_manifest.rscrates/package-manager/src/install.rscrates/package-manager/src/install_frozen_lockfile.rscrates/package-manager/src/build_modules/tests.rscrates/lockfile/src/save_lockfile/tests.rscrates/workspace/src/projects/tests.rscrates/lockfile/src/resolution.rscrates/workspace/src/root_finder/tests.rscrates/lockfile/src/resolved_dependency.rscrates/workspace/src/root_finder.rscrates/lockfile/src/resolution/tests.rscrates/config/src/lib.rscrates/workspace/src/projects.rscrates/package-manager/src/symlink_direct_dependencies.rscrates/package-manager/src/symlink_direct_dependencies/tests.rscrates/workspace/src/manifest.rs
🧠 Learnings (3)
📚 Learning: 2026-05-07T23:19:08.272Z
Learnt from: KSXGitHub
Repo: pnpm/pacquet PR: 401
File: tasks/integrated-benchmark/src/work_env.rs:343-344
Timestamp: 2026-05-07T23:19:08.272Z
Learning: When reviewing Rust code in pnpm/pacquet for deprecated API usage, do not automatically treat `serde_saphyr::to_string` as deprecated. In `serde-saphyr` v0.0.25, `serde_saphyr::to_string` has no `#[deprecated]` attribute (the `#[deprecated]` later in `serde-saphyr-0.0.25/src/lib.rs` applies to a different function). Only flag `serde_saphyr::to_string` as deprecated if the resolved dependency version’s source shows `#[deprecated]` on that specific function.
Applied to files:
crates/package-manager/src/build_sequence.rscrates/real-hoist/src/tests.rscrates/package-manager/src/build_sequence/tests.rscrates/workspace/src/project_manifest/tests.rscrates/package-manager/src/install_package_by_snapshot.rscrates/workspace/src/manifest/tests.rscrates/workspace/src/lib.rscrates/lockfile/src/resolved_dependency/tests.rscrates/real-hoist/src/lib.rscrates/package-manager/src/installability/tests.rscrates/package-manager/src/create_virtual_store.rscrates/workspace/src/project_manifest.rscrates/package-manager/src/install.rscrates/package-manager/src/install_frozen_lockfile.rscrates/package-manager/src/build_modules/tests.rscrates/lockfile/src/save_lockfile/tests.rscrates/workspace/src/projects/tests.rscrates/lockfile/src/resolution.rscrates/workspace/src/root_finder/tests.rscrates/lockfile/src/resolved_dependency.rscrates/workspace/src/root_finder.rscrates/lockfile/src/resolution/tests.rscrates/config/src/lib.rscrates/workspace/src/projects.rscrates/package-manager/src/symlink_direct_dependencies.rscrates/package-manager/src/symlink_direct_dependencies/tests.rscrates/workspace/src/manifest.rs
📚 Learning: 2026-05-01T10:01:33.766Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 349
File: crates/reporter/src/tests.rs:121-121
Timestamp: 2026-05-01T10:01:33.766Z
Learning: In Rust test code, follow the repo’s CODE_STYLE_GUIDE test-logging rule: add logging (e.g., `eprintln!`/`eprintln!(...)`) so that useful diagnostic values are printed when a test fails, unless the assertion is `assert_eq!` (where the differing values are already included). Concretely, if you use assertions like `assert!`, `assert_ne!`, etc., ensure the test logs the relevant actual/expected values (or context) before/around the assertion so failures can be diagnosed without rerunning.
Applied to files:
crates/real-hoist/src/tests.rscrates/package-manager/src/build_sequence/tests.rscrates/workspace/src/project_manifest/tests.rscrates/workspace/src/manifest/tests.rscrates/lockfile/src/resolved_dependency/tests.rscrates/package-manager/src/installability/tests.rscrates/package-manager/src/build_modules/tests.rscrates/lockfile/src/save_lockfile/tests.rscrates/workspace/src/projects/tests.rscrates/workspace/src/root_finder/tests.rscrates/lockfile/src/resolution/tests.rscrates/package-manager/src/symlink_direct_dependencies/tests.rs
📚 Learning: 2026-05-01T10:01:33.766Z
Learnt from: zkochan
Repo: pnpm/pacquet PR: 349
File: crates/reporter/src/tests.rs:121-121
Timestamp: 2026-05-01T10:01:33.766Z
Learning: In this repo’s Rust tests (run via `cargo nextest`), stdout/stderr from passing tests is captured and is only shown when a test fails. As a result, `eprintln!` (and similar stderr logging) in these tests should generally not be flagged as CI “noise” on the happy path; CI output should only appear for failing tests.
Applied to files:
crates/real-hoist/src/tests.rs
🔇 Additional comments (15)
crates/package-manager/src/installability/tests.rs (1)
60-60: LGTM!crates/package-manager/src/build_modules/tests.rs (1)
253-256: LGTM!crates/package-manager/src/build_sequence/tests.rs (1)
47-50: LGTM!crates/lockfile/src/resolution.rs (1)
65-85: LGTM!Also applies to: 92-126, 128-174, 184-185, 194-201, 212-214, 242-243, 268-273
crates/package-manager/src/create_virtual_store.rs (1)
700-713: LGTM!crates/lockfile/src/resolution/tests.rs (1)
2-4: LGTM!Also applies to: 9-9, 363-533
crates/package-manager/src/install_package_by_snapshot.rs (1)
195-211: LGTM!Also applies to: 281-288
Cargo.toml (1)
37-37: LGTM!Also applies to: 92-92
crates/lockfile/src/resolved_dependency.rs (1)
21-21: LGTM!Also applies to: 24-161
crates/lockfile/src/save_lockfile/tests.rs (1)
87-162: LGTM!crates/lockfile/src/resolved_dependency/tests.rs (1)
1-9: LGTM!Also applies to: 11-18, 20-27, 29-55, 57-58
crates/real-hoist/src/tests.rs (1)
26-26: LGTM!crates/package-manager/src/build_sequence.rs (1)
142-151: LGTM!crates/real-hoist/src/lib.rs (1)
341-351: LGTM!crates/workspace/src/manifest.rs (1)
1-147: LGTM!
Integrated-Benchmark Report (Linux)Scenario: Frozen Lockfile
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 2.5962747819799996,
"stddev": 0.08865942580706526,
"median": 2.59714185138,
"user": 2.60447104,
"system": 3.61983306,
"min": 2.46138070888,
"max": 2.72179310288,
"times": [
2.63889948688,
2.72179310288,
2.46138070888,
2.53155832388,
2.71234428488,
2.63019900088,
2.49508666888,
2.56408470188,
2.55481523788,
2.65258630288
]
},
{
"command": "pacquet@main",
"mean": 2.64969458678,
"stddev": 0.06494354745949904,
"median": 2.64544669538,
"user": 2.6277687399999996,
"system": 3.68217406,
"min": 2.55640683788,
"max": 2.7333184638800003,
"times": [
2.73196790488,
2.6126393228800002,
2.55640683788,
2.7333184638800003,
2.62402593188,
2.62332196288,
2.70280569688,
2.68684411688,
2.66686745888,
2.55874817088
]
},
{
"command": "pnpm",
"mean": 6.460643567379999,
"stddev": 0.07843185595198221,
"median": 6.459978277379999,
"user": 9.51861294,
"system": 4.59242806,
"min": 6.3217595608799995,
"max": 6.60370576588,
"times": [
6.46662568688,
6.50496020588,
6.38383998688,
6.5142795078799995,
6.453330867879999,
6.500430992879999,
6.3217595608799995,
6.60370576588,
6.404643732879999,
6.452859365879999
]
}
]
}Scenario: Frozen Lockfile (Hot Cache)
BENCHMARK_REPORT.json{
"results": [
{
"command": "pacquet@HEAD",
"mean": 0.7082260775400002,
"stddev": 0.049438469153299094,
"median": 0.6920180630400001,
"user": 0.38427461999999996,
"system": 1.48750662,
"min": 0.67016103254,
"max": 0.8393263795400001,
"times": [
0.8393263795400001,
0.6989926085400001,
0.70831389554,
0.6919423625400001,
0.6808556815400001,
0.67813965454,
0.6879979155400001,
0.7344374815400001,
0.6920937635400001,
0.67016103254
]
},
{
"command": "pacquet@main",
"mean": 0.72595592754,
"stddev": 0.04667510413223731,
"median": 0.69879369204,
"user": 0.38495442,
"system": 1.51847872,
"min": 0.6849787835400001,
"max": 0.8110957915400001,
"times": [
0.7395563365400001,
0.7551873295400001,
0.6918275315400001,
0.6932644355400001,
0.69424667354,
0.8110957915400001,
0.70334071054,
0.6915225505400001,
0.6849787835400001,
0.7945391325400001
]
},
{
"command": "pnpm",
"mean": 2.7549885392399998,
"stddev": 0.12564874780573618,
"median": 2.6891557535399997,
"user": 3.362664219999999,
"system": 2.2878424199999996,
"min": 2.65652361654,
"max": 3.03532940754,
"times": [
2.6729590005399997,
2.67495020254,
2.87990414354,
2.69666261054,
2.68152560554,
2.68164889654,
2.65652361654,
2.7178803065399997,
3.03532940754,
2.85250160254
]
}
]
} |
|
The branch was based on a stale local
I can file these as separate issues / pick them up as targeted PRs once the runtime-deps slice (#437) work isn't holding the branch. The lockfile-types slice in this PR doesn't touch any of those files. Written by an agent (Claude Code, claude-opus-4-7). |
Add the lockfile types pnpm v11 writes for runtime dependencies
(`node@runtime:`, `deno@runtime:`, `bun@runtime:`):
- `BinaryResolution { url, integrity, bin, archive, prefix? }`
matching upstream's [`BinaryResolution`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L41-L49).
`bin` is `BinarySpec::Single(String) | BinarySpec::Map(BTreeMap)` —
the untagged union pnpm writes. `archive` is the lowercase
`BinaryArchive::Tarball | BinaryArchive::Zip` discriminator.
`prefix` (the archive's top-level directory basename, only set on
the `.zip` branch in upstream's node-resolver) skips serialization
when `None`.
- `PlatformAssetTarget { os, cpu, libc? }` and
`PlatformAssetResolution { resolution, targets }` per
[`resolving/resolver-base/src/index.ts`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/resolver-base/src/index.ts#L60-L69).
`libc` is `Option<String>` (rather than an enum) so an upstream
addition beyond the current `musl` value lands without a churning
serde migration.
- `VariationsResolution { variants }` and the `LockfileResolution`
+ `TaggedResolution` arms that route both new shapes through the
existing `from/into ResolutionSerde` round-trip. The lockfile
major stays at 9 — confirmed against
[`core/constants/src/index.ts`](https://github.com/pnpm/pnpm/blob/94240bc046/core/constants/src/index.ts)
— so the existing `lockfile_version.major == 9` assertion holds for
v11 lockfiles carrying runtime entries.
- Install dispatch stubs in `install_package_by_snapshot.rs` and
`create_virtual_store.rs` raise `UnsupportedResolution { kind:
"binary" | "variations" }` until Slice D wires the fetcher.
Adding these arms keeps the workspace compiling without forcing
the full install path to land in this slice. `Variations` warm-
prefetch returns `Ok(None)` so the dispatcher routes through the
cold path where the unsupported-kind error fires; pnpm's pipeline
unwraps `Variations` before this layer ever sees one, so the
branch is unreachable on a well-formed install. Slice D replaces
these stubs with real dispatch.
Tests: serde round-trip for tarball-shape `BinaryResolution` (with
`bin: <string>`, no `prefix`), zip-shape `BinaryResolution` (with
`bin: <map>` and `prefix`), and a two-variant `VariationsResolution`
covering `(darwin, arm64)` and `(linux, x64, musl)` to pin the
`libc?` omission rule.
Part of #437.
---
Written by an agent (Claude Code, claude-opus-4-7).
Two doc-comment wording nits from PR #457 review: - `install_package_by_snapshot.rs:218` claimed the arms guard against a "non-exhaustive-match panic". That's the wrong failure mode: adding a `LockfileResolution` variant without the arms would surface as a *compile-time* non-exhaustive-match error, not a runtime panic. Reword so the comment reflects the actual mechanic — these arms are what makes Slice A standalone. - `create_virtual_store.rs:738` claimed the install dispatcher unwraps `Variations` before this helper sees it, but the match arm explicitly handles it. Reword to describe what's actually happening: `Variations` is a meta-shape with no warm-key shape of its own; both `Binary` and `Variations` route through the cold path until Slice D lands variant selection + fetcher dispatch. No behavior change; comment text only. --- Written by an agent (Claude Code, claude-opus-4-7).
Pull in 4 commits from upstream main: - feat(lockfile): BinaryResolution + VariationsResolution (#457) - feat: hoisting support (hoistPattern + publicHoistPattern) (#445) - test(git-fetcher): port §E git-fetcher tests (#462) - feat(real-hoist): ancestor-path-aware peer-shadow refusal (#461) Conflict: `crates/config/src/lib.rs` — the hoisting PR (#445) added `pub mod matcher;` adjacent to my `mod env_replace;`. Keep both module declarations.
Summary
Slice A of #437. Adds the lockfile types pnpm v11 writes for runtime dependencies (
node@runtime:,deno@runtime:,bun@runtime:); the install pipeline doesn't dispatch them yet (subsequent slices). No new workspace deps.BinaryResolution { url, integrity, bin, archive, prefix? }— mirrors upstream'sBinaryResolution.binisBinarySpec::Single(String) | BinarySpec::Map(BTreeMap)(untagged);archiveis the lowercaseBinaryArchive::Tarball | BinaryArchive::Zipdiscriminator;prefix(only set on the.zipbranch upstream) skips serialization whenNone.PlatformAssetTarget { os, cpu, libc? }+PlatformAssetResolution { resolution, targets }perresolver-base.libcisOption<String>(not an enum) so an upstream addition beyond the currentmuslvalue lands without a serde migration.VariationsResolution { variants }+ theLockfileResolution/TaggedResolutionarms routing both new shapes through the existingfrom/into ResolutionSerderound-trip.core/constants/src/index.ts(LOCKFILE_MAJOR_VERSION = '9'), so the existinglockfile_version.major == 9assertion holds for v11 lockfiles carrying runtime entries.Install-dispatch stubs.
install_package_by_snapshot.rsandcreate_virtual_store.rsraiseInstallPackageBySnapshotError::UnsupportedResolution { kind: "binary" | "variations" }until Slice D wires the fetcher. Adding these arms keeps the workspace compiling without forcing the full install path to land in this slice. The warm-prefetch path returnsOk(None)forVariations, routing through the cold dispatcher where the unsupported-kind error fires; upstream unwrapsVariationsbefore this layer ever sees one, so the branch is unreachable on well-formed input.Test plan
just ready— 830 tests pass (2 skipped)taplo format --check— cleanjust dylint(perfectionist) — cleanBinaryResolutionwithbin: <string>and noprefix; zip-shapeBinaryResolutionwithbin: <map>andprefix; two-variantVariationsResolutioncovering(darwin, arm64)and(linux, x64, musl)to pin thelibc?omission rule; single-variantVariationsResolutionserialise.Follow-up slices on #437
pick_variant(variants, host_target)+ host platform plumbing.pacquet-tarballwithignore_file_pattern; zip path withzip = "5"workspace dep + path-traversal validation +NODE_EXTRAS_IGNORE_PATTERN).Binary/Variations+ bin linking viapacquet-cmd-shim.--no-runtimeCLI flag +Config.skip_runtimes.plans/TEST_PORTING.mdInstallation Of Runtimes section.Upstream
pnpm/pnpm@
94240bc046.Written by an agent (Claude Code, claude-opus-4-7).
Summary by CodeRabbit