Welcome back. In the previous lesson, you learned to identify the kinds of requirements that fit Jev: bounded semantic judgments with predefined outputs, rather than arithmetic, open-ended generation, or long-form investigation.
This lesson turns that product-level distinction into an application architecture. You will learn to separate an AI-assisted workflow into three clear responsibilities:
- Deterministic application logic for facts, validation, policy, side effects, and control flow.
- Atomic Jev judgments for narrow interpretations of ambiguous language or other unstructured evidence.
- A deterministic composition layer that decides what the system actually does with those judgments.
The goal is not to make Jev “run the application.” It is to make Jev one reliable decision component inside an application whose behavior remains inspectable and testable.
Jev is a decision layer, not your control plane
A useful architecture starts with a strict ownership rule:
Jev evaluates evidence against declared questions. Your application decides which questions to ask, what the answers mean operationally, and which action is permitted.

This is a deliberately different shape from an agent loop that receives a large prompt, reasons about what to do, invokes tools, and writes a response. An agent can be appropriate for research or drafting. But when the product behavior can be expressed as a bounded workflow, explicit partitioning gives you stronger operational control.
Consider a support ticket:
“I was charged twice for order A-104. Please give me my money back. I am considering cancelling my subscription.”
A loosely specified AI feature might say, “Handle the ticket automatically.” That hides several distinct jobs:
- Is the ticket already closed?
- Does order
A-104exist and belong to this customer? - Was the customer actually charged twice?
- Does the message explicitly request a refund?
- Which support team should receive the case?
- Does the message indicate churn risk?
- Is the case eligible under the current refund policy?
- Should an automatic refund happen, a draft be created, or should a human review it?
- What should the customer-facing reply say?
Only some of these are semantic judgments. The rest are either exact computations, policy decisions, side effects, or text generation.
Before going further, watch a compact walkthrough of this separation in a voice-controlled browser example.
Jev: The New AI Model That's Breaking The Internet (Full Tutorial)
In “Jev: The New AI Model That's Breaking The Internet,” Moritz | AI Systems explains a workflow in which Jev evaluates a small set of predefined questions while ordinary backend code applies thresholds and controls browser actions. Watch it to see the decision-layer boundary in a concrete interactive system.
Watch the three-step design. Focus on the distinction between the structured state sent to Jev, the fixed questions Jev answers, and the threshold-based decisions made by the backend.
The key idea is not that Jev is infallible. It is that its output is constrained and inspectable, so your software can apply a deliberate policy to it.
The three-way partition
For every step in an AI-assisted feature, assign a clear owner.
| Owner | Responsibility | Support-ticket examples |
|---|---|---|
| Application code | Exact facts, validation, policy rules, control flow, integrations, and side effects | Load order facts, check ticket status, calculate duplicate-charge amounts, create a refund case |
| Jev | Focused semantic judgments over supplied evidence | Determine whether a message explicitly requests a refund; classify its primary topic; assess expressed frustration |
| Generative system or templates | User-facing prose or other newly created content | Write an empathetic reply, summarize an incident, explain a policy outcome |
The boundary is especially important for policy. A model can provide evidence for a policy decision, but should not silently define the policy.
For example:
- “Does the message explicitly ask for a refund?” is a Jev judgment.
- “Is the order within the 30-day refund window?” is code.
- “May this account receive an automatic refund without human approval?” is a business-policy rule in code.
- “Write a concise explanation of the approved refund” is generation or an approved template.
A tempting but poor question would be:
“Should we refund this customer?”
That question mixes at least four concerns: interpreting customer intent, retrieving facts, applying policy, and authorizing a financial side effect. It may produce a convenient-looking answer, but it creates an opaque decision boundary. When a disputed refund occurs, you cannot easily tell whether the failure came from missing order data, a misunderstood message, an incorrectly expressed policy, or an unsafe action rule.
The TypeSafe documentation frames this approach as keeping deterministic work in code, asking narrow independent questions, then composing results explicitly.
Read TypeSafe AI’s “System One” documentation for its concise refund-workflow example. It shows the intended division: construct relevant state, ask independent judgments, and combine their typed results in code.
In the section “Fast judgments inside a larger workflow,” read the refund workflow. Notice that the application builds the state and performs final routing; Jev supplies only the bounded judgments needed for that routing.
What belongs in deterministic application logic?
“Use code when you can” is not merely a performance optimization. It is a way to preserve correctness and accountability.
Keep a step in code when its result follows exactly from data and defined rules. Typical examples include:
Fact retrieval and validation
Your server should determine whether a user is authenticated, whether an order belongs to them, whether an identifier has the expected format, and whether a ticket is already resolved. None of these require a model judgment.
function canProcessTicket(ticket: Ticket, customer: Customer): boolean {
return (
ticket.status === "open" &&
ticket.customerId === customer.id &&
ticket.message.trim().length > 0
);
}
Exact computation
Dates, amounts, counts, comparisons, and aggregation belong in code.
function isWithinRefundWindow(order: Order, now: Date): boolean {
const refundDeadline = new Date(order.deliveredAt);
refundDeadline.setDate(refundDeadline.getDate() + 30);
return now <= refundDeadline;
}
A model should not decide whether 29 days have passed, whether a balance exceeds a threshold, or whether an order has a particular status. Those are deterministic facts.
Policy and authorization
A policy may use model outputs, but its enforcement must remain explicit in application code.
function canAutoApproveRefund(input: {
order: Order;
duplicateChargeConfirmed: boolean;
refundRequestedProbability: number;
topicConfidence: number;
}): boolean {
return (
input.order.amountCents <= 5_000 &&
input.duplicateChargeConfirmed &&
input.refundRequestedProbability >= 0.9 &&
input.topicConfidence >= 0.85
);
}
The specific thresholds above are illustrative, not universal defaults. In production, you will choose and validate them against review data later in the course. What matters now is the ownership boundary: code holds the rule and can be unit-tested without a model call.
Side effects and workflow control
Only your application should:
- create or update tickets;
- call a payment provider;
- send email or chat messages;
- invoke internal tools;
- redact data;
- write audit events;
- decide whether to retry, review, block, or fall back.
Jev’s answer should be input to an action policy, never the action itself.
What makes a Jev judgment atomic?
An atomic question asks the model to evaluate one property of the supplied state. It has one decision boundary and a result that code can inspect independently.
Compare these two questions.
| Broad, entangled question | Atomic questions |
|---|---|
| “Is this a legitimate refund request that we should approve automatically?” | “Does the customer explicitly request a refund or account credit?” |
| “Does the message indicate a duplicate charge?” | |
| “Which team should handle the ticket?” | |
| Code: “Do transaction records confirm a duplicate charge?” | |
| Code: “Does the order meet the automatic-approval policy?” |
The atomic form may initially look more verbose. In practice, it gives you much more control:
- Each judgment has a specific definition that product, support, and engineering can review.
- You can identify which judgment is uncertain or wrong.
- You can adjust one question without changing unrelated behavior.
- Code can combine signals differently for different product paths.
- Independent questions can be evaluated together rather than requiring serial model calls.
A good atomic question has four properties.
1. It judges one semantic property
Good:
Does
ticket.messageexplicitly request a refund or account credit?
Less useful:
Is this a billing problem, a refund request, an urgent escalation, or spam?
The second question bundles topic classification, remedy detection, urgency, and safety classification. Its answer cannot cleanly drive a single operation.
2. Its answer has a defined consumer
Ask, “What code will use this result?”
| Judgment | Code that consumes it |
|---|---|
primary_topic | Select a support queue |
refund_requested | Show refund-specific intake fields |
mentions_open_order | Attach a candidate order to the case |
expressed_frustration | Adjust service-priority policy |
requests_sensitive_credential | Block or escalate the message |
If no component needs the answer, it is probably not worth asking.
3. It does not replace a known fact
Good:
Does the message refer to one of the supplied open orders?
Not good:
Is order A-104 currently open?
The first requires interpreting language against structured evidence. The second should come from your database.
4. It is independently reviewable
A reviewer should be able to read the state, question, criteria, and output, then make a meaningful assessment of whether that one judgment was correct. This is essential when you eventually build evaluation datasets.
TypeSafe’s workflow guide emphasizes this exact discipline: deterministic work in code, minimal relevant state, explicit atomic questions, and code-based composition.
Read the “Design a System One workflow” section in TypeSafe AI’s guide. It provides the engineering rationale for keeping exact work in code and decomposing broad requirements into inspectable judgments.
In “Design a System One workflow,” read the workflow-design guidance. Pay particular attention to steps 1, 4, 6, and 7: deterministic work stays in code; broad questions are decomposed; independent questions can be asked together; and application logic combines the resulting signals.
A worked partition: support refund triage
Let’s turn the earlier ticket into a realistic decision service. Assume the frontend sends a message and an order reference to your backend.
Step 1: Build trusted state in code
Your backend authenticates the user, fetches the relevant records, removes fields that are unnecessary for the decision, and creates a small state object.
type TriageState = {
ticket: {
message: string;
submittedOrderId?: string;
};
customer: {
plan: "free" | "pro";
openOrders: Array<{
id: string;
status: "processing" | "shipped";
totalCents: number;
}>;
};
policy: {
refundWindowDays: number;
autoApprovalLimitCents: number;
};
};
This is not just request serialization. It is part of the decision design. You expose the evidence Jev needs and omit distracting, irrelevant, or sensitive material.
For example, Jev does not need:
- internal database primary keys unrelated to the request;
- the customer’s entire history if only open orders matter;
- payment card details;
- internal support notes that should not influence the decision;
- a complete copy of a policy if the relevant policy facts can be represented structurally.
Step 2: Short-circuit deterministic cases
Before asking Jev anything, handle conditions whose answer is already known.
function shouldSkipModel(ticket: Ticket): boolean {
return ticket.status === "closed" || ticket.message.trim() === "";
}
You could also immediately route a message to a known queue if a verified form field already specifies its category. Avoid using a model to rediscover facts that your application possesses directly.
Step 3: Ask only semantic questions
For this workflow, a first set of atomic judgments might be:
| Question ID | Question | Why it belongs to Jev |
|---|---|---|
topic | Which team should handle the customer’s primary request? | Natural language may express billing, delivery, or account issues in many ways. |
refund_requested | Does the customer explicitly request a refund or account credit? | A complaint and a requested remedy are not the same thing. |
mentions_open_order | Does the message refer to one of the supplied open orders? | The model relates unstructured wording to the provided order evidence. |
frustration | How frustrated does the customer appear? | Expressed tone is semantic and cannot be reliably reduced to keyword counting. |
Notice what is missing:
- “Is the refund allowed?” is code.
- “Should we issue the refund?” is code.
- “How much should we refund?” is code.
- “Write a reply” is generation or templating.
Step 4: Compose the typed answers in a pure function
Keep composition separate from the API call. This makes the business behavior easy to test with ordinary objects.
type Judgments = {
topic: {
choice: "billing" | "orders" | "account";
confidence: number;
};
refundRequested: {
probability: number;
};
mentionsOpenOrder: {
probability: number;
};
frustration: {
score: number;
confidence: number;
};
};
type TriageDecision =
| { kind: "human_review"; reason: string }
| { kind: "route_billing"; refundFlow: boolean }
| { kind: "route_orders"; candidateOrderMatch: boolean }
| { kind: "route_account"; priority: "normal" | "high" };
function composeTriage(
state: TriageState,
judgments: Judgments
): TriageDecision {
if (judgments.topic.confidence < 0.75) {
return { kind: "human_review", reason: "uncertain_topic" };
}
if (judgments.topic.choice === "billing") {
return {
kind: "route_billing",
refundFlow: judgments.refundRequested.probability >= 0.7,
};
}
if (judgments.topic.choice === "orders") {
return {
kind: "route_orders",
candidateOrderMatch: judgments.mentionsOpenOrder.probability >= 0.7,
};
}
const highFrustration =
judgments.frustration.confidence >= 0.7 &&
judgments.frustration.score >= 1.5;
return {
kind: "route_account",
priority: highFrustration ? "high" : "normal",
};
}
This function does not need to know how Jev is called. It receives typed values and enforces product behavior deterministically. You can write unit tests for every branch immediately, including low-confidence and contradictory combinations.
Later, when you integrate the SDK, the model adapter’s job will be narrow:
- Create the state and question definitions.
- Call Jev.
- Map the returned typed answers into
Judgments. - Pass them to
composeTriage. - Execute the action described by
TriageDecision.
That separation is valuable in a TypeScript backend: your controller, model adapter, decision policy, and side-effecting services remain independently testable.
A practical refactoring method
When you inherit a vague AI requirement, use this process before writing prompts or SDK code.
1. Write the final application actions
Start with outcomes your software can actually execute:
- route to billing;
- route to account support;
- open a human-review task;
- attach an order;
- block a suspicious request;
- show a particular UI form;
- call an allowlisted backend function.
If you cannot name the actions, the feature is not yet specified enough for automation.
2. List the exact facts each action requires
For example, automatic refund approval might require:
- authenticated customer identity;
- order ownership;
- delivery date;
- transaction amount;
- duplicate-charge evidence;
- a current policy limit.
Most of these come from databases and deterministic services, not Jev.
3. Mark the remaining ambiguity
Ask which facts cannot be derived exactly because they appear in unstructured input:
- Is the person asking for money back?
- Which issue is primary?
- Is the message threatening, abusive, or likely malicious?
- Does “the package from last week” plausibly refer to a supplied order?
These are candidates for atomic model judgments.
4. Phrase one question per ambiguity
Keep each question focused on a single property. Do not hide your full workflow behind a question such as “What should happen next?”
5. Decide the fallback before enabling automation
Every judgment should have an explicit uncertainty path. Depending on risk, that may mean:
- route normally;
- request more information;
- defer to a generative model for a draft only;
- send the case to a human;
- block an unsafe action;
- take no action.
The application owns this decision, because it reflects product risk tolerance rather than semantic interpretation alone.
6. Keep actions downstream of validation
Even a confident model result should not bypass authorization, policy checks, schema validation, idempotency controls, or audit logging. A model may help select a candidate action; your code must ensure that action is allowed.
Key takeaways
A well-partitioned Jev workflow has a narrow and deliberate model boundary:
- Code retrieves facts, validates inputs, performs calculations, applies policy, controls branching, and performs side effects.
- Jev answers small semantic questions over relevant state.
- Code combines typed answers and confidence information into explicit product decisions.
- Generative models or templates produce prose when prose is actually needed.
An atomic judgment evaluates one property, has a bounded answer, and has a known consumer in your application. If a proposed question asks Jev to interpret intent, apply policy, calculate facts, and authorize an action at once, split it apart.
Next, you will move from design to implementation: configure credentials and make an authenticated Jev request using the JavaScript SDK.
Can't find a good explanation? Sign up and we'll make it for you
Sign up