Repository navigation
Make the vendored-to-hosted takeover atomic - #1039
Merged
Merged
Conversation
A group commit can now defer the vendored artifact deletions a revert makes (GroupCommit::defer_removals): every per-unit revert removal goes through remove_tree_and_prune (cargo and golang now too, instead of their own remove_tree + prune copies) and the bun workspace tarball removal through remove_mirror, and both queue the deletion for after the commit when the open group asks for it. A rollback_to forgets the queued deletions and a dropped group never makes them, so a staged revert can be undone with its artifact intact. Also: - commit_unjournaled: the all-or-nothing replace without the crash journal, for runs that must write nothing under .socket/; - a journal that had to create .socket/vendor/ prunes it again; - group_commit::exists is public, for overlay-aware existence checks. Audit B03/B14 groundwork. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The disk flow took over cargo, npm, golang, pypi and Gradle maven entries, while the in-memory engine refused only cargo, npm and golang, so a vendored PyPI package reached the Python rewriters in memory. Both now use hosted::takeover::in_reach (audit B15). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
scan/get --mode hosted reverted a vendored package's wiring on disk first and planned the hosted pin afterwards. When the rewriter then refused (a lock-level refusal, a missing berry checksum, unavailable wheel metadata, a Poetry 0.x lock, ...), the package was left unpatched in both modes, and only six hand-copied per-ecosystem pre-gates tried to predict those refusals. The dry run counted every takeover as redirected. The takeover now runs inside the run's group commit: - each vendored revert is staged in the overlay under a savepoint (a failing or drift-keeping revert is rolled back and refused); - the hosted rewrite reads the overlay, so it plans against the reverted project; - a staged purl the rewrite does not pin is retracted: the overlay goes back to its pre-revert state, the purl stays vendored byte for byte (redirect_takeover_kept_vendored, skipped with the cause), and the rest are staged and rewritten again; - the hosted pins and the vendored ledger are written into the same overlay and committed once (journaled); artifacts go after the commit. A dry run does the same and drops the overlay, so it reports the wet outcome. A hosted run without a takeover commits its files unjournaled, putting back the ones replaced if one fails. Deleted: the bun, berry (lock and dep), classic, vlt, Gradle, pypi platform-wheel and requirements pre-gates (9 copies of rewriter logic -> 0; the requirements reach check only explains a retraction now), the dry-run TakeoverPreview path in the engine, and the stranded-takeover reporting (redirect_takeover_unpatched), which can no longer happen. Audit B03, B14, B37 (takeover part). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The staged vendored-to-hosted takeover runs the real revert inside a group commit and relies on the overlay plus deferred removals to undo it. The JVM revert deleted the tree files under .socket/vendor/gradle and .socket/vendor/maven2 directly, and wrote or deleted the owned .socket/gradle/.gitattributes, .socket/vendor/.gitattributes and the derived maven-metadata.xml files straight to disk. A dry run, or a takeover the hosted Gradle planner refused and retracted, therefore deleted the vendored jars while the restored wiring still named them. Capture the owned .gitattributes files and the derived metadata in the group overlay, and route the tree-file deletions through group_commit::defer_removal so they happen only after the commit. A new test stages the revert (with and without a sibling version sharing the metadata) and checks that dropping or rolling back the group leaves the project byte-identical and that committing lands the plain revert. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
commit_hosted_writes writes the files the group does not capture (the Gradle hosted index and script under .socket/gradle/) straight to disk before the commit. When writing a later file, saving the vendored ledger or the commit itself failed, the error said nothing was changed while those files stayed on disk. Record their previous bytes and put them back on every failure path except an interrupted journaled commit, which the next locked command finishes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Snapshot every project file, .socket/ and the vendored artifacts included, around the dry-run vendored-to-hosted takeover for pnpm, package-lock, vlt, golang and cargo (bun and the uv retract test already compare the artifact). Rewrite the stale CLI_CONTRACT Gradle paragraph that still described the deleted takeover_refusal pre-gate, and the real-Gradle refusal test's doc comment. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The takeover pre-gates that called preflight_yarn_classic_hosted and preflight_yarn_berry_hosted from outside are gone. The classic one is now private and the berry one pub(crate) (upstream/npm.rs still uses it). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With a yarn-offline-mirror configured the classic hosted rewriter refuses every entry, so nothing is pinned, yet it still warned that a berry install would drop the hosted pins (#907's warning counted the refused entries as pinned). The staged takeover reports a retracted purl's first rewrite warning as its cause, so a vendored classic project with a mirror was skipped as redirect_yarn_classic_berry_ migration_risk and the real refusal, redirect_yarn_classic_offline_ mirror, was never reported (in_process_vendor's classic_vendored_to_hosted_takeover_refuses_with_offline_mirror failed once main's #917 landed beside the staged takeover). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolves the conflicts with #657: the berry takeover pre-gate it extended stays deleted in hosted.rs, preflight_yarn_berry_hosted takes main's manifest argument, preflight_yarn_berry_hosted_dep stays deleted (its only caller was the deleted pre-gate), and the contract keeps main's root package.json line-ending sentence. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
#657 (merged on main) made the hosted and vendored modes refuse a mixed root package.json, and gated the vendored-to-hosted takeover before its revert. The staged takeover dropped that pre-gate and let the hosted rewriter judge the reverted project, but the berry revert re-renders package.json in its majority line ending, so a mixed manifest passed the rewriter's check after the revert and the takeover went ahead (in_process_vendor berry_takeovers_refuse_before_reverting_the_old_mode failed after the merge). Judge the berry project gates once per staging pass, on the pre-revert overlay, through the rewriter's own preflight_yarn_berry_hosted (the shared berry_gates set, no copied logic). A refused yarn-berry entry is skipped with the gate's code, followed by redirect_takeover_kept_vendored. preflight_yarn_berry_hosted is public again for this caller. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
marked this pull request as ready for review
October 7, 2026 17:07
Tanmay Singla (Tanmay182003)
approved these changes
Oct 7, 2026
Collaborator
Author
|
bugbot run Generated by Claude Code |
…asons When a staged takeover is retracted and no rewriter warning names the package, explain() fell back to the rewrite's first warning as the lock-level cause. That warning can be a success advisory from a pin that did land (redirect_npm_allow_remote, redirect_pnpm_trust_lockfile, redirect_yarn_classic_berry_migration_risk), so the skipped purl and redirect_takeover_kept_vendored reported the wrong code. Skip those advisories when picking the fallback; with nothing else left the reason is NOT_PINNED. names_package accepted `/` as a left boundary unconditionally, so an unscoped name like `node` matched inside `@types/node` and a retracted takeover could inherit another package's warning. A `/` now counts as a boundary only after a path segment, not after an `@scope`. Co-Authored-By: Claude <noreply@anthropic.com>
Collaborator
Author
|
bugbot run 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 406e111. Configure here.
Resolve conflicts with main's #946 (PyPI takeover pre-gate), #1042 (containment helper) and #1077 (classic berry-migration warning): - hosted.rs: keep this PR's staged takeover; main's new `preflight_pypi_takeover` pre-gate inside the deleted `vendored_takeover` is dropped. The staged takeover's `explain` now calls `preflight_pypi_takeover` (instead of only the requirements check), so a retracted uv pin-down (#723) or Poetry 0.x (#945) takeover is still skipped with `redirect_uv_takeover_version_unreachable` / `redirect_poetry_lock_unsupported`, as main's tests expect. - socket_dir.rs: use main's `containment::ensure_unlinked` guard, then this PR's deferred removal. - redirect/mod.rs: take main's `pinned_any` (a mirror-refused entry counts only when it already carries our hosted pin), which subsumes this PR's mirror fix. - CLI_CONTRACT.md: describe the uv/Poetry cases as retractions. - mode_migration_pypi.rs: keep both sides' tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
github-merge-queue
Bot
removed this pull request from the merge queue due to a manual request
Oct 8, 2026
Mikola Lysenko (mikolalysenko)
enabled auto-merge
October 8, 2026 03:16
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Oct 8, 2026
Resolve CLI_CONTRACT.md: keep this PR's staged-takeover wording and add #1060's redirect_gem_version_not_locked code. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The required 'Audit GHA Workflows' check (zizmor ref-version-mismatch) now fails on every head because the pinned setup-php hash no longer matches the moving v2 tag. Same one-line change as #1118, so it merges cleanly when that lands. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Oct 8, 2026
Resolve the hosted.rs conflict with #1045: this branch moved the takeover out of hosted.rs into hosted/takeover.rs, so keep that layout and port #1045's change there. The takeover's ledger drop now compares PurlKeys and the local canonical_purl key helper is gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Resolve CLI_CONTRACT.md: keep this PR's staged-takeover wording and add main's new gem redirect codes (bundle lockfile, twin manifest). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adopt #1032's jvm::layout module: group_commit captures through layout::CAPTURED_FILES (now also listing the Gradle script and vendor .gitattributes this PR captures) plus the derived maven-metadata paths; drop this PR's duplicate VENDOR_TREES for layout::VENDOR_TREES; the takeover reach check uses layout::LEDGER_ECOSYSTEM. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 8, 2026
Mikola Lysenko (mikolalysenko)
added a commit
that referenced
this pull request
Oct 8, 2026
scan/hosted.rs: add main's takeover module (#1039) and keep this branch's vlt_heal alias in place of scan/hosted/vlt.rs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Oct 8, 2026
Resolve two CLI_CONTRACT.md conflicts by keeping main's new text (the atomic vendored-to-hosted takeover wording from #1039 and the gem_lock_unsupported warning from #768) while re-applying this PR's migration away from the removed spellings: `scan --apply` becomes `scan --mode agent`, and `--apply`/`--vendor` in the lockfile supplement become agent mode / vendored mode. Co-Authored-By: Claude <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Oct 8, 2026
Main's #1039 made the vendored-to-hosted takeover staged in the run's group commit (reverts live in an overlay until one commit, an unpinned takeover is retracted and stays vendored, dry runs stage too). The PR's attribution gate is re-applied on that structure: - RewriteOptions::takeover_uuids is the staged takeovers' uuids (Takeover::staged_uuids), in wet and dry runs alike: the rewriters' verdict decides them and main's retract loop handles an unpinned one. - Scan's prior discovery is reused only when no takeover is staged: its re-stat sees the disk, not the overlay holding the reverts. - done.unattributed joins `skipped` after the retract loop, from the final rewrite. - The writes go through main's commit_hosted_writes; the paths created for discovery_after_writes are taken before the commit (written paths not yet a regular file on disk, plus takeover files the overlay creates or removes), and a takeover's reverts count as writes when choosing the post-write discovery. - engine::rewrite drops the TakeoverPreview argument main deleted; docs and CLI_CONTRACT describe the staged takeover. Co-Authored-By: Claude <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Oct 8, 2026
Picks up the atomic vendored-to-hosted takeover (#1039); merges cleanly on top of the earlier main merge. Co-Authored-By: Claude <noreply@anthropic.com>
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Oct 8, 2026
main's #1039 (atomic vendored-to-hosted takeover) dropped the takeover_previews parameter from hosted::engine::rewrite. The merge itself is clean, but this branch's bun.lockb rewrite test still passed `&[]` for it, so the merge queue failed to compile socket-patch-core's tests. Drop the stale argument. Assisted-by: Claude Code:claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TSx4W4Qfb8hsBhw4NEvkv9
Mikola Lysenko (mikolalysenko)
pushed a commit
that referenced
this pull request
Oct 8, 2026
Main's #1039 made the vendored-to-hosted takeover atomic: it moved the takeover into scan/hosted/takeover.rs and dropped dry-run takeover previews. Take main's hosted.rs; the branch's pnpm gitBranchLockfile takeover gate is now covered by the staged takeover's retract path, since the hosted rewrite emits redirect_pnpm_git_branch_lockfile and leaves the purl vendored. Keep the branch's per-member and Rush lock arguments to pnpm_trust and its governing-lock gate, minus the takeover_previews plumbing main removed. Co-Authored-By: Claude <noreply@anthropic.com>
This was referenced Oct 8, 2026
Decide: keep the in-memory hosted engine and napi addon as a supported product, or delete them
#1200
Open
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.
Problem
Architecture audit B03:
scan/get --mode hostedover a vendored package (the vendored→hosted takeover) reverted the vendored wiring on disk first and only then planned the hosted pin. When the hosted rewriter refused (a lock-level refusal, a missing berry checksum, unavailable wheel metadata, a Poetry 0.x lock, a uv pin-down, ...), the package was left unpatched in both modes. Hand-copied pre-gates for bun, berry, classic, vlt, Gradle, pypi platform wheels and requirements tried to predict those refusals, and they drifted from the rewriters they copied (the root cause behind #945, #723 and the closed #699). The hosted→vendored direction is already atomic (#963).Change
The takeover now runs inside the run's
GroupCommit(commands/scan/hosted/takeover.rs):redirect_requirements_takeover_unreachable, the rewriter's lock-level refusal, orredirect_takeover_not_pinned), followed by the newredirect_takeover_kept_vendoredwarning. Exit 0.GroupCommit::defer_removals; the per-unit revert removal goes throughremove_tree_and_prune, bun workspace tarballs throughremove_mirror, and the JVM revert's Gradle/Maven tree files throughgroup_commit::defer_removal). The JVM-owned.gitattributesfiles and the derivedmaven-metadata.xmlfiles are now in the captured set, so the Gradle revert's writes stay in the overlay too.--dry-runruns the same steps and drops the overlay instead of committing, so it reports the wet outcome (B37).commit_unjournaled) because hosted mode writes nothing under.socket/vendor/. If one replacement fails, the files already replaced are put back (B14). The few files the group does not capture (the Gradle hosted index and script under.socket/gradle/) are written just before the commit and put back if a later step or the commit fails.hosted::takeover::in_reachis the one predicate both engines use.Duplicate copies deleted
takeover_refusal, pypi platform wheel, requirements reach).preflight_requirements_takeoveronly explains a retraction now. Review found the Gradle gate was not yet safe to remove, because the JVM revert deleted the vendored tree straight from disk. That is fixed in this PR (see below), so the count stands.preflight_yarn_classic_hostedis now private. After merging main's Fix yarn berry project gates drifting between modes (#628, #629) #657, which moved the berry project gates into the sharedformats/yarn/berry_gates, the takeover again checks yarn-berry entries against those gates on the pre-revert project. It calls the rewriter's ownpreflight_yarn_berry_hostedonce per staging pass, so no logic is copied. This is needed because the berry revert re-renderspackage.jsonin its majority line ending, so after the revert the rewriter could no longer see the mixed manifest that Hosted yarn berry rewrites a mixed-line-ending package.json that vendored mode refuses #628 refuses. Copied pre-gates: 9 → 0. Shared-gate call sites: 1.stages.rsclosure +hosted.rsclosure →hosted::takeover).TakeoverPreviewinstall-policy preview and the CLI's withheld-and-counted preview are deleted. The dry run is the real rewrite now.redirect_takeover_unpatched,partial_failure,unrecorded) is deleted, because a takeover can no longer strand.remove_tree+prune_empty_vendor_levels) now use the sharedremove_tree_and_prune.Behavior changes (documented in CLI_CONTRACT.md)
trustLockfileas written to a newpnpm-workspace.yaml, which is what the wet run does: the revert removes the vendor-created file. The old preview said "merged into the existing" one.yarn-offline-mirror, the yarn classic hosted rewriter no longer also warnsredirect_yarn_classic_berry_migration_risk, because the mirror refused every pin and nothing was pinned. That warning came from Fix hosted yarn classic pins missing berry warning (#907) #917 on main. Without this fix, a retracted classic takeover reported the berry warning as its cause instead ofredirect_yarn_classic_offline_mirror.vendored_revert_failed) instead of the deleted vlt pre-gate. The state stays the same.Testing
All commands were run in the worktree with
CARGO_INCREMENTAL=0through the shared limiter,-j4, on the branch after merging origin/main (431b818, head 830726e):cargo test -p socket-patch-core --lib: 5608 passed, plus the new mirror test.cargo test -p socket-patch-cli --lib: 869 passed.cargo test --no-fail-fast -p socket-patch-cliwith--testset to each of: coverage_fix_scan_hosted_dryrun_vendored, e2e_golang_hosted_state, covgap_commands_scan_hosted, in_process_redirect, hosted_memory_engine, mode_migration_pypi, in_process_vendor, in_process_vendor_bun_takeover, in_process_vendor_npm_v1_takeover, in_process_vendor_pnpm_takeover, in_process_vendor_pypi_takeover, vendor_eject, vendor_jvm_cli, contract_gradle_codes, gradle_agent_cli, e2e_sbt_vendor, e2e_scala_cli_vendor, covgap_commands_vendor, covgap_commands_vex, e2e_vex_redirect, e2e_redirect_gradle_build, e2e_vendor_gradle_build. All passed. The real-Gradle tests are#[ignore]d.After the second merge and the berry gate:
--lib, in_process_vendor (121, including Fix yarn berry project gates drifting between modes (#628, #629) #657'sberry_takeovers_refuse_before_reverting_the_old_mode), mode_migration_npm (19, real yarn), mode_migration_pypi, mode_migration_cargo, mode_migration_bun, mode_migration_vlt, in_process_alternate_installers, remove, repair, e2e_redirect_gem_stale_install and the takeover files above all passed.mode_migration_cargo::vendored_then_hosted_takeover_leaves_pure_hosted(real cargo) andmode_migration_npm::{berry,classic}_vendored_then_hosted_takeover_leaves_pure_hosted(real yarn): passed.cargo clippy -p socket-patch-core -p socket-patch-cli --all-targets -- -D warnings: no findings in code this PR changed, but it fails on 20 pre-existing lints in files this PR does not touch, or in lines it did not write (checked with git blame against the merge-base):python_crawler.rs:2760unusedunix_default, and:5375patch/apply.rs:3736jvm_jar.rs(8 ×from_ref)redirect/mod.rs:10292(test)upstream/uv.rs:2097bun_binary.rs:1051maven_repo.rs:2503nuget_feed.rs:2005pnpm_lock.rs:3877yarn_berry_lock.rs:1483yarn_layering_tests.rs:1023,1028prebuilt_common/common(module loaded twice, needless borrows).With
-A unused_variablesso the core library compiles, the CLIsrc/has no findings.Not run locally: the real-Gradle leg
e2e_redirect_gradle_build -- --ignored gradle_hosted_(includinggradle_hosted_takeover_refusal_keeps_vendored). This machine has no JDK, so it is left to the Gradle CI leg. The same staged revert is covered in-process by the new core test below.New or flipped regression tests (each fails without its fix):
vendor::jvm::gradle::tests::a_staged_revert_changes_nothing_until_its_group_commitscovers the review blocker. It vendors a Gradle patch, with and without a sibling version that sharesmaven-metadata.xml, then stages the real revert in adefer_removalsgroup. Dropping the group (the dry run) or rolling it back (the retracted takeover) leaves the full tree byte-identical, and committing lands exactly the plain revert. Before the fix, the drop case deleted the jar, pom, marker, metadata and both.gitattributes..socket/and the vendored artifacts included) now wrap the dry-run takeover incoverage_fix_scan_hosted_dryrun_vendored(pnpm, package-lock, vlt),e2e_golang_hosted_state::hosted_takeover_of_vendored_module_removes_vendored_state(golang, viaget --dry-run) andmode_migration_cargo::vendored_then_hosted_takeover_leaves_pure_hosted(cargo). Bun (mode_migration_bun,assert_unchanged) and uv (uv_takeover_without_wheel_metadata_keeps_the_package_vendored, which includes the wheel) already compare the whole state.patch::redirect::tests::yarn_classic_offline_mirror_refusal_skips_the_berry_risk_warning. It fixesin_process_vendor::classic_vendored_to_hosted_takeover_refuses_with_offline_mirror, which failed after merging main's Fix hosted yarn classic pins missing berry warning (#907) #917.mode_migration_pypi::uv_takeover_without_wheel_metadata_keeps_the_package_vendored,a_crash_inside_the_takeover_commit_is_finished_by_the_next_run,ledger_update_failure_changes_nothing,covgap_commands_scan_hosted::ledger_save_failure_after_successful_revert_fails_closed,in_process_redirect::partial_lockfile_write_failure_exits_1_and_writes_no_ledger,hosted_memory_engine::vendored_pypi_takeover_is_refused_like_the_disk_flow,group_commit::tests::deferred_unit_removals_wait_for_the_commit.mode_migration_npm::berry_vendored_then_hosted_takeover_leaves_pure_hostednow expects a hostedresolutionsentry inpackage.jsoninstead of a pristine one. I checked it on origin/main (431b818, real yarn) in a detached worktree, and it already fails there atmode_migration_npm.rs:1223("the berry resolutions entry must be reverted"). Since #465, main's hosted berry pin writesresolutionsintopackage.json. So the old assertion was stale, and this PR does not change that behavior.Deferred
mod.rs:5525,5552vsnuget_feed.rs:219) is not in this PR. Composer/NuGet are not takeover ecosystems, and that decision needs C34.remove_tree_and_pruneorremove_mirror(both deferring). JVM was the only backend deleting uncaptured.socket/files directly.vendor --revert's sweep does..socket/gradle/hosted-index.tsv,socket-patch.hosted.settings.gradle) stay outside the captured set. They are written just before the commit and put back on failure, but a crash in that window leaves them on disk; the captured settings line is what makes them live.--jsontop-levelerror(scan and get emit both a string and a {code, message} object) #704) is unchanged: a failed commit keeps the existing hosted error envelope.🤖 Generated with Claude Code
Note
Medium Risk
Changes core hosted-mode lockfile and vendor-ledger mutation paths and exit/status contracts; behavior is safer when redirects fail but regressions could affect multi-package takeovers or crash recovery.
Overview
Vendored → hosted takeover is now staged and committed atomically instead of reverting vendored wiring on disk before planning hosted pins. Hosted
scan/getopen aGroupCommit, run takeover logic in newhosted/takeover.rs, stage each revert under savepoints, plan the hosted rewrite against the overlay, and retract any package the rewriter would not pin (overlay rolled back; package stays vendored withredirect_takeover_kept_vendored, exit 0). Successful runs commit vendored reverts, lockfile redirects, and ledger updates in one step; artifact deletes are deferred until after commit.Hosted writes are transactional: takeover runs use a journaled commit; hosted-only runs use
commit_unjournaledwith rollback on partial failure.--dry-runruns the same pipeline and drops the overlay, so previews match wet runs without touching disk.Removed the stranded-takeover path (
redirect_takeover_unpatched,partial_failureexit 1) and ecosystem-specific takeover pre-gates copied from rewriters;hosted::takeover::in_reachis shared with the in-memory engine. CLI_CONTRACT.md documents staged takeover, new skip/warning codes, and updated failure semantics (e.g. ledger save failure leaves the project unchanged).Tests add full-tree dry-run snapshots and flip expectations for ledger/commit failures and partial lock writes.
Reviewed by Cursor Bugbot for commit 406e111. Configure here.
Generated by Claude Code