# Requirement change

A driver who has arrived does not wait forever. At the moment they are stuck: once the trip is
`DRIVER_ARRIVED` the only things that can happen are the rider getting in or the rider cancelling, so
a driver sitting outside a house where nobody is coming has no way out of the state machine at all.

So: **a new event, `WaitExpired`**, raised by a timer when the driver's wait runs out. Your contract
folder has an updated `TripEvent` and a new `WaitExpired` alongside it; `TripEvent` is still sealed, so
it now permits six kinds of event rather than five. Drop both files over the ones you were given.

**What it does.** `WaitExpired` takes the trip from `DRIVER_ARRIVED` to `CANCELLED`. The rider did not
come out, so the trip is over — this is a terminal state like any other cancellation, and there is
still no fee or penalty of any kind.

**The new part, and the reason this is not just another row.** It is only legal once the driver has
actually been waiting for **at least five minutes**.

- The five minutes are measured from **when the driver arrived** — that is, from the timestamp of the
  transition that put the trip into `DRIVER_ARRIVED` — to **now**.
- **Now comes from the injected clock.** Do not call `Instant.now()`, and do not take the caller's word
  for how long the wait has been: `WaitExpired` deliberately carries nothing, because the trip already
  knows when the driver arrived and already has a clock. Working it out is the trip's job.
- Exactly five minutes **is** long enough. The rule is "at least", not "more than".
- **A `WaitExpired` that arrives too early is refused with `IllegalTripTransitionException`** — the
  same refusal as any other event that cannot happen right now. That is the right one of the two on
  purpose: the trip is live, and this very same event will be accepted a few minutes later once
  something else has happened, which in this case is time passing. It is not a
  `TripFinishedException`, because the trip is not finished.
- A refused expiry changes nothing, exactly like every other refusal: no history entry, no side
  effect, no state change.

**About the clock, because this genuinely changes one rule.** Until now the clock was read once per
*accepted* transition and never for a refusal. Deciding whether a wait is long enough requires knowing
what time it is *before* the trip can know whether to accept, so from now on the rule is: **the clock
is read once per event that the transition table permits** — and that one read is the one that
timestamps the entry if the event is accepted. Two consequences you should make true rather than
stumble into:

- An event refused by the **table** (a `WaitExpired` while the trip is still `MATCHED`, a
  `TripStarted` on a trip with no driver, anything at all on a finished trip) must **still not read the
  clock**. Those refusals are decided before time is relevant.
- An event the table permits but the **five-minute rule** refuses **does** read the clock, once. That
  is a real cost and it is visible, because the clock you are given moves on every time it is read.

**Where it is refused.** Only `DRIVER_ARRIVED` has a cell for `WaitExpired`. From `REQUESTED`,
`MATCHED` and `IN_PROGRESS` it is refused by the table with `IllegalTripTransitionException`, and on a
completed or cancelled trip it is refused as finished, with the same precedence as before.

**Downstream of it.** The rider has to be told the driver gave up — that is a notification like any
other, so it goes wherever your other notifications go, and it must run for this transition too.
Nothing about how side effects behave changes.

**Everything else is untouched:** the driver is still derived the same way and a no-show trip still
records the driver it had, the history still records every accepted transition in order, replaying a
history still rebuilds the trip exactly, and the two exception types keep the same precedence.
