[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
pnpm's modulesDir setting (modules-dir in .npmrc, modulesDir: in pnpm-workspace.yaml) renames the project's node_modules. Since pnpm 10.12.0, the default virtual store follows it (<modulesDir>/.pnpm), so a project with modulesDir: deps has no node_modules at all. Every package lives in deps/.pnpm/<name>@<ver>/node_modules/<name>.
The npm crawler only collects directories literally named node_modules, plus the configured roots in configured_install_roots (yarn classic --modules-folder from #493, and Rush common/temp from #518). It never reads pnpm's modulesDir. So agent-mode apply / scan --apply sees nothing installed. Because pnpm-lock.yaml resolves the purl, it classifies the installed package as lockfile-only (package_not_installed, "resolved by the project lockfile"), which by contract never fails the run. Result: exit 0, status success, and the installed copy stays unpatched.
Release 4.0.0 failed loudly on the same fixture (exit 1, "no matching packages were found on disk"). The v5 lockfile-only classification turned this into a silent pass.
Impact
Repro (pnpm 12.8.1, Linux, main 045d7ec)
mkdir proj && cd proj
echo '{"name":"root","version":"1.0.0","dependencies":{"is-odd":"3.0.1","left-pad":"1.3.0"}}' > package.json
printf 'modulesDir: deps\n' > pnpm-workspace.yaml # pnpm 10: echo modules-dir=deps > .npmrc
pnpm install
ls deps/.pnpm # is-number@6.0.0 is-odd@3.0.1 left-pad@1.3.0 lock.yaml
# .socket/manifest.json + blobs: a patch for pkg:npm/left-pad@1.3.0 package/index.js (prepends a marker)
socket-patch apply --offline
# Note: 1 manifest patch targets a package not installed on this host (resolved by the project lockfile; skipped):
# - pkg:npm/left-pad@1.3.0
# Summary: 0 of 1 targeted patch applied, 0 already patched, 1 not found on disk
echo $? # 0
head -c 30 deps/.pnpm/left-pad@1.3.0/node_modules/left-pad/index.js # upstream bytes, no marker
NODE_PATH=deps node -e 'require("left-pad")' # loads the unpatched copy
socket-patch vex --offline --json --output v.json # exit 1, no_applicable_patches (honest)
It's the same in a workspace (packages: [packages/*] + modulesDir: deps, with a member depending on left-pad): 0 of 1 applied, exit 0.
Expected vs actual
Matrix (Linux, Node 22, main 045d7ec; each cell run 2×)
| pnpm |
modulesDir honoured where |
virtual store |
agent apply |
| 7.33.7 / 8.15.9 / 9.15.9 |
.npmrc modules-dir=deps |
node_modules/.pnpm (deps/ holds only links into it) |
pass (store copy patched) |
| 10.0.0 / 10.5.2 / 10.7.1 / 10.9.0 / 10.10.0 / 10.11.1 |
.npmrc |
node_modules/.pnpm |
pass |
| 10.12.0 / 10.12.1 / 10.20.0 / 10.28.0 / 10.34.5 |
.npmrc |
deps/.pnpm |
fail: package_not_installed, exit 0 |
| 11.28.3 / 12.8.1 |
pnpm-workspace.yaml |
deps/.pnpm |
fail: same |
First pnpm version affected: 10.12.0 (the virtual store moved under modulesDir). socket-patch release 4.0.0 on pnpm 12.8.1: exit 1, loud "no matching packages were found on disk". Main is silent (exit 0). macOS and Windows weren't probed (the routine's probe branches are on hold), but the cause is platform-independent.
Suspect code
crates/socket-patch-core/src/crawlers/npm_crawler.rs:45 configured_install_roots handles .yarnrc --modules-folder and rush.json but not pnpm modulesDir (from pnpm-workspace.yaml on 10+ and .npmrc modules-dir on ≤10, plus pnpm's global config.yaml / rc).
- The lockfile-only classification behind the
package_not_installed detail ("resolved by the project lockfile") is what turns the miss into exit 0.
No duplicate found: #362 covers virtualStoreDir, #493 covers yarn classic --modules-folder (closed via #520, yarn only), and #373 / #495 / #359 cover other stores.
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
pnpm's
modulesDirsetting (modules-dirin.npmrc,modulesDir:inpnpm-workspace.yaml) renames the project'snode_modules. Since pnpm 10.12.0, the default virtual store follows it (<modulesDir>/.pnpm), so a project withmodulesDir: depshas nonode_modulesat all. Every package lives indeps/.pnpm/<name>@<ver>/node_modules/<name>.The npm crawler only collects directories literally named
node_modules, plus the configured roots inconfigured_install_roots(yarn classic--modules-folderfrom #493, and Rushcommon/tempfrom #518). It never reads pnpm'smodulesDir. So agent-modeapply/scan --applysees nothing installed. Becausepnpm-lock.yamlresolves the purl, it classifies the installed package as lockfile-only (package_not_installed, "resolved by the project lockfile"), which by contract never fails the run. Result: exit 0, statussuccess, and the installed copy stays unpatched.Release 4.0.0 failed loudly on the same fixture (exit 1, "no matching packages were found on disk"). The v5 lockfile-only classification turned this into a silent pass.
Impact
modulesDirgets no agent-mode patches at all, and CI sees a greensocket-patch apply.vexstays honest (no_applicable_patches, exit 1), so there's no false attestation in agent mode. HostedvexwithmodulesDiris untested here; Agent mode ignores yarn classic's--modules-folder: packages installed there are reported "not installed" andscan --mode agentexits 0 leaving them unpatched #493 saw the hosted false-attestation variant with yarn classic's modules folder.Repro (pnpm 12.8.1, Linux, main
045d7ec)It's the same in a workspace (
packages: [packages/*]+modulesDir: deps, with a member depending on left-pad):0 of 1 applied, exit 0.Expected vs actual
virtualStoreDir(Fix npm crawler missing relocated dependency stores (#359, #362) #365), yarn classic's--modules-folder(Agent mode ignores yarn classic's--modules-folder: packages installed there are reported "not installed" andscan --mode agentexits 0 leaving them unpatched #493) and Rush'scommon/temp(npm crawler never looks in Rush's common/temp store: hostedvexattests a transitive dep not_affected while its installed copy is unpatched, and agent apply reports it package_not_installed #518). At minimum, an installed-but-unseen package must not be reported as lockfile-only. CLI_CONTRACT.md:1136 reserves the never-failspackage_not_installedskip for a purl the lock resolves with no installed copy ("a platform-gated optional dependency, a devDependency under--omit=dev").success, exit 0, nothing patched.Matrix (Linux, Node 22, main
045d7ec; each cell run 2×)modulesDirhonoured where.npmrcmodules-dir=depsnode_modules/.pnpm(deps/ holds only links into it).npmrcnode_modules/.pnpm.npmrcdeps/.pnpmpackage_not_installed, exit 0pnpm-workspace.yamldeps/.pnpmFirst pnpm version affected: 10.12.0 (the virtual store moved under
modulesDir). socket-patch release 4.0.0 on pnpm 12.8.1: exit 1, loud "no matching packages were found on disk". Main is silent (exit 0). macOS and Windows weren't probed (the routine's probe branches are on hold), but the cause is platform-independent.Suspect code
crates/socket-patch-core/src/crawlers/npm_crawler.rs:45configured_install_rootshandles.yarnrc--modules-folderandrush.jsonbut not pnpmmodulesDir(frompnpm-workspace.yamlon 10+ and.npmrcmodules-diron ≤10, plus pnpm's globalconfig.yaml/rc).package_not_installeddetail ("resolved by the project lockfile") is what turns the miss into exit 0.No duplicate found: #362 covers
virtualStoreDir, #493 covers yarn classic--modules-folder(closed via #520, yarn only), and #373 / #495 / #359 cover other stores.