Repository navigation
Fix vendored member refusal not naming root (#1904) - #1913
Mikola Lysenko (mikolalysenko) merged 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Running a vendored scan, get or vendor from a workspace member with no lockfile of its own refused with "no lockfile ... run your package manager's install first". Following that advice only updated the workspace root's lock, so the next run refused the same way. The vendored refusal now keeps its vendor_lockfile_missing code but says which lock installs the member and which directory to vendor from, the same lookup hosted mode's refusal already used. The lookup (package.json and vlt workspaces, pnpm workspace or lockfile-dir) moves out of the hosted refusal into one shared helper; hosted messages are unchanged. Fixes #1904 Assisted-by: Claude Code:claude-opus-5-5
Review follow-ups to the workspace-member refusal: - A pnpm project whose lock lives elsewhere through lockfile-dir was told to vendor from the lock's directory, which holds no project. It now names the setting and points at hosted mode instead. - The message showed "." for the default --cwd; it now shows the member's own path. - Callers that keep only the refusal code skip the workspace lookup. - The run-from wording follows the stray-lock refusal's convention. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
Burn-down agent: labeled Ready for review.
Generated by Claude Code |
Final review brief (
|
Wenxin Jiang (Wenxin-Jiang)
left a comment
There was a problem hiding this comment.
[agent] Reviewed 8a97c8ddd6715e7d056951ce06bbd1d17d75dd6d. Checked shared governing-root lookup and vendored refusal guidance for workspace and lockfile-dir layouts. No major correctness issues found. Validation: source and regression-test review plus the available exact-head CI checks; no local test pass is claimed.
…mber-lockfile-refusal
|
[agent] The merge queue dropped this PR with MERGE_CONFLICT. #1928 (for #1921) had moved the same hosted npm block in Local checks: The push dismissed the approval, so this needs a re-approval and a re-queue. Generated by Claude Code |
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit c9d1b5f. Configure here.
|
Burn-down agent: re-applied Ready for review at
Generated by Claude Code |
|
[final reviewer] Re-enqueued at Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1904
Summary
When a vendored run (
scan --mode vendored,get --mode vendoredorvendor) starts in a workspace member that has no lockfile of its own, it refused with "no package-lock.json … run your package manager's install first". Following that advice only updates the workspace root's lock, so the next run refused the same way. The refusal now keeps thevendor_lockfile_missingcode (so the JSON contract doesn't change), but it says which lock installs the member and which directory to vendor from:This covers npm, yarn (classic and berry) and Bun
package.jsonworkspaces, vlt workspaces, and pnpm workspaces. For a pnpmlockfile-dirproject outside a pnpm workspace, the lock's directory holds no project, so the refusal names the setting and points at hosted mode rather than sending the user somewhere else that also doesn't work.Root cause
Step 4 of the lock-flavor probe (
vendor/npm_flavor.rs) always returned the generic detail. It never ran the "the lock lives in another directory" lookup that hosted'sredirect_*_lockfile_elsewhererefusal uses inhosted/governing_root.rs.Change
governing_root: the npm part of hosted'srefusal()(package.json workspaces, vlt workspaces, the pnpm workspace orlockfile-dirlock, with the nearer root winning) moves into onenpm_lock_elsewhere()helper. It returns aLockElsewhere { dir, dir_kind, vendorable_dir, detail }. Hosted builds its refusal from that, and its messages are byte-for-byte unchanged (the existing governing_root tests pass untouched).npm_flavor:detect_vendorable_npm_flavor(forward vendoring;vendor_npm_anyand the yarn berry takeover preflight) swaps the generic detail for the governing-root one.preflight_packagesandlock_text_refusalskeep only the code, so they use a code-only probe and skip the lookup.Test evidence
vendor::npm_flavor::tests::lockless_workspace_member_refusal_names_the_workspace_rootvendor::npm_flavor::tests::lockless_pnpm_member_refusal_names_the_lock_directoryvendor --json)vendor_failure_paths::lockless_workspace_member_refusal_names_the_workspace_root(--test vendor)lockfile_dir_project_refusal_names_the_setting_not_a_dead_endlockless_standalone_project_keeps_the_install_remedyTo get the red runs I disabled the detail swap locally; with it disabled, both core tests and the CLI test failed.
Commands run locally:
cargo fmt --all -- --check: okcargo clippy --workspace --all-features -- -D warnings: okcargo test -p socket-patch-core --all-features: 6998 passed, 4 failed. The 4 failures are chmod-based fault-injection tests (copy_tree::relax_loop_must_not_traverse_symlinked_root,vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry,pypi_poetry::wire_write_failure_…,pypi_requirements::wire_failure_rolls_back_…). They can't fail a write when run as root, and this container runs as uid 0. None of them touch this change. CI runs as non-root.cargo test -p socket-patch-cli --all-features --test vendor -- vendor_failure_paths: 28 passedcargo test --workspacelocally: the container ran out of disk building every test binary. CI covers it.No wrapper changes: the npm/PyPI/gem wrappers only pass the CLI's output through.
Review findings not fixed (from
/code-review high)detect_npm_lock_flavor, used byvendor --check/--revert, the lock inventory, VEX, crawlers) still has the generic text. Left as is on purpose. Those consumers either keep only the code or don't show this refusal to the user as a remedy. Adding the ancestor walk there would put filesystem reads on every lockless crawl and VEX snapshot, and the VEX snapshot reads are recorded.has_own_npm_family_lockis checked again insidenpm_lock_elsewhereandpnpm_lock_elsewhere. Each check is a handful of stats on a refusal path only, and the guard keeps thepub(crate)helper correct for any caller.https://claude.ai/code/session_011f9aeR3rq51BGZkfNJkypH
Note
Medium Risk
Shared workspace-root resolution now drives vendored error text; mistakes could misdirect monorepo users, though hosted behavior is refactored-not-rewritten and covered by existing tests.
Overview
Fixes #1904: vendoring from an npm-family workspace member with no local lock no longer tells users to “run install first” (which only updates the root lock and loops). The
vendor_lockfile_missingcode is unchanged, but the error text now points at where the lock actually lives and says to vendor from that directory—matching what hosted mode already inferred.hosted/governing_root: npm “lock elsewhere” detection is consolidated intoLockElsewhereandnpm_lock_elsewhere()(package.json / vlt / pnpm workspaces andlockfile-dir, with the same nearer-root rules). Hosted refusals are built from that struct so existing hosted messages stay the same; vendored mode reuses the same lookup.vendor/npm_flavor:detect_vendorable_npm_flavorswaps inlock_elsewhere_detail()on the missing-lock path; read-only callers that only need the code usedetect_vendorable_npm_flavor_codeto skip the ancestor walk. pnpmlockfile-dirprojects outside a real workspace get a different message (hosted scan / fix layout) instead of a bogus “vendor from” hint.Tests cover npm/yarn/Bun members, pnpm members,
lockfile-dir, standalone lockless projects, and a CLIvendor --offlinecase.Reviewed by Cursor Bugbot for commit c9d1b5f. Configure here.
Generated by Claude Code