# Best practices

Source: https://docs.temprl.org/guide/best-practices

> Patterns that work with Simo - ask everything at once, gate on calibrated probabilities, read before deciding, and write clear states and options.

## Ask everything at once

Ten questions about one screenshot cost little more than one, because the cost is in reading the input. One request per question pays for the same read over and over.

```python
# Good: one read, four answers
r = c.ask(ticket, {"refund": ..., "team": ..., "mood": ..., "order": ...})
```

## Gate on probabilities

Act above a high threshold, escalate in the middle, refuse or ask a person below. Because the probabilities are calibrated, the thresholds mean what they say: set them from what a mistake costs, not by trial and error.

| Action | A wrong call costs | A sensible threshold |
|---|---|---|
| Tag a ticket | Almost nothing | 0.6 |
| Send an automatic reply | An awkward email | 0.9 |
| Issue a refund, delete data | Money or trust | 0.97 or higher, else a person |

## Read, then decide

If a decision depends on a number or date in the input, `Extract` or `Fill` it and let [`two_pass` / `derive`](https://docs.temprl.org/guide/read-then-decide) put it in front of the decision. Do arithmetic in code, never in the model.

## Put the instructions in the state

Policies, rules and history belong in the state. A dict works well, because the keys become labels:

```python
state = {"policy": POLICY, "ticket": ticket_text, "history": str(history)}
```

The question then stays short and specific: "The customer is eligible for a refund under the policy".

## Write statements for Noul

`Noul` answers whether a **statement** is true. Write "The customer asks for a refund", not "Does the customer ask for a refund?". Add `criteria` when the boundary is fuzzy.

## Describe every option

`{"refund": "the customer wants money back"}` is clearer to the model than a bare key. The key is what your code reads; the description is what the model reads.

## Ask "did it happen?" of video

The model sees a handful of frames with timestamps. It is good at whether something happened, and not at pinpointing an exact frame.

## Handle failures

- Retries on 429, 502, 503 and 504 are automatic in the SDK, and those failures are not charged.
- Log `request_id` with any error you report.
- Check `center is not None` before acting on a `Locate`.
- Check `valid` on reads, or use `self_check` and threshold `check`.

## Pro only slows down when it is unsure

On a confident decision Simo-1 Pro answers at full speed, and deliberates only on decisions that are genuinely uncertain. It suits both fast loops and the calls where a wrong answer is expensive.
