Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.
This repository was archived by the owner on May 14, 2026. It is now read-only.

Write a filtered current lockfile (#434 slice 6) #493

Description

@zkochan

Follow-up to #434 (umbrella, closed). Pacquet currently writes the raw wanted lockfile as <virtual_store_dir>/lock.yaml (install.rs:389-393). Upstream pnpm writes a filtered version — the lockfile with optional + skipped subtrees pruned and include flags applied — so a subsequent install can diff against what was actually materialized rather than against the resolver's full ambition.

Without the prune, the current lockfile claims optional snapshots that were dropped by --no-optional (slice 5) or by installability (slice 1) or by fetch failures (slice 4) are present. The next install's diff would treat those as "already done" and skip work that should actually run.

Scope

Port filterLockfileByImportersAndEngine as a Lockfile::filter_for_current on pacquet-lockfile, with one pacquet-specific simplification: instead of re-running engine + supportedArchitectures + skipped checks at filter time, reuse the SkippedSnapshots set already produced during install — its union of installability + fetch_failed + optional_excluded is the exact set upstream's filter would also drop, just precomputed during the install pipeline. Same observable filter result, no duplicated walk.

Upstream's flow pinned at pnpm/pnpm@94240bc046:

  • Filter call: deps-restorer/src/index.ts:311const { lockfile: filteredLockfile, ... } = filterLockfileByImportersAndEngine(wantedLockfile, initialImporterIds, filterOpts).
  • Current-lockfile write: deps-restorer/src/index.ts:687-695writeCurrentLockfile(currentLockfileDir, filteredLockfile).
  • Importer-side filter (include): filterImporter.ts:4-16 — drop dependencies / devDependencies / optionalDependencies whose include bool is false.
  • Importer.optionalDependencies post-filter: filterLockfileByImportersAndEngine.ts:75-83 — even when include.optionalDependencies is true, drop entries whose resolved snapshot didn't survive the packages-level filter.

Pacquet's implementation

  • New helper on pacquet-package-manager (not pacquet-lockfileIncludedDependencies lives in pacquet-modules-yaml and SkippedSnapshots lives in pacquet-package-manager, so the filter belongs where it can see both): filter_for_current(lockfile: &Lockfile, included: IncludedDependencies, skipped: &SkippedSnapshots) -> Lockfile.
  • Importer filter: drop dep maps per include; further filter optional_dependencies so entries pointing at dropped snapshots are removed too.
  • Reachability walk: from filtered importer roots, BFS through snapshot dependencies + optional_dependencies, skipping any key in skipped. The result is the set of snapshot keys to keep.
  • Snapshot + packages filter: drop entries whose key isn't reachable.
  • Wire site: install.rs:389-393 already calls save_current_to_virtual_store_dir. Replace the raw write with lockfile.filter_for_current(included, &frozen_skipped).save_current_to_virtual_store_dir(...).

Tests to port

Plus unit tests on filter_for_current itself: importer-level filtering, reachability walk, skipped-snapshot drop, optional_dependencies post-filter against the packages-level prune.

Out of scope

  • Hoisted-linker variant (optionalDependencies.ts:633) — pacquet doesn't fully wire the hoisted node-linker through the lockfile-write path yet; folding it into slice 6 mixes concerns. Tracked separately under Support nodeLinker: 'hoisted' — umbrella #438 (hoisted-linker umbrella).
  • flipping current_lockfile_exists — actually already happens through the on-disk file presence check; not a separate bool.
  • pnpm install --filter slicing — selectedImporterIds upstream concept; pacquet doesn't have --filter yet.

Upstream pin

pnpm/pnpm@94240bc046. Pacquet umbrella slice 1 in #439, slice 2 in #456, slice 3 in #467, slice 4 in #474, slice 5 in #485; this is umbrella slice 6.


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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions