Skip to content

Fix stale terminal surfaces, New Tab UIA/cwd, and loop opens after deleting an attached loop - #663

Merged
coneilen merged 1 commit into
mainfrom
coneilen-fix-workspace-surface-and-tabs
Oct 8, 2026
Merged

coneilen merged 1 commit into
mainfrom
coneilen-fix-workspace-surface-and-tabs

Conversation

@coneilen

@coneilen coneilen commented Oct 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes the Windows workspace terminal-surface and tab findings from the beta17 Dev Box qualification (0.1.78-windows.beta17, commit 4ab2fcf4): a stale terminal surface drawn over the sidebar, a stranded canvas New Loop / Open Folder button, UIA showing fewer tabs than drawn after New Tab, New Tab shells starting in the install bin directory, and loop opens failing after the attached loop was deleted.

Changes

  • Stale WinghosttyEmbeddableSurface over the sidebar (finding 1, operator report 2). A surface created while the workspace is collapsed (the graph shows) was created visible at its 480x240 placeholder bounds at client 0,0. Two paths did this: a graph refresh re-attaching the open loop's pane, and a project rebind restoring saved panes. resize() then also un-collapsed the workspace. The new App test reproduces the Dev Box geometry exactly (visible terminal over the graph at 0,0 480x240). Surfaces now start hidden and unfocused while collapsed. Creation re-applies the layout without un-collapsing (relayout). syncTopology hides everything while collapsed, and hides any pane with no area instead of showing it at stale bounds.

  • Stranded canvas New Loop / Open Folder buttons (finding 1, operator report 1). The native-row project switch and graph arrivals (startup restore, Ctrl+O) never re-laid-out these buttons. New Loop stayed at the 220px empty-project centre (the d6-diag-rows.png position), and Open Folder stayed visible after a project opened. syncAccessibility now lays them out with every publication. layoutEmptyStateControls touches the native control only when its position, visibility or text changes.

  • UIA tab count after New Tab (finding 2). A native click on New Tab, a split, tab cycling, or a tab select/close changed the tab strip without republishing UIA. These paths now republish UIA (publishWorkspaceTabs).

  • New Tab working directory (finding 3). New sessions start in the open loop's directory, as on macOS (LoopWorkspaceView workingDirectory): the loop's worktree, else its project folder, or home for a global loop. A remote project, or a folder that doesn't exist, falls back to the shell's own directory (Workspace.setShellDirectory / sessionDirectory).

  • Loop opens after deleting the attached loop (finding 4). While the graph shows, a deleted loop's exit is not drained. When the next loop opened:

    • The ended loop's passive recreate cancelled that explicit open.
    • The new loop attached into the empty slot, but the layout still named the dead loop. That hid the terminal and gave Unable to restore selected terminal focus, and every later replacement failed with Unable to open selected loop.

    Passive checks no longer displace an explicit open. The unshown loop pane is now rebound to the loop being opened (bindLoopPane).

  • Tests: there are four App tests (workspace surface:). Three use real winghostty child windows, a fake zmx .cmd, and native WM_LBUTTONDOWN/UP clicks. The fourth uses real native buttons. There is also one TerminalSurface layout and wait test. A test-only accessibility_publication_observer lets the App tests see each production syncAccessibility publication. It is absent from product builds.

  • Parity ledger: the Tab pills row goes from Validated to Partial, because the Dev Box found the mismatch and the fix has only unit evidence.

Test plan

All commands ran from graphcode-windows with the pinned Zig 0.15.2 (C:\gc-tools\zig-0.15.2\zig.exe), the pinned Winghostty 6286560d (C:\gc-providers\winghostty), and the same link line as the App shell executable tests section of WindowsShell.Tests.ps1. All tests were written and run failing before the fix.

