Specifying Behavior

A principle has never stopped anyone shipping anything. A constraint is a rule you can catch being broken, the only kind that survives generated output.

Falk Gottlob7 min readNew

The short version

A design constraint is a rule with a failure condition attached, and it is the unit of work in a practice that specifies behavior instead of producing artifacts. The shape is two clauses: what is always true of the product, and the observable moment it failed. Then name a checker, a person, a reviewer, an eval, or a test. Four tests decide whether a candidate is real: can a stranger point at a violation, can you name the cost of breaking it, could a reasonable colleague argue the opposite, and who catches it. Three to six per surface, living in the brief and the prompt rather than in a principles document nobody opens.

Design principles are the most durable unproductive artifact our field has produced.

Every company has them. Delightful. Human. Trustworthy. Bold but never loud. They go on a wall, they open the onboarding deck, and in the entire history of software I have never seen one stop a single thing from shipping. That is not because the values are wrong. It is because a principle has no failure condition, so there is no moment at which anyone can say it was broken.

A constraint has one. That single difference is what makes it operate.

The two clauses

Rule: what is always true of the product. Broken when: the specific observable failure.

Nothing leaves the user's account without an explicit action from them in that session. Broken when a message, post, or invitation goes out from a background job the user did not initiate.

A confirmation dialog is never the first place a user learns what the system already did. Broken when the dialog describes a completed action rather than a pending one.

When the model or a dependency is unavailable, the manual path still works. Broken when an outage in a generated feature blocks the underlying task.

Read those three and notice what they let you do. You can hand any of them to a reviewer with five real outputs and get a straight answer about which one violates it. You can hand two of them to an engineer and get a test. You cannot do either of those things with "trustworthy."

There is a third line worth adding, and most teams skip it. Checked by. A person on a quarterly walkthrough, a reviewer on every new action, an eval on the audit log, a test on the tool-call path. A constraint nobody checks is a wish with better grammar.

Why this became the job

When a team could produce three directions a month, the review was the control system. Work came in, a senior person looked at it, and their judgment got applied one artifact at a time. Principles were decoration on top of a process that ran on human attention.

Now generation is free and the review cannot keep up, because the number of things being made is no longer bounded by the number of things a person can look at. I made the general case for that in Design Just Got Promoted. Which leaves two options. Judgment gets written into rules that execute before the work is made, or it gets applied to a shrinking sample of the output while the rest ships unexamined.

So the constraint set is the control system now. Written first, in front of generation, checkable afterward by somebody who is not you.

The four tests

Run every candidate through these before it goes in the doc. Most do not survive. Good.

The stranger test. Hand it to someone who was not in the room, with five real outputs, and ask them to point at the one that violates it. Hesitation means it is not specific yet. Not that they are wrong, that you are vague.

The cost test. Name what breaking it costs. Harm, trust, rework, money, or time. If you cannot name a cost, cut it. This one kills more candidates than the other three combined, and every one it kills was going to dilute the set.

Disagreement test. Could a reasonable person on your team argue for the opposite? If not, you wrote a truism. "The product should be usable" passes nobody's day and belongs in nobody's constraint doc.

And the check test. Name who or what catches it. If the real answer is "we would notice eventually," you have written a hope and given it a checker's badge.

Three to six, and where they come from

Three to six per surface, and that is not a soft number.

Ten means you wrote principles and relabelled them. Twenty means they are not all load-bearing, and the practical result is that the team learns to skim all of them because of the eight that never mattered. The set has to stay small enough that everyone can hold it in their head while making something.

Pull the first three from failures that have already happened. Constraints invented from first principles describe a product nobody has shipped. Constraints pulled from real incidents describe yours, and they carry the political weight of a thing that already went wrong, which makes them much harder to argue away in a planning meeting.

Three categories produce the most useful constraints, in my experience. Reversal parity: any action a user can take in one tap is reversible in one tap. Disclosure: anything the system does on a user's behalf is visible to their admin in an audit trail within the hour. Refusal: when the agent declines, it names the reason and the nearest thing it can do, broken when the response is a generic inability message with no next step.

