mirror of
https://github.com/stablyai/orca.git
synced 2026-10-19 00:03:20 +00:00
fix(mobile): paired clients re-derive a kept terminal after a cold restore (#23109)
* fix(mobile): paired clients re-derive a kept terminal after a cold restore A renderer frame published before a cold-restored terminal's PTY registered was fenced to an empty tab list and recorded as accepted, and the renderer never resends unchanged content. When registerPty binds a surface the accepted frame fenced out, re-merge that frame so the fence reads current state. * test(mobile): drive the live desktop window through the runtime's desktop seam * test(mobile): the re-derive path never flushes the store synchronously * test(mobile): a re-derived frame must not bring back a surface the host retired after accept * fix(mobile): a re-derived frame changes membership only for the registering surface The replay re-ran the whole accepted frame, so a surface the host retired after accept (a phone close whose remote PTY is still exiting, or a closed chat tab) came back. Every other surface now keeps the host's current decision; the removal repair is extracted from the terminal retirement helper so non-terminal tabs are removed the same way. * test(mobile): a re-derived frame must not drop or disown a phone-created terminal the desktop has not published * fix(mobile): a re-derived frame does not infer renderer retirements from its older frame * revert(mobile): drop the replay of a fenced renderer frame Reverts the production parts ofa88e1eaa0a,f5b99d0003and5af1c6d97a: the kept renderer frame, rederiveFencedRendererSurface and its registerPty call, and the mergeRendererMobileSnapshot / removeMobileSessionSnapshotTabs extractions. The fence will instead read the host's saved membership record. The test file stays and is rewritten for that mechanism. * fix(mobile): the paired-list fence admits a terminal the saved session still lists After a cold restore the in-memory mobile snapshot and PTY table start empty, so in a repo with host-authoritative terminal membership the fence dropped a restored terminal whose renderer frame arrived before its PTY registered, and paired clients never listed it. The fence now also admits a surface the host's saved workspace session still lists (tab under the worktree, leaf in its layout), and registerPty pushes the listing so pending-handle turns ready at once. A restored pane whose PTY never returns is listed as pending-handle, as in repos that are not host-authoritative. * test(mobile): keep the desktop window stub's type assertion on its SAFETY line * fix(mobile): coalesce the registration push for a listed restored terminal registerPty pushed the paired list immediately on every registration that backs a listed surface. The desktop's graph sync after a spawn already publishes the same pending-handle to ready flip on the 50 ms coalescing window, so each restored pane cost two pushes, and a restore of N panes cost N immediate full-list pushes per client. The touch now rides the same coalescing window, which still covers a registration no graph change follows. The test's "unchanged" sync dropped the graph's tab, which is itself a change, and its no-extra-push assertion ran before any coalesced push could fire; both are fixed, and a restore of two panes is asserted to push once. The fence comment no longer claims the new clause keeps pending leaves out of the graph: once the surface is listed, its leaves pass the shared predicate through that listing, as any listed surface's do. * fix(mobile): read saved membership only from the worktree's own session partition For a runtime-host workspace, emptying the owning partition re-routes session reads to a single other partition that still lists the worktree. If that older copy lists a surface a retirement just removed, a lagging renderer frame could re-admit it. The saved-membership check now reads only the partition the worktree's host names, so it never trusts a fallback copy. * test(mobile): pin the own saved partition for every workspace host kind Also correct the immediate-emit comment: only an exit bypasses the window; a registration's ready flip coalesces.
This commit is contained in:
@@ -107,6 +107,15 @@ export class RuntimeWorkspaceSessionController {
|
||||
return hostId ? (this.deps.getStore()?.getWorkspaceSession?.(hostId) ?? null) : null
|
||||
}
|
||||
|
||||
/** The session only when the worktree's own host partition owns it, not a rotated-owner fallback. */
|
||||
getOwnPartition(worktreeId: string): WorkspaceSessionState | null {
|
||||
const store = this.deps.getStore()
|
||||
const hostId = store ? this.getPreferredHostId(worktreeId, store) : null
|
||||
return hostId && hostId === this.tryGetHostId(worktreeId)
|
||||
? (store?.getWorkspaceSession?.(hostId) ?? null)
|
||||
: null
|
||||
}
|
||||
|
||||
set(worktreeId: string, session: WorkspaceSessionState): void {
|
||||
this.deps.getStore()?.setWorkspaceSession?.(session, this.getHostId(worktreeId))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user