Features: teardown resolves the pane's real tab (fleetd #342)

Dai Ha
2026-09-04 16:41:52 +07:00
parent ff77005cc3
commit bd7a1ac9cd
+35
@@ -4309,3 +4309,38 @@ each key one at a time, as the brief asked, and contradicted me on two entries:
already covered, and `worktreeRoot` was uncovered and missing from my list. Both corrections were
checked again on merge with a third mutation. **A list in a ticket is a starting point, not a
measurement** — re-derive it, and say so when it disagrees.
---
## Teardown now closes the tab a member really sits in
**What it does.** `HerdrPeerLauncher.stop` used to look for a tab to clean up only when one of *its
own* configured profiles used tab placement (`usesTabPlacement()`). It now resolves the pane's real
tab every time, and the single-occupant check decides whether that tab is closed. That check is
unchanged: a tab holding other panes is never closed.
**On.** Always on (fleetd #342).
**Why it exists.** `CompositePeerLauncher` routes a stop through the adapter recorded in
`spawnedBy`, and that map is in memory only — a daemon restart empties it. On a miss in a
one-daemon fleet, the stop goes to `delegates.getFirst()`. When two adapters share one herdr daemon
and disagree on `tab` versus `pane` placement, teardown could run through an adapter whose config
says nothing true about how that pane was placed, and the whole tab-cleanup block was skipped. The
member still stopped, but its now-empty tab stayed. Nothing reaps an orphaned tab, so the operator's
herdr session collected one more of them on every affected teardown, silently.
**Why not fix the routing instead.** Probing for the pane's real owner looks like the obvious fix
and does nothing here. `probeOwner` groups candidates in an `IdentityHashMap` keyed by
`HerdrClient`, so two delegates sharing one daemon collapse to whichever was inserted first — that
is `delegates.getFirst()` again, the same answer the shortcut already gave. The routing cannot tell
these two adapters apart at all.
**One thing to know for maintenance.** The single-occupant check is now the *only* thing protecting
a shared tab, so treat it as load-bearing. Measured on merge: weakening it from `tabPaneCount() == 1`
to `>= 1` fails two tests, including the pane-placement one. One case is uncovered on purpose — a
pane-placement member that is the sole occupant of its tab will now have that tab closed.
`spawnAsPane` splits an existing tab, so the count is normally at least 2, and the tab is empty
after the member's pane goes anyway.
The same in-memory `spawnedBy` breaks `clearContext` a different way: it plainly no-ops on a cache
miss. Open as fleetd #352, and the consequence is not measured yet.