Create your own
Lesson illustration

Decomposing Business Judgments into Atomic Decisions

Welcome. A production decision such as “should we automatically refund this customer?” often sounds like one question, but it is usually a bundle of different judgments, policy constraints, and safety checks. The useful Jev design move is to expose that bundle: ask Jev only for the small fuzzy judgments, then make the business decision in deterministic code.

In this lesson, you will turn a compound support decision into a set of independently inspectable questions and a deterministic composition function. This is a core pattern for building systems that can be tuned, tested, and safely changed without repeatedly rewriting a large prompt.


From a vague verdict to a decision contract

Consider this product requirement:

“Automatically refund customers who were charged twice, unless the case is risky or outside policy.”

That is not one model judgment. It contains at least four kinds of work:

Kind of workExampleBest owner
Structured factIs the order within the 30-day refund window?Deterministic code / database
Language judgmentDoes the customer explicitly request a refund?Jev
Language judgmentDoes the message report a duplicate charge?Jev
Business policyIs automatic refund allowed for this amount?Deterministic code
Safety ruleShould this case be escalated rather than automated?Deterministic code using Jev signals

The distinction matters. A model can judge what a customer appears to be asking, but it should not silently invent your refund limits, perform a payment action, or decide that a high-risk exception is acceptable.

The hierarchy places deterministic code at the bottom for explicit rules, Jev in the middle for bounded fuzzy judgments, LLMs for open-ended generation, and humans for unresolved or high-consequence decisions. This lesson focuses on turning a business requirement into the Jev and deterministic-code layers.

A useful mental model is:

  1. Jev produces typed evidence about ambiguous input.
  2. Your code applies policy to that evidence and to authoritative structured facts.
  3. A fallback path handles uncertainty and exceptions.

This means that “auto-refund” is an output of your application—not an opaque conclusion handed over to the model.

Jev - The Ultimate Classification Model?

Watch Sam Witteveen’s “Jev - The Ultimate Classification Model?” for a compact explanation of why a broad business analysis should be broken into small judgments and composed in normal application code.

Watch the decomposition idea. Focus on the contrast between asking for one vague business verdict and asking several narrow, intuitive questions whose relative importance is controlled by code.


The atomic-question principle

An atomic question asks about one observable property of the supplied state. It should be answerable quickly by a knowledgeable person who has the relevant evidence.

For a support message, compare these two approaches.

Compound question — avoid

“Should we auto-refund this customer, prioritize the case, decide whether it is fraud, and determine the right support team?”

This mixes four unrelated outputs. If the decision is wrong, you cannot tell whether the model misunderstood the request, your policy was unclear, the priority logic was flawed, or the safety concern was misclassified.

Atomic questions — prefer

  • Does ticket.message explicitly request a refund or account credit?
  • Does ticket.message report a duplicate charge?
  • Does ticket.message contain a request to disclose a sensitive credential?
  • How frustrated does the customer appear?
  • Which team owns the customer’s primary request?

Each answer now has a clear meaning, a stable ID, an appropriate question type, and a separately testable role.

Primitives (Questions)

Read Typesafe AI’s “Primitives (Questions)” guide for the core design rule: ask a focused judgment per question, then combine independent signals in application code.

In the section “Ask for one snap judgment per question,” read the focused-judgment discussion. Notice the distinction between a rapid classification and a request that secretly requires several steps of analysis. Then, in “Split a complex judgment into several questions,” read the composite-scoring explanation, and continue to the end of that subsection. Focus on why weights and combination rules belong in code rather than in an all-purpose prompt.

“Independent” does not mean unrelated

Here, independent means that each question evaluates a distinct property and can be interpreted on its own. The questions may inspect the same customer message and may be correlated in real data.

For example, urgency and frustration often co-occur. They are still valid separate questions if your product treats them differently:

  • urgency might affect SLA routing;
  • frustration might affect queue priority or retention handling.

A poor split is one where one question merely repeats another in different words:

  • “Is the customer angry?”
  • “Does the customer sound upset?”
  • “Is the customer dissatisfied?”

Unless these terms are given operationally different definitions, they create duplicate noisy signals rather than useful evidence.


A repeatable decomposition method

Start with the action, not with a question. Write the decision as a contract your code can enforce.

For the refund workflow:

The system may issue an automatic refund only when the customer explicitly requests one, the message reports a duplicate charge, transaction records support that claim, the amount is below the automatic-refund cap, and no safety rule requires review.

