Fix -g touching the cwd project's state (#436, #445) - #446
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Regression tests for #436 and #445: get/scan refuse hosted and vendored mode under -g, rollback/remove -g leave a hosted or vendored project's wiring and ledgers alone, and apply/scan -g patch the global copy of a purl the project vendors. All but the control fail on main. Assisted-by: Claude Code:claude-opus-5-5
Global installs have no project lockfile, but a global run started inside a project still touched that project: get -g --mode hosted|vendored and scan -g --mode vendored rewired it, rollback -g and remove -g unwound its hosted pins and vendored wiring (on vlt deleting the installed package), and the project's vendor ledger made apply -g and scan -g skip the global copy of a purl the project vendors. One rule now decides this (project_state_in_scope): under global scope get and scan refuse hosted and vendored mode with one shared usage error, rollback and remove skip their hosted and vendored legs and the pre-v5 ledger retirement, and the ledger no longer owns global copies. A global rollback still keeps the project's vendored manifest records. Fixes #436 Fixes #445 Assisted-by: Claude Code:claude-opus-5-5
a418733 to
92c71ad
Compare
|
BugBot review Generated by Claude Code |
1 similar comment
|
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 92c71ad. Configure here.
|
[agent] Ready for review on Reviewer focus: Generated by Claude Code |
|
[burn-down agent] Ready for review on
Note: Slack announcement could not be sent this run (no Slack send tool available in the agent session); next run will retry. Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #436
Fixes #445
Summary
A
-g/--global-prefixrun is meant for globally installed packages, which have no project lockfile. But when you ran one from inside a project, it still read and changed that project's hosted and vendored state. Now global scope leaves the project alone:get -g --mode hosted|vendoredandscan -g --mode vendored(or--vendor) are usage errors (exit 2), the same asscan -g --mode hostedalready was. Before, they rewrote the project's lockfile and left the global copy unpatched (get -g --mode hosted|vendoredandscan -g --mode vendoredrewrite the current project's yarn.lock instead of refusing, leaving the global copy unpatched #436).rollback -gandremove <purl> -gno longer run their hosted and vendored legs against--cwd. Before, they restored the project's hosted pins to the registry and unwired and deleted its.socket/vendor/artifacts, which on vlt also deleted the installed package. They also no longer retire the project's pre-v5 hosted ledger (rollback -gandremove <purl> -galso unwind the current project's hosted pins and vendored wiring; on vlt they delete node_modules/left-pad too #445).apply -gandscan -g --mode agentnow patch the global copy of a purl that the project vendors. Before, they skipped it withvendored_ownership_retained(rollback -gandremove <purl> -galso unwind the current project's hosted pins and vendored wiring; on vlt they delete node_modules/left-pad too #445, reverse direction).Root cause
Nothing enforced "global scope excludes project state", so each command decided for itself whether the cwd project's hosted pins and vendor ledger counted under
-g:getswitched to agent mode under-gonly when--modewas absent.scanrefusedhostedbut notvendored.rollbackandremovediscovered and unwound the cwd hosted pins and vendor ledger with no global check.apply_patches_innerand scan'spartition_agent_selection) used the cwd ledger's ownership set for global copies too. Scan also folded the cwd ledger's records into update detection, so it counted a global copy as already patched.Fix
One rule in
commands/mod.rs:project_state_in_scope(common)is false under global scope.global_mode_conflict(common, mode)builds the shared usage error.scan(resolve_mode_flags) andgetrefuse hosted and vendored mode throughglobal_mode_conflict. Scan's existing hosted message is unchanged; vendored says...no project lockfile to wire vendored artifacts into.rollbackandremove, under global scope, discover no hosted pins and no vendor ledger, so the hosted and vendored legs have nothing in scope.retire_legacy_redirect_ledgeris a no-op, and so is rollback's ledgerless-wiring check.rollbackstill reads the ledger, but only to keep the manifest records of purls the project vendors. Dropping them would hand a latervendorreconcile a revert with no backing record. An unreadable ledger still skips cleanup and GC fail-closed, but under-git no longer fails the run, because no vendored leg runs.applyandscan: the cwd ledger no longer owns or records global copies.CLI_CONTRACT.md is updated in the mode-resolution,
get, rollback state-discovery and exit-code sections.Test evidence
New suite:
crates/socket-patch-cli/tests/global_scope_project_state.rs(offline, plus a wiremock API forscan).get -g --mode hosted|vendoredget_refuses_project_modes_under_global_scopescan -g --mode vendored/--vendorscan_refuses_vendored_mode_under_global_scoperollback -g, hosted projectglobal_rollback_leaves_hosted_project_pinsremove -g, hosted projectglobal_remove_leaves_hosted_project_pinsrollback -g, vendored projectglobal_rollback_leaves_vendored_project_stateremove -g, vendored projectglobal_remove_leaves_vendored_project_stateapply -gglobal_apply_patches_a_purl_the_project_vendorsscan -g --mode agentglobal_agent_scan_patches_a_purl_the_project_vendorsproject_rollback_restores_the_hosted_pinRed on main: I reverted
src/to main and rancargo test -p socket-patch-cli --all-features --test global_scope_project_state: 8 failed, the control passed. With the fix: 26/26 passed (including the shared harness self-tests).Local checks:
cargo clippy --workspace --all-features -- -D warningsis clean. In this container a singlecargo test --workspace --all-featuresrun hits the disk limit while linking about 200 test binaries, so I ran every cli and core test target in batches instead. All of them pass except about a dozen write-failure tests (*_write_failure_*,*unremovable*,relax_loop_must_not_traverse_symlinked_root). Those tests rely on read-only permissions, which don't apply to root, and the agent container runs as root. Several are insocket-patch-core, which this PR doesn't touch. CI on92c71ad: 475 checks passed, 6 skipped by workflow conditions, 0 failed.cargo fmt --all -- --checkalready fails onmain: #277 landed about 120 files that aren't rustfmt-clean, and CI runs no fmt check. This PR's own hunks are rustfmt-stable (I checked them againstcargo fmtoutput). I left the unrelated files alone so the PR stays reviewable.The wrappers (
npm/,pypi/,gem/) only dispatch to the binary, so they need no change.Notes and follow-ups
remove <purl> -gstill drops the manifest record you named, even when the project vendors that purl through a legacy manifest-tracked (non-detached) vendor entry. v5 vendored entries are manifest-free, so this doesn't affect them.vex -gandlist -gstill read cwd lockfile discovery. Neither one writes to the project.🤖 Generated with Claude Code
https://claude.ai/code/session_013tdBJBzhf47finAWKtDQVF
Note
Medium Risk
Changes rollback/remove/apply/scan semantics for
-gruns and tightens mode validation; incorrect gating could leave project or global state inconsistent, but behavior is covered by a dedicated test suite.Overview
Global scope (
--global/--global-prefix) no longer reads or mutates the--cwdproject’s hosted pins, vendor ledger, or lockfile wiring when the run is only meant to target globally installed packages.Shared helpers in
commands/mod.rs—project_state_in_scopeandglobal_mode_conflict— centralize the rule.getandscannow reject--mode hostedorvendoredunder global scope (exit 2, aligned with scan’s existing hosted guard).rollbackandremoveskip hosted/vendored legs and legacy ledger retirement for project state; global rollback still loads the project ledger only to preserve manifest entries for purls the project vendors.applyand agentscanno longer treat the cwd vendor ledger as owning global copies, so they patch globals instead of emittingvendored_ownership_retained.CLI_CONTRACT.mddocuments the behavior. New integration tests inglobal_scope_project_state.rscover mode guards, rollback/remove isolation, and global apply/scan over project-vendored purls.Reviewed by Cursor Bugbot for commit 92c71ad. Configure here.
Generated by Claude Code