# Line by line: what each one guarantees, and what breaks without it

Read `worked/src/` first and come back. Six files, and two lines in them are the lesson. The rest is
here because a rate limiter with no rules in it would not let you see why those two lines matter.

Everything below compiles. From the repository root:

```
.toolchain/jdk-21/bin/javac -Xlint:all -d workspace/_c3out lessons/C3/worked/src/*.java
.toolchain/jdk-21/bin/java -cp workspace/_c3out Main
```

`-Xlint:all` prints nothing and `javac` exits 0.

---

## `Clock.java` — one method, and that is the seam

```java
public interface Clock {
    Instant now();
}
```

**What it guarantees.** There is exactly one place in this design that knows what time it is, and it
is a type you can hand something else. That is the whole of dependency inversion here:
`FixedWindowLimiter` depends on `Clock`, and `Clock` is satisfied by the test's fake and by
production alike. Neither one is more real than the other from the limiter's side.

**What breaks with more methods on it.** Every double has to implement all of them. Add zones,
calendars, formatting and a `sleep`, and `ManualClock` grows four stub methods that throw, which is
how a seam turns into paperwork. `corpus/rate-limiter/contract/Clock.java` says this out loud under
the heading *"One method, on purpose"*. The limiter needs to know what time it is. It does not need
time zones, calendars, formatting or sleeping.

**The naming trap, because you will hit it.** This is the default package's own `Clock`, not
`java.time.Clock`. Add `import java.time.Clock;` to any file in the directory and the import wins,
and `javac` then reports a type mismatch on a line you did not touch. The corpus contract warns
about the same thing in the same words. `corpus/trip-state-machine/contract/StepClock.java` goes the
other way and extends `java.time.Clock`. That is defensible: the problem timestamps transitions and
never does arithmetic on windows, so the standard type's extra surface costs it nothing. Two shapes,
one idea. What separates them is what each problem does with the time once it has it.

---

## `ManualClock.java` — the substitute the seam exists for

```java
private Instant now;
private int reads;
```

**What `reads` guarantees.** "One request reads the clock once" becomes an assertion instead of a
comment. `faded/GapTest.java` uses it: `assertEquals(1, clock.reads())` after one `tryAcquire` with
two rules configured. Without a counter that property is invisible, and a design that reads the
clock once per rule passes every other test you can think of.

**Why the field is not `volatile` here, when the corpus makes it so.** Nothing in this lesson reads
the clock from two threads. `corpus/rate-limiter/contract/ManualClock.java` does mark it `volatile`,
and its javadoc gives the reason. Its concurrency suite reads a frozen clock from a couple of
hundred threads at once. *"A clock that serialised its readers would be measuring the harness rather
than your limiter."* Copying the `volatile` here would be copying a decision without its reason.

```java
if (by.isNegative()) {
    throw new IllegalArgumentException("time does not run backwards: " + by);
}
```

**What it guarantees.** Every window index this clock can produce is greater than or equal to the
last one. That is what makes "has this window rolled over?" a question with an answer.

**The bug it prevents** is not in the limiter — it is in the test that would otherwise be written.
A double that accepts a negative step lets a suite assert a bucket refilling by winding time
*backwards* into the previous window. That test passes, and it describes nothing that can happen in
production.

---

## `FixedWindowLimiter.java` — the two lines

### Line one: the field and the constructor

```java
private final Clock clock;

public FixedWindowLimiter(Clock clock) {
    this.clock = Objects.requireNonNull(clock, "clock");
}
```

**What `final` guarantees.** There is no moment in this object's life when it exists without a
clock. `javac` proves the assignment happens exactly once on every path through the constructor.
`lessons/J4/` has the two compiler messages that enforce it: `variable clock might not have been
initialized`, and `variable clock might already have been assigned`. That proof is what makes an
injected dependency trustworthy. No method in this class has to consider the case where there is no
clock yet.

**Why not a setter.** `setClock(Clock)` costs three things at once. Every method has to tolerate a
null clock, because there is now a window where the object exists and the clock does not. Two
callers can disagree about which clock is installed, and the later one wins silently. And the
question "what does this limiter measure time with" stops having one answer, which is exactly the
question the seam was opened to make answerable. Constructor injection makes the dependency part of
the type's contract; setter injection makes it a suggestion.

**What `requireNonNull` buys over plain assignment.** The failure moves from the first request to
the construction site. `new FixedWindowLimiter(null)` throws immediately, with the parameter named,
at the line that made the mistake. Without it the first `tryAcquire` throws a
`NullPointerException` from inside the limiter, and the stack trace points at code that is correct.

