Skip to content

[Bug]: Remote workspace reconciliation: concurrent active edits during a genuine offline window are parked, not resolved (live-handshake gap) #22333

Open

Description

@LesleyMurfin

Operating system

Other

Orca version

Applies to current main (post #22038 fix, commit be4c61de4a on the linked PR branch); not tied to a specific tagged release.

Details

Short summary

The offline-client tab-resurrection fix in #22038 closes the reconciliation problem for a client that reconnects after being genuinely offline: it correctly gates on activeConnectionIdsAtShutdown so a host that was still connected at shutdown is never treated as stale. But it operates per host, not per worktree — and that leaves one case genuinely undecidable with the data available today: a different client edits a worktree's tabs (opens/closes) while this client is genuinely offline for that same host, then this client reconnects.

What happens today (safe, but not resolved)

Once a host is treated as possibly-stale at boot (the target was disconnected at this client's last shutdown), a worktree the client's local base has never cached is indistinguishable — from the data this fix can see — from one whose tabs were genuinely closed while offline. Both look like "confirmed host, absent base row, non-empty host-partition mirror."

The fix's write path never deletes in this situation: the un-adopted worktree's row survives in contestedHostWorkspaceSessions[hostId] (the write-side shadow) rather than being dropped or blindly re-adopted. That row is recoverable the moment a live SSH reconnect actually happens for that target — a different code path this fix does not touch. So the current behavior is "park it, never guess" rather than either resurrecting a closed tab or silently losing a newly opened one. That's the safe fallback, not a fix for the ambiguity itself.

Reproduction (documents the boundary, not a crash)

  1. Client A and Client B are both paired to the same SSH host/target and have an open worktree W with tab T1.
  2. Client B goes offline for that target (disconnects, e.g. sleep/network loss) — B's activeConnectionIdsAtShutdown no longer lists the target.
  3. While B is offline, Client A opens a new tab T2 in worktree W (or closes T1) via the live SSH host.
  4. Client B reconnects (relaunches or regains connectivity).

Expected (long-term): Client B's session for worktree W reflects the host's actual current tab state (T1 + T2, or T1 closed) once reconnected.

Actual today: Client B's stale local picture of worktree W is neither adopted nor deleted — it's parked in contestedHostWorkspaceSessions[hostId] until a live reconnect for that specific target occurs through the SSH transport, which is a separate mechanism from the boot-time hydration path this fix covers.

Why this needs a live signal, not another boot-time heuristic

The boot-time hydration path (fetchWorkspaceSessionWithRuntimeHostOwners / workspace-session-host-hydration.ts) only has access to on-disk client state at the moment of relaunch. It has no way to ask the host "what are this worktree's tabs right now?" — there is no live manifest or epoch the client can compare against. Resolving this case correctly needs the host to be able to answer that question on reconnect, not another inference from locally-cached data.

Possible fix direction (not prescriptive)

One plausible direction, sketched during investigation of #22038 but deliberately not implemented there: a live reconnect-time handshake where the host answers with its current authoritative tab/worktree manifest (something like a hasPendingReconnectionHandshake gate on the write path, held until the host's live answer lands, rather than resolving purely from the last-known on-disk snapshot). This is offered as a starting point for discussion, not a design this issue is asking to be implemented as specified — the actual transport and data shape should be whatever fits the existing SSH reconnect machinery, which was out of scope for #22038 to design.

Related

Activity

  1. LesleyMurfin commented on Sep 22, 2026

    @LesleyMurfin
    ContributorAuthor

    Filed alongside the fix for #22038 — see PR #22334, which documents this exact boundary in its "Known limitation" section and links here.

  2. AmethystLiang commented on Sep 23, 2026

    @AmethystLiang
    Contributor

    thanks for reporting. looking into it

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions