The Range Spec
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...
From this piece
The template
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.
- Pull ten real outputs. Real ones, from a prototype or from production, not ones you wrote.
- Have two people independently sort them into four piles: best case, acceptable, below the floor, should have been refused.
- 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