Skip to content

feat(wsl-mover): the ledgered desktop rewrite stage that finishes a committed move (D1b-7b) - #29597

Merged
nwparker merged 3 commits into
mainfrom
nwparker/wsl-mover-d1b-7b-rewrite-ledger
Oct 16, 2026
Merged

nwparker merged 3 commits into
mainfrom
nwparker/wsl-mover-d1b-7b-rewrite-ledger

Conversation

@nwparker

@nwparker nwparker commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 8 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​512 $\color{#cf222e}{\Huge{\mathbf{−}}}$​3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​509
Prod 15 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​501 $\color{#cf222e}{\Huge{\mathbf{−}}}$​15 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​486

ELI5

After a WSL project's move commits, the desktop still has to update some of its own saved state, for example "last opened worktree" and sidebar host filters, so it points at the WSL host's copy. That update spans several separate stores, and the app could crash halfway through. This PR adds the bookkeeping: a ledger of which stores are done, a startup pass that finishes a move that was interrupted, and two IPC calls for stores that live in the window. It registers no actual stores yet; those come in later PRs. Everything sits behind the internal WSL host gate, so nothing changes for anyone.

What Changed

This is step D1b-7b of the lossless WSL project mover.

  • Ledger rules (wsl-move-cutover-journal.ts):
    • rewrittenStores only grows (append-only, deduplicated), and only while the move is at destination-committed.
    • A removal, reorder, replacement or duplicate is refused, and so is a new record that already has entries.
    • The move can't advance to client-rewritten until every registered store is recorded and the store registry is declared complete. WSL_MOVE_DESKTOP_REWRITE_REGISTRY_COMPLETE is false until the last store PR (7f) flips it, so a move can't skip stores that land later.
  • Store registry (wsl-move-desktop-rewrite-stores.ts): {id, side: 'main' | 'renderer', run, flush}. Registration order is run order for main stores. Renderer stores are independent of that order.
  • Driver (wsl-move-desktop-rewrite.ts):
    • Per store: for each committed move, each unrecorded main store runs, then flushes durably, then appends its ledger entry, re-reading the record from disk first.
    • Timeout: each store gets a timeout, so a hung store can't block later passes.
    • Failure: a failure or timeout stops that move's pass with one warning and no entry, and never throws.
    • Ordering: passes run one at a time.
  • Renderer IPC: wslMove:listPendingRendererRewrites and wslMove:recordStoreRewritten. Recording refuses unknown, main-side, already-recorded or not-pending stores. A preload bridge, a web stub (empty) and a typed client with no callers yet are included.
  • Startup: a gated pass runs right after the fence loads. With the gate off it returns before any file work.
  • Dispositions: per owner decision C (2026-10-16), native chats stay on the desktop. Item 44 (saved chat launches) and every table of item 52 (the chat journal) are now not-applicable. workspaceSessionsByHostId is now rewrite-desktop (seeded later). A new test pins item 52 to not-applicable only; items 19, 32 and 38 legitimately mix moved and not-applicable fields.

Why

The rewrite spans stores that flush at different times, including localStorage in the window. A crash can land between any two of them. Recording each store only after its own durable flush lets the next start redo just the missing ones, with no store applied twice.

Merge policy

This PR qualifies to merge under the owner's policy. With ORCA_INTERNAL_WSL_HOSTS off, none of it is reachable: the startup pass returns before any file work, and both IPCs answer empty or gated-off before touching disk. It touches no shared user paths (SSH, terminal launch, runtime lists, sidebar, session persistence). Outside the mover's own modules it only adds the IPC registration line, the preload key and the web stub.

Linked Issue

N/A (maintainer; tracked in the WSL-via-orcad implementation tracker, step D1b-7).

Visual Proof

N/A: no UI.

Testing

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

  • Ledger: the ledger only grows; the advance is refused until every store is recorded and the registry is complete; a new record with entries is refused.

  • Driver:

    • runs in order: run, then flush, then append;
    • a crash injected after each store redoes only the unrecorded stores;
    • a re-run is idempotent;
    • a failure warns once and leaves the move as it was;
    • a timeout doesn't block later passes;
    • an unreadable journal warns once.
  • Renderer IPC: checks for an unknown store, an already-recorded store, a main-side store and a pending move, plus the gate-off answers.

  • Startup: the pass is gated.

  • Dispositions: coverage holds, and item 52 is not-applicable only.

  • pnpm tc:node, pnpm tc:web, both oxlint configs, the focus-read and layout-writer ratchets, and the changed-code quality gate pass.

  • Adversarial review: no HIGH findings, and it confirmed the merge-policy claim. One MEDIUM (half of decision C applied to the chat-journal tables) and five LOWs are fixed here.

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

The typed renderer client has no caller until 7d registers the first renderer store. The dead-code scan isn't run in CI, and main already has 36 unused files and 137 unused exports.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c444ff10-d72d-4140-aff2-2bfc80b08d2b
📥 Commits

Reviewing files that changed from the base of the PR and between dbc0564 and 0c65c48.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 85b7d592-2782-4ea5-a8f7-f97298e3ad09
📥 Commits

Reviewing files that changed from the base of the PR and between e687b18 and dbc0564.

📒 Files selected for processing: 23
  • src/main/ipc/register-core-handlers/register-core-handlers.test.ts
  • src/main/ipc/register-core-handlers/register-core-handlers.ts
  • src/main/ipc/wsl-move-handlers.test.ts
  • src/main/ipc/wsl-move-handlers.ts
  • src/main/persistence/__fixtures__/wsl-mover/wsl-move-journal-seeding.ts
  • src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.test.ts
  • src/main/persistence/moving-wsl-projects/wsl-move-cutover-journal.ts
  • src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite-stores.ts
  • src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite.test.ts
  • src/main/persistence/moving-wsl-projects/wsl-move-desktop-rewrite.ts
  • src/main/persistence/moving-wsl-projects/wsl-move-rewrite-ledger.test.ts
  • src/main/startup/main-process-ready-foundation.ts
  • src/preload/api-types.ts
  • src/preload/api/wsl-move-bridge.ts
  • src/preload/index.ts
  • src/renderer/src/lib/wsl-move-renderer-rewrite-client.ts
  • src/renderer/src/web/web-preload-api-composition.test.ts
  • src/renderer/src/web/web-preload-api.ts
  • src/shared/wsl-move/wsl-move-dispositions.test.ts
  • src/shared/wsl-move/wsl-move-dispositions.ts
  • src/shared/wsl-move/wsl-move-out-of-store-dispositions.ts
  • src/shared/wsl-move/wsl-move-renderer-rewrite-types.ts
  • src/shared/wsl-move/wsl-move-storage-dispositions.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.

📝 Walkthrough

The change adds a WSL move rewrite registry and journal rules for recording completed store rewrites. A gated main-process pass handles desktop stores, and IPC and preload APIs let the renderer list and record pending rewrites. Startup starts the pass. The change also updates several WSL storage dispositions and adds tests for the rewrite paths, journal rules, and disposition consistency.

Estimated code review effort

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to dbc05

The rewrite stage remains gated and cannot mark a move complete until its store registry is complete. No issue identified here blocks merging.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 51.72% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 29 functions across 23 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly identifies the main change: adding the ledgered desktop rewrite stage for committed WSL moves. It is concise and specific.
Description check Passed The description covers the required sections, explains the change and rationale, documents testing, provides the linked-issue exception for a maintainer, and marks visual proof as not applicable. The …
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description covers the required sections, explains the change and rationale, documents testing, provides the linked-issue exception for a maintainer, and marks visual proof as not applicable. The AI Disclosure and Review sections are empty, but they are not critical omissions for this maintainer PR.

✨ Finishing Touches: 💡 2
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant