Stop one tab's status banner from speaking for all the others #10

Merged
jaap-jan merged 1 commits from claude/status-bar-tab-isolation-caa52b into main 2026-08-12 09:37:56 +00:00
Owner

A shell that ended printed "The remote closed the session." into the status
banner at the foot of the terminal. Switch to a tab whose shell was still very
much alive and the sentence was still there, sitting under a live prompt and
describing a terminal that was no longer on screen.

There is one #status element for the whole page, because there is one page for
every terminal — the panes are stacked in the same box and all but the active one
are hidden — and SESSION_CLOSED wrote its reason straight into it. The other half
of the same mistake ran the other way: SESSION_OPENED and SESSION_REMOVED both
cleared the element outright, so opening or closing any tab wiped a message that
belonged to a different one. Whichever tab spoke last owned the banner.

The fix is to separate the two things that were being put in one place by who
they are actually true of. A session's last words are a fact about one terminal
and are now held on the session record, drawn only while that session's pane is
the one showing; activate() re-renders, so the banner follows the tab and a dead
tab still says what became of it when you come back to it. The socket's own state
— "Connecting…", "Reconnecting the terminal view…" — stays page-wide, because
there is a single socket behind every pane, and it wins when both have something
to say: a page whose socket is down is not showing live output on any pane.

A SESSION_CLOSED for a session this page has no pane for is now dropped rather
than printed. There is nothing to attach it to, and putting it in the banner
anyway is precisely the bug in miniature.

Verified by driving the real handleFrame through a stub DOM under node, which is
as close as this repo gets — there is no JS test harness and CI runs dotnet only,
so nothing here is a standing test. Twelve checks over open, close, switch,
reopen, remove and a socket drop pass against this file; the same script run
against the previous one reproduces the report exactly, epitaph under a live tab
included. Not seen in a running app: no C# changed, and the page is unreachable
without one.

A shell that ended printed "The remote closed the session." into the status banner at the foot of the terminal. Switch to a tab whose shell was still very much alive and the sentence was still there, sitting under a live prompt and describing a terminal that was no longer on screen. There is one #status element for the whole page, because there is one page for every terminal — the panes are stacked in the same box and all but the active one are hidden — and SESSION_CLOSED wrote its reason straight into it. The other half of the same mistake ran the other way: SESSION_OPENED and SESSION_REMOVED both cleared the element outright, so opening or closing any tab wiped a message that belonged to a different one. Whichever tab spoke last owned the banner. The fix is to separate the two things that were being put in one place by who they are actually true of. A session's last words are a fact about one terminal and are now held on the session record, drawn only while that session's pane is the one showing; activate() re-renders, so the banner follows the tab and a dead tab still says what became of it when you come back to it. The socket's own state — "Connecting…", "Reconnecting the terminal view…" — stays page-wide, because there is a single socket behind every pane, and it wins when both have something to say: a page whose socket is down is not showing live output on any pane. A SESSION_CLOSED for a session this page has no pane for is now dropped rather than printed. There is nothing to attach it to, and putting it in the banner anyway is precisely the bug in miniature. Verified by driving the real handleFrame through a stub DOM under node, which is as close as this repo gets — there is no JS test harness and CI runs dotnet only, so nothing here is a standing test. Twelve checks over open, close, switch, reopen, remove and a socket drop pass against this file; the same script run against the previous one reproduces the report exactly, epitaph under a live tab included. Not seen in a running app: no C# changed, and the page is unreachable without one.
jaap-jan added 1 commit 2026-08-12 09:34:45 +00:00
Stop one tab's status banner from speaking for all the others
ci / build and test (pull_request) Failing after 10s
ci / desktop nightly (pull_request) Skipped
ci / api image (pull_request) Skipped
ci / android head (pull_request) Failing after 6s
8c58e5a558
A shell that ended printed "The remote closed the session." into the status
banner at the foot of the terminal. Switch to a tab whose shell was still very
much alive and the sentence was still there, sitting under a live prompt and
describing a terminal that was no longer on screen.

There is one #status element for the whole page, because there is one page for
every terminal — the panes are stacked in the same box and all but the active one
are hidden — and SESSION_CLOSED wrote its reason straight into it. The other half
of the same mistake ran the other way: SESSION_OPENED and SESSION_REMOVED both
cleared the element outright, so opening or closing any tab wiped a message that
belonged to a different one. Whichever tab spoke last owned the banner.

The fix is to separate the two things that were being put in one place by who
they are actually true of. A session's last words are a fact about one terminal
and are now held on the session record, drawn only while that session's pane is
the one showing; activate() re-renders, so the banner follows the tab and a dead
tab still says what became of it when you come back to it. The socket's own state
— "Connecting…", "Reconnecting the terminal view…" — stays page-wide, because
there is a single socket behind every pane, and it wins when both have something
to say: a page whose socket is down is not showing live output on any pane.

A SESSION_CLOSED for a session this page has no pane for is now dropped rather
than printed. There is nothing to attach it to, and putting it in the banner
anyway is precisely the bug in miniature.

Verified by driving the real handleFrame through a stub DOM under node, which is
as close as this repo gets — there is no JS test harness and CI runs dotnet only,
so nothing here is a standing test. Twelve checks over open, close, switch,
reopen, remove and a socket drop pass against this file; the same script run
against the previous one reproduces the report exactly, epitaph under a live tab
included. Not seen in a running app: no C# changed, and the page is unreachable
without one.
jaap-jan merged commit b80bf23341 into main 2026-08-12 09:37:56 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: DodoTech-Public/DodoSSH#10