# Requirement change — tell us who we are turning away

We said metrics were out of scope and we meant it at the time. We are taking that back, for the
narrowest possible reason: support cannot answer "are we rate-limiting this customer?" without
guessing, and the account team found out we had been refusing a paying client for eleven days by
being told about it on a call.

So: **count the denials, per client key, and let us read the number.**

## What it means precisely

One new method: `long denialsFor(ClientKey key)`. The revised `RateLimiterApi` in `contract-delta/`
states it as convention (10), and every part of it is spelled out because every part is arbitrary.

- **One per denied request**, however many of the key's rules refused it. A request turned away by
  three rules at once is **one** denial. That follows from the all-or-nothing rule you already have:
  the request was refused once, as a whole, and charged nothing.
- **Nothing is counted for an allowed request**, and nothing for a key with no rules, since such a
  key is never refused.
- **Zero for a key that has never been refused**, including one nobody ever configured. It never goes
  down and it is never negative.
- **Neither `configure` nor `reset` clears it.** Those two discard *usage*. This is not usage — it is
  a record of what happened. An operator letting a client back in must not erase the evidence they
  acted on, and a count that reset every time somebody edited a rule could never answer the question
  we are asking it.
- **It is exact under load.** When two hundred threads are refused at the same instant, all of them
  are counted. Note what this is: a **second** read-modify-write on shared state, sitting next to the
  counters, and it is *not* covered by whatever you put around those.
- Counting must never block a request and must never change a decision.

## What we are not asking for

- Not allowed-request counts, hit rates, latency, or a metrics registry. One number, per key.
- Not a listener or a callback on denial. We will read the number when we want it.
- Not per-rule attribution — not "how many times did the hourly rule refuse them". One count per key.
- Not a time series, not a window, not a decay. A running total for the life of the limiter.
- Not persistence. It goes when the process goes, like everything else here.

## The question behind it

You have one lock discipline for the counters already. This number is shared mutable state too, it is
written on a different path, and nobody is waiting on it. Does it go under the lock you already have,
or somewhere else, and why? And where does the increment go so that a request refused by three rules
is counted once?
