A typed verdict, not a paragraph
Make the verdict machine-readable so the decision is taken by a node — and meet the boolean that fails open on the approve branch.
The reviewer has an opinion. Something now has to route on it, and a gate that searches for the word “approved” somewhere in a paragraph is not a gate — it is a substring match with consequences.
So the verdict comes back as JSON, is parsed by a node, and is read as a field. Three nodes, in this order:
Verdict → parse → route
The reviewer returns JSON; a transform parses it; a condition compares one field. The decision is made by the third one.
Scroll for all 12 steps →
This is the verdict from a real run, unedited:
{
"decision": "approve",
"score": 5,
"account_name": "Nimbus Retail",
"violations": [],
"critique": "The proposed resolution correctly denies a cash refund as per policy,
offers appropriate non-cash remedies, escalates the repeat incident,
notifies the account manager, and includes all affected accounts."
}The point is not that the model returns typed JSON. It is that the decision is taken by a node. The model produces a value; a comparison — not a paraphrase, not an inference — decides what happens next. Every hard rule in this course is a condition node, and a proposal that reaches the gate has already had its judgement converted into something that cannot be argued with.
Three ways this breaks, all of them quiet
| The mistake | What happens | The fix |
|---|---|---|
| asking for a boolean and comparing it to “true” | the template boundary hands the condition Python’s True and False — capitalised — so the approve path silently never matches while the reject path appears to work | have the model emit a lowercase string and compare that |
| writing the response format as a plain string | it passes validation as valid and runnable, then fails at run time with “expected an object, but got a string” | it is an object with a type inside it |
| using words instead of symbols in the condition | the operator must be ==, not equals | the validator catches this one and names the allowed set — run it |
asking for a boolean and comparing it to “true”
- What happens
- the template boundary hands the condition Python’s
TrueandFalse— capitalised — so the approve path silently never matches while the reject path appears to work - The fix
- have the model emit a lowercase string and compare that
writing the response format as a plain string
- What happens
- it passes validation as
validandrunnable, then fails at run time with “expected an object, but got a string” - The fix
- it is an object with a type inside it
using words instead of symbols in the condition
- What happens
- the operator must be
==, notequals - The fix
- the validator catches this one and names the allowed set — run it
The fields worth having, beyond the decision
- A score. Not for the gate — for the audit row and for you, reading twenty runs later and asking which ones were marginal.
- The violations, as a list. So an escalation can say what was wrong, and so you can count which rule fires most often. Do not interpolate that list into a message body — see lesson 17.
- A critique. The only field written for a reader, and the one the correction loop feeds back.
A note on providers. Object-mode responses are enforced by some providers and merely encouraged by others; where they are not enforced, a model can still return prose and your parse step will fail. That is the correct place for it to fail — loudly, before the gate — but build knowing that the guarantee is not universal.
Related lessons
Base rates — what a piece of evidence is actually worth
A face-recognition system that is 99.9% accurate and almost entirely wrong, and a number that sent an innocent woman to prison. Both are the same arithmetic, and it is the arithmetic that decides what any piece of evidence is worth.
ReadConfirmation and survivorship — what you never looked for
Two questions about evidence you did not go looking for. One is a rule you have to discover, and one is a pattern in five famous people — and in both, the thing that would have told you the truth is the thing nobody checks.
ReadLoss aversion, sunk cost and regression — what it costs you
Four questions you answer about yourself rather than about a scenario, and your own answers are the finding. Then the pattern that makes praise look useless and criticism look like it works, whatever you actually do.
Read
