Part V · Practice
Chapter 24
Whiteboard it cold
The whole book on one page: the three stamps, the request and the answer, the pocket numbers, the weak spots, and a thirty-minute script for explaining it at a whiteboard.
On this page
In this chapter, we will learn to draw and defend the whole design in thirty minutes with only a pen. First a cheat sheet, then a script in six steps: the picture to draw, the number to quote and the question you will be asked.
The one sentence
Let the model stamp, and let the office work. A decision model gives three kinds of typed answer with probabilities. The application computes the facts, keeps the rules, chooses the thresholds, fills the templates and acts.
The three stamps
A stamp is one typed question: Choice picks an option, Noul gives the probability of yes, and Score places the state on a scale. The request and answer shapes are from TypeSafe's documentation. The row of code constructs comes from a forum comment by TypeSafe's chief executive.
| Choice (the tray stamp) | Noul (the yes/no dial) | Score (the ruler) | |
|---|---|---|---|
| It asks | Which one of these? | Is this statement true? | Where on this scale? |
criteria in the request | an object: option name to description, up to 255 | optional: true and false descriptions | an ordered array of 2 to 10 level descriptions, level 0 first |
| The answer | choice, probabilities, confidence | noul, the probability of yes | score, probabilities, legend, confidence |
| In code it becomes | a match statement | an if statement | a sort, or a threshold |
| Use it when | the answers are a known list with no order | it is a clean yes or no and the probability is the signal | you can describe each step of a scale in words |
| At the desk | trade | may_enter | severity, levels 0 to 3 |
The request and the answer on one screen
A request is a state plus a map of questions, and the answer is a map with the same keys.
This is the desk's request for one tenant, with the middle of the message cut where the three dots are. The
question texts are those of experiments/desk.py.
{
"model": "typesafe/jev-1.13",
"state": "Tenant message:\nDear Maintenance Team,\n\nI live in flat 14B, and since yesterday evening there has been no cold water coming from any of the taps ... You may let yourselves into the flat if I am not home.",
"questions": {
"trade": {
"type": "choice",
"instructions": "Which trade should handle this request?",
"criteria": {
"plumbing": "Leaks, drains, taps, toilets, water pressure.",
"electrical": "Power, lights, sockets, fuse box.",
"heating": "Radiators, boiler, hot water, air conditioning.",
"appliance": "Oven, fridge, washing machine, dishwasher.",
"pests": "Insects, mice, rats, birds.",
"locks": "Doors, locks, keys, windows, intercom."
}
},
"severity": {
"type": "score",
"instructions": "How severe is the problem described?",
"criteria": [
"Cosmetic. Nothing stops working.",
"Inconvenient. Something works badly but the flat is usable.",
"An essential service is lost: no water, no heat, no power, no working toilet or no secure door.",
"Danger to people or to the building: fire, gas, flooding, electric shock."
]
},
"may_enter": {
"type": "noul",
"instructions": "The tenant has given permission to enter the flat while they are out.",
"criteria": {
"true": "The message clearly says staff may enter without the tenant present.",
"false": "The message does not give that permission, or asks staff to wait."
}
}
}
}
And this is what came back in experiment 0002. The answers and the usage are as stored in its
answers.json, and the model line is the snapshot named in the response. We left out the
legend, which repeats the four level descriptions, and the trade options with probability 0.
{
"model": "typesafe/jev-1.13-20260917",
"answers": {
"trade": { "type": "choice", "choice": "plumbing", "probabilities": { "plumbing": 1 }, "confidence": 1 },
"severity": { "type": "score", "score": 1.73, "probabilities": { "0": 0, "1": 0.27, "2": 0.73, "3": 0 }, "confidence": 0.73 },
"may_enter": { "type": "noul", "noul": 0.98 }
},
"usage": { "input_tokens": 684, "output_tokens": 99, "cost": 0.000028728 }
}
score 0 x 0 + 1 x 0.27 + 2 x 0.73 + 3 x 0 = 1.73 cost 684 x $0.042 / 1,000,000 = $0.000028728
The division of labour
The division of labour is the line between what the clerk judges and what the back office does. Draw this picture first, with a thick line.
tenant message
|
v
+--------------------+ state + questions +---------------------------+
| THE BACK OFFICE | --------------------> | THE CLERK |
| (ordinary code) | | (the decision model) |
| | <-------------------- | trade, severity, |
| facts, sums, | typed answers with | may_enter |
| dates, look-ups | probabilities +---------------------------+
| rule book |
| thresholds, gate | sure form letter from fixed phrases
| templates | ------------------> and the action (book the van)
| audit line |
| | unsure
+--------------------+ ------------------> Rosa, with the reason
the letter writer (a language model): only when a real letter must be written
The pocket numbers
A pocket number is a number worth knowing by heart, together with where it came from. Measured means one of our experiments printed it on 7 October 2026, on synthetic requests that gpt-5.1 wrote and labelled, from one laptop (Jev through OpenRouter, gpt-5.1 through Azure). A time with no label is a median.
| What | Value | Source |
|---|---|---|
| One call, three questions: input tokens | 694 on average | measured, 0002 |
| Time for that call | median 251 ms, 95th percentile 386 ms | measured, 0002 |
| Cost of that call | $0.000029, so $0.029 per 1,000 requests | measured, 0002 |
| Correct on 215 requests: trade, severity (exact level, within one level), may_enter | 99.5%, 92.6% and 99.5%, 100% | measured, 0002 |
| All three right on one request | 92.1%; gpt-5.1 96.7% at 1,064 ms and $0.756 per 1,000 | measured, 0002 and 0003 |
| 1 question against 100 in one call | 222 ms against 305 ms, on 12 requests | measured, 0007 |
| The whole desk | 87.9% answered automatically, 98.9% of those right. gpt-5.1 writing the reply: 88.8% right, 1,281 ms, $0.953 per 1,000 | measured, 0017 |
| A catalogue of five candidates, nine questions, no gate | whole reply right on 89.7% of 107, 234 ms | measured, 0030 |
The confidence formulas
Confidence is one number between 0 and 1 that says how peaked the probabilities are. The formulas are published by TypeSafe. In experiment 0014 they matched the returned values within 0.006.
Choice (p_max - 1/n) / (1 - 1/n) n options, p_max the top probability
six options, top 0.96: (0.96 - 0.167) / (1 - 0.167) = 0.95
Score max(0, 1 - spread / even_spread)
spread = sum of p x distance from the most likely level
even_spread = the same for equal probabilities, from the middle: 1.0 for four levels
0, 0.27, 0.73, 0: spread = 0.27 x 1 = 0.27 1 - 0.27 / 1.0 = 0.73
Noul no confidence is returned. If you want one: |2p - 1|
p = 0.98: |2 x 0.98 - 1| = 0.96
The weak spots and their fixes
A weak spot is a kind of input on which the stamps are less reliable, paired with what the back office does about it. Every number is ours, with its experiment.
| Weak spot | What we measured | The fix |
|---|---|---|
| Vague Score levels | 29.6% with bare labels, 88.0% with described levels, on 108 requests (0006) | Describe a situation for every level |
| Arithmetic | 92% from raw line items, 100% when code sent the total (0009). All 8 misses were among the 15 quotes within 60 of the limit (0038) | Compute in code, send the result |
| Dates near a limit | 100 distinct date pairs: 93 right from raw dates, 100 when code sent the days. All 7 misses were open exactly 14 days (0041) | Compare dates in code |
| The wording of a comparison | Raw dates, 100 varied date pairs per wording (0040): "more than 14 days" right on 94, and on 15 of 20 at exactly 14 days; "at least 15 days" on 97; "14 or more days" on 79. Spelling out that exactly 14 is not more than 14 made it worse: 68 | Send days_open: 100 of 100 distinct cases (0041) |
| Numeric dates such as 08/10/26 | Extracting month and day as Choices, the documented fix, on 90 distinct dates (0041). Day 1 to 12: 7 of 34 right with no format line, 34 of 34 with one that the questions name. Day 13 to 31: 56 of 56 either way | Give the date format in the state, or split the string in code: 90 of 90 |
| Text that steers | A fake staff note forced level 3 on 100%, for Jev, gpt-5-mini and gpt-5.1 (0012) | Fence the message in the instruction: 0% for Jev in the same test |
| A paper that fits no tray | Forced into a trade, at confidence 0.9 or more on 24 of 40 (0025) | Offer other: it took 38 of 40 |
| Hesitant answers | Severity confidence below 0.50: 38.5% right (0004) | Gate them to a person |
| Very long option lists | 100% at 6 options, 92.5% at 255 (0011). Four of the six misses chose "painting" for a marked surface: partly our label (0033) | Test at your size, and read the misses |
| Other languages | Severity 96.7% in English, 90.0% to 95.0% in five others (0013) | Test your language first |
| Two problems in one message | One of the two was dropped, at confidence 0.95 (0019, one message) | Not solved in this book |
| Option order | Six orders against one order six times (0042, 0044): the trade changed on 4 of 291 requests against 0, and on 3 of 60 close calls against 2. Every flipped message was torn between two trades. On close calls the winner's probability moved by a median of 0.07 against 0.03. The first-listed option won 16.5% and 15.0% of calls (16.7% with no effect): no lean to the first position | Shuffle the options on a sample and gate the close calls. Longer lists: not tested |
| Repeats | 100 requests sent 10 times each: no trade changed, the route changed on 5 (0032) | Expect requests near a line to cross it, and test for it |
The two APIs side by side
The two APIs are TypeSafe's, which we called through OpenRouter, and OpenAI's Decisions API, which we could not call. The right-hand column comes from OpenAI's published guide and nothing else.
| Jev (TypeSafe) | OpenAI Decisions API | |
|---|---|---|
| Endpoint | POST https://api.typesafe.ai/v1/systemone | POST https://api.openai.com/v1/decisions |
| Model | jev-1.13.0, alias jev-latest | gpt-6-luna, public beta |
| What to judge | state: string, object or array, text only | input: a string, or messages with text and images |
| Questions | a map from your id to a question | an array, each question with a name |
| Yes or no | noul, answer field noul | predicate, answer field probability |
| Options and levels | criteria for both | choices and levels, arrays of small objects |
| Confidence | returned for Choice and Score, formulas published | returned for choice and score, no formula in the guide |
| A refusal answer | none | possible: an answer of type refusal |
| Price per million input tokens | $0.042, output free | $0.10, no output charge |
Thirty minutes at the whiteboard
The script is six steps of five minutes: a picture, a sentence, a number, and the question that follows.
| Minutes | Draw | Say | Quote | You will be asked | The honest answer |
|---|---|---|---|---|---|
| 0 to 5 | A desk, a clerk, three stamps | "The model only stamps: which tray, how sure of yes, where on the ruler. It never writes." | Three questions in one call: 694 tokens, 251 ms, $0.000029 | "Is this not just classification?" | Mostly, yes. What is new is the interface: typed answers, probabilities and many questions in one cheap call. |
| 5 to 10 | State and questions going in, answers coming out | "You write the question and every allowed answer. The model returns one, with its probabilities." | Trade 99.5%, severity 92.6% exact, permission 100%, on 215 requests | "How does it compare with a large chat model?" | gpt-5.1 got all three right on 96.7% against 92.1%, and it wrote the test data. It was about 4 times slower and 26 times dearer. |
| 10 to 15 | The thick line: clerk on one side, back office on the other | "If code can compute it, code computes it, and sends the result." | A sum: 92% from raw items, 100% when code sent the total | "Why not let the model add up?" | The documentation says it is not a calculator, and our test agrees. |
| 15 to 20 | A fork after the clerk: sure to a form letter, unsure to Rosa | "The answer says what. The confidence says whether to act." | 94 of 107 answered automatically, 93 right. 13 to a person, 3 of them wrong | "Can I trust the probabilities?" | At the ends they held in our test. The middle depends on whose truth you use: of 30 requests given 0.5 to 0.7 for danger, 20.0% were dangerous by our severity label and 73.3% by a vote of three model readers. |
| 20 to 25 | The list of weak spots beside the fork | "It slips on sums and dates near a limit, and it believes what the paper says." | A fake staff note: level 3 on 100%. Bare labels: 29.6% | "So a user can steer it?" | Yes. A fenced instruction brought it to 0% in our test. Separate fields were not enough: 31 of 60 still moved. |
| 25 to 30 | Two price tags and a box marked "unknown" | "It is cheap enough to ask many questions, and here is what we could not check." | $0.029 per 1,000 against $0.953 for gpt-5.1 writing the reply | "How does it work inside? And what about OpenAI's?" | Not disclosed. And we could not call OpenAI's API, so we know only its guide. |
slower 1,064 / 251 = 4.2 times dearer 0.756 / 0.029 = 26 times handed on 107 - 94 = 13 requests
What we do not know
A book about probabilities should say where its own knowledge stops.
- The inside of Jev. TypeSafe names a new architecture, a parallel sampler and a training method called RLCD. It has published no paper. Every mechanism in this book is a hypothesis.
- OpenAI's Decisions API in practice. We never called it. Its accuracy, speed and token counts on our requests are unknown to us.
- Real mail and human labels. gpt-5.1 wrote and labelled every request of the dataset. The three readers of experiment 0029 were models too. No person has labelled a single row, so calibration against human truth is open. Even which way of getting a probability is best depends on the labels. By Brier score (lower is better), Jev was best of the four ways of experiment 0018 against the severity label, at 0.080. Against the readers the four scored 0.063 to 0.073 and Jev was not the best, though gpt-5.1 was a reader (0038).
- Speed from a server. Our times include a laptop's connection and OpenRouter. We did not test the published rate limits.
- Other versions and other days. Everything ran against one snapshot,
typesafe/jev-1.13-20260917, on one day. - Voice with sound. Experiments 0016 and 0034 used typed sentences, not audio.
- Patterns we only read about. Composite scoring, reranking and self-consistency are published by TypeSafe and not tested by us.
What we tried and could not reproduce. TypeSafe documents these weak spots. Our tests were small and clean, and they did not show. That does not clear the model.
- Scoping words. "At least one", "all", "only" and "none" were right on 100% of 196 different requests (0022).
- Indirection. Two look-ups through a list of eight tenants: right on 100% of 80 cases (0023).
- Contradictory criteria. With the true and false criteria swapped, the permission Noul was still right on 100% of 108 (0031).
- A crowded state. With up to 150 unrelated old messages, no answer lost more than one request in 60 (0008).
Try it yourself
Close the book. Draw the division of labour and write the three stamps table from memory. Then explain the six steps against a timer to a friend, who interrupts with the questions in the fifth column.
Common questions
Which three numbers should I remember?
251 milliseconds for a call with three questions, $0.029 per 1,000 requests, and 29.6% against 88.0% for bare labels against described levels: speed, cost and the main lever, wording.
What if someone asks for a number I do not have?
Say that we did not measure it, and say what would measure it.
May I quote the vendor's speed claims?
Yes, as the vendor's. TypeSafe says "about 100 ms" on one page and "70ms-500ms" on another. Our median was 251 milliseconds through OpenRouter from a laptop.
Is the pocket table still true next year?
The method is. The numbers belong to one model version on one day. Re-run the experiments against the version you use, which is what Chapter 15 asks for.
Carry this
- One sentence: let the model stamp, and let the office work.
- Three stamps, three code constructs: Choice and
match, Noul andif, Score and a sort or threshold. - Draw the thick line, then the fork: sure to a template, unsure to Rosa.
- End with what is not known: the inside of Jev, OpenAI's API in practice, and real mail.
Check yourself
1. A Choice with four options returns a top probability of 0.70. What is its confidence?
Answer
even split 1 / 4 = 0.25 confidence (0.70 - 0.25) / (1 - 0.25) = 0.45 / 0.75 = 0.60
These are invented probabilities, put through the published formula.
2. Someone asks: "You said 98.9% right. So the desk is 98.9% accurate?" What is the precise answer?
Answer
No. 98.9% is 93 right out of the 94 requests the desk answered by itself. The other 13 of 107 went to a person, and the model's level was wrong on 3 of those. The gate is part of the result.
automatic and right 93 / 94 = 98.9% answered automatically 94 / 107 = 87.9%
3. Name two rows of the side-by-side table that you would have to mark "not verified by us", and say why.
Answer
Every row of the OpenAI column, for example the refusal
answer and the $0.10 price. We had no key and could not call the API, so all of it comes from the published
guide.