leaveIsIdempotent

fun leaveIsIdempotent(): TestResult

UNGATED CORE. leave() twice must not throw — on a host and on a joiner, whose paths differ: a joiner's leave announces a Goodbye on the still-live seam first.

No fault injection needed, and none wanted: this is the happy-path half, and it is the half a room gets wrong by forgetting a closed-flag entirely. leaveIsIdempotentEvenWhenTeardownFails is the other half — idempotency that survives a first call which failed — and only that one needs a fault.