assertAbortsOnMidHandshakeCollapse
Consumer-level invariant: an establishment await over a controllable seam must abort (throw within a bound) when membership drains mid-handshake — it must never suspend forever.
What it models — the #1466 hardware failure
A membership drain is distinct from a transport tear: Seam.peers collapses to {self} while Seam.state stays us.tractat.kuilt.core.SeamState.Woven — the co-elector simply left the roster, no close() and no Torn latch. A consumer that only wakes on a seam tear (the transport-death half) silently suspends forever on this event; that is exactly how #1466 shipped green. FakeSeam.removePeer reproduces the drain precisely (drops _peers, leaves state us.tractat.kuilt.core.SeamState.Woven) — this helper drives it.
The protocol it drives
Launch establish in a caught driver coroutine so a thrown exception is captured, not propagated to (and cancelling) the test scope.
runCurrent — let establish subscribe to
incoming/ broadcast its first handshake frame and suspend at the mid-handshake point (awaiting aFreeze, aFreezeAck, etc.).Drain membership: FakeSeam.removePeer drops drainedPeer from
peers— the seam stays Woven (no tear). This is the collapse.Assert establish resolves by throwing E within timeout. A TimeoutCancellationException here means establish suspended past the bound — the very hang this invariant forbids — and is reported as a loud AssertionError, never a silent timeout.
Runs under TestScope; pair with runTest(timeout = TEST_WEDGE_BACKSTOP) and a StandardTestDispatcher.
This does not depend on kotlin-test (not a commonMain dependency of :kuilt-test); it raises a plain AssertionError on failure, which every kotlin-test runner surfaces identically.
Parameters
the controllable seam the consumer establishes over — must be the same FakeSeam reads, so drainedPeer's removal is observed by the in-flight handshake.
the co-elector to drop mid-handshake (the elected host, or the awaited member).
Type Parameters
the terminal exception establish must throw on the collapse (e.g. LobbyTornException).