# Reference patch — 03-the-overdue-shelf

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/LibraryApi.java`, `../contract-delta/LibraryException.java` and
   `../contract-delta/OverdueLoanException.java` onto `contract/` — the first two replace files of
   the same name, the third is new. Contract files are given, so nothing here is charged.
2. **Add** `Overdue.java` and `NoOverdueLoans.java` (in this directory) to `reference/src/`. New
   files, so they are free.
3. **Add two lines** to `reference/src/Library.java`, above `finesOwedMinor`:

   ```java
   @Override
   public List<Loan> overdueLoans() { return Overdue.among(loans.outstanding(), clock.now()); }
   ```

4. **Add a row** to `reference/src/LibraryFactory.java`, in `standardBorrowingRules()`:

   ```diff
   -                new FinesUnderThreshold(FINE_BLOCKING_MINOR));
   +                new FinesUnderThreshold(FINE_BLOCKING_MINOR),
   +                new NoOverdueLoans());
   ```

Measured: `reference_diff = 5` — `Library.java` 2+0, `LibraryFactory.java` 2+1 — so
`diff_budget = max(3, 5 + ceil(5/2)) = 8`.

Both the curveball suite (7 tests) and the base suite (17 tests) are green after the patch. The base
suite staying green matters here, and it is not luck: the new rule only bites a member who is holding
an overdue book at the moment they ask for another, and every base test that winds the clock forward
returns the book before borrowing again. The one base test where a member is blocked after a late
return is blocked by the *fines*, which are still checked first.

## What the 5 lines are, and what they are not

**Two of the five are the new contract method**, which every design must declare somewhere. The
budget carries them rather than charging them as a design failure — the same reasoning as
vending-machine's `enterMaintenance`. **Three are one row added to a list of rules.**

The requirement itself — a definition of "overdue", a report ordered by due date, and a lending rule
that refuses on it — is **two new files and nothing else**. Read `Overdue.java` and notice how much
of the requirement is not written down twice:

| The requirement said | Where it is enforced |
|---|---|
| the morning list is every overdue loan in the library | `Overdue.among(loans.outstanding(), now)` |
| a member holding one may borrow nothing else | `Overdue.among(held, now)` — the same function, a different input |
| a returned book is not overdue | nowhere — a returned loan is not in `outstanding()`, so it cannot be in either answer |
| the rule comes after the limit and the fines | nowhere — it is third in the factory's list |
| somebody else's overdue book is not your problem | nowhere — the rule is handed only this member's loans |

Five statements, one filter, one list position, and two of them enforced by nothing at all.

## Where the requirement landed, and why the repository is the reason

`LoanRepository` was **not opened**, and that is the measurement this curveball exists to take.

The requirement is a new *question about the loans that exist*. There are two shapes it can land in:

- **The tempting shape: a method on the storage interface.** `List<Loan> findOverdue(Instant now)`
  reads well and is what most designs reach for. It costs an edit to the interface *and* an edit to
  every implementation of it, and it establishes the pattern: the next question about loans — due
  this week, out longest, never returned, borrowed by section — is another method on the interface and
  another method in every implementation. The seam that was supposed to absorb change becomes the
  place change is charged to.
- **The shape the reference took: `outstanding()` plus a filter.** The repository already hands over
  everything that is out, because three base operations needed exactly that — the borrowing-limit
  count, the availability derivation, and one member's loan list. A fourth question is therefore a
  new file. That is why the storage interface has four methods and not seven, and it is the decision
  in `LoanRepository`'s javadoc worth defending out loud.

**What this costs with the loans in a `HashMap` field inside the class that runs the desk** — the
design this problem is built to distinguish:

- the filter goes into that class, because that is the only place the map is visible, so the class
  that lends, returns, fines and validates gains a query method
- the lending rule's check goes there too, since the eligibility rules are guard clauses in `borrow`
  rather than a list — a fourth `if` in the method the other three are already in
- the ordering rule ("limit, then fines, then overdue") becomes the order those `if`s happen to be
  written in, which is a comment at best
- and the map has been read directly from four places by now, so the day somebody wants loans kept
  anywhere else, all four move

The reference's cost is five lines, three of which are a row in a list, and **nothing at all in the
class that decides what "overdue" means or where loans live**.

## The one thing that is genuinely new: an exception

`OverdueLoanException` had to be added, and it is worth being able to say why it is not
`OutstandingFinesException` with a different message. Nothing is charged until a book comes back, so a
member can be blocked by this while owing nothing at all — the two refusals mean *bring it back* and
*pay up*, and a desk that cannot tell them apart tells the reader the wrong thing. That is the same
argument the hierarchy was built on, applied to a seventh case, which is what a hierarchy is for.
