Skip to content

Fix gem checks judging unused system gem homes (#1098, #1109) - #1290

Merged
Mikola Lysenko (mikolalysenko) merged 6 commits into
mainfrom
agent/fix-gem-bundler-system-homes
Oct 9, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 6 commits into
mainfrom
agent/fix-gem-bundler-system-homes

Conversation

@mikolalysenko

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

Copy link
Copy Markdown
Collaborator

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

Fixes #1098
Refs #1109 (the deployment variants are fixed; the version-dependent .bundle flags are not, see below)

Summary

Two gem checks judged a copy in the machine's gem env home that Bundler never loads for the project:

Root cause

Nothing gave one answer to "does Bundler use system gems for this project?":

  • bundler_sets_explicit_path modeled only path / path.system / disable_shared_gems. It missed deployment, which Bundler's Settings#path reads after the tier loop (path = "vendor/bundle" if self[:deployment]). I checked this in Bundler 2.5.22 and 4.0.18, which agree.
  • Only the stale guard asked that question. The vex copy lookup goes through get_gem_paths, which keeps the gem env homes as apply write targets for default gems.

Fix

  • bundler_sets_explicit_path now counts a truthy deployment (first tier that sets it, through to_bool) once no tier decides the path.
  • A new RubyCrawler::bundler_uses_system_gems is the one predicate. bundler_install_homes (the stale guard) uses it, and so does a new bundler_unused_system_gem_homes.
  • find_manifest_package_copies_reusing (used by vex and apply --check) drops gem copies under those unused homes, unless the copy is a default gem (spec in specifications/default/), which Bundler loads from the system home under any path.
  • Apply's write targets are unchanged. CLI_CONTRACT.md's gem stale-install section and the vex_consumed table now document the rule.
  • A separate commit reformats one test in patch/redirect/upstream/mod.rs that is unformatted on main, where cargo fmt --check fails.

Not covered: the .bundle default (#1109 stays open)

default_install_uses_path is honored only by Bundler 2.x (settings_flag), and simulate_version 5 only by Bundler 4.x (bundler_5_mode?). In 4.0.18 use_system_gems? never reads default_install_uses_path, and 2.5.22 never reads simulate_version. A scan can't tell which Bundler will run: BUNDLED WITH records who wrote the lock, not who installs it (#751). Skipping the system home on either flag could therefore attest a copy Bundler does load, so both flags keep the system homes judged (fail closed). Regression tests pin this. Closing that gap would need something like probing bundle --version from the project root, which needs a maintainer decision.

Test evidence

Red on main (0a56308, tests only) and green with the fix:

Issue Test Without fix With fix
#1109 gem_hosted_deployment_ignores_system_home_copy (local / env / global deployment) stale warning, exit 1 no_applicable_patches no warning, exit 0, attested
#1109 controls gem_hosted_system_gems_settings_still_flag_system_home_copy (falsy deployment, path.system / disable_shared_gems: false over deployment, simulate_version 5, default_install_uses_path) pass pass (still warns, not attested)
#1098 gem_hosted_standalone_vex_ignores_unused_system_home_copy (fresh local / env / global path, fresh deployment, installed BUNDLE_PATH: gems; control without a path) not_applied, exit 1 attested, exit 0; control still not_applied
unit bundler_sets_explicit_path_counts_deployment, is_default_gem_copy_reads_the_default_specifications_dir — pass

Commands run locally:

  • cargo fmt --all -- --check: clean.
  • cargo clippy --workspace --all-features -- -D warnings: clean.
  • cargo test -p socket-patch-cli --all-features --test e2e_redirect_gem_stale_install: 40 passed. Without the fix (src stashed): 38 passed, and the 2 new e2e tests failed.
  • BUNDLER_TEST_VERSION=4.0.18 cargo test -p socket-patch-cli --all-features --test e2e_redirect_gem_build --test e2e_vendor_gem_build -- --ignored: 28 + 8 passed (real Bundler 4.0.18, Ruby 3.3.6).
  • cargo test --workspace --all-features --no-fail-fast: 13508 passed, 13 failed, all outside the gem code. 12 are write-failure tests that make a path unwritable, which root ignores in this sandbox (*_state_write_failure_*, *_write_failure_*, repair_*_unremovable, relax_loop_must_not_traverse_symlinked_root, an_unremovable_hidden_lock_keeps_every_store_entry). The other is pipenv_hosted_to_vendored_names_the_unpatched_requirements, which needs network access to pypi.org.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YRcjmQwhWGod7X58Hbe5FW


Generated by Claude Code

Assisted-by: Claude Code:claude-opus-5-5
Add regression tests for the false stale-install warning under
Bundler deployment / .bundle-default settings (#1109), and for
standalone vex refusing a project whose Bundler path never loads the
unpatched system gem-home copy (#1098). Both fail on main.

Assisted-by: Claude Code:claude-opus-5-5
cargo fmt --check fails on main in the bun lock remedy test; rewrap
the assertion so the format gate passes.

Assisted-by: Claude Code:claude-opus-5-5
Bundler stops using the system gem homes under deployment mode as well
as under an explicit path, but the stale-install guard only modeled
the explicit path. A fresh deployment checkout with an old copy of the
patched gem in the machine gem home got a false stale warning, and
scan --mode hosted --vex exited 1 with nothing to attest (#1109).

Standalone vex and apply --check still judged every gem env copy
whenever vendor/bundle was empty, even under an explicit or deployment
path, so they refused to attest a project that never loads that copy
(#1098).

One predicate now answers whether Bundler uses system gems, counting
deployment after the path tiers like Bundler::Settings#path. The stale
guard and the vex copy lookup both use it; default gems stay judged.
The .bundle default from default_install_uses_path or simulate_version
depends on the Bundler version, so those keep the system homes judged.

Assisted-by: Claude Code:claude-opus-5-5
@mikolalysenko Mikola Lysenko (mikolalysenko) changed the title Fix gem VEX judging unused system gem homes (#1098, #1109) Fix gem checks judging unused system gem homes (#1098, #1109) Oct 9, 2026
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 9, 2026 16:09
@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 ff9da68. Configure here.

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] CI on ff9da68: every check passes except hosted-e2e and e2e (ubuntu-latest, e2e_safety_pnpm) (plus the ci-ok roll-up). These two are not caused by this PR:

  • The same jobs (and e2e-macos … e2e_safety_pnpm) fail on main's push CI for 7b3983c, 06dab02 and a8e9397 (15:46–15:49 UTC, e.g. run 37954539425).
  • Both run against the live production patch API (hosted-e2e reports "suite failed on all 3 attempts"; e2e_safety_pnpm runs socket-patch get against patches-api.socket.dev). This PR only touches gem install-home selection and gem copy filtering for vex / apply --check, and neither job exercises gems.

That points to a live-API problem that started around 15:45 UTC, not a code change. I know of no fix PR to port. I've re-run the failed jobs once (run 37957045166). Bugbot's review of ff9da68 found no issues.


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 9, 2026
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

Ready for review (burn-down agent).


Generated by Claude Code

Ports #1301 so this PR's CI is not blocked by #1293: production no
longer serves the free minimist@1.2.2 patch 80630680, which breaks
hosted-e2e and e2e_safety_pnpm on main as well. Same change as #1301;
it becomes a no-op once #1301 lands on main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YRcjmQwhWGod7X58Hbe5FW
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] Pushed eda5620, which ports #1301 (re-pins the live minimist@1.2.2 suites to the republished patch 642d7f02, see #1293). That should clear hosted-e2e and e2e_safety_pnpm. The change is identical to #1301, so it becomes a no-op once #1301 lands on main. I couldn't run the live-API suites from this sandbox (it can't reach patches-api.socket.dev), but #1301 is green on its own head, and the touched test binaries build and pass fmt locally.


Generated by Claude Code

The republished minimist patch (642d7f02) keys its files without the
package/ prefix, so key.split('/', 1)[1] raised IndexError in every
native vlt leg. Ports the matching line from #1302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YRcjmQwhWGod7X58Hbe5FW
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[agent] eda5620 also triggered the native vlt legs (it touches scripts/backtest-vlt.py). They failed with IndexError: list index out of range in every case: the republished patch 642d7f02 keys its files without the package/ prefix, which key.split('/', 1)[1] assumes is there. #1301 doesn't cover this. I've pushed 06065a0 with #1302's one-line fix (key.removeprefix('package/')), which handles keys with or without the prefix. Neither fix PR has run the vlt legs yet, so this push is their first CI run.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[final reviewer] I disarmed auto-merge. Tanmay Singla (@Tanmay182003), two commits that aren't merges from main landed after your approval at ff9da689. Please take another look at head 06065a03:

  • eda5620 repins the live minimist@1.2.2 suites to the republished patch 642d7f02. It's the same test/doc data change as Follow the republished minimist canary patch #1302, which is in the merge queue now.
  • 06065a0 changes scripts/backtest-vlt.py so it reads patch file keys with or without the package/ prefix.

Neither commit touches the gem system-home fix you approved. CI on 06065a03 is still running. I'll re-arm auto-merge once you re-approve and it's green.


Generated by Claude Code

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

Development

Successfully merging this pull request may close these issues.

Gem VEX judges an unused system gem-home copy when the project sets a Bundler path, so standalone vex never attests

3 participants