Summary
pacquet does not apply pnpm.overrides during fresh-lockfile resolution. The override set is recorded in the lockfile's overrides: section, but the overridden versions are never substituted into the resolved dependency graph, so a fresh pacquet install resolves overridden dependencies to their un-overridden versions. This affects all override forms — plain version pins, npm: aliases, and catalog: values — not just one. Surfaced while working the lockfile-parity npm: alias slice (#12266).
Reproduction
# pnpm-workspace.yaml
overrides:
js-yaml: 4.0.0
pacquet install --lockfile-only # resolves js-yaml@4.2.0 (override ignored)
pnpm install --lockfile-only # resolves js-yaml@4.0.0 (override applied)
Same divergence with a transitive consumer (write-yaml-file@5.0.0 → js-yaml) and with npm:/catalog: override values:
| override |
pnpm |
pacquet |
js-yaml@^4.0.0: 4.0.0 |
4.0.0 |
4.2.0 |
js-yaml@^4.0.0: npm:@zkochan/js-yaml@0.0.11 |
@zkochan/js-yaml@0.0.11 |
4.2.0 |
js-yaml@^4.0.0: 'catalog:' (→ npm:@zkochan/js-yaml@0.0.11) |
@zkochan/js-yaml@0.0.11 + expanded in overrides: |
4.2.0 + literal 'catalog:' in overrides: |
Root cause
VersionsOverrider (pacquet-package-manager/src/overrides.rs) correctly rewrites a manifest's deps and is unit-tested — but it is only invoked in check_lockfile_freshness (install.rs:~1256), against a cloned root manifest, for the frozen-path specifier comparison. The fresh-resolution path (install_with_fresh_lockfile) never applies it: its only resolver manifest hook is the packageExtensions hook (into_manifest_hook), and the importer manifest handed to the resolver is pristine.
pnpm applies overrides via the readPackage hook (createVersionsOverrider), which runs on every resolved manifest, so overrides take effect on direct and transitive deps alike.
Fix direction
Thread the override-applying hook into the fresh resolver as a manifest hook (composed with the existing packageExtensions hook), so it rewrites every resolved manifest transitively — matching pnpm's readPackage flow. Two dependent symptoms then resolve too:
catalog:-valued overrides expand to their concrete spec in the lockfile overrides: section (currently written literally as 'catalog:'), since the resolved override map is used.
- Transitively-overridden deps (e.g.
write-yaml-file → js-yaml) pick up the override.
The catalog-snapshot half of category 2 (aliased entries dropped from catalogs:) is fixed separately in #12274.
Written by an agent (Claude Code, claude-opus-4-8).
Summary
pacquet does not apply
pnpm.overridesduring fresh-lockfile resolution. The override set is recorded in the lockfile'soverrides:section, but the overridden versions are never substituted into the resolved dependency graph, so a freshpacquet installresolves overridden dependencies to their un-overridden versions. This affects all override forms — plain version pins,npm:aliases, andcatalog:values — not just one. Surfaced while working the lockfile-parity npm: alias slice (#12266).Reproduction
Same divergence with a transitive consumer (
write-yaml-file@5.0.0→js-yaml) and withnpm:/catalog:override values:js-yaml@^4.0.0: 4.0.04.0.04.2.0js-yaml@^4.0.0: npm:@zkochan/js-yaml@0.0.11@zkochan/js-yaml@0.0.114.2.0js-yaml@^4.0.0: 'catalog:'(→npm:@zkochan/js-yaml@0.0.11)@zkochan/js-yaml@0.0.11+ expanded inoverrides:4.2.0+ literal'catalog:'inoverrides:Root cause
VersionsOverrider(pacquet-package-manager/src/overrides.rs) correctly rewrites a manifest's deps and is unit-tested — but it is only invoked incheck_lockfile_freshness(install.rs:~1256), against a cloned root manifest, for the frozen-path specifier comparison. The fresh-resolution path (install_with_fresh_lockfile) never applies it: its only resolver manifest hook is thepackageExtensionshook (into_manifest_hook), and the importer manifest handed to the resolver is pristine.pnpm applies overrides via the
readPackagehook (createVersionsOverrider), which runs on every resolved manifest, so overrides take effect on direct and transitive deps alike.Fix direction
Thread the override-applying hook into the fresh resolver as a manifest hook (composed with the existing
packageExtensionshook), so it rewrites every resolved manifest transitively — matching pnpm'sreadPackageflow. Two dependent symptoms then resolve too:catalog:-valued overrides expand to their concrete spec in the lockfileoverrides:section (currently written literally as'catalog:'), since the resolved override map is used.write-yaml-file→js-yaml) pick up the override.The catalog-snapshot half of category 2 (aliased entries dropped from
catalogs:) is fixed separately in #12274.Written by an agent (Claude Code, claude-opus-4-8).