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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants