# Reference patch — 02-global-backstop-cap

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** `BackstopScopes.java` (in this directory) to `reference/src/`. A brand-new file, so
   `measureChange` charges nothing for it. It implements the same package-private `Scopes` interface
   `Scopes.own()` already satisfies, in three lines of body.
2. **Add** `contract-delta/Entry.java` (the full revised entry point, with `createWithBackstop`
   beside the existing two factories) to the candidate's contract. Not counted in the measured diff —
   a contract extension is free, and only the reference's own absorption of it is charged.

That is the entire change. `RateLimiter.java`, `KeyBudget.java`, both algorithms,
`StandardAlgorithms.java`, `AlgorithmFactory.java`, `Scopes.java` and `Availability.java` are
**untouched**, and no file in `reference-patch/` is byte-identical to its baseline.

Measured: `reference_diff = 0` (0 added, 0 removed, 0 files touched, 1 new file), so
`diff_budget = max(3, 0 + min(ceil(0/2), 6)) = 3`.

The curveball suite (7 tests) and the base suite (28 tests) are both green after the patch, across
four consecutive runs of each.

## Why zero, and why it is zero on purpose rather than by luck

`RateLimiter` was written from the start to take a *list* of budgets. `decide` checks every budget
before charging any of them; `locked` acquires every one of them in the order `Scopes` returned and
releases in reverse; `scopeOf` skips the ones that do not exist. None of that had a second
implementation to justify it at the time, and `Scopes`' own javadoc says so plainly — it calls itself
"the one genuine up-front bet in this design" and states the price (a functional interface, a one-line
default, a list where a single value would do) before stating what it buys. This curveball is the bet
being settled.

The part that would have been genuinely expensive to retrofit is not the list. It is the **lock
order**. Adding a second budget to a design that never had one means two locks held at once for the
whole of check-then-charge, and the cure for a lock cycle is a single, stated, globally consistent
acquisition order. In this design that order already exists in one method (`locked`) and is owned by
one interface (`Scopes`), so `BackstopScopes` only has to return `[backstop, key]` and say why it is
always that way round. A design in which the second budget arrived as a second field, checked in a
second place, would have an order too — an emergent one, written nowhere, and correct until the day
somebody sorted the keys by name.

## A real defect this curveball found in the base reference, and fixed there rather than here

Writing this curveball caught a genuine bug in `reference/src/RateLimiter.java`: `remaining(key)`
read `budgets.get(key)` directly instead of going through `scopeOf(key)`, while `tryAcquire` went
through `Scopes` properly. With `Scopes.own()` the two are indistinguishable — one budget or none,
either way — so the base suite could never tell them apart, and it passed 28/28 with the bug in
place. With a second scope it is straightforwardly wrong: `remaining` would report the caller's own
95 remaining while the very next `tryAcquire` refused them under a shared cap it had not consulted.
One seam, honoured in one of the two methods that answer questions about it.

The fix — route `remaining` through `scopeOf`, and extract the "tightest figure across the scope"
loop that `decide` already contained into a `fewestRemaining` helper both call — was made in
**`reference/src/RateLimiter.java` directly**, before this curveball's baseline was measured, exactly
as the corpus's rule for an expensive curveball prescribes: fix the reference, not the budget. The
base suite was re-verified green (28/28) and the concurrency suite re-run afterwards.

The counterfactual is worth recording, because it is the difference between a seam that works and one
that only looks like it does. Measured with `diffLines` against the pre-fix code:

| absorption of `remaining` inside the curveball patch | measured lines |
|---|---|
| cheapest correct version (min loop inlined into the lambda) | **13** |
| done properly (helper extracted, `decide`'s call site updated too) | **20** |
| what it actually cost, with the base reference fixed first | **0** |

So this curveball would have measured 13–20 and every one of those lines would have landed inside
`RateLimiter` — the one class in this design that owns the locking and the all-or-nothing commit, and
the one place the authoring brief names as where a careless edit is a correctness bug rather than a
behaviour change. That is precisely the signal a large `reference_diff` is supposed to send, and the
right response to it was to fix the seam.

## The one thing worth watching in a candidate's answer

Zero is available to any candidate whose limiter can ask more than one budget. The interesting part is
the two questions the tests turn into assertions:

- `remainingSpansBothBudgets` fails anybody who has the same bug the reference had.
- `twoCallersContendingOnTheSharedCapNeitherOvershootNorDeadlock` runs 128 threads across two
  callers, five rounds, against a frozen clock: every request needs the shared cap's lock plus a
  different second lock, so an inconsistent order does not give a wrong number, it **hangs**, and the
  test says so in its failure message rather than timing out anonymously. A candidate who cannot say
  which lock is taken first and why has not answered this curveball even if the suite is green.
