Choice, Score and Noul: Designing Typed Questions for Content Workflows
A team wires a decision model into their publishing pipeline, then watches it misfire in ways nobody can debug.
A team wires a decision model into their publishing pipeline, then watches it misfire in ways nobody can debug. A Score question meant to grade editorial readiness keeps landing on "almost ready" for pages that are clearly broken, because the levels were never described in words. A Choice router sends legal-sensitive drafts straight to publish, because the option list had no "escalate to a human" branch and the model picked the closest wrong answer. The model did exactly what it was asked. The questions were the bug.
TypeSafe AI's Jev, released on 15 September 2026 as the first "System One model," makes this failure mode common. It reads state you hand it, answers typed questions you define, and stops. It writes no prose and no rationale, so the quality of every decision is set before the call, by how you wrote the question. Choice, Score, and Noul are the three shapes those questions take, and most of the pain builders reported since launch came from writing them badly.
This guide is the practical design manual: when to reach for each type, how to write option lists and scales that hold up, and why the question is a content-modelling problem first. That last part is why it sits here. Sanity, the AI Content Operating System, keeps content structured and queryable, which is what lets you hand a typed model the exact field a question is about instead of a wall of markup.

When do you use Choice, Score, or Noul?
Pick the question type by the shape of the answer you need, not by the topic. Choice, Score, and Noul are the three typed questions Jev answers, and each fits a different decision shape.
Choice picks one option from a set you define, up to 255 options, and returns the winner, a probability for every option, and a confidence value. Reach for it when the answer is one label from a known, mutually exclusive set. A content-workflow example: routing an inbound support draft. The question is "Which team owns this ticket?" with options billing, technical, account management, abuse, and other. The model returns one owner plus a probability across all five.
Score places the state on an ordered scale of 2 to 10 verbally described levels, and returns a probability-weighted position that can land between levels. Reach for it when the answer is a position on a gradient rather than a category. Example: grading a draft's editorial readiness on a four-level scale from "blocking issues" to "publish-ready." The returned 2.6 tells you more than a rounded "level 3" would, because it says the draft sits between "needs edits" and "minor polish."
Noul is a yes/no question returning a single number from 0 to 1, the probability the answer is yes, with no separate confidence field because the probability is the certainty measure. Reach for it when you need one belief about one fact. Example: "Does this product description make a medical claim?" A 0.88 is both the answer and its certainty. Match the type to the answer's shape and half the design work is already done.
How do you write a good Choice option list?
A good Choice option list is mutually exclusive, carries an explicit "other," describes each option instead of naming it bare, and is derived from the content model rather than typed into code by hand. Get the list wrong and the model returns a confidently wrong valid answer, because Jev's format guarantee fixes the answer space, not the correctness inside it.
Mutually exclusive matters because overlapping options split probability. If "pricing question" and "billing question" both appear, the model spreads belief across two labels that mean nearly the same thing, and neither wins cleanly. Collapse them or draw a sharp line in the descriptions.
The explicit "other" option is the single most important habit. Best practice is to include it so the model can say nothing fits rather than picking the closest wrong answer. Without it, a page that belongs to no category still gets forced into one, and you never learn your taxonomy has a gap.
Option descriptions beat bare labels because a label like "technical" means whatever the model guesses it means. A described option, "technical: bug reports, integration errors, and API failures," pins the boundary you actually intend.
The deepest habit is deriving the option set from the content model. A schema already defines answer spaces: enumerated fields, references to taxonomy documents, content types, and workflow states are Choice sets that exist before anyone writes a prompt. In Sanity, an enumerated field or a set of references to taxonomy documents is queryable with GROQ at request time, so the option list you pass Jev is read from the same content model editors already maintain, not a copy in application code that drifts out of sync with it.
How do you write a good Score scale?
A good Score scale describes every level in words, keeps the levels evenly spaced in meaning, and uses the between-level position rather than rounding it away. Jev places the state on an ordered scale of 2 to 10 levels and returns a probability-weighted position, so a vague scale produces a vague number.
Describe every level, not just the endpoints. A scale that says only "1 is bad, 5 is good" leaves the middle three levels undefined, and the model invents boundaries you did not choose. Spell them out: for editorial readiness, "1: blocking factual or legal issues; 2: substantive edits needed; 3: minor polish only; 4: publish-ready." Now the returned position means something you can act on.
Even spacing in meaning keeps the scale honest. If levels 1 through 3 cover shades of "broken" and level 4 alone covers everything acceptable, the scale is lopsided and most real drafts pile up at the top with no resolution between them. Space the levels so each covers a comparable slice of the range you care about.
The between-level position is the reason to use Score at all. Jev can land on 2.6, and that fractional position carries information a rounded integer throws away. A 2.6 says the draft sits closer to "minor polish" than "substantive edits," which is exactly the signal a review queue wants when deciding what a human looks at first.
Remember what Score is bad at. Jev is unreliable at counting and treats dates as text rather than ordered quantities, so do not build a scale that secretly asks it to count occurrences or reason about how recent something is. Score is for judged position on a described quality gradient, not for arithmetic dressed up as levels.
How do you write a good Noul, and when do you split questions?
A good Noul asks about one fact, phrased so that "yes" is unambiguous, and you ask one Noul per item rather than asking the model to count across many. Noul returns a single number from 0 to 1, the probability the answer is yes, and that probability is the whole answer, so ambiguity in the question becomes noise in the number.
One fact per question is the core rule. "Does this description make a medical or legal claim?" bundles two facts, and a 0.6 leaves you unable to tell which one tripped. Split it into two Nouls, one per claim type, and each number means one thing. Phrase each so "yes" is the clear positive case: "Does this text contain a medical claim?" reads cleanly, while "Is this text free of medical claims?" inverts the polarity and invites mistakes downstream.
Ask one Noul per item instead of one question that counts. Jev is unreliable at counting, so "How many products in this list are out of stock?" is the wrong shape. Ask "Is this product out of stock?" once per product and count the yeses in your own code, where counting is exact.
On one big question versus several small ones, the architecture settles it. Questions in a single request are evaluated independently against one shared read of the state, so a tenth question costs tokens but almost no extra time. Several narrow questions are cheap and usually clearer than one broad one. The catch: questions cannot condition on each other, because a question does not see another's answer. Dependent logic, "if this is a medical claim, then check whether it cites a source," belongs in your code, running the second question only when the first came back yes.
How do you route decisions when the model gives no reason?
You route on confidence, not just the answer, because Jev returns a decision with no rationale attached. The answer says what to do; the confidence value, or the Noul probability itself, decides whether it is safe to do automatically. This is confidence-gated routing, and it is the pattern that makes a no-rationale model usable in production.
Thresholds rise with the cost and irreversibility of a mistake. Auto-tagging a blog post can act on modest confidence, because a wrong tag is cheap to fix. Auto-publishing a page that makes a regulated claim needs a much higher bar, because the mistake ships to the public. The shape is an escalation cascade: the decision model handles the confident majority at volume, and the uncertain minority goes to a frontier model like GPT-5.6 Sol or Claude Opus 5, or to a human. Do not invent threshold numbers; evaluate them against reviewed labels before you trust them, and never convert a timeout or rate limit into a high-confidence default.
Because the model gives no reason, you build the audit trail around it. Store the returned label and the full probability distribution, not just the winner, and record what state the model actually saw. In Sanity, a Function can write the label and probabilities straight back onto the document and run the judgement again on the next change, and Workflows model the review stages as TypeScript beside the content, so "what published without legal review" becomes one GROQ query, because the process left a trail in the content repository. That surrounding telemetry is how you answer "why this decision?" when the model cannot.
One honest limit: none of this makes hostile state safe. Prompt injection still works when attacker-controlled text sits in the state, and injected text can flip an allow into a deny. A decision model shrinks what an attacker can make the system do to your option set; it does not sanitize the input for you.
Why is a typed question a content-modelling problem first?
Because the quality of a typed judgement depends entirely on the state you hand it, and the state comes from your content model. Jev has a 32,000-token state budget, so what you can pass is bounded, and structure decides whether that budget carries the exact field a question concerns or a wall of markup that buries it.
Structured content lets you pass exactly the field, block, or section a question is about. If the Noul asks whether a product description makes a medical claim, you want to hand the model that description field alone, not the entire rendered page. An HTML blob can only pass a wall of markup, and the signal the question needs drowns in navigation, boilerplate, and layout. This is where the content platform is the protagonist, not the model. Sanity, the AI Content Operating System, stores content as addressable structured data and Portable Text, so a GROQ query at request time pulls precisely the field, block, or reference the question concerns and hands it over inside the budget.
Re-judging on change is a content pipeline, not glue code you maintain. When a description updates, the typed judgement about it is stale, so it has to run again. Sanity Functions react to content changes, with event.on values create, update, and delete, which is the shipped mechanism for re-running a judgement the moment the content changes. Content Lake keeps the underlying index fresh, so freshness stops being a class of bug you own. Where the question needs ranking rather than a filter, GROQ mode blends structured filters with semantic ranking through text::semanticSimilarity(), which is only valid as an argument to score(), because semantic search ranks and does not filter, so you narrow with a filter first and then rank what is left. Design the content model well and the typed question almost writes itself.
How content platforms support typed-question workflows
| Feature | Sanity | Contentful | Strapi | Adobe Experience Manager |
|---|---|---|---|---|
| Pass the exact field as state | GROQ pulls precisely the field, block, or Portable Text section a question concerns, so the 32,000-token budget carries signal, not markup. | Structured fields exist and can be queried, but the model is coupled to storage and the editorial GUI, so extracting one field cleanly means working around a UI-defined shape. | Content types expose fields via REST or GraphQL, so a single field is retrievable, though you assemble the extraction and budgeting logic yourself. | Component and fragment models are addressable, but content lives in a heavier in-platform structure, so isolating one field for state takes more plumbing. |
| Derive Choice option sets from the model | Enumerated fields and references to taxonomy documents are read with GROQ at request time, so the option list comes from the content model rather than a copy in code. | Enumeration and reference fields exist, but the schema is defined through the GUI, so reading option sets as code-defined structure means working around a GUI-defined model. | Enumeration fields in content types can seed an option list, though you export and reshape them into the Choice set in your own application code. | Taxonomies and tag structures exist, but they are managed in-platform, so turning them into a code-side option set is an integration step rather than a query. |
| Re-judge on content change | Functions react to create, update, and delete events, and Content Lake keeps the index fresh, so re-running a judgement on change is not glue code you maintain. | Webhooks and the App Framework can trigger an external step on change, so re-judging is possible as a build you own and operate. | Lifecycle hooks fire on change and are commonly wired to LangChain.js, but keeping a judgement index fresh is glue code you build and maintain. | Workflow and event listeners can trigger downstream jobs, though re-judging is assembled as a heavier in-platform or external integration. |
| Store label plus full probabilities | A Function writes the winning label and the full probability distribution straight back onto the document, next to the content it judged. | A returned label can be written back to a field via the API, so storing the outcome is straightforward with your own write step. | You can store the label and probabilities on a document, though the write-back path is code you own end to end. | Metadata and properties can hold the label and probabilities, but writing them alongside content is a more involved in-platform operation. |
| Route low confidence to review | Workflows model review stages as TypeScript beside the content, and Content Releases stage and gate what publishes, so low-confidence items enter human review governed with the content. | Editorial workflows and roles exist for review, so uncertain items can be held, configured through the platform rather than as code beside the model. | Draft and publish states support a review step, though a confidence-gated queue is application logic you build on top. | Strong approval and workflow governance is a core strength, so routing to review is well supported, if configured in-platform rather than in source control. |
| Record what the model saw | Document history plus a Function's own write of the judged state and label leave an auditable trail, so "what published without legal review" is one GROQ query. | Version history exists, so prior states are recoverable, though linking the exact state the model saw to its output is a trail you assemble. | History depends on your setup, so recording exactly what the model read alongside its label is custom logging you own. | Robust versioning and audit tooling exist, but tying the judged state to the returned decision is assembled across platform and integration layers. |