Fix berry mode takeover reverting before gates (#468, #369) - #470
Conversation
Assisted-by: Claude Code:claude-opus-5-5
Switching a yarn berry package between hosted and vendored mode removed the old mode's wiring before checking whether the new mode could wire that package. When the new mode then skipped or refused it, the package ended up patched in neither mode: - vendored -> hosted: a grant without the yarnBerry10c0 cache checksum deleted the vendored patch, then skipped the redirect, and the run still exited 0 saying the package was fully hosted (#468). - hosted -> vendored: another locked version of the name or a user-authored resolutions entry restored the registry entry, then failed vendoring with vendor_override_conflict (#369). Both takeovers now run the target mode's per-package gates first and leave the existing mode byte-identical, reporting the gate's own code, as CLI_CONTRACT.md already promises. Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
Ready for review at
Generated by Claude Code |
|
Reviewed No standalone blocking findings. Both takeover directions run the new package/grant refusal gates before reverting the old mode, and the focused tests preserve the previous wiring byte-for-byte on refusals. Validation: Integration with #465 needs a fix. Do not combine #465 and #470 unchanged: their automatic merge is textually clean, but the combined Berry suite fails berry_crlf_takeovers_round_trip_both_directions. The new target preflight rejects the Socket-owned left-pad@npm:1.3.0 resolution added by #465 as vendor_override_conflict. The preflight needs to recognize owned hosted resolutions or evaluate the restored state. I tested the clean combined tree: 5 passed, 1 failed, versus all 6 passing on #470 alone. |
The hosted->vendored takeover's per-package preflight read the still-hosted package.json / yarn.lock. Hosted wiring that also writes a Socket-owned package.json resolutions pin (#465) was then mistaken for a user override (vendor_override_conflict) and the takeover refused. The preflight now dry-runs the takeover's own restore_upstream and runs resolutions_gate / scan_berry_target on the restored text (RestoreOutcome.staged_text), so only the user's own wiring can refuse. The #369 regression test now mounts the upstream entry the restore reads and drops a leftover debug eprintln. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014hMbzxwUnf5voAqbc8g4df
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014hMbzxwUnf5voAqbc8g4df
|
Fixed the #465 integration in
Validation:
Trade-offs:
Generated by Claude Code |
|
BugBot review Generated by Claude Code |
|
CI on
I couldn't re-run the job: the API returns 403 with this session's credentials. Please re-run Generated by Claude Code |
|
Pushed compatibility fix The latest #465 moves checksum validation so an already-complete pin can retain its stored checksum. #470's eager rewrite preflight conflicted with that change. This commit keeps the unconditional grant check at the fresh vendored → hosted takeover boundary and restores #470's original, equivalent inline rewrite gate. Neither PR needs to absorb the other. Hosted → vendored still checks the staged restored files before changing the project. Validation: standalone 124 core Berry tests + 6 takeover tests passed. Combined with #465's latest The historical-installer failures inspected on this head were external patch API HTTP 504s: Poetry 1.2.2/macOS failed before rewriting, and PDM 2.22.4/Linux failed during a rescan. Uploaded artifacts confirm both causes. I retried the affected jobs: Poetry passed; PDM passed as well. Full platform CI is still required. |
|
CI on
I can't confirm it from here: this sandbox can't reach the patch API or download artifacts, and re-running returns 403. Please re-run Generated by Claude Code |
|
A second Python job failed on Generated by Claude Code |
|
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 852472c. Configure here.
|
[agent] Status on Generated by Claude Code |
LLM Description written by Claude Code:claude-opus-5-5
Fixes #468
Fixes #369
Summary
Switching a yarn berry package between hosted and vendored mode removed
the old mode's wiring before checking whether the new mode could wire
that package. When the new mode then skipped or refused it, the package
ended up patched in neither mode. Both takeovers now run the target
mode's per-package gates first and, on a refusal, leave the existing
mode byte-identical and report the gate's own code. This is what
CLI_CONTRACT.md already promises ("refuses before reverting").
Root cause (shared)
Each berry takeover preflight only covered the project-level gates
(line endings, cacheKey, compressionLevel). The per-package gates ran
after the revert:
commands/scan/hosted.rs, Vendored → hosted takeover on yarn berry deletes the vendored patch, then skips the hosted rewrite when the grant has no yarnBerry10c0 checksum, and still exits 0 "fully hosted" #468): the berryrewriter's per-dep
redirect_yarn_berry_missing_checksumgate (a grantwith no
yarnBerry10c0checksum, which vendored mode never needs) ranafter
dispatch_revert_onehad deleted the vendored wiring, ledgerentry and artifact. The run then exited 0 with "now fully hosted".
commands/vendor.rstakeover invendor_records_reusing, reached byscan/get --mode vendoredandvendorwith the service, Hosted → vendored takeover on yarn berry reverts the hosted redirect before a per-package vendor refusal, leaving the package unpatched in both modes #369):resolutions_gateandscan_berry_target(another locked version of the name, a userresolutionsoverride, non-npm protocol, mixed or duplicate entries)ran after
restore_upstreamhad already removed the hosted pin.Changes
patch/redirect:preflight_yarn_berry_hosted_dep(dep)checks the grant checksum before a fresh vendored → hosted takeover. The ordinary rewrite gate remains unchanged in this PR, so it composes with Fix yarn berry hosted pin leaking npm auth (#404) #465's lock-aware handling of already-complete pins.scan/hosted.rs: Berry vendored takeovers run that per-package gate before reverting. Warning deduplication retains each package's detail.vendor/yarn_berry_lock.rs:yarn_berry_vendor_target_preflight(root, purl, pin, opts)previews the takeover's own upstream restore and runs the backend's resolution and lock-entry gates on the resulting file text. Socket-owned hosted resolutions therefore do not look like user overrides.RestoreOutcome.staged_text, including removals; a dry run writes nothing.vendor.rs: the per-target preflight runs after the project-level checks and before the real restore. The preview resolves upstream metadata before mutation; the wet restore resolves it again.Tests
crates/socket-patch-cli/tests/in_process_vendor.rs)berry_vendored_to_hosted_takeover_keeps_vendored_without_berry_checksum(wet +--dry-run)redirect_yarn_berry_missing_checksumrefusal; takeover announced)berry_hosted_to_vendored_takeover_runs_package_gates_first(other locked version, userresolutions; wet +--dry-run)vendor_takeover_reverted_redirect, hosted pin gone)The #369 test passes
--patch-server-urlso the vendor run recognisesthe hosted pin as a takeover. Without it, the run takes the eject path,
which was already safe.
Local runs:
cargo clippy --workspace --all-features -- -D warnings: clean.cargo test -p socket-patch-cli --test in_process_vendor berry_: 6/6 ok.scripts/yarn-berry-vex-matrix.sh 4.12.0(withCOREPACK_NPM_REGISTRY=https://registry.npmjs.org, becauserepo.yarnpkg.com is blocked in this sandbox): all yarn 4 suites ok. The
two
yarn@2.4.3legacy-cachekey legs could not get yarn 2 here (it isnot on the npm registry); they are unrelated refusal tests.
cargo test --workspace --all-features --no-fail-fast: everythingpasses except:
in this sandbox. They fail identically on a main-based branch.
mode_migration_npmberry_*_takeover_*(2): they panic in fixturesetup (
mode_migration_npm.rs:351, the test's ownreqwestfetch ofregistry metadata hits the sandbox's TLS proxy,
UnknownIssuer)before any CLI code runs. CI runs them.
cargo fmt --checkreports the same pre-existing diffs asmain(CIdoesn't gate on fmt); the files this PR adds are rustfmt-clean.
Follow-ups
packageManagerset: the two-document pnpm-lock.yaml makes vendor refuse, andvendor --revert, rollback and the hosted takeover half-revert the project and break frozen installs #466 item 4 (pnpm vendored → hosted) is the same takeover-orderingshape for pnpm, but its main cause is the two-document pnpm 12 lock.
It is tracked there and not changed here.
🤖 Generated with Claude Code
Note
Medium Risk
Changes Yarn Berry hosted/vendored takeover ordering and lockfile restore preview paths; mistakes could leave projects in a broken patch state, but behavior aligns with documented refuse-before-revert contract and is covered by new integration tests.
Overview
Fixes Yarn Berry mode takeovers (#468, #369) so per-package gates run before tearing down the current mode. Previously, reverting vendored or hosted wiring first could leave a package unpatched when the target mode then refused or skipped it.
Vendored → hosted (
hosted.rs): Berry takeover refusal now includespreflight_yarn_berry_hosted_dep(grant must haveyarnBerry10c0) ahead of vendored revert; refusals are owned/cloned so skip reasons use the gate’s code; duplicatepre_warningsare deduped by full JSON.Hosted → vendored (
vendor.rs+yarn_berry_vendor_target_preflight): After project-level berry checks, a dry-runrestore_upstreampopulates newRestoreOutcome.staged_text; resolution/lock-entry gates run on that preview so user overrides and conflicting lock entries fail withvendor_override_conflictwithout removing the hosted pin.Regression tests cover grants missing the berry checksum and hosted→vendored with an extra locked version or user
resolutions.Reviewed by Cursor Bugbot for commit 852472c. Configure here.
Generated by Claude Code