Now classify every component.

1. Extract deterministic facts first

Do not ask Jev to decide things your system already knows exactly.

type RefundFacts = {
  ticketIsOpen: boolean;
  paymentWasSettled: boolean;
  duplicateChargeFoundInLedger: boolean;
  orderAgeDays: number;
  amountCents: number;
  previousRefundExists: boolean;
};

From these facts, normal code can determine whether a refund is structurally possible. For example, the application can calculate whether orderAgeDays falls inside a 30-day window and whether amountCents is below a policy limit.

This also reduces unnecessary state sent to the model. Jev should receive evidence that helps it make the language judgments, not your entire customer database.

2. Identify the irreducibly fuzzy judgments

Now isolate what must be inferred from language or unstructured evidence.

Question IDTypeAtomic propertyWhy it is separate
refund_requestedNoulThe customer explicitly asks for a refund or creditA complaint is not necessarily a request
reports_duplicate_chargeNoulThe message claims the customer was charged twiceA refund can be requested for other reasons
credential_requestNoulThe message asks someone to disclose a password, API key, or similar secretA safety signal should override automation
customer_frustrationScoreThe degree of expressed frustrationUseful for queue priority, not refund eligibility
topicChoiceThe primary team that owns the requestUseful for routing, independently of refund action

Notice the deliberate separation between what the customer claims and what your payment ledger proves. Jev can classify the former; your services should verify the latter.

3. Give each signal one job

A question becomes clearer when its downstream purpose is explicit.

  • refund_requested participates in refund eligibility.
  • reports_duplicate_charge participates in refund eligibility.
  • credential_request is a safety override.
  • customer_frustration sets service priority after routing.
  • topic selects the support queue.

If a question appears only because it “might be useful later,” either define its purpose or omit it. Extra signals are cheap to run together, but every signal included in production policy should have a documented meaning and owner.

4. Define terms at the boundaries

The important edge case is often the difference between two nearby concepts:

Ambiguous wordingOperational distinction
“I was charged twice. What happened?”Duplicate-charge report, but not necessarily a refund request
“Please return the duplicate charge.”Duplicate-charge report and explicit refund request
“Why is my payment pending?”Payment problem, but not a duplicate charge
“Send me your API key so I can investigate.”Credential request; escalate or block, regardless of topic

This is where clear criteria matter. “Detect refund intent” is underspecified; “require an explicit request for money back or account credit” is a decision boundary.


Design the questions around the state

A question should point to the evidence it needs. A minimal state for this workflow might look like:

const state = {
  ticket: {
    message:
      "I was billed twice for order A-104. Please refund the extra charge.",
    channel: "email",
  },
  order: {
    id: "A-104",
    amountCents: 2499,
    purchasedAt: "2026-02-18T10:12:00Z",
  },
  policy: {
    sensitiveCredentials: ["password", "security code", "API key"],
  },
};

The corresponding question specifications should make their scope explicit. The following is a conceptual TypeScript representation of the contract; the precise SDK construction can vary, but the design intent should remain the same.

const decisionQuestions = {
  refund_requested: {
    type: "noul",
    instructions:
      "Does `ticket.message` explicitly request a refund or account credit?",
    trueMeans:
      "The customer directly asks for money back or a credit.",
    falseMeans:
      "The customer complains or asks a billing question without requesting a remedy.",
  },

  reports_duplicate_charge: {
    type: "noul",
    instructions:
      "Does `ticket.message` report that the customer was charged more than once for the same purchase?",
    trueMeans:
      "The message claims duplicate or repeated billing for one purchase.",
    falseMeans:
      "The message describes a different payment issue, such as a pending charge.",
  },

  credential_request: {
    type: "noul",
    instructions:
      "Does `ticket.message` ask the recipient to disclose a credential listed in `policy.sensitiveCredentials`?",
    trueMeans:
      "It asks for the credential itself, such as a password or API key.",
    falseMeans:
      "It does not request a credential. A legitimate password-reset instruction is not a request to disclose one.",
  },
};

The wording avoids hiding multiple judgments inside any one question. In particular, reports_duplicate_charge does not ask whether the claim is true, whether it meets policy, or whether the refund should be issued.


Compose answers in deterministic code

Once Jev returns typed answers, policy becomes regular application code. This is where you encode the decision order, thresholds, and overrides.

