# Reference patch — 02-fines-stop-at-the-replacement-cost

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

1. **Add** `CappedAtReplacementCost.java` (in this directory) to `reference/src/`. New file, so
   `measureChange` charges nothing for it.
2. **Change one line** in `reference/src/LibraryFactory.java`, in `standard()`:

   ```diff
   -                new DailyFine(FINE_PER_DAY_MINOR),
   +                new CappedAtReplacementCost(new DailyFine(FINE_PER_DAY_MINOR)),
   ```

`DailyFine` is decorated, not deleted. Fifty a day is still stated once, in the factory, and the
ceiling is expressed as what it is — a limit on top of a tariff — so lifting it is the same line in
reverse.

Measured: `reference_diff = 2` (1 added, 1 removed, one file touched), so
`diff_budget = max(3, 2 + ceil(2/2)) = 3`.

The curveball suite (6 tests) is green after the patch, and **so is the base suite (17 tests)**.
Every fine the base suite asserts is 50, 250 or 500 against replacement costs of 4500 and up, so a
ceiling cannot reach them.

## Where the requirement landed, and where it did not

`Library` was not opened, and neither was `Lateness`. That second one is the interesting half of the
measurement.

- **`FinePolicy` separates what lateness costs from the act of returning.** The obvious collapse is
  `daysLate * 50` inside `giveBack()`, and it is one line. This requirement would then have gone into
  the method that also looks up the loan, frees the copy, updates the member and builds the receipt —
  next to code whose meaning it changes.
- **`FinePolicy` is handed the `Title`, not only the day count.** This is the decision the curveball
  actually tests. A tariff that knew only "ninety-one days" *cannot express this rule at all*: the
  ceiling is a fact about the book. With the title in the signature, the ceiling is a decorator; with
  only the day count, it is a change to the interface, to `DailyFine`, and to the call site that has
  to look the title up and pass it in. The base design has one implementation that ignores the
  parameter, which looks like waste right up until this requirement arrives.

  The honest version of the defence is that the parameter was not free: `FinePolicy` takes a
  `Title` on the argument that *every* interesting variation on a fine is a fact about the book. It
  deliberately does **not** take the `Member`, even though "children are not fined" is just as
  plausible a requirement — because that one is a much larger claim about the library, and guessing
  at both parameters would be designing for two futures instead of one.
- **`Lateness` is separate from `FinePolicy`**, which is why the receipt still says two hundred days
  when the charge has stopped at 4500. Had the ceiling lived where the days are counted, capping the
  money would have quietly capped the count — the requirement explicitly asks for the days to stay
  true, and here that is not something anybody had to remember.

## What this costs without the seam

With the fine computed inline in the return path:

- the ceiling arithmetic goes into `giveBack()`, where the loan lookup, the copy release, the member
  update and the receipt construction already are
- the title has to be fetched at that point for its replacement cost — it happens to be there
  already in the reference, but only because the return path validates it
- and the ordering trap becomes live: `min(daysLate * 50, cost)` written where `daysLate` is
  computed is one keystroke from capping the day count too

The reference's cost is two lines, in a class that does nothing when a book comes back.
