Repository navigation
Conversation
…topology Core step C5a (plan B2-6a). A tab or pane this window creates or closes is pending until main's topology catches up, so the mirror and the pane reconciler show it ahead of main without letting an older push undo it: - createTab marks the tab pending; a pane the window makes that main's layout doesn't name yet is pending. An add ends when a slice names it. - Every tab or pane close goes through commitTerminalSurfaceClose, which hides it until the mirror holds main's reply publishSeq; a refused close shows main's copy again. - The reconciler keeps pending panes and never re-inserts a closed one; this replaces the "spawn still pending" check and trackRetiredLeafIds. - Drag-out to a new tab waits for main's move and its push, then only places, activates and moves the live attachment. It no longer creates the tab or writes layouts itself, so a push that beats the reply no longer closes the new tab. A pane main doesn't hold keeps the local move. - replaceTerminalLayoutPanePtyId is deleted: leaf bindings come from main.
This was referenced Oct 7, 2026
Closed
A web client's tabs and a paired Orca server's (`runtime:`) worktree tabs come from the host's snapshot, not main's topology push, so nothing ever settled a pending tab add made there, and a close there waited on a push main never sends. One rule now decides it: isTerminalTabMirroredFromMain (not a web client, not a runtime-owned worktree, not a runtime-hosted tab) gates the tab add, the pane add, and the mirror's keep. Main's reply names no publishSeq for a worktree it publishes no slice for, so such a close settles on the reply. A pane split in a host tab is still kept until the host lists it: the host-snapshot sync retains a leaf the window's layout names and the host cannot resolve yet, so the layout keeps naming it (regression test added).
10 of 12 tasks
Contributor
Author
|
Closing: the layout rework is being redesigned so the runtime holds the only copy of the layout and every window/client is a view. This branch is kept for reference. |
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.
ELI5
When you open, close or drag out a terminal tab or pane, the window shows the change right away, but main (the part of Orca that saves terminal layout) learns about it a moment later. Since the earlier core steps, the window copies main's layout. That opened two gaps: an update from main that was sent before it heard about your change could undo it on screen (a new tab vanishing, a closed pane coming back), and dragging a pane out could close the new tab it was dragged into. This step keeps your change on screen until main's own layout includes it.
This is core step C5a of the terminal layout refactor (C5 is split into a..d). The core steps are reviewed as stacked PRs and merged together as one unit, so
mainnever gets a half-finished version. Stacked on C4 (#26301).What Changed
Pending tabs and panes (new
store/terminals/terminal-pending-panes.ts). A short list of tabs and panes the window shows or hides ahead of main:createTabmarks its tab, and a pane the window creates that main's layout doesn't name yet (a split, or a new tab's first pane) is marked too. It stays until a layout update from main names it.commitTerminalSurfaceClose. It now hides the tab or pane until the window has applied the update that holds main's reply (the reply'spublishSeq). This works the same whether the reply or the update arrives first. If main refuses the close, the window shows main's copy again.terminal-topology-mirror.ts) keeps a pending new tab, and doesn't bring back a pending closed one.trackRetiredLeafIds).Drag-out to a new tab (
terminal-pane-tab-detach.ts). The window waits for main to move the pane and for main's update to arrive, then only places the new tab where you dropped it, activates it, and moves the live PTY tracking (syncPaneDetachPtyOwnership). It no longer creates the tab or writes either layout itself. Main's update creates the tab, and the reconciler detaches the old pane. Before: if main's update arrived before its reply, the window couldn't find the pane and closed the new tab.Deleted
replaceTerminalLayoutPanePtyId. Which PTY a pane is attached to now comes from main's layout. The Codex restart path already gets the new id throughupdateTabPtyId, and main records the replacement.Web clients keep today's window-only detach (the
not_heldanswer). Their tabs live on a remote Orca server, which has no "move a pane" request. Adding one would change what the client and server send each other, and mixed versions would have to negotiate it, so it isn't a small change.Why
The window can only follow main's layout if its own changes aren't undone while main catches up. One small list, read by the layout copy and the reconciler, does that without new state in each caller. An added tab or pane is cleared when main's layout names it, not by its reply. That way no spawn site needs new code, and a spawn that fails keeps its pane and error on screen, as today. A close is cleared by its reply, because removals are where an older update would show the closed tab or pane again.
Rejected: keeping the window's own tab and layout writes in drag-out (they raced main's update), and adding a pending flag at each of the 28
createTabcallers (createTabitself is the one place they all go through).Linked Issue
STA-9417 (fixed by the core as a unit).
Visual Proof
N/A. This is a stacked core step. The parity check below records the visible behavior.
Testing
pnpm tcpasses.pnpm run check:code-quality:changedpasses. Renderer, shared andtests/e2e/*.unitsuites pass, apart from failures caused by this machine's setup (fish config,pg), which C4 also hits.terminal-pending-panes.test.ts(real store): a new tab survives an update that doesn't include it yet, and goes away when main later drops it. A closed tab doesn't come back from an older update, whether the reply or the update arrives first. A refused close shows main's copy again. A closed pane stays hidden until the update holding the close arrives.terminal-pane-tab-detach-commit.test.ts(real store): drag-out shows the new tab once when main's update arrives before the reply, and also when the reply arrives first. A pane closed during the move closes main's new tab, and it never appears. A sibling closed during the move closes the source tab without killing the PTY. A refusal shows the error toast. A repeated drop is ignored.terminal-mounted-layout-reconcile.test.ts: a pending pane is kept, and a pane closed here isn't re-added from an older layout.pnpm run test:e2e:terminal-layout-parity -- --base 80d45095d2ff --head HEAD, background launch): all 9 scenarios identical to main, including drag-out-to-tab, which failed on C3 and C4.Known gaps owned by later steps: