fix(desktop): make Profile migration and plugin recovery fail closed - #251
Merged
yaojin3616 merged 4 commits intoSep 1, 2026
Merged
Conversation
…, gate removal-backup deletion Windows 0.7.1 (issue #250) chained three defects that turned one bad pnpm fetch into a corrupted profile with missing plugins: 1. migrateProfileToGenerations collapsed staging/peer-validation failures into a boolean that launchHarness treated like "nothing to migrate" — so the shared-tree repair ran pnpm on the broken state and clobbered the recovery surface for the next launch. 2. rollBackMigration swallowed every rename/rm error via `.catch(() => undefined)` and still reported success — a single in-use file or virus scanner on Windows wiped the snapshot while logging "rolled back", and the next launch had nothing left. 3. confirmPluginRemovalsBooted deleted each plugin's recovery backup on the second clean launch with no user interaction, so a single bad launch could permanently destroy the only copy of a paid plugin. Fix: - migration returns a tri-state `MigrationOutcome` so launchHarness only runs repairProfilePackages on `no-op`. `deferred-failure` logs the reason and skips the repair, so a broken tree is not clobbered. - rollBackMigration verifies each rename (snapshot path gone, live path present) and returns false on any failure, preserving the snapshot and refreshing the deferred marker so the next launch can show the user what went wrong. - plugin-removal no longer auto-deletes verified backups. The launcher records `bootVerifiedAt` and only `cleanupVerifiedRemovalBackup` deletes on explicit user action; the recovery UI now has a real surface for the user to inspect before deletion. Regression coverage: 5 new tests in migration-failure-paths.test.ts cover staging 404, peer-validation failure, two flavours of rollback rename failure, and the confirm-migration cleanup; plugin-removal tests now assert that no backup is auto-deleted across repeated clean launches and that cleanup is per-plugin. Fixes #250
yaojin3616
deleted the
agent/debugger/01a051f5-524f-7d26-8b0c-6c7657fd2c15
branch
September 1, 2026 10:38
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.
Summary
Completes the fail-closed recovery work for #250. A failed migration, rollback, registry read, or plugin restore can no longer fall through into startup maintenance that rewrites the active Profile, and recovery material is never deleted by launch count.
Root causes fixed
migrateProfileToGenerations()now returnsmigrated | no-op | deferred-failure. A single startup-maintenance owner stops immediately ondeferred-failure; it does not project, prune, or run package repair on the legacy Profile.node_modules,package.json, lockfile, and install marker), persists restore intent before rename, verifies every quarantine/restore/cleanup step, and keeps the journal plus snapshot whenever Windowsrename/rmor the journal commit fails.bootVerifiedAt. Backups remain until the user explicitly chooses cleanup in Safe Mode; cleanup itself is a resumable ledger -> trash -> delete -> final-ledger transaction.Recovery hardening
Regression coverage
Includes end-to-end failure-path coverage for:
404and deferred retry without Profile repairrename/rm/journal failures across snapshot and rollbackVerification
npx patch-package --error-on-failnpm test -- --run- 76 files, 621 tests passednpm run typechecknpm run buildnode --checkfor all three generation modulesgit diff --checkFixes #250