ResumeResult
How a resume attempt turned out — on either side of the protocol.
The two sides see disjoint halves of this hierarchy, and the halves are named so the compiler can enforce it (#2364):
HostVerdict is what a host's JoinerReconnectController.tryResume renders from its own window state. It never leaves the host as a value — it is encoded as an us.tractat.kuilt.session.admit.AdmitMessage.Reject carrying a RejectCode.
JoinerOutcome is what us.tractat.kuilt.session.Room.resume answers a joiner, and it includes outcomes no host can produce: silence (TimedOut) and a room that is already over (WindowClosed).
Why the split is typed rather than documented. Both surfaces used to return the whole hierarchy, so a consumer could — and the agent cookbook did — write a when over Room.resume(token) with arms for WindowNotYetOpen and TokenInvalid, which are host verdicts a joiner can never receive. It compiled, so nothing caught it; @sample compilation proves a branch typechecks, never that it is reachable. Narrowing the two return types makes that same when a compile error.
Inheritors
Types
The half a host renders: what JoinerReconnectController.tryResume decided about its own window state. Travels to the joiner as a RejectCode, not as one of these values.
The half a joiner observes from us.tractat.kuilt.session.Room.resume: the host's answer (Success / Refused), its silence (TimedOut), or the local room having nothing left to resume onto (WindowClosed).
The token was valid and the window was open. Peer is now resumed.
No verdict — neither ResumeAck nor Reject — arrived within HeartbeatConfig.resumeTimeout.
The token failed structural validation. reason describes the failure.
There is no window to resume onto, and no host refusal was involved.
No window has opened for this peer yet.