# The Range Spec

> Three columns. When output is assembled at runtime there is no final state to
> draw, so you specify the band instead: the best case worth aiming at, the worst
> case you would still ship, and what the product refuses to do. Everything
> between the second and third columns is allowed and does not need your review.
> That last sentence is the point. This is how you stop being the bottleneck.

---

## Why three columns and not a mockup

A mockup of a generated surface is one sample from a distribution, presented as
if it were the decision. It is useful for alignment and useless as a
specification, because the thing that ships will be a thousand states nobody
drew.

The three columns cover all of them:

- **Best case** is the target. It tells the team what to optimize toward and what
  a great output looks like when everything is available and clean.
- **Worst acceptable** is the floor. Below it, do not ship. This column does more
  work than the other two combined, because it is the only one that makes
  "good enough" a decision instead of a mood.
- **Refuses to** is the boundary. Not a quality bar, a hard line. The product
  declines rather than degrades.

---

## The template

One row per surface. One file per feature.

| Surface | Best case | Worst acceptable | Refuses to |
|---|---|---|---|
|  |  |  |  |
|  |  |  |  |

For each cell write **what the user sees**, not what the system does. "Retrieval
returns three documents" is not a cell. "Answer with two cited sources, both
opened from the answer in one click" is.

---

## A worked example

Surface: a support-reply drafter inside an agent console.

| | |
|---|---|
| **Best case** | Draft answers the customer's actual question in three sentences, cites the policy article it drew from, matches the last five replies this agent sent in tone, and needs no edit before sending. |
| **Worst acceptable** | Draft is factually correct and cites its source, but reads generic and needs light editing. Agent sends it in under thirty seconds of work. |
| **Refuses to** | Draft anything containing a commitment about refunds, dates, legal outcomes, or account access. Those return an empty draft and a pointer to the human process. |

Note what the refusal column is doing. It is not saying the model is bad at
refunds. It is saying the cost of a confident wrong answer about a refund is high
enough that we would rather ship nothing there. That is a design decision, and it
belongs to design.

---

## The sorting test

This is how you find out whether the range is actually specified.

1. Pull ten real outputs. Real ones, from a prototype or from production, not
   ones you wrote.
2. Have two people independently sort them into four piles: best case,
   acceptable, below the floor, should have been refused.
3. Compare.

Agreement on eight or more means the range is doing its job. Disagreement
clusters at exactly one boundary, and that boundary is where you have work to do.
Rewrite that column and sort again.

Do this before launch and once a quarter after. The boundaries move as the model
and the product change, and a range spec nobody re-tests becomes fiction.

---

## The four states people forget

Every range spec needs an answer for these, and most first drafts have none.

**Nothing to work with.** No context, empty account, first run. What does the
best case look like when there is no data.

**Partial input.** Half the fields, an ambiguous request, a truncated document.
What is the acceptable behavior when the input is not good enough for the best
case.

**Conflicting sources.** Two retrieved documents disagree. Does the product pick,
present both, or decline.

**The long tail language or format.** The input is in a language, format, or
domain you did not test. Refuse, degrade, or attempt.

| State | Behavior | Which column it lands in |
|---|---|---|
| No context |  |  |
| Partial input |  |  |
| Conflicting sources |  |  |
| Untested language or format |  |  |

---

## Rules for writing good cells

Write the worst acceptable column first. It is the hardest one and it disciplines
the other two. Teams that start with best case write an aspiration and then
reverse-engineer a floor to match it.

Make refusal specific to a category, not a topic. "Refuses medical advice" is a
topic and it will be argued about forever. "Refuses to state a dosage, a
diagnosis, or a course of treatment" is a category and a reviewer can catch it.

Do not put probabilities in the cells. "Correct ninety percent of the time" is a
model target, not a design specification, and it tells nobody what to do with the
other ten percent. The range spec is about what happens in each case, not how
often each case occurs.

Keep it to one page per feature. If it does not fit, the feature has more than
one surface in it, and each surface gets its own row.

---

## Where it goes

In the brief, in the ticket, and in the eval set. The range spec is the input to
all three. When the worst acceptable column changes, the eval changes with it,
and that link is what keeps the spec from turning into a document that describes
a product nobody is building anymore.

---

## The one thing to do this week

Take the feature you are working on right now and fill in the refusal column
only. Not the other two. Just write down what the product will decline to do.
Send that list to your PM and your engineering lead. If they are surprised by any
line on it, you just found the most important conversation of your week.

---

_From "You Cannot Mock a Distribution", chapter 5 of The Design Operating Model._
_falkster.com/design/you-cannot-mock-a-distribution_