RED: zig test src\App.zig (App shell link line) --test-filter "workspace surface:" -> 0 passed, 4 failed: "visible terminal over the graph at 0,0 480x240" (TestUnexpectedVisibleTerminal); UIA tab count "expected 2, found 1" after native New Tab; selected pane "expected loop-b, found loop-a" after deleting the attached loop; New Loop button not visible after the restored graph arrived (TestUnexpectedResult)
GREEN: zig test src\App.zig (App shell link line) --test-filter "workspace surface:" -> All 4 tests passed
REGRESSION: zig test src\App.zig (App shell link line) -> All 892 tests passed; zig test src\TerminalSurface.zig -target x86_64-windows-msvc -lc -luser32 -lgdi32 -ladvapi32 -I...\winghostty\include zig-out\lib\ghostty-vt-static.lib -> All 165 tests passed

Additional evidence:

  • In the combined RED, the New Tab test stopped at its UIA assertion before reaching the directory check. I ran the directory check on its own with only the attach-directory change reverted. It failed with expected directory ...\wt-a, shell started in ...\bin (TestUnexpectedDirectory).
  • TerminalSurface test an explicit open rebinds a stale loop pane and survives a passive recreate of the ended loop, run against the HEAD TerminalSurface: expected 0, found 1 (the stale tab was not selected). With the fix it passes, as part of the 165 above.

Limits:

  • This is unit and native-linked test evidence on a dev machine. It is not a Dev Box rerun.
  • The daemon is simulated by frames and a fake zmx listing/attach script. No real agent backend, real zmx session, or rendered glyphs were exercised.
  • The tests check child-window visibility and geometry, not on-screen pixels.
  • Live UIA was not run.
  • validate.ps1 -Task windows-shell was not run locally. It would rebuild the shared provider checkout; CI runs it.
  • make test / make check are macOS-only and were not run. No macOS or shared Swift code changed.

Checklist

  • I have read the Contributing Guidelines
  • I have signed off my commits (git commit -s) per the DCO
  • Tests pass locally (make test): macOS-only, not run; Windows Zig suites above pass
  • Code follows the existing style (make check): macOS-only, not run; no new zig fmt differences in changed hunks
  • I added the test/contract before the implementation and observed the intended RED failure

…leting an attached loop

Beta17 Dev Box qualification (4ab2fcf) found, on the Windows shell:
- a WinghosttyEmbeddableSurface (480x240 at client 0,0) left drawn over the
  sidebar while the graph showed, with the canvas New Loop button stranded;
- UIA exposing one workspace tab after a native New Tab click drew two;
- the New Tab shell starting in the install bin directory;
- every loop open failing after the attached loop was deleted.

A surface created while the workspace was collapsed (passive re-attach,
project rebind restore) was created visible at its placeholder bounds and
resize() un-collapsed the workspace. Surfaces now start hidden while
collapsed, creation re-applies the layout without un-collapsing, and
syncTopology hides everything while collapsed and any pane with no area.

A passive re-observation (the ended loop's recreate) cancelled the explicit
open of another loop, and attaching a loop into an empty slot left the
layout's loop pane naming the dead loop, so the new terminal stayed hidden
and later replacements failed. Passive checks no longer displace an explicit
open, and the unshown loop pane is rebound to the opened loop.

Native New Tab, split, tab cycling and tab select/close clicks republish
UIA. New shells start in the loop's worktree, else its project folder
(home for a global loop), as on macOS. The canvas New Loop/Open Folder
buttons are re-laid-out with every UIA publication, touching the native
controls only when their state changes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Colin Neilens <coneilen@microsoft.com>
@coneilen
coneilen force-pushed the coneilen-fix-workspace-surface-and-tabs branch from ea5d87d to 17e685f Compare October 8, 2026 22:27
@coneilen
coneilen merged commit 607494c into main Oct 8, 2026
24 checks passed
coneilen added a commit that referenced this pull request Oct 9, 2026
…s folder (#667)

#663 started each zmx attach in the loop's worktree or project folder. The
installed shell names zmx bare (zmx.exe) and found it only through its own
working directory (the install bin), and a child resolves a relative program
against its own working directory and then PATH. On a Dev Box whose PATH does
not name the install, every sidebar loop open, New Tab, and split failed with
FileNotFound (Unable to open selected loop / Unable to create tab).

Resolve the configured zmx name against the shell's directory once before the
attach spawns, and make the live App terminal fixture use the installed
bare-name layout so the gap that hid this is covered.

Signed-off-by: Colin Neilens <coneilen@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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