Skip to content

Fix: restore the tab strip when a split view is exited - #76

Merged
DevMando merged 1 commit into
mainfrom
fix/exit-split-restores-tabs
Sep 11, 2026
Merged

DevMando merged 1 commit into
mainfrom
fix/exit-split-restores-tabs

Conversation

@DevMando

Copy link
Copy Markdown
Owner

Summary

Leaving a split view left the agents that had been in it with no tab, so there was no way back to
them. One line, at the point where every pane-set change already passes through.

What was happening

While an agent is in a pane, its tab is deliberately hidden — its name is on the pane header, so the
strip goes back to being a list of what is not currently visible. That part is correct.

On Exit Split View, nothing put those tabs back. RefreshTabStrip owns that visibility rule and
ExitSplit never called it, so the headers stayed collapsed while the panes they belonged to were
gone. The agents were still open and still loaded — simply unreachable until something unrelated
happened to refresh the strip.

Closing a pane with its [x] looked fine, which is what made this confusing to place. That path
is not better-written; it just routes through SelectTab, which happens to refresh on the way past.

What changed

  • The refresh moved into ApplyPaneLayout. The strip lists what is not on screen, so it is a
    function of the pane set — and ApplyPaneLayout is the single method every pane-set change goes
    through. Putting it there makes the two impossible to leave out of step.
  • Fixing only ExitSplit was the obvious smaller change, and is why I did not do it. The same
    omission would be waiting for the next person who adds a pane operation. An audit of all seven
    places that mutate the pane set found three more relying on an indirect refresh, and one —
    ValidateSplit, which runs whenever an agent is closed — with no refresh on either branch.
  • Widths are recomputed too. LayoutTabStrip divides the viewport among visible headers only,
    so restoring visibility alone would have left the returned tabs at widths calculated while they
    were hidden.

Scope and risk

Low, with one thing worth a reviewer's eye.

RefreshTabStrip now runs more often — two or three times per tab selection, since SelectTab and
SwitchPage both still call it explicitly and both reach ApplyPaneLayout. I left those calls in
place rather than pruning them, to keep this diff to the fix. The repeats are cheap and idempotent:
the method sets brushes and visibility on a handful of headers, and LayoutTabStrip is arithmetic
plus a Width assignment. Checked for recursion — RefreshTabStrip does not call ApplyPaneLayout,
SelectTab, or SwitchPage, so there is no cycle.

Verification

  • dotnet build src/MandoCode.Desktopsucceeded, 0 warnings, 0 errors.
  • dotnet test src/MandoCode.Desktop.Tests490 passed, 0 failed.
  • Re-ran the pane-set audit after the change: all seven mutation sites now reach RefreshTabStrip.

Not covered, and this is the honest part: no automated test catches this. Split view has no UI
coverage — PaneLayoutTests pins the grid geometry and nothing else. More to the point, a unit test
would not have helped: the rule was always right, it simply was not run, and a test of the rule
passes identically before and after this fix. Making the coupling structural is the mitigation,
not the test suite.

So this needs a manual pass:

  1. Open three agents, split two of them, confirm those two tabs disappear.
  2. Exit Split View — both tabs should come back, at full width.
  3. Split again, close one pane with [x] — that tab should come back (this already worked).
  4. Split two agents, then close one of them entirely from its tab — the split should collapse and
    both tabs should be correct (this is the ValidateSplit path, which had no refresh at all).

Changelog

Deliberately none. The bug arrived with the pane headers in #73, which is still in [Unreleased]
and has never been tagged, so it never reached a user — the repo's convention is not to log fixes
for bugs that never shipped, and the feature entry already describes the intended behaviour.

Exiting a split left the agents that had been in it with no tab at all. Their
headers were collapsed — correctly, while they were on screen with their names
on the pane headers — and nothing un-collapsed them, so the agents became
unreachable until something else happened to refresh the strip.

RefreshTabStrip owns that rule, and ExitSplit never called it. Closing a pane
looked fine only by accident: RemovePane routes through SelectTab, which
refreshes on the way past.

Fixed at the choke point rather than at the call site. The strip lists what is
NOT on screen, so it is a function of the pane set, and ApplyPaneLayout is the
one method every pane-set change goes through. Refreshing there makes the two
impossible to leave out of step; fixing only ExitSplit would have left the same
trap for the next person to add a pane operation.

An audit of all seven places that mutate the pane set found three more relying
on an indirect refresh, and one — ValidateSplit, which runs when an agent is
closed — with no refresh on either branch.

This also re-divides the strip's width. LayoutTabStrip shares the viewport
among visible headers only, so without the refresh the restored tabs would have
kept widths computed while they were hidden.

The bug was introduced with the pane headers and has not shipped, so there is
no changelog entry.
@DevMando
DevMando merged commit 195edd6 into main Sep 11, 2026
1 check passed
@DevMando
DevMando deleted the fix/exit-split-restores-tabs branch September 11, 2026 05:18
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