SIGN IN SIGN UP

fix(arborist): repair wrong-but-existing symlink target in linked strategy (#9628)

In continuation of our exploration of using `install-strategy=linked` in
the [Gutenberg
monorepo](https://github.com/WordPress/gutenberg/pull/75814), which
powers the WordPress Block Editor.

Under `install-strategy=linked`, if a top-level `node_modules/<dep>`
symlink points to a store key that exists on disk but is the **wrong
version**, re-running `npm install` does not repair it. npm reports
success and leaves the dependency resolving to the wrong version. This
is the state an interrupted update leaves behind: the new store key is
extracted but the symlink has not yet been repointed.

A symlink pointing at a **non-existent** target is already repaired on
reinstall; only a wrong-but-existing target slips through, because
cleanup validates the link name, not its target.

## Why

For linked installs, `#buildLinkedActualForDiff` synthesizes the
"actual" tree the diff compares against from the **ideal** children,
never reading the real on-disk symlink target. So a link whose on-disk
target is a valid-but-wrong store key looks identical to the ideal node,
the diff reports no change, and the symlink is left untouched. The
hoisted strategy is unaffected because it self-heals the analogous
corruption.

## How

In `#buildLinkedActualForDiff`, when an existing link's resolved on-disk
target differs from its ideal target, skip creating a synthetic actual
entry for it. With no actual entry to match, the diff treats the link as
an `ADD`, and `#reifyNode` removes the old symlink and recreates it
pointing at the correct store key. A new `#linkTargetMismatch` helper
compares the two resolved targets; it runs only after the existing
`existsSync` guards, so both paths are known to exist.

This repairs both the top-level symlink and wrong transitive/sibling
links inside the store, and leaves already-correct trees untouched (no
spurious relinking on an idempotent reinstall).

## References

Fixes #9611
M
Manzoor Wani committed
0ffce98cb6f2e189fa3a866c1ba1209293fb48f9
Parent: 981e249
Committed by GitHub <noreply@github.com> on 6/24/2026, 6:33:55 PM