type NoulAnswer = {
  noul: number;
  confidence: number;
};

type RefundSignals = {
  refundRequested: NoulAnswer;
  reportsDuplicateCharge: NoulAnswer;
  credentialRequest: NoulAnswer;
};

type RefundDecision =
  | "auto_refund"
  | "route_to_billing"
  | "human_review"
  | "security_review";

function decideRefund(
  facts: RefundFacts,
  signals: RefundSignals,
): RefundDecision {
  const isWithinRefundWindow = facts.orderAgeDays <= 30;
  const isBelowAutoRefundCap = facts.amountCents <= 5_000;

  if (!facts.ticketIsOpen || !facts.paymentWasSettled) {
    return "route_to_billing";
  }

  if (signals.credentialRequest.noul >= 0.70) {
    return "security_review";
  }

  const intentIsUncertain =
    signals.refundRequested.confidence < 0.75 ||
    signals.reportsDuplicateCharge.confidence < 0.75;

  if (intentIsUncertain) {
    return "human_review";
  }

  const mayAutoRefund =
    signals.refundRequested.noul >= 0.80 &&
    signals.reportsDuplicateCharge.noul >= 0.80 &&
    facts.duplicateChargeFoundInLedger &&
    isWithinRefundWindow &&
    isBelowAutoRefundCap &&
    !facts.previousRefundExists;

  if (mayAutoRefund) {
    return "auto_refund";
  }

  return "route_to_billing";
}

Several design choices are worth noticing:

  1. Safety rules come first. A credential-related signal overrides the normal refund route.
  2. Confidence is not the same as probability. The noul value expresses support for the proposition; confidence helps determine whether to automate or review.
  3. The ledger remains authoritative. A customer’s report of duplicate billing is evidence, not proof.
  4. Thresholds live in code. Changing the automation threshold from to is an explicit policy change that can be tested and reviewed.
  5. Every route is observable. You can log the result, input facts, selected signals, and the specific rule that produced the outcome.

The exact numbers above are initial policy values, not universal settings. Later, you would calibrate them using real labeled outcomes and the cost of incorrect automation versus human review.


Rules, weights, and decision order

Not every compound decision should use the same composition mechanism.

Use deterministic rules when all required conditions must hold or when one condition is a hard stop:

  • issue a refund only if both intent and ledger evidence are strong;
  • never auto-approve when a security cue is present;
  • always send orders above a monetary limit to review.

Use a weighted score when multiple independent factors contribute gradually to a ranking or priority. For example, a support queue could combine severity, customer frustration, and account tier:

The weights are product policy. They should not be implied by prose inside a model prompt, because product owners may need to change them independently of question wording.

A common mistake is to use a weighted average for a safety-critical veto. If credential_request is a security boundary, it should normally be an explicit rule, not merely a small negative weight that can be outweighed by other signals.


Review the design with concrete cases

Before connecting a live API call, run the decision contract mentally against representative cases.

CaseKey signals and factsExpected deterministic result
“I was charged twice. Please refund the extra charge.” Ledger confirms duplicate charge; amount is below cap.Strong explicit request, strong duplicate-charge report, valid policy factsauto_refund
“Why was I charged twice?” Ledger confirms duplicate charge.Report exists, but no explicit remedy requestedroute_to_billing
“Refund my duplicate charge immediately.” Amount exceeds the cap.Strong language signals, but outside automation limitroute_to_billing or human_review, per policy
“Send your API key to process my refund.”Credential-request signal is highsecurity_review
“I need help with a charge.”Broad, uncertain intenthuman_review or billing route, depending on your confidence policy

These examples expose whether the questions are truly atomic and whether the composition logic reflects the product requirement. They also become the beginnings of a regression suite once you record real responses.


Key takeaways

A compound business decision becomes reliable when you separate:

  • authoritative facts handled by code and internal systems;
  • atomic fuzzy judgments returned by Jev;
  • explicit policy composition implemented and tested in your application;
  • review or safety paths that prevent uncertain cases from being silently automated.

Do not ask Jev, “What should we do?” Ask it for the bounded evidence your code needs: refund requested, duplicate charge reported, security cue present, primary topic, or frustration level. The resulting workflow is easier to inspect, tune, and evolve as product policy changes.

Next, you will apply this structure in one request by batching mixed Choice, Score, and Noul questions and mapping their typed answers into application data.

Can't find a good explanation? Sign up and we'll make it for you

Sign up