# Reference patch — 03-usage-addon

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/CostExplorerApi.java` onto `contract/` — replaces the file of the
   same name, adding `recordUsage(String, YearMonth, long)` and the "Usage-based add-on" section.
   Contract files are given, so nothing here is charged.
2. **Add** `UsageLedger.java` (in this directory) to `reference/src/`. New file, so
   `measureChange` charges nothing for it.
3. **Four edits to `reference/src/CostExplorer.java`** — a field, a new method, and two existing
   methods widened:

   ```diff
        private final SubscriptionRepository subscriptions;
        private final AtomicLong nextId = new AtomicLong(1);
   +    private final UsageLedger usage = new UsageLedger();
   ```

   ```java
   @Override
   public void recordUsage(String subscriptionId, YearMonth month, long units) {
       subscriptions.find(subscriptionId);
       usage.record(subscriptionId, month, units);
   }
   ```

   ```diff
    @Override
    public MonthlyCharge costForMonth(String subscriptionId, YearMonth month) {
   -    return subscriptions.find(subscriptionId).costForMonth(month);
   +    MonthlyCharge base = subscriptions.find(subscriptionId).costForMonth(month);
   +    long usageMinor = usage.chargeMinor(subscriptionId, month);
   +    return usageMinor == 0 ? base : new MonthlyCharge(month, base.amountMinor() + usageMinor, base.prorated());
    }
   ```

   ```diff
   -    BillingAccount account = subscriptions.find(subscriptionId);
        List<MonthlyCharge> months = new ArrayList<>(12);
        long totalMinor = 0;
        for (int m = 1; m <= 12; m++) {
   -        MonthlyCharge charge = account.costForMonth(YearMonth.of(year, m));
   +        MonthlyCharge charge = costForMonth(subscriptionId, YearMonth.of(year, m));
   ```

`edits.json` beside this file is the same four edits in machine-readable form.

Measured: `reference_diff = 13`, all in `CostExplorer.java` (10 added, 3 removed), so
`diff_budget = max(3, 13 + ceil(13/2)) = 20`.

Both the curveball suite (7 tests) and the base suite (13 tests) are green after the patch.
`Subscription.java` is untouched, and so are the other two curveballs' new files
(`TrialAccount.java`, `AnnualSubscription.java`, neither of which is present when this curveball is
measured on its own, since curveballs are measured independently against the pristine base).

## Why this one touches two existing methods, and the other two curveballs touch one

The first two curveballs (trial, annual) each add a **new way to start** a subscription, which is
naturally a brand-new method plus, at most, a brand-new `BillingAccount` implementation — the
existing `costForMonth`/`projectYear` machinery already asks whatever account it finds, unchanged.
This one is different in kind: usage is not a new *way to start*, it is a **second source of
charge layered on top of every existing account**, so it genuinely has to be read from inside the
one place a month's charge is assembled. There is no seam in the base design that already
anticipates "more than one thing can contribute to a month's total" — and building one on
spec, before this requirement existed, would have been the exact kind of speculative interface the
shopping-cart and library problems' decision logs argue against.

**Why `projectYear` changes at all, rather than being left alone.** Before this patch, `projectYear`
asked the `BillingAccount` directly, bypassing the orchestrator's own `costForMonth`. That was a
harmless shortcut while there was only one thing to combine; the moment a second contributor
(usage) exists, the shortcut becomes a second place that has to remember it. Routing `projectYear`
through `this.costForMonth(...)` is the fix that makes it impossible for the two to disagree again —
a third contributor added later would need this edit made only once, not twice.

**Why usage lives in its own `UsageLedger` rather than as a field or two on `CostExplorer`.** A raw
`Map<String, Map<YearMonth, Long>>` field with the rate as a constant would have measured about the
same number of lines, but it would have put a nested-map lookup and a rate literal inside the
orchestrator, which is exactly the class this design keeps free of anything a pricing or billing
requirement could reach. `UsageLedger` is small enough that pulling it out costs nothing and keeps
`CostExplorer.recordUsage` and `CostExplorer.costForMonth` reading as one line of intent each:
record against the ledger, ask the ledger.

**Why the usage charge does not touch `MonthlyCharge.prorated()`.** The contract states this
directly, and the reference honours it by construction: `costForMonth` only ever passes through
`base.prorated()` from the underlying account, never recomputing it. `prorated` answers "was this
month covered by more than one plan segment", and usage has no plan segments — conflating the two
would make `prorated` mean two different things depending on which kind of charge caused it.
