GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||
GeezerVison is showing github.com — Fix gem source-block bang lost after x = if … end (#1476) by mikolalysenko · Pull Request #1478 · SocketDev/socket-patch Conversation
|
| Issue case | Test | Before fix | After |
|---|---|---|---|
#1476 v = if … end lock ! + Gemfile byte-identical |
unit source_block_declaration_keeps_its_bang_through_restore (new manifests: if, case+begin, unless/while, deeper end) |
FAILED (\n\ngem "rails" at column 0, ! dropped) |
ok |
#1476 scanner shapes (if/unless/case/begin/while/until/for, labels, ternary, literals, heredocs, =begin) |
unit source_block_detection |
FAILED | ok |
layout after an inner end |
unit manifest_blocks_restore_in_place |
— | ok |
#1476 e2e on real Bundler (v = if … end + w = case … end), rollback + remove, frozen install of the restored pair |
e2e_redirect_gem_build::gem_hosted_unwind_keeps_a_source_block_bang (new ScanVexSourceBlockAssignment driver) |
issue repro: exit 16 on 4.0.22 | ok on Bundler 4.0.22 and 4.0.18 |
Commands run locally (Ruby 3.3.6):
cargo fmt --all -- --check ✅cargo clippy --workspace --all-features -- -D warnings ✅cargo test -p socket-patch-core --all-features --lib redirect::upstream::gem: 17 passed; with the fix reverted, 2 failedBUNDLER_VERSION={4.0.22,4.0.18} SOCKET_PATCH_BUNDLER_E2E_REQUIRED=1 cargo test -p socket-patch-cli --all-features --test e2e_redirect_gem_build --test e2e_vendor_gem_build -- --ignored: 29 + 8 passed on eachcargo test --workspace --all-features --no-fail-fast: 14337 passed, 13 failed. All 13 are environmental and outside gem code: 12 use chmod to force write failures, which root ignores (the sandbox runs as uid 0), and e2e_bun_lockb::binary_shared_bundled_record_hosted_pin_is_managed needs the real patch API (tunnel error). CI runs these unprivileged.No wrapper (npm/, pypi/, gem/) changes: this is core Rust logic only.
/code-review high, two passes)All confirmed findings are fixed in c9f3945 and 9f2c94f. Not changed:
vex/discover/gem.rs parse_source_block_decls keeps its own linegem lines) and fails closed: an early close only drops! or an attestation. Sharing the lexerblock_stack runs twice per restored direct gem (in_source_block anddeclaration_prefix) over a small Gemfile prefix. Threading one stackrestore_one → restore_manifest costs more code than it saves.ruby_words looks like gem_line_tail_blocks_edit's classifier inredirect/mod.rs, but the two answer different questions (modifier vs#{} interpolationputs %w[…]).🤖 Generated with Claude Code
https://claude.ai/code/session_01HuKqLAEGGwH73DucozCrY6
Generated by Claude Code
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Assisted-by: Claude Code:claude-opus-5-5
A gem declared in the user's own source "…" do block loses its DEPENDENCIES `!` on hosted rollback/remove when an assignment-form keyword construct (v = if/case/begin … end) precedes it, so frozen installs fail on Bundler 4.0.19+ (#1476). Add unit cases for the block scanner and the restore round trip, and an e2e Bundler case. Assisted-by: Claude Code:claude-opus-5-5
The hosted gem unwind only counted if/case/begin/… as opening a block when the keyword started its line. In `v = if …` nothing was opened, but the matching `end` still closed the user's source block, so the restored lock dropped its `!` pin and Bundler 4.0.19+ frozen installs failed after rollback or remove. The restored declaration also came back at column 0 after a blank line. Count keywords word by word wherever they start an expression (after =, (, ',', ;, …), treat `end` as closing one, net out one-line constructs, skip modifiers, names like x.class or if:, and endless defs. Derive the restored declaration's indent from the same block stack. Fixes #1476 Assisted-by: Claude Code:claude-opus-5-5
After an `end` indented deeper than the block's body (a case/when laid out under its assignment), the restored declaration copied that `end`'s indent, so the Gemfile did not come back byte for byte. Take the indent of the line that opened the enclosing block + 2 instead. Assisted-by: Claude Code:claude-opus-5-5
Review follow-ups for the source-block scanner (#1476): - a keyword after a label (require: if), =>, a ternary, and/or/not or an operator starts an expression, so its end is counted; - %w[]/%i[] arrays, regexps, backticks, =begin/=end comments and heredoc bodies are no longer read as code; - a ; ends a loop's statement, so a later do opens its own block; - def begin / x.then if treat the keyword-like word as a name; - the restored declaration keeps a blank line before a following declaration after an inner end, as before; - the stack is computed once per restore, with opener line offsets. Assisted-by: Claude Code:claude-opus-5-5
Second review pass on the source-block scanner (#1476): - mask strings and %-literals that span lines, and find the comment with the same literal rules (a ' in a regexp, # in %q()); - add %s() / %x() literals; - class <<self and list <<name are not heredocs; - a modifier on a backslash-continued line stays a modifier; - endless defs with operator names or nested parens; - a multi-line block opener indents from its first line. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem 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 9f2c94f. Configure here.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Burn-down agent: labeled Ready for review at head
Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Final review brief (merge steward)What it does: Hosted gem Risk: medium. The change is only in the gem unwind path, but it replaces a small line-level heuristic with roughly 450 lines of hand-written Ruby lexing (literals, heredocs, Look here:
Verified:
Changes I made: none. Open questions: none blocking. Known lexing limits are listed in the PR description: nested-quote Auto-merge (squash) is armed, so approving sends this straight to the merge queue. Generated by Claude Code |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
* ci(release): publish npm from release.yml, not publish-npm.yml Every socket-patch npm package's trusted publisher is registered against release.yml, and npm allows only one publisher per package. The 5.0.0 release dispatched publish-npm.yml, whose OIDC token named that file, so npm rejected it with E401 before staging anything. Move the npm leg back inline as release.yml's npm-publish job (same steps as publish-npm.yml) and delete publish-npm.yml, so the existing registration keeps working. Add an `npm-retry-version` input that skips the version gate, build, tag, GitHub release and crates.io jobs and re-stages npm from an existing release's assets; this retries 5.0.0 now and replaces the manual Publish npm dispatch. crates.io stays dispatched through publish-cargo.yml, since crates.io allows several publishers per crate. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> * chore(release): fold 22 more PRs into the 5.0.0 notes Cover the PRs merged to main after #1432's base (1779317..4cb3643): Cargo source replacement and registry = "crates-io" (#338/#455, #386), pnpm lockfile=false (#1074), berry removed descriptors (#1435), yarnrc ${VAR} reads (#1100), CRLF .npmrc append (#1196), Composer vendor-dir cascade and global home (#439/#686, #586), Go +incompatible vex (#484), gem moved BUNDLE_GEMFILE and commented Gemfile revert (#952, #988), Poetry source = "pypi" (#1282) and Hatch path characters (#547). No entries for #1411 (macOS fix to code #1393 added in this release; the #1393 entry already describes the intended behavior), #1426 (perf regression introduced and fixed within 5.0.0) or the CI/test/bench PRs. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> * chore(release): cover #1419, #1434, #1440, #1442, #1444 in the 5.0.0 notes Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> * chore(release): 5.0.1 Cut [Unreleased] into [5.0.1] — 2026-10-13 and stamp 5.0.1 with scripts/version-sync.sh. The 5.0.1 notes cover main through 501c6d9 (#1449), i.e. every PR after the v5.0.0 tag (6ad6add): the npm publish fix (5.0.0 never reached npm or crates.io, 5.0.1 is the first v5 there), #1465, #759, #1460, #1462, #1445, #869, #1447, #1450, #1467, and #1449 under Maintenance. CI/test-only PRs (#1448, #1452, #1454, #1457, #1459) have no entries. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> * chore(release): 5.0.1 notes for PRs merged since the cut Covers #1469, #1470, #1474, #1475, #1478, #1479, #1480 and #1482; #1484 is CI-only. The notes now cover main through 285a5e8. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]> --------- Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Hosted gemrollback / remove still strip the DEPENDENCIES ! when the user's source … do block holds an assignment-form v = if/case/begin … end, so frozen installs fail on Bundler 4.0.19+
There was an error while loading. Please reload this page.