Repository navigation
Vendored gem revert restores Gemfile.lock but leaves the Gemfile path: line when that line carries a trailing comment, and no re-run can finish it #988
Description
[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: register comment.
Kind: bug. Source: new finding, register E68 (same class as E24, the nine revert mechanisms).
Problem
Vendored gem decides whether the Gemfile wiring is "ours" in two different ways:
- Forward (
vendor, hot path): the Gemfile only has to contain the copy path:gemfile_text.contains(©_rel)(gem.rs#L361-L362). - Revert (
revert_gemfile_record): the recorded line must match a Gemfile line exactly:lines.iter().position(|l| *l == written)(gem.rs#L2226-L2242).
The records are also reverted one by one, lock first (gem.rs#L1194-L1240). A drifted Gemfile record doesn't stop the lock records from being written. Poetry's legacy formats have the atomic variant revert_lock_fragment_splice_atomic (common.rs#L714-L723) for exactly this, and #822 fixed the same half-revert in uv.
Proof: I ran a throwaway test in vendor::gem::tests three times on 9c43dfc, using the existing fixture(GEMFILE_DIRECT, LOCK_DIRECT) and run_vendor:
- Vendor
rack 3.2.6. The Gemfile line becomesgem "rack", "3.2.6", path: ".socket/vendor/gem/<uuid>/rack-3.2.6". - Append
# CVE fix, do not bumpto that line. - Re-run vendor:
success=true, no files patched, no new entry (in sync). revert_gem(&entry):success=true,kept_artifact=true, with warningsvendor_lock_entry_drifted("Gemfile no longer carries what vendor wrote for rack") andvendor_artifact_kept.- The Gemfile still says
path: ".socket/vendor/gem/<uuid>/rack-3.2.6". Gemfile.lockwas restored to the registry: the PATH section is gone,rack (3.2.6)is back under GEM, and DEPENDENCIES saysrack (~> 3.1).
- The Gemfile still says
- A second
revert_gem: drift-keep again, the same two warnings. It can never finish.
Symptoms
- Vendored requirements.txt can't be reverted once the user touches the
# socket-patch vendor:comment:vendor --revertdrift-keeps forever (exit 0), and the suggested "re-vendor" remedy is a no-op or adds a duplicate line #977 is the same forward/revert recognizer split in requirements.txt (code-only match forward, whole-line match on revert). This issue is the gem instance, plus the half-revert, which Vendored requirements.txt can't be reverted once the user touches the# socket-patch vendor:comment:vendor --revertdrift-keeps forever (exit 0), and the suggested "re-vendor" remedy is a no-op or adds a duplicate line #977 doesn't have.
Impact
- A user who annotates their Gemfile line, or whose formatter rewrites it, ends up with a Gemfile that names a
path:source while the lock says rubygems.org.bundle install --frozen/--deploymentrefuse that pair, because the Gemfile and lock disagree. - The revert reports
success, and the warning's remedy ("undo the drift … or re-vendor") doesn't help: re-vendor thinks it is in sync until the lock is half-reverted, and after that the second revert still drift-keeps. - The size is small: one file plus tests.
Proposed change
- Make the Gemfile revert recognize our line by the same predicate the forward path uses: a
gem "<name>"declaration whosepath:names this uuid's copy. Then restoreoriginalover that line, keeping any trailing comment the user added. Delete the exact-lineposition(|l| *l == written)match. - Make the gem revert all-or-nothing across its coupled records (
gemfile_line,gemfile_lock_spec,gemfile_lock_checksum): plan every record first, and write nothing if any record drifted, asrevert_lock_fragment_splice_atomicdoes.
Size and scope
vendor/gem.rsonly, about 60–120 production lines plus tests.- Out of scope: the shared revert engine (E24, tracked separately) and requirements.txt (Vendored requirements.txt can't be reverted once the user touches the
# socket-patch vendor:comment:vendor --revertdrift-keeps forever (exit 0), and the suggested "re-vendor" remedy is a no-op or adds a duplicate line #977).
Acceptance criteria
- A regression test: vendor, then append a comment to the wired Gemfile line, then revert. Both files return to registry form, the comment is either kept on the restored line or documented as dropped, and the artifact is removed.
- A regression test: a genuinely drifted Gemfile line (the
path:was removed or points elsewhere) leaves both the Gemfile andGemfile.lockbyte-identical (no half-revert), and the artifact is kept. - The existing
test_revert_round_trip_*,test_revert_converged_files_are_silent_and_still_removeand the legacy-ledger gem fixtures stay green.
Dependencies
None. This is independent of the E24 tracking issue, which it informs.
Backlog review — 2026-10-08
Priority: P1 → P2. A trailing comment creates a partial Gem rollback and install failure. Concrete defect, but conditional and observable.
Activity
audit-ecosystems: file E24 (#989, #990), add E68 (#988)
mikolalysenko commentedon Oct 7, 2026
[agent] Triaged as
priority:p1(Bundler). Confirmed onmain(9c43dfc): the forward in-sync check is a substring test (gemfile_text.contains(©_rel),crates/socket-patch-core/src/vendor/gem.rs:362), butrevert_gemfile_recordonly accepts an exact line match (lines.iter().position(|l| *l == written),gem.rs:2232). So a trailing comment on the wired line reads as "in sync" when vendoring and as "drifted" when reverting.Related to #977 (requirements.txt has the same forward/revert recognizer split), but the fixes live in separate code (
vendor/gem.rsvs. the requirements line reverter), so I'm not clustering them. #989 tracks the shared engine that would fix both.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
[agent] Re-checked against main @
03b9418(architecture audit, ecosystems and formats). The code moved (#768, #1043), and the defect is unchanged.gem.rs#L416-L419(gemfile_text.contains(©_rel)).revert_gemfile_record,gem.rs#L2273-L2300(lines.iter().position(|l| *l == written)), returningDriftedotherwise.revert_gemstill reverts record by record, so a drifted Gemfile record does not stop the lock records.No open PR touches these lines.
vendor/gem.rsis still listed as blocked by an open PR in the refactor routine's queue.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
[agent] Re-checked on main @
9ab72d4by the architecture audit (ecosystems and formats). The finding still holds after #1245, which moved the gem finish ontovendor::revert::finishbut kept the per-record walk.gem.rs#L416-L418(gemfile_text.contains(©_rel)).revert_gemfile_record, #L2254-L2283 (position(|l| *l == written)).revert_gem#L1188-L1303). A drifted Gemfile record therefore still doesn't stop the lock records from being restored.Generated by Claude Code
mikolalysenko commentedon Oct 12, 2026
[agent] Claiming this issue (shared root cause: vendored gem revert matches the Gemfile line by exact text and reverts its coupled records one by one). Branch: agent/fix-gem-revert-gemfile-line. Claim-ID: 2026-10-12T00:20:51Z-f44927
Generated by Claude Code
mikolalysenko commentedon Oct 12, 2026
[agent] Draft PR: #1406
Generated by Claude Code
Test gem revert of a commented Gemfile line
Revert gem Gemfile and lock together