A state machine makes accepted transitions explicit. A request can't resolve before it starts, and a completed request should not restart merely because an old event arrives. Encoding states and events as unions limits the vocabulary; checking the current state enforces the runtime rule.
You will implement a small request machine, then attach typed result payloads, count genuine transitions, and preserve immutable history snapshots. The same event can be valid in one state and ignored in another. Keep that behavior separate from event validation. A typed resolve event carries a number, while a reject event carries a reason, so narrowing by the discriminant makes the correct payload available. Hidden fixtures include duplicate events, results before fetch, zero payloads, and reset events that leave an idle machine unchanged.