Skip to content

Fix gem unwind dropping source-block ! (#1056) - #1303

Merged
Mikola Lysenko (mikolalysenko) merged 7 commits into
mainfrom
agent/v5-gem-unwind-bang
Oct 10, 2026
Merged

Mikola Lysenko (mikolalysenko) merged 7 commits into
mainfrom
agent/v5-gem-unwind-bang

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 #1056

Summary

Bundler locks a gem declared inside the user's own source "…" do block as name (= v)!, rubygems.org blocks included. The hosted unwind (rollback, remove <purl>) put the declaration back inside that block but always stripped the ! from DEPENDENCIES. The restored pair then didn't match what Bundler writes, so every frozen install (BUNDLE_FROZEN=true bundle install) failed with exit 16 after a "successful" rollback.

Root cause

lock_edit in crates/socket-patch-core/src/patch/redirect/upstream/gem.rs ran entry.strip_suffix('!') on every non-transitive gem. It never checked whether the restored manifest declaration still sits in a source block.

Fix

  • lock_edit now takes a DepEntry (Unpin / Keep / Drop) in place of the transitive bool.
  • restore_one picks Keep when the hosted block being undone sits inside a user source … do block. That check is in_source_block, a line-level do/end scan that also covers a group nested in the source block and the source(…) do form. Otherwise it picks Unpin (hosted mode added the !) or Drop (transitive append).
  • The module docs and the CLI_CONTRACT.md "Hosted unwind coverage" gem row now describe the exception.

Tests (per issue)

Red→green: with the Keep arm disabled, the e2e fails with DEPENDENCIES\n vuln-gem (= 1.0.0) where it expects vuln-gem (= 1.0.0)!. The unit round-trip test failed the same way before the fix.

Commands run

  • cargo test -p socket-patch-core --lib gem: 338 passed
  • cargo test -p socket-patch-cli --test e2e_redirect_gem_build -- --ignored (Ruby 3.4, Bundler 4.0.15): 29 passed
  • cargo clippy --workspace --all-features -- -D warnings: clean
  • cargo fmt --all -- --check: clean for the changed files. The only diff is in upstream/mod.rs, which already differs on main.

🤖 Generated with Claude Code


Generated by Claude Code


Note

Medium Risk
Changes gem lockfile restore semantics for rollback/remove; wrong ! handling breaks frozen Bundler installs, but the change is narrowly scoped and heavily tested.

Overview
Fixes hosted gem unwind (rollback / remove) so Gemfile.lock DEPENDENCIES lines keep Bundler’s ! source pin when the restored gem declaration still lives inside the user’s own source "…" do block (#1056). Previously the unwind always stripped !, so the restored lock no longer matched Bundler’s format and BUNDLE_FROZEN=true bundle install failed after a “successful” restore.

The upstream restore path replaces the transitive-only flag with a DepEntry action (Unpin / Keep / Drop). in_source_block scans the manifest to choose Keep for source-block declarations; hosted-added pins still Unpin, transitive appends still Drop. CLI_CONTRACT.md documents the exception, with unit and ignored e2e coverage for rollback and remove.

Reviewed by Cursor Bugbot for commit f8c511c. Configure here.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A gem declared inside the user's own `source "..." do` block is locked
by Bundler as `name (= v)!`. The hosted unwind (`rollback`, `remove`)
puts the declaration back inside that block but always dropped the `!`
from DEPENDENCIES, so the restored pair no longer matched what Bundler
writes and every frozen install failed with exit 16.

The restore now drops the `!` only when the restored declaration is
outside every `source ... do` block (the case where hosted mode added
the pin), and keeps it otherwise. Unit and real-bundler e2e tests pin
the byte-identical round trip and the frozen install.

Fixes #1056

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mikolalysenko
Mikola Lysenko (mikolalysenko) marked this pull request as ready for review October 9, 2026 17:06
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

BugBot review

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

Stale Bugbot comment from a previous run.

Comment thread crates/socket-patch-core/src/patch/redirect/upstream/gem.rs
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[final reviewer] I disarmed auto-merge at 41bda596 because ci-ok is red on this head. Only hosted-e2e and e2e (ubuntu-latest, e2e_safety_pnpm) fail, which is the main-wide minimist@1.2.2 failure (#1293), not this PR. #1302 fixes it and is in the merge queue now. Once main carries it, merge main in here (no other commits needed) and I'll re-arm auto-merge after CI goes green. The approval still covers this head.


Generated by Claude Code

in_source_block pushed only on `do` lines but popped on every `end`,
so the `end` of an `if`/`case`/`def`/`begin` inside a user
`source "..." do` block cleared the source from the stack. restore_one
then chose Unpin and stripped the DEPENDENCIES `!` for a gem still
inside that block, and the frozen install failed as in #1056. Push a
non-source entry for line-leading keyword constructs (not modifiers,
not ones closed on the same line) so their `end` pops that instead.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[burn-down agent] Disabled auto-merge before pushing f8c511c (fix for the Bugbot in_source_block finding, plus origin/main with the #1301 minimist repin). The final reviewer re-arms it after re-reviewing.


Generated by Claude Code

@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

bugbot run


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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is ON. A cloud agent has been kicked off to fix the reported issue.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit f8c511c. Configure here.

Comment thread crates/socket-patch-core/src/patch/redirect/upstream/gem.rs
@mikolalysenko

Copy link
Copy Markdown
Collaborator Author

[final reviewer] Not enqueuing. Tanmay Singla (@Tanmay182003), one non-merge commit landed after your approval at 2e0f5800:

  • 9b9441de Count keyword blocks when finding a Gemfile source block (redirect/upstream/gem.rs, +32/-1; the Bugbot in_source_block fix)

ci-ok is red on the current head f8c511c2 and 1 review thread is open. Please re-look at that commit once it's green.


Generated by Claude Code

Resolve CLI_CONTRACT conflict: take main's pypi paragraph (hosted uv
override marker) and keep this branch's gem paragraph (the `!` stays
inside the user's own source block).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
in_source_block and declaration_prefix cut each line at the first '#', so
a user source line interpolating its URL ("https://#{host}/") lost its
trailing do, never opened a source frame, and the restore unpinned the
lock's ! for a gem put back inside that block. ruby_code now strips only a
# outside a quoted string.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@mikolalysenko Mikola Lysenko (mikolalysenko) added the Ready for review Agent-verified: mergeable, CI green, Bugbot clean — awaiting human review label Oct 10, 2026
Merged via the queue into main with commit d5d7a53 Oct 10, 2026
53 checks passed
@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the agent/v5-gem-unwind-bang branch October 10, 2026 15:23
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

3 participants