Files
orca/src
Neil 8b99c8365d fix(remote-workspace): host silence must not delete a local row it was never told about (#16748)
Two fields in `mergeDirectSshRemoteWorkspaceSession` treated an absent remote
entry as an authoritative delete. Both are records whose *absence* is meaningful,
so deleting them on silence loses information the host never had.

1. The closed-last-terminal tombstone.
   `src/renderer/src/components/terminal/initial-terminal.ts:5` states the
   contract verbatim: "a missing row means never initialized; an explicit empty
   row records that the user closed the last terminal." `mergedWorktreeIds` was
   `keys(remote.tabsByWorktree)` union the replaced worktrees whose local tab
   list is NON-EMPTY (`:41-45`), so a worktree holding an explicit `[]` and
   absent from the host snapshot was excluded, `omitTargetWorktrees` stripped the
   key, and nothing re-added it. Measured before the fix:
   `Object.hasOwn(merged.tabsByWorktree, WORKTREE)` => false.

   Downstream, `worktree-initial-terminal-seeding.ts:125` computes
   `shouldHonourClosedTerminalTombstone = Object.hasOwn(store.tabsByWorktree, id)
   && ...` => false, so `shouldAutoCreateInitialTerminal(0, false)` => true and a
   terminal is created. The user closes their last terminal on an SSH workspace
   and it comes back on reconnect.

   The projection is innocent: `remote-workspace-session-projection.ts:47-59` and
   `:161-168` both round-trip an empty array faithfully. The row is lost only
   when the host snapshot has no entry for that worktree path at all -- a first
   sync, a snapshot predating the close, or `resolveWorktreeId(path)` returning
   null during startup.

   Fix: admit a replaced worktree whose local row EXISTS (`Object.hasOwn`) rather
   than whose local row is non-empty. That is the same "the host is authoritative
   for what it knows, not for what it has never been told" rule the rest of this
   function already applies to tabs.

2. `defaultTerminalTabsAppliedByWorktreeId`. This was the only field in the
   function with no preservation branch: `:257-260` deleted the local entry for
   every replaced worktree and trusted the remote snapshot to carry it. The
   marker is write-once and is the sole guard on `applyDefaultTerminalTabs`
   (`worktree-default-terminal-tabs.ts:34`), so deleting it re-applies the whole
   default-tab template over the user's tabs. Removal belongs to the
   worktree-teardown path, not to a reconnect.

Why this shape rather than a revision counter: both are statements about what
absence means, local to one function, so they survive the SSH-v3 consolidation
unchanged. Neither adds a per-tab identity field.

Deliberately not done: the `hostUnknown` preserve branch is untouched, and no
close-suppression is added here -- that is the durable close tombstone, and it
belongs on top of this rather than mixed into it.

Before: 3 failed | 18 passed. After: 21 passed (45 across the wider merge,
default-tabs and initial-terminal suites).
2026-08-27 19:43:26 -07:00
..