### Line two: where the clock is read

```java
public Decision tryAcquire(String client) {
    Instant now = clock.now();
```

**What it guarantees.** Every rule for this client is judged against one instant.

**The bug it prevents, concretely.** A client with a per-second rule and an hourly rule is checked
twice. If each check reads the clock itself, the two readings differ by however long the first
check took. A request can then be inside the second-window and outside the hourly one at once. The
`Decision` assembled from those two readings is not a decision about any moment that existed.
`corpus/rate-limiter/reference/DECISION_LOG.md` states it in the same terms. It then adds the part
that matters in a round: reading it in one place makes that structural *"instead of something every
algorithm has to remember."*

That is also the answer to the question an interviewer asks next — *"why not have each rule read the
clock itself?"* It can. Then not doing it becomes something every rule has to remember.

**Note where the instant goes after that.** Into `windowIndex(now, …)` and
`untilNextWindow(now, …)`, both `static`. A static method cannot reach a field, so neither of them
*can* read a clock. That is the same discipline `corpus/rate-limiter/reference/src` applies to
`RateLimitAlgorithm`, whose stated terms forbid an implementation from reading a clock at all: the
instant arrives as a parameter.

### The two-pass loop, which is not about time

```java
for (Rule rule : forClient) {                       // would anybody refuse?
    ...
}
long headroom = Long.MAX_VALUE;
for (Rule rule : forClient) {                       // nobody refused, so spend
    ...
}
```

**What it guarantees.** A denied request spends nothing. Check-then-spend in one pass would charge
the per-second rule before discovering that the hourly rule refuses. A client hammering a wall would
then have its allowance eaten by requests that were never served.

Both passes use the same `now`, so both agree about which window they are in. That is the point
above, paying off in the same method.

### `windowIndex`, and the field that is deliberately absent

```java
static long windowIndex(Instant at, Duration window) {
    return Math.floorDiv(epochNanos(at), window.toNanos());
}
```

**What it guarantees.** A window is a function of the instant alone. There is no "when did this
window start" field, so two limiters started an hour apart agree about where the boundaries are.
A restart does not hand every client a fresh allowance either.
`corpus/rate-limiter/reference/DECISION_LOG.md` makes the same call for the same reason.

**Why `floorDiv` rather than `/`.** Java's `/` truncates towards zero. For any instant before 1970
the division rounds the wrong way, so the window boundaries sit in different places on the two sides
of the epoch. `Instant.parse("1969-12-31T23:59:00Z")` is a legal argument. This is a one-token fix
for a class of bug otherwise found by a test nobody writes.

**`remaining` reads the clock too, and that is where designs leak.** It is a second entry point, and
it needs to know which window's counters to look at. One `Instant.now()` left in this method is the
most common way this design fails in a real submission. It fails quietly, too: `tryAcquire` still
behaves, so every test aimed at the interesting part stays green.

---

## `Main.java` — the driver, and the second implementation

```java
Clock production = Instant::now;
```

**What it guarantees.** The interface has two implementations, so it is not speculative. That counts
for scoring, not only for design. STANDARD v1.0's D3 level 3 requires a minimal seam set, and
`when-not.md` is about a seam with one implementation and no second one in sight.

One line, and no factory, no configuration file, no registry. If wiring the real clock needed more
than this, that would be an argument for looking at the seam again.

**What the driver shows that a wall-clock driver cannot.** Run it and read the timestamps:

```
-- 10:00:20, two per minute and three per hour --
   2026-08-18T10:00:20Z  ALLOWED, 1 left
   2026-08-18T10:00:20Z  ALLOWED, 0 left
   2026-08-18T10:00:20Z  DENIED by burst, retry after PT40S
-- wind on 40s, which is exactly what the denial asked for --
   2026-08-18T10:01:00Z  ALLOWED, 0 left
   2026-08-18T10:01:00Z  DENIED by hourly, retry after PT59M
```

Three windows, two rules and an hour-scale limit, in a program that finishes instantly. `PT40S` is
the interesting number: the denial at 10:00:20 says wait 40 seconds, and 40 seconds later the
request is allowed. On the wall clock you could print that number but not demonstrate it.

Demonstrating it is the difference between D2 level 2 and level 3. Level 3 wants the base suite green
*"with the clock still running, and the driver shows the interesting cases rather than the happy
path only."*

The hourly denial is the case worth pointing at in a round. It is reachable in a driver only
because time is a parameter of the program rather than a property of the machine.
