Repository navigation
Fix vendored re-runs failing on unserved upgrades (#1235) - #1707
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A gem vendored at patch A fails every `scan --mode vendored` re-run with exit 1 once the API offers a superseding patch B whose prebuilt .gem is still building or unavailable, although nothing was touched and A stays in force (#1235). The npm family already keeps A and reports a skip (#954). Add regression tests: the kept case for pending_build, build_failed and not_found, the unwired older patch that must still fail, and a first vendor that must still fail with vendor_prebuilt_required. Assisted-by: Claude Code:claude-opus-5-5
Vendored re-runs outside the npm family (Composer, Cargo, Go, gem, PyPI, Maven, NuGet) failed with exit 1 while a superseding patch had no prebuilt artifact yet, or at all. Only npm backends told the vendor loop that the patch was merely not served; every other backend reported a generic vendor_prebuilt_required refusal (#1235). The shared service policy now gives every backend's refusal the vendor_prebuilt_pending / vendor_prebuilt_unavailable code, and the vendor loop keeps a live older vendored patch for those refusals as it does for npm. With nothing to keep, the refusal is still reported as vendor_prebuilt_required, so first-vendor failures, takeover dry runs and repair messages are unchanged. Fixes #1235 Assisted-by: Claude Code:claude-opus-5-5
The contract row for vendor_prebuilt_pending / _unavailable quoted the npm wording only; other backends name their own artifact (.gem, crate, module zip, wheel, ...). Also build the not-kept fallback only when the older patch is not kept. Assisted-by: Claude Code:claude-opus-5-5
|
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 507fbf7. Configure here.
|
Labeled Ready for review by the burn-down agent.
Generated by Claude Code |
|
Labeled Ready for review by the burn-down agent.
Generated by Claude Code |
Final review briefWhat it does. Vendored re-runs for Composer, Cargo, Go, gem, PyPI, Maven and NuGet failed with exit 1 whenever a newer patch for an already-vendored package wasn't built yet (or never would be). The older vendored patch was still in force the whole time. Now they behave like npm (#954): the old patch is kept and reported as a Risk: low–medium. The core change is one line: non-npm backends now return the unserved code instead of the generic Look here
Verified
Changes I made: none. Open questions: none blocking. The PR description lists the review findings deliberately left as they are, with reasons. Auto-merge is armed, so approving sends this straight to the merge queue. Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1235
Summary
Vendored re-runs outside the npm family (Composer, Cargo, Go, gem, PyPI, Maven, NuGet) failed with exit 1 from the moment a superseding patch was published until the service built its artifact, or forever when it was
build_failed/not_found. The older vendored patch was untouched and still in force the whole time. They now behave like npm (#954): the older patch is kept and reported as askippedvendor_prebuilt_pending/vendor_prebuilt_unavailableevent naming both patches, with exit 0.Root cause
ServicePolicy::unserved(crates/socket-patch-core/src/vendor/service_fetch.rs) carried the "not served (yet)" code only underServicePolicy::Failure, which only the npm-family backends use. Every other backend settles its service artifact underServicePolicy::Refused, where pending and unavailable both became the genericvendor_prebuilt_requiredrefusal.keep_older_vendored_patchin the CLI only looked for the unserved marker on a failedDone, so it never fired outside npm.Fix
ServicePolicy::unservednow gives theRefusedoutcome the unserved code itself. All non-npm backends (andservice_archive_copy, which Maven and NuGet use) go throughsettle, so this is the one change point.keep_older_vendored_patchrecognises the unserved code on aRefusedoutcome as well as on a failedDone, with the samevendor_entry_livecheck. When there is no live older vendoring, the refusal is reported asvendor_prebuilt_requiredexactly as before, so first-vendor failures keep their code and message.takeover_dry_refusal(dry-run takeover preview) andredownload::detail(repair restores) both map an unserved refusal back tovendor_prebuilt_required, because neither has an older patch to keep.vendor::is_unservedandvendor::VENDOR_PREBUILT_REQUIREDare new in core and shared by the CLI and redownload.scan --mode vendoredparagraph and thevendor_prebuilt_*row, and described the per-backend artifact noun in the detail.Tests
New CLI regression tests in
crates/socket-patch-cli/tests/in_process_vendor.rs(gem, throughscan --mode vendoredagainst a mock API):scan_vendor_gem_keeps_the_older_patch_while_the_superseding_one_is_unserved(pending_build, build_failed, not_found)failedvendor_prebuilt_required"prebuilt .gem is still building"skippedwith the unserved code naming both uuids; Gemfile, lock, ledger and artifact byte-identicalscan_vendor_gem_unserved_upgrade_fails_when_the_old_patch_is_unwiredvendor_prebuilt_required, no unserved code leaksscan_vendor_gem_unserved_first_vendor_still_failsvendor_prebuilt_requiredIn the per-backend core tests,
service_pending_*/service_unavailable_*for cargo, golang, composer, gem, pypi, nuget andservice_copy_*(the Maven and NuGet path) now assert that the refusal carriesvendor_prebuilt_pending/vendor_prebuilt_unavailable. That proves each backend hands the CLI the marker. The existing npm #954 tests stay green.Local runs:
cargo fmt --all -- --check: cleancargo clippy --workspace --all-features -- -D warnings: cleancargo test --workspace --all-features --no-fail-fast: all vendor tests pass (core lib 6725 passed;in_process_vendorall passed). 12 unrelated tests fail only in this container: 10 read-only/unremovable-file and symlinked-parent tests that cannot fail as uid 0 (in_process_redirect×3,repair×2, corecopy_tree/vlt_heal/pypi_poetry/pypi_requirements; the two pypi ones fail identically on unmodifiedmainhere), and 2e2e_bun_lockbtests that need network access to the public patch API and a different bun. CI runs these as non-root.Per-issue checklist:
Review notes (
/code-review high)Fixed: the contract row now describes the per-backend artifact noun (
.gem,crate,module zip, …) rather than npm-only wording, and the fallback outcome is no longer cloned up front.Not changed, with reasons:
refusal_is_benign. Only two production paths classify backend outcomes. The vendor loop goes throughkeep_older_vendored_patchfirst, andtakeover_dry_refusalmaps unserved codes tovendor_prebuilt_requiredbefore the benign check. A separate marker onVendorOutcome::Refusedwould touch hundreds of match sites for no behaviour gain.discover_wiringruns once per unserved package. This is unchanged from the npm path, and it only runs for packages whose superseding patch is unserved.https://claude.ai/code/session_01WSzRRL9zy5mWcTuc6sxJQw
Generated by Claude Code