Skip to content

fix(reify): report added count for fresh linked installs - #9667

Merged
owlstronaut merged 2 commits into
release/v11from
backport/v11/9661
Jun 25, 2026
Merged

fix(reify): report added count for fresh linked installs#9667
owlstronaut merged 2 commits into
release/v11from
backport/v11/9661

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Backport of #9661 to release/v11.

Under `install-strategy=linked`, a fresh `npm install` that actually
creates `.store` entries and symlinks printed `up to date, audited N
packages` instead of `added N packages`, misleading users and CI into
thinking nothing changed.

`reify-output` counts adds with `actualTree.inventory.has(d.ideal)`.
Under the linked strategy the diff's `ideal` nodes belong to the
isolated store tree (locations under
`node_modules/.store/<key>/node_modules/<name>`), while the `actualTree`
returned after reify is the logical hoisted-layout tree. The two never
share node identity, so the lookup always failed and `added` stayed `0`.

The ADD branch now also counts a node when it is a real store package
node (`isInStore && !isLink`), which maps 1:1 to a hoisted package add.
This excludes the internal store symlinks and the top-level consumer
symlink, so the count matches hoisted for registry dependencies
(verified: `minimatch` 4/4, `rimraf` 12/12, `express` 69/69).
Omitted/incompatible optional deps have no store entry and are still not
counted, and hoisted behavior is unchanged.

Known limitations (tracked separately): workspace and `file:`/`npm link`
additions are represented as links rather than store nodes under linked,
so they are not yet counted here — counting them is entangled with the
self-link bug (#9398) and the undeclared-workspaces bug (#9618). The
`--json` `add[].path` for a counted store package points to its `.store`
realpath rather than a logical `node_modules/<name>` path.

## References

Fixes #9623

(cherry picked from commit 0c33947)
The `ls --install-strategy=linked` tests for undeclared and declared-but-missing workspaces passed without ever entering the undeclared-workspace branch of `filterLinkedStrategyEdges` in lib/commands/ls.js, because their mock filesystems omitted the hidden `node_modules/.package-lock.json` that a real linked install writes. Without that hidden lockfile, loadActual resolves the workspace root edges via the workspace globs instead of marking them missing, so the `edge.missing` guard is never satisfied and the branch stays uncovered.

This surfaced as a global coverage gate failure (ls.js branch below 100%) on the first PR after the actual-tree workspace changes in #9666, because the Test matrix only runs on PRs and not on direct pushes to release/v11.

Add the hidden lockfile to both tests so they reproduce a real linked install: the undeclared workspace now resolves as a missing root edge and is correctly skipped, and the declared-but-missing workspace resolves as missing and is still reported as UNMET DEPENDENCY. This exercises both branches and restores 100% coverage. No production code changes.
@owlstronaut
owlstronaut merged commit 5b6ff9c into release/v11 Jun 25, 2026
20 checks passed
@owlstronaut
owlstronaut deleted the backport/v11/9661 branch June 25, 2026 20:48
@github-actions github-actions Bot mentioned this pull request Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants