# Reference patch — 01-sliding-window-log

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** `SlidingWindowLogAlgorithm.java` (in this directory) to `reference/src/`. A brand-new
   file, so `measureChange` charges nothing for it. It implements the same package-private
   `RateLimitAlgorithm` interface `FixedWindowAlgorithm` and `TokenBucketAlgorithm` already
   implement, and nothing else in `reference/src` needs to know it exists.
2. **Replace** `reference/src/StandardAlgorithms.java` with the copy in this directory. The change
   is **one added line**:

   ```java
   implementations.put(Algorithm.SLIDING_WINDOW, SlidingWindowLogAlgorithm::new);
   ```

3. **Add** `contract-delta/Algorithm.java` (the full revised enum, with `SLIDING_WINDOW` and its
   conventions documented beside the existing two constants) to the candidate's contract. Not
   counted in the measured diff — the same convention every other curveball in this corpus that
   extends the contract follows: 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`, `Availability.java`,
`AlgorithmFactory.java`, `Scopes.java`, `FixedWindowAlgorithm.java` and `TokenBucketAlgorithm.java`
are **untouched**, and no file in `reference-patch/` is byte-identical to its baseline.

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

The curveball suite (5 tests) and the base suite (28 tests) are both green after the patch, and the
concurrency suite still passes — the new algorithm holds a plain unguarded `ArrayDeque` because
`RateLimitAlgorithm`'s stated terms say the owning budget's lock is held on every call and the
instance is never shared between keys, so there was nothing new for the stress suite to re-prove.

## Why this curveball exists, and why the number being 1 is the point

`StandardAlgorithms`' own javadoc made the claim before this curveball was written: *"Adding an
algorithm is a new file implementing `RateLimitAlgorithm` plus one added line in the constructor
below. Nothing else in the design changes, and in particular `KeyBudget` and `RateLimiter` do not:
neither of them can name an algorithm."* This is the measurement that checks the claim rather than
repeating it. One line, and it is the line whose entire job is to be the one line.

The alternative design — a `switch (rule.algorithm())` inside `KeyBudget` — would work, would pass
every base test, and would put this edit **inside the class that owns the locking and the
all-or-nothing commit**. That is the specific cost `AlgorithmFactory` exists to avoid, and it is why
the factory is a separate seam from the algorithm interface rather than the same one: "how does a
fixed window count" and "which class counts a `FIXED_WINDOW` rule" look like one question and are
two.

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

A `reference_diff` near zero is available to any candidate who put the behaviour behind an interface,
so the interesting part of grading this one is not the number — it is whether the boundary convention
is right. `(now - window, now]` means a request made *exactly* a window ago has gone, and the
implementation gets that from a single `!isAfter(cutoff)` comparison rather than from an inclusivity
`if`. `noFreshAllowanceAtAClockBoundary` checks the nanosecond either side of that edge, and
`theWaitIsMeasuredFromTheRequest` fails any implementation that quietly computed `retryAfter` from a
clock-aligned boundary — the two algorithms give different answers for the same history there (nine
seconds versus six), which is exactly what makes it a usable discriminator rather than a restatement
of the fixed window's test.