Three years ago none of those were design surfaces. They are now where most of the trust in a product is won or lost.

One thing constraints cannot do on their own is describe quality on a generated surface, because quality there is a band rather than a line. That is a different instrument, the range spec, and it is in You Cannot Mock a Distribution.

Where they have to live

In the brief, in the ticket, and in the prompt.

Not in a design principles page and not in a Figma cover frame. A constraint set that is not in the place where work gets made is archived rather than operating, and archived rules change nothing about what ships.

This is the part that tends to get resistance, because putting constraints in the system instructions means design is writing something that runs. Good. That is the job now. Behavior written in a prompt is behavior specified, and the alternative is that the behavior gets specified anyway by whoever was closest to the code at eleven at night.

The constraints that can be checked by a machine should be, and the mechanics for that are the same ones in The Eval Is The Spec, pointed at interface behavior instead of model output. The ones that need a human get a named reviewer and a moment in the process where the review happens. Both kinds go in the same doc. Splitting them into a "design" list and an "engineering" list is how half of them stop being enforced.

This week

Take one surface. Write three constraints, two clauses each, plus a checker.

Then run the stranger test with somebody who was not in the room. Give them five real outputs from that surface and ask which one breaks the rule. Whichever constraint they hesitate on is the one to rewrite, and that hesitation is the most useful signal you will get all week.

The full template, the four tests, and twenty worked examples across consumer, enterprise, and agent products are in The Constraint Template. The compressed version for someone who wants the method without the argument is How do you write a design constraint?


Chapter 3 of a series on the design operating model. Next: the boundary conversation with PM and engineering, restated for a world where all three can generate.

Share this post

Take the template

Constraint template with twenty worked examples

Download

Frequently asked

What is the difference between a design principle and a design constraint?+

A principle has no failure condition, so nobody can catch it being broken. Delightful, human, trustworthy has never once stopped anyone from shipping anything. A constraint is two clauses: the rule, and the observable moment it failed. Any action a user can take in one tap is reversible in one tap, broken when accepting takes a tap and undoing requires a settings screen. The second clause is what makes it checkable by a person, a reviewer, or an eval.

How do you write a design constraint?+

Write two clauses and name a checker. The rule states what is always true of the product. The broken-when clause names the specific observable failure. Then say who or what catches it: a person, a reviewer, an eval, or a test. If the broken-when clause is hard to write, the rule is a principle wearing a costume and it should be rewritten or cut.

How many constraints should a surface have?+

Three to six. Ten means you wrote principles and called them constraints. Twenty means they are not all load-bearing, and the team will learn to skim the good ones because of the eight that never mattered. Pull the first three from failures that have already happened in your product rather than from first principles, because invented constraints tend to describe a product nobody has shipped.

How do you know if a constraint is specific enough?+

Run four tests. The stranger test: hand it to someone who was not in the room along with five real outputs and see if they can point at the one that violates it. The cost test: name what breaking it costs in harm, trust, rework, money, or time. The disagreement test: could a reasonable colleague argue the opposite. The check test: name who or what catches it. The cost test kills the most candidates, and that is the point.

Where should design constraints live?+

Where generation happens, so the constraint arrives before the output does. That means the brief, the ticket, and the prompt or system instructions, not a separate design principles document. A constraint set that is not in the place work gets made is not operating, it is archived, and archived rules do not change what ships.

Can design constraints be tested automatically?+

Some of them. A constraint whose failure is visible in a log or a payload can be an eval: permission-aware output checked with fixtures per permission tier, or overnight actions checked on the session-start payload. Others need a human reviewer, like whether a suggestion outweighs the user's own compose control. Naming the checker is part of writing the constraint, because a rule nobody checks is a wish with better grammar.

Related reading

Chapters and essays on the same thread, across both handbooks.

THE SHORT ANSWER

PART OF

AI Product Management