# Reference patch — 01-driver-cancels

The answer key for how the reference absorbs this change, and the thing that makes `budget.json`
reproducible. **Never shipped to the candidate.**

1. **Overlay** `../contract-delta/TripEvent.java` onto `contract/TripEvent.java`, and add
   `../contract-delta/DriverCancelled.java` to `contract/`. Contract files are given, so nothing here
   is charged.
2. **Overlay** the four files in this directory onto their namesakes in `reference/src/`:
   `TripRules.java`, `TripProjection.java`, `RiderNotification.java`, `Demo.java`.

Measured: `reference_diff = 8` — `diff_budget = max(3, 8 + min(ceil(8/2), 6)) = 12`.

The curveball suite (11 tests) and the base suite (18 tests) are both green after the patch.

## Where the 8 lines went

| File | Lines | What changed |
|---|---|---|
| `TripRules` | 4 | two appended `Edge` rows — `MATCHED + DriverCancelled → REQUESTED` and `DRIVER_ARRIVED + DriverCancelled → REQUESTED` — plus the comma the row above them now needs |
| `TripProjection` | 1 | one arm in the `driverOf` fold: `case DriverCancelled cancelled -> Optional.empty()` |
| `RiderNotification` | 1 | one arm in `message`: the rider is told the search has restarted |
| `Demo` | 2 | one arm in `narrate`, wrapped over two lines |

**Nothing else in the design was opened.** `Trip`, `TransitionTable`, `Edge`, `TripJournal`,
`InMemoryJournal`, `EffectRunner` and `TripFactory` are byte-for-byte what they were. In particular
`Trip.handle` did not change: a trip going *backwards* to a state it has already been in needs no new
code, because the sequence "ask the table, record, react" never cared which direction an edge points.

The `TripRules` cost is 4 rather than 2 and it is worth being precise about why: two rows are added,
and the row above them gains a comma, which a line-level diff charges as a removal plus a
re-addition. Java forbids a trailing comma in an argument list, so that is the floor for appending to
this list — two lines of punctuation. The base reference's javadoc now says so rather than claiming a
purity the language does not allow.

## The three lines that are the actual point of this curveball

`REQUESTED` becoming a state the trip can *re-enter* is cheap in any table-driven design. The part
that separates a good design from one that merely passes is `driverId()`, and the requirement is
written to make that unavoidable: after a driver cancellation the trip has been matched before but has
no driver now.

- **A stored `driverId` field, assigned in the `Matched` branch, gets this wrong** and gets it wrong
  silently. The field still holds `d-7`. Fixing it means finding every place that writes it and adding
  a clearing write — a second place for the same fact to be wrong, which is decision 1 in the decision
  log.
- **A fold with a `default -> driver` arm gets it wrong too**, and this is the more interesting
  failure, because it compiles. The new event falls into the default, the fold returns the previous
  driver, and the trip reports a driver who has gone home.
- **The reference's fold has no `default`, so it did not compile at all** until someone answered the
  question. That is the whole property the problem is built to teach, and it is measured here at one
  line.

## Verified: three files stop compiling

Compiling `reference/src` against the delta, before applying any patch, fails with:

```
Demo.java:106: error: the switch expression does not cover all possible input values
        return switch (entry.event()) {
```

`javac` reports only the first exhaustiveness error per compilation and stops, so removing `Demo.java`
from the compilation surfaces `RiderNotification.java:30`, and removing that surfaces
`TripProjection.java:52`. Three sites, each named with a line number, all before a single test ran.
The one-at-a-time reporting is a property of the compiler rather than of the design.

Note what did **not** break: `TripRules`. `Edge` keys on `Class<? extends TripEvent>`, which is not
exhaustiveness-checked, so a sixth event with no row compiles fine and is simply refused. That is the
cost `Edge`'s own javadoc states in the base reference, and this curveball is where it is paid — the
missing rows are caught by the test suite, not by `javac`. It is still the right trade: an unknown
event being refused is a safe default. But a candidate who claims the compiler catches *everything*
should be pushed on this exact point.
