Skip to content

pacquet: implement preferFrozenLockfile dispatch + stale-lockfile rewrite #11815

Description

@zkochan

Problem

pacquet install (no flag) doesn't read pnpm-lock.yaml at all. Two failure modes:

  • Lockfile is fresh (matches package.json): pacquet re-resolves everything from the registry instead of taking the cheap frozen-lockfile path. Slower than pnpm install, which silently goes frozen when the lockfile matches.
  • Lockfile is stale (manifest changed since last install): pacquet still ignores the lockfile and resolves from scratch, then (once issue pacquet: port the writable-lockfile install path (resolver → Lockfile adapter) #11813 lands) writes a new lockfile — losing any pinned versions / integrity / peer resolutions the lockfile encoded.

In pnpm, preferFrozenLockfile defaults to true and gates exactly this fast path. Pacquet already has the config field — config/src/lib.rs:319-323 defines prefer_frozen_lockfile: bool with #[default = true] — but it's not wired into the install dispatch.

Root cause

The dispatch in install.rs (around line 421 onward) looks at exactly two signals: the --frozen-lockfile flag and config.lockfile. It never consults config.prefer_frozen_lockfile, and the freshness check (install.rs:437-463) lives inside the frozen branch — so it's unreachable from any other dispatch.

Proposed change

Restructure the dispatch into four ordered checks:

  1. --frozen-lockfile flag → frozen path (unchanged).
  2. Lockfile exists and prefer_frozen_lockfile == true and the freshness check passes → frozen path. Same code, just hoisted out of the if-frozen branch into a shared predicate.
  3. Lockfile exists and matched by (2) is false (stale or preferFrozenLockfile: false) → re-resolve + write back. Reuse the writable-lockfile machinery landed by issue pacquet: port the writable-lockfile install path (resolver → Lockfile adapter) #11813. Important: the re-resolve should seed itself from the stale lockfile's pinned versions ("prefer wanted ranges if they still satisfy the spec") so unrelated entries don't shift — mirrors upstream's update: false resolver mode.
  4. No lockfile → writable-lockfile path (already covered by issue pacquet: port the writable-lockfile install path (resolver → Lockfile adapter) #11813).

Plus:

  • Lift the freshness check (satisfies_package_manifest, check_lockfile_settings, the overrides-aware manifest re-apply) into a standalone helper that callers in 1–3 share.
  • Honor the --prefer-frozen-lockfile / --no-prefer-frozen-lockfile CLI flags pnpm exposes so users can override per invocation.
  • Port the upstream installing/deps-installer/test/lockfile.ts cases that exercise the four dispatch states.

Dependencies

Blocked by issue #11813 (the writable-lockfile path is the dispatch target for states 3 and 4).

Why this is its own issue

The dispatch restructure is independently reviewable — it's a config-driven branching change against the existing helpers, not a new feature. Bundling it with issue #11813 would conflate "add the missing path" with "choose between paths", and the second decision is easier to review once the path it routes to is already in tree.


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

Metadata

Metadata

Assignees

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