The PR looked reasonable at the top: one function changed, a test added, the ticket referenced. Scrolling down, the lockfile section kept going. Four hundred changed lines of package-lock, two hundred of them unrelated to the fix. A dozen transitive dependencies had climbed minor versions, and one had jumped a major.
The agent had not meant to upgrade anything. It had opened a terminal, run a fresh install to reproduce the bug, and let the package manager resolve the whole tree from scratch instead of adding only the one package the fix needed. The old lockfile was thrown away during that pass, and the diff carried every new resolution into the review.
Lockfile churn hides supply-chain changes
Reviewers read the application code, not four hundred lines of nested version hashes, so the transitive bumps pass through with the bug fix. Nobody decides to take a new minor version of a runtime helper; it simply arrives. A major jump nested two levels deep rarely gets a dedicated review, and the changelogs for those packages are never opened.
It also breaks reproducibility between machines. A developer who never ran the fresh install still works off the old tree until they pull, while CI rebuilt from the new lockfile. Behavior that passed locally and failed in CI can trace back to a quietly bumped transitive package, with no commit that owns that decision.
When the fix and the upgrades share one PR, reverting the fix on a production incident also reverts the dependency state, and rolling back dependencies cleanly after a mixed diff is a chore nobody wants at midnight.
Pin the one change, keep the lockfile still
For a fix, the install should touch exactly the package being added: install that single pinned version, then leave the rest of the locked tree alone. Reproduce the bug against the existing lockfile first, and only introduce a new dependency after the failure has been observed.
Separate the two concerns. Bug fixes land in small PRs with unchanged lockfiles; intentional dependency upgrades get their own PR where the version diff, changelogs, and risk are reviewed on their own. When a lockfile section in a small PR is large, that is a signal to split it, not to skim past it.
Ask the agent, before it runs any install, whether the change genuinely needs a new package or whether the existing tree already covers it. Most one-line fixes do not. How much lockfile churn tends to slip into your agent-authored PRs?
Top comments (2)
If package.json did not change, npm install still rewrites the lockfile whenever a range allows a newer release. npm ci installs the locked tree and stops if the two files disagree. The post says the old lockfile was thrown away during a fresh install. Was package.json part of that diff, or only the lockfile?
Keeping the lockfile stable for a focused fix makes the dependency decision reviewable on its own. I would add a CI guard that summarizes direct and transitive lockfile changes separately, then requires an explicit dependency-change label when either set is nonempty.