Repository navigation
Fix gem source-block detection for multi-line and brace openers (#1509) - #1520
Merged
Mikola Lysenko (mikolalysenko) merged 4 commits intoOct 14, 2026
Merged
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
force-pushed
the
agent/fix-gem-source-block-scanner
branch
from
October 14, 2026 04:23
cb269c1 to
466f92c
Compare
Hosted rollback and remove dropped the `!` source pin from a gem
declared inside a `source(...)` block whose arguments span lines, or
inside a `source("...") { ... }` brace block. Bundler 4.0.19+ then
refused every frozen install of the restored Gemfile.lock, and the
brace form also came back with the gem at the wrong indent.
The Gemfile block scanner now keeps a statement open while a `(` or
`[` is unclosed, remembers that the statement began with `source`
until its `do` or `{`, and tracks `{ }` blocks alongside `do ... end`.
Fixes #1509
Assisted-by: Claude Code:claude-opus-5-5
A brace block now counts as the source's own block only right after
the `source(...)` argument list, so `source ENV.fetch(...) { ... } do`
keeps its `!` pin. Hash braces keep a statement open like parens, a
stray `}` no longer closes a `do` block, and `?(`-style character
literals are no longer read as brackets. A restored first gem in a
multi-line `source(` block no longer gets a blank line after the
opener. Only the end of an unfinished line is carried forward, so a
long open bracket no longer costs quadratic time.
Refs #1509
Assisted-by: Claude Code:claude-opus-5-5
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 14, 2026 05:35
Collaborator
Author
|
BugBot review Generated by Claude Code |
An `if` at the start of a line inside an open `(`, `[` or hash was
read as a modifier, so it opened nothing while its `end` still closed
the enclosing `source` block, and the gem lost its `!` pin on
rollback or remove. A stabby lambda's `-> {` was read as a hash.
A line that leaves only a bracket open now starts a fresh expression
on the next line, `-> {` opens a block, and an open bracket carries
only a `source` statement on to its block, so a bracket the scanner
misses elsewhere no longer hides every later source block.
Refs #1509
Assisted-by: Claude Code:claude-opus-5-5
Collaborator
Author
|
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 943ec44. Configure here.
Tanmay Singla (Tanmay182003)
approved these changes
Oct 14, 2026
Mikola Lysenko (mikolalysenko)
deleted the
agent/fix-gem-source-block-scanner
branch
October 14, 2026 06:57
This was referenced Oct 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1509
Summary
A gem declared inside the user's own
sourceblock keeps its!pinthrough hosted
rollback/remove(#1056). That only worked for theone-line
source "…" dospelling. Two other valid spellings lost the!, and Bundler 4.0.19+ then refused every frozen install of therestored pair (exit 16):
source(opener whose arguments span lines before) dosource("…") { … }brace block, which also came back with the gemat column 0 after an extra blank line
Root cause
block_stackincrates/socket-patch-core/src/patch/redirect/upstream/gem.rsis the Gemfile scanner behind both the
!check (in_source_block) and therestored declaration's indent (
declaration_prefix). It ended a statementat the end of any line not ending in an operator, so an unclosed
(didn'tkeep the
sourcestatement open until itsdo. It also never opened aframe for
{ … }.Fix
(,[or hash{is unclosed, andremembers that it began with
sourceuntil its block opens. Thedoat depth 0 is the source's block.
{opens a frame that}closes. A{in expression position is ahash, which counts toward depth and has no frame. Only the brace block
directly after the
source(…)argument list is the source's, so insource ENV.fetch("S") { … } dothedois still the source block. Astray
}never closes adoblock.?(,?}) are masked so they aren't read asbrackets.
Framerecords the line its opener sits on, so a gem restored firstin a multi-line
source(block gets no blank line after) do.all
starts_expressionreads. This keeps a long open bracket linear.The second and third commits apply the
/code-review highfindings: the bracebinding, hash braces in arguments, a
;inside the argument list, stray}and?(literals, the multi-line opener's blank line, quadraticcarry, and a duplicate ident helper. The third commit fixes a review finding: a leading
ifinside an open bracket or-> {lambda now opens its own frame, and an open bracket only carries asourcestatement.Tests (red → green)
source(…) dosource_block_detection,source_block_declaration_keeps_its_bang_through_restore, e2egem_hosted_unwind_keeps_a_source_block_bang(ScanVexSourceBlockMultiLineOpener, rollback + remove)source(…) { }(!and indent)ScanVexSourceBlockBraces(rollback + remove, lock and Gemfile byte-restored, frozen install)assertion failed: at("source(\n \"https://x\"\n) do …"), and the restore lost the!:rails (= 7.0.0)vsrails (= 7.0.0)!). The e2e test failed on Bundler 4.0.22 withrollback: the lock comes back byte for byte,!includedandDEPENDENCIES\n vuln-gem (= 1.0.0)without the!.cargo test -p socket-patch-core --all-features --lib -- gem: 357 passedcargo test -p socket-patch-cli --all-features --test e2e_redirect_gem_build -- --ignored(Ruby 3.3.6, Bundler 4.0.22): 30 passedcargo fmt --all -- --checkandcargo clippy --workspace --all-features -- -D warnings: cleancargo test --workspace --all-features: couldn't finish locally: the session's disk allowance ran out linking every integration-test binary, so CI runs it.cargo test -p socket-patch-core --all-features --lib(all 6472) passes except 4 chmod-based permission 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_…). Those can't fail as expected under uid 0 in this sandbox, and this diff doesn't touch them.No wrapper changes:
npm/,pypi/andgem/only dispatch to the binary.🤖 Generated with Claude Code
https://claude.ai/code/session_01Hsu76uJiHbbPSV1iSeEukP
Generated by Claude Code