Skip to content

Fix -g touching the cwd project's state (#436, #445) - #446

Open
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
agent/fix-global-scope-project-state
Open

Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
mainfrom
agent/fix-global-scope-project-state

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

LLM Description written by Claude Code:claude-opus-5-5

Fixes #436
Fixes #445

Summary

A -g / --global-prefix run 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:

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:

  • get switched to agent mode under -g only when --mode was absent.
  • scan refused hosted but not vendored.
  • rollback and remove discovered and unwound the cwd hosted pins and vendor ledger with no global check.
  • The agent paths (apply_patches_inner and scan's partition_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) and get refuse hosted and vendored mode through global_mode_conflict. Scan's existing hosted message is unchanged; vendored says ...no project lockfile to wire vendored artifacts into.
  • rollback and remove, under global scope, discover no hosted pins and no vendor ledger, so the hosted and vendored legs have nothing in scope. retire_legacy_redirect_ledger is a no-op, and so is rollback's ledgerless-wiring check.
  • rollback still reads the ledger, but only to keep the manifest records of purls the project vendors. Dropping them would hand a later vendor reconcile a revert with no backing record. An unreadable ledger still skips cleanup and GC fail-closed, but under -g it no longer fails the run, because no vendored leg runs.
  • apply and scan: 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 for scan).

Issue Regression test main this PR
#436 get -g --mode hosted|vendored get_refuses_project_modes_under_global_scope FAIL pass
#436 scan -g --mode vendored / --vendor scan_refuses_vendored_mode_under_global_scope FAIL pass
#445 rollback -g, hosted project global_rollback_leaves_hosted_project_pins FAIL pass
#445 remove -g, hosted project global_remove_leaves_hosted_project_pins FAIL pass
#445 rollback -g, vendored project global_rollback_leaves_vendored_project_state FAIL pass
#445 remove -g, vendored project global_remove_leaves_vendored_project_state FAIL pass
#445 reverse, apply -g global_apply_patches_a_purl_the_project_vendors FAIL pass
#445 reverse, scan -g --mode agent global_agent_scan_patches_a_purl_the_project_vendors FAIL pass
control project_rollback_restores_the_hosted_pin pass pass

Red on main: I reverted src/ to main and ran cargo 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 warnings is clean. In this container a single cargo test --workspace --all-features run 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 in socket-patch-core, which this PR doesn't touch. CI on 92c71ad: 475 checks passed, 6 skipped by workflow conditions, 0 failed.

cargo fmt --all -- --check already fails on main: #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 against cargo fmt output). 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

  • vlt is fixed through the shared hosted and vendored legs, not by vlt-specific code. The issue's npm/vlt projects take the same code path the pypi hosted and npm vendored tests cover.
  • remove <purl> -g still 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.
  • Not changed here: vex -g and list -g still 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 -g runs 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 --cwd project’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_scope and global_mode_conflict — centralize the rule. get and scan now reject --mode hosted or vendored under global scope (exit 2, aligned with scan’s existing hosted guard). rollback and remove skip 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. apply and agent scan no longer treat the cwd vendor ledger as owning global copies, so they patch globals instead of emitting vendored_ownership_retained.

CLI_CONTRACT.md documents the behavior. New integration tests in global_scope_project_state.rs cover 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

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
CLI_CONTRACT.md: get and scan refuse --mode hosted|vendored under
global scope, and rollback, remove, apply and agent scans under global
scope neither unwind nor defer to the project's hosted/vendored state.

Refs #436, #445

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

1 similar comment
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] Ready for review on 92c71ad: CI shows 475 checks passed and 6 skipped by workflow conditions. Bugbot reviewed 92c71ad and found no issues, and there are no unresolved review threads.

Reviewer focus: project_state_in_scope / global_mode_conflict in commands/mod.rs, and the rollback cleanup guard that keeps the project's vendored manifest records under -g.


Generated by Claude Code

@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 1, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[burn-down agent] Ready for review on 92c71ad: mergeable, 0 commits behind main.

  • CI: 482/482 check runs green on 92c71ad (6 skipped by workflow conditions, none failing).
  • Bugbot: reviewed 92c71ad, no findings; 0 unresolved review threads.
  • Reviewer focus: project_state_in_scope / global_mode_conflict in commands/mod.rs, and the rollback cleanup guard that keeps the project's vendored manifest records under -g.

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

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review

Projects

None yet

2 participants