Refuse to compute.
The most underrated feature in a regulated system is a clean no. When a request falls outside what your system can do correctly, the choice is between rejecting it at the door and producing your best approximation. One of these costs a support ticket. The other surfaces eighteen months later with penalties attached.
The economics of the no
Consider a tax engine asked to compute a filing for a fiscal year that predates the regulation it implements, or for a company in a sector whose special brackets aren’t built yet. It has most of what it needs. The tempting move — and the one users, sales, and sometimes your own pride will push for — is to compute anyway: apply the current rules, flag a caveat somewhere, ship the result.
The arithmetic will be flawless. The result will be wrong — wrong in the specific, quiet way that computes cleanly, renders a professional document, and gets signed. Nobody re-examines a number that looks right. In compliance work, the feedback loop on that mistake is measured in audit cycles, and by the time it closes, it isn’t a bug anymore. It’s a finding.
Framed as economics, refusal is almost always the cheaper branch: the cost of a rejection is immediate, small, and lands on you; the cost of an approximation is deferred, large, and lands on your client.
Where the refusal lives matters
It’s not enough for the system to refuse; it matters where. The design I use: rejections happen at the boundary, before the computation is ever invoked. The engine itself never has to know a rule is missing — requests it can’t serve correctly never reach it.
Push scope checks into the engine and you contaminate every calculation with conditionals about what’s implemented; the “partially supported” states multiply, and eventually one of them computes. Keep them at the boundary and the engine stays a clean machine with no approximate modes — which is also what makes it testable against hand-derived expected values.
A good refusal is also specific. “Cannot process this request” is a dead end that invites workarounds. “Rejected: fiscal year predates the implemented regulation” is actionable, honest, and — not incidentally — exactly the kind of behaviour that makes an auditor trust every answer the system did give.
The agent version of the same law
Everything above predates language models, but LLMs raise the stakes, because approximation is their default behaviour. An agent asked something at the edge of its competence doesn’t crash — it produces something plausible. Plausible is the problem.
The same architecture transfers directly. An agent that escalates is useful; an agent that guesses is a liability. Concretely: every consequential action an agent can take gets a boundary check in code — is this resolvable against real data, within implemented scope, above the confidence threshold? — and everything that fails the check routes to a person, carrying the original input, the candidates considered, and the reason it stopped. In the quoting pipeline I published, unresolved lines aren’t an error state; they’re the normal case, designed to arrive at a human with everything needed to resolve them in one pass.
Saying no is a sales problem, briefly
The objection to refusal is always commercial: users hate errors. But users hate them for a reason worth respecting — most refusals are lazy. A refusal that names its reason, suggests the path (“this sector needs rules that aren’t implemented; here’s what we support”), and arrives instantly is not a worse product than a wrong answer. It’s a better one, and sophisticated buyers — the kind with auditors — know it. In three years of building this way I have never lost trust by refusing correctly. The systems that lose trust are the ones that answered confidently and wrongly, once.
Does your system know how to say no?
I design boundaries that refuse cleanly — for computation engines and AI agents alike. mail@adamshawa.com · adamshawa.com