Announce a session's end when it is actually over, and for closes too
ci / android head (push) Successful in 3m17s
ci / desktop nightly (push) Successful in 41s
ci / build and test (push) Successful in 2m27s
ci / api image (push) Successful in 28s

The phone's notification kept saying '1 shell connected' after the
shell was gone, and both close routes were at fault. A shell exiting on
its own raised SessionEnded from inside its run's finally block — where
the run task is by definition not yet complete, so the LiveSessionCount
the keep-alive reads still counted the dead shell, and nothing fired
later to correct it. A tab closed by hand announced nothing at all, by
a recorded decision that assumed every subscriber was the closer; the
keep-alive is not, and a close it never heard about left the
notification claiming a shell over nothing.

The end is now announced from a continuation after the run completes,
and CloseSessionAsync announces after its own drain — every subscriber
was already a reconcile-to-reality handler, so the echo the old remark
feared costs nothing. Shutdown stays silent: it is dismantling the
subscribers along with the sessions.
This commit is contained in:
2026-08-09 13:01:14 +02:00
parent 506d2803a2
commit e936ab4646
6 changed files with 132 additions and 33 deletions
+8 -2
View File
@@ -2130,13 +2130,19 @@ foreground service is protecting), wait thirty seconds with the shell doing noth
**Pass:** the notification stayed up the whole time, and the shell is exactly where it was — same scrollback,
same prompt — with typing reaching the host immediately. Exit the shell.
**Pass:** the notification goes with it, once nothing else is open.
**Pass:** the notification goes with it, once nothing else is open. Open another shell and close it from the
shells strip's ✕ instead of exiting — the notification comes down for that route too, which is the route
that used to leave it up: a deliberate close announced nothing to the keep-alive at all, and a shell exiting
on its own was announced while the count still included it.
**Failure means:** an upload that stalls with the screen off is the count not reaching
`SessionForegroundService`, and Android has stopped the process mid-transfer. A notification left up
afterwards is `ActivityChanged` not being subscribed — the other end of the same wire. A shell that has
disconnected on return is `MainWindowViewModel.TerminalSessionOpened` never reaching `SessionKeepAlive` — the
service only ever heard about a shell *ending*, so it never came up for one in the first place.
service only ever heard about a shell *ending*, so it never came up for one in the first place. A
notification still saying "1 shell connected" after the shell is gone — by either route — is
`TerminalWorkspace.SessionEnded` firing before the run completed, or a close not announcing; see
`AnnounceEndedAsync` and the event's own remark.
### 14.6a A Files connection with nothing moving still survives backgrounding