Skip to main content
A Decision evaluates one shared input against one or more independently answerable questions. Keep each question narrow: use the primitive whose result your application can consume directly, give it a stable ID, and make its criteria or options concrete.

Text or structured state

Input does not have to be JSON. A string is valid and is wrapped as text automatically:
Use JsonContent when field names add useful context:
JsonContent::text(), object(), list(), from(), and fromJson() preserve the root kind. The same value type is accepted for question instructions, option descriptions, criteria descriptions, and Score levels.

Noul: probability of yes

Use Noul for a binary proposition. Its answer is one probability in [0, 1]: the probability that the proposition is true.
A result near 1 supports yes, a result near 0 supports no, and a result near 0.5 is uncertain. Noul intentionally has no separate confidence field: the probability is the result.

Choice: winner from a closed set

Use Choice when exactly one application-owned option should win. Option IDs are strings and remain strings even when they look numeric.
The provider must choose from this closed set. Add an explicit other, unknown, or not_applicable option when the named choices are not exhaustive. Choice requires at least one option, and option IDs must be unique. Dynamic options are ordinary typed values, so they can be built from current application state:

Score: position across ordered levels

Use Score when the application needs an ordered judgment. Levels are indexed from 0 in the order supplied and must contain at least two entries.
The result is the probability-weighted position across those indexes, so it may be fractional. For example, 1.4 lies between the second and third supplied levels; it is not an arbitrary rating on a hidden scale. Make adjacent levels concrete, distinct, and independently understandable.

Group questions over shared state

Use Questions::of() to evaluate several independent judgments over the same state in one request:
Question IDs must be unique. An executable DecisionRequest requires at least one question. Use Questions::question($id) to inspect a definition and all(), count(), or toArray() when building tooling around a collection. Do not make one question depend on another answer inside the same request. Execute a second Decision when a later judgment genuinely depends on the first result.

Portable question payloads

Every question and collection supports toArray(). Questions::fromArray() reconstructs the discriminated noul, choice, and score variants:
Unknown fields, unknown question types, duplicate IDs, invalid probabilities, empty option sets, and invalid level sets fail early with InvalidArgumentException instead of being forwarded as ambiguous provider input.