Follow-up to #434 (umbrella, closed). Pacquet's slice 1 (#439) computes a SkippedSnapshots set on every frozen-lockfile install but never serializes it. The next install always recomputes from scratch — correct for the common case (constraints in the lockfile drive the recompute), incorrect for the edge case upstream cares about: a snapshot that was previously skipped should stay skipped on the next run even when the lockfile's per-snapshot metadata is later relaxed.
Scope
Mirror pnpm/pnpm@94240bc046 at three sites:
Write
Modules.skipped: Vec<String> is already declared at crates/modules-yaml/src/lib.rs:197 and sorted-on-write at :407, but build_modules_manifest leaves it Default::default(). Wire SkippedSnapshots (produced inside InstallFrozenLockfile::run) up to Install::run so build_modules_manifest can serialize the PackageKeys as the sorted depPath string list pnpm writes — see upstream literal at index.ts:1625.
Read + seed
On a subsequent install, read .modules.yaml.skipped (via read_modules_manifest) and seed the in-memory SkippedSnapshots before invoking compute_skipped_snapshots. The seed entries short-circuit the per-snapshot re-check, mirroring upstream's early return at lockfileToDepGraph.ts:194: if a key is already in the skip set, the per-snapshot installability check is bypassed and no pnpm:skipped-optional-dependency event is re-emitted.
The seed-preservation must also apply on the fast path (any_installability_constraint returns false), so a previously-skipped snapshot survives even when the lockfile's per-snapshot constraints have since been removed.
Per-snapshot re-check
For non-seeded snapshots, compute_skipped_snapshots already re-runs package_is_installable from scratch — that covers the "host arch changed since last install" case upstream guards at :206-215. No change needed beyond accepting the seed input.
Tests
Port from installing/deps-installer/test/install/optionalDependencies.ts:
Out of scope
- Current-lockfile write (
<virtual_store_dir>/lock.yaml) — that's umbrella slice 6, builds on this slice.
--no-optional plumbing — umbrella slice 5.
--force headless re-check (which bypasses the seed) — pacquet doesn't expose --force yet.
Upstream pin
pnpm/pnpm@94240bc046. Pacquet slice 1 in #439, slice 2 in #456; this is umbrella slice 3.
Written by an agent (Claude Code, claude-opus-4-7).
Follow-up to #434 (umbrella, closed). Pacquet's slice 1 (#439) computes a
SkippedSnapshotsset on every frozen-lockfile install but never serializes it. The next install always recomputes from scratch — correct for the common case (constraints in the lockfile drive the recompute), incorrect for the edge case upstream cares about: a snapshot that was previously skipped should stay skipped on the next run even when the lockfile's per-snapshot metadata is later relaxed.Scope
Mirror pnpm/pnpm@94240bc046 at three sites:
Write
Modules.skipped: Vec<String>is already declared atcrates/modules-yaml/src/lib.rs:197and sorted-on-write at:407, butbuild_modules_manifestleaves itDefault::default(). WireSkippedSnapshots(produced insideInstallFrozenLockfile::run) up toInstall::runsobuild_modules_manifestcan serialize thePackageKeys as the sorted depPath string list pnpm writes — see upstream literal atindex.ts:1625.Read + seed
On a subsequent install, read
.modules.yaml.skipped(viaread_modules_manifest) and seed the in-memorySkippedSnapshotsbefore invokingcompute_skipped_snapshots. The seed entries short-circuit the per-snapshot re-check, mirroring upstream's early return atlockfileToDepGraph.ts:194: if a key is already in the skip set, the per-snapshot installability check is bypassed and nopnpm:skipped-optional-dependencyevent is re-emitted.The seed-preservation must also apply on the fast path (
any_installability_constraintreturns false), so a previously-skipped snapshot survives even when the lockfile's per-snapshot constraints have since been removed.Per-snapshot re-check
For non-seeded snapshots,
compute_skipped_snapshotsalready re-runspackage_is_installablefrom scratch — that covers the "host arch changed since last install" case upstream guards at:206-215. No change needed beyond accepting the seed input.Tests
Port from
installing/deps-installer/test/install/optionalDependencies.ts::74skip optional dependency that does not support the current OS— removenode_modules, reinstall withfrozenLockfile: true, verify skipped packages remain skipped. This is the first survives-frozen-reinstall coverage and the canonical write-then-seed-then-read flow.:470skip optional dependency that does not support the current OS, when doing install on a subset of workspace projects— same shape, multi-importer.Out of scope
<virtual_store_dir>/lock.yaml) — that's umbrella slice 6, builds on this slice.--no-optionalplumbing — umbrella slice 5.--forceheadless re-check (which bypasses the seed) — pacquet doesn't expose--forceyet.Upstream pin
pnpm/pnpm@94240bc046. Pacquet slice 1 in #439, slice 2 in #456; this is umbrella slice 3.
Written by an agent (Claude Code, claude-opus-4-7).