departures
Cold flow that emits a Tag.peerKey for every peer that leaves the network.
There is no default, deliberately. A source that genuinely has no leave signal — a test fake that emits a fixed roster, a platform stub, a browse API that only ever reports arrivals — must return emptyFlow explicitly. An inherited default made that opt-out invisible: an implementor could omit the member and ship a source that silently never removes anybody, which is precisely what four implementations in this repo did. Written out, the opt-out is a line somebody chose; inherited, it is a line nobody noticed.
The emitted key must be the Tag.peerKey of the Tag this same source emitted from discoveries for that peer. discoveryRoster removes by exact key, so a departure carrying any other identifier — a display name, a socket address, another transport's handle — is indistinguishable from no departure at all, and leaves the same ghost as the explicit emptyFlow while looking like it works.
A source returning emptyFlow here is exactly a source discoveryRoster's ghost caveat applies to: everything it discovers stays in the roster forever, because nothing can ever remove it. That caveat covers those sources and no others.
A source with a real leave signal stays open until the collector's scope is cancelled; the explicit emptyFlow completes at once, having nothing to hold open.