Ask a decision model for a total and you may get a confident number that is slightly wrong. Ask it to compare two dates and it may treat them as text. Ask it for a currency amount and it may return a plausible value with no decimal. These are not model bugs in the usual sense. They are the boundary between what a fast, non-generative decision model is good at and what belongs in ordinary code.
The practical rule is simple: let the model read and classify, and let code compute. The interesting part is designing the questions so that rule survives contact with real inputs.
Counting is a code job
The jaggedness notes list counting as unreliable, with error growing as the number of items grows. The guardrail is not a better prompt. It is one Noul question per item, then a sum in code. The cookbook example counts per-item booleans rather than trusting a single “how many?” answer.
That pattern generalizes. If you need to know how many line items are missing a field, ask one Noul per line item and count the true answers. If you need a total, ask for the components and add them yourself. If you need to compare magnitudes, ask for the level and compare in code.
Dates are text until you make them components
The date-extraction cookbook is the template. It asks seven Choice questions about a date's shape and parts (mode, month, day, year from 1900 to 2050, and weekday) and does no arithmetic in the model. Code resolves the parts against a pinned TODAY and infers missing years. On the cookbook's six examples, five were auto-accepted. An absent kickoff date returned none at 0.46 confidence, with a note that the absolute date was incomplete.
The conventions matter as much as the questions. Bare weekdays mean the next occurrence on or after today; “next” means the following calendar week. Anything under 0.60 confidence goes to a person. Those are policy decisions, and they belong next to the code that resolves the date, not in a prompt the model may reinterpret.
The same logic applies to durations, ages, deadlines, and reporting periods. Extract the components, then compare or subtract in code.
Amounts and units need a verbatim source
The pre-parsed extraction cookbook solves a different half of the problem. Regex finds candidate emails, phone numbers, and amounts; Jev picks the requested span. Because the model only chooses among spans that code already found, the returned value is copied verbatim and cannot be invented. In the cookbook, a receipt email was picked at 0.98, a cell number normalized to +14155550177, and an invoice total read as $1,315.50. A $50.00 courtesy credit was flagged at P(credit) 0.99. Amounts parse to Decimal in code.
That is the strongest pattern for numeric values: do not ask the model to produce the number. Ask it to identify which candidate is the one you want, then copy the candidate.
The caveats are practical. Choice caps at 255 options, and candidates without a regex (names, for example) need a roster, NER, or an LLM to generate them. The model is doing selection, not extraction from free text. That is exactly why the value is trustworthy.
Score levels are not a ruler
The jaggedness notes warn that Score levels are weak at numeric calibration. If you ask for a severity score from 1 to 5, you can use the level as an ordinal judgment, but you should not interpolate an exact magnitude between levels. “3.7” is not a measurement; it is a number the model produced because the interface allowed it.
The composite-scoring pattern handles this well. It asks four Score questions in one parallel request, normalizes each score by dividing by len(criteria) - 1, and combines them with weights in code. The weights are policy, not model output. That keeps the model on the part it does well (placing a candidate on an ordered scale) and keeps the arithmetic where it can be tested.
The primitives guide is the reference for which primitive to use. Choice for a label, Score for an ordered level, Noul for a yes/no or a probability. If the decision needs a magnitude, ask whether the magnitude is really a level in disguise. If it is, use Score and treat it as ordinal. If it is a count or a total, use code.
Normalize the units before the state
A model sees what is in the state. If one field is in cents and another in dollars, the model has no reliable way to know. Normalize units before the request: currency to a single base, durations to a single unit, dates to ISO components, and measurements to the unit the policy uses.
The advanced structure guide allows structured JSON in criteria and instructions, which helps. You can give the model a legend or a schema that says what each field means. But a legend does not replace normalization. It documents the convention; it does not enforce it.
For mixed inputs, include the raw value and the normalized value in the state, and ask the question about the normalized field. The state design guide calls this out as a general rule: include the material the model cannot infer, and leave out conclusions. A normalized number is material. A verdict about whether the number is acceptable is a conclusion.
A short checklist
- Count in code, one Noul per item, then sum.
- Extract date components with Choice, then resolve and compare in code.
- Find candidate amounts with regex, ask Jev to pick, and copy the span verbatim.
- Parse money to
Decimal; never trust a float from a language model. - Treat Score levels as ordinal, not as a calibrated ruler.
- Normalize units before the request, and document the convention.
- Send low-confidence dates and amounts to review rather than guessing.
The pattern is consistent across all of them: the model reads and chooses, and code owns the math. Once that boundary is explicit, the numeric failures become testable instead of mysterious.