# Running and planning

> Expressions are values. await and .run() execute them; .plan() shows what would be sent without sending it.

An expression is a value until you run it. Building one sends nothing; `await` or `.run()` sends the requests; `.plan()` describes them without sending.

## Plans

```ts
import { from } from "jevlish";
import { tickets } from "./support.js";
import { disruption, reportsProblem } from "./vocabulary.js";


const query = from(tickets)
  .seenAs((t) => ({ subject: t.subject, body: t.body }))
  .where((t) => t.status === "open")
  .and(reportsProblem)
  .rankedBy(disruption)
  .take(5);


// Nothing has been sent yet. The query is a value.
const plan = query.plan();


plan.subjectCount; // 3
plan.decidedByCode; // 1: the closed ticket never reaches the model
plan.questionCount; // one Noul and one Score for each of the other two
plan.requestCount; // 2
plan.requests[0]?.state; // exactly what leaves the process for the first subject
plan.notes; // ["filter: ...", 'ranked by "...", highest first', "take 5"]


// Now spend.
const result = await query;
result.scored;
```

A `Plan` has:

* `subjectCount`: how many subjects the expression covers (one for `given`, the list length for `from`).
* `decidedByCode`: how many of them code predicates settled with no request.
* `questionCount` and `requestCount`: what would be asked, and how it batches.
* `requests`: each request’s `state` (exactly what the model would see) and `questions`.
* `notes`: a description of the filter, ranking, and limit on a query.

Every runnable expression has `.plan()`: predicates, branches, queries, measurements, choices, and `ask`. On a branch, `plan()` does not run any handler.

## Running

`await expression` and `await expression.run()` do the same thing. Each call runs the expression again: a second request, or a cache hit if a cache is configured and nothing changed. Expressions are not memoized.

```ts
import { given } from "jevlish";
import type { Ticket } from "./support.js";
import { blocked } from "./vocabulary.js";


// Build expressions in plain functions so callers can still .plan() them.
export const isBlocked = (t: Ticket) => given(t).seenAs((x) => ({ body: x.body })).when(blocked);


isBlocked({ id: "T-1", status: "open", subject: "s", body: "b" }).plan(); // fine


// An async function awaits the expression for you: the caller gets a
// Promise<Judgment<boolean>> and can no longer plan it.
export const isBlockedNow = async (t: Ticket) => given(t).when(blocked);


// .run() and await do the same thing; each call runs the expression again.
const expression = isBlocked({ id: "T-1", status: "open", subject: "s", body: "b" });
const first = await expression.run();
const second = await expression; // a second request (or a cache hit)
first.status === second.status;
```

## Keep expressions in plain functions

An `async` function awaits its return value. A function that returns `given(t).when(blocked)` hands the caller an expression they can `.plan()`, `.run()`, or `.withPolicy()` further. An `async` function that returns the same thing hands them a `Promise<Judgment<boolean>>` that is already in flight. If callers need to inspect before spending, build expressions in plain functions and let the caller decide when to `await`.

Most application code should let TypeScript infer expression types. Libraries that need to name a builder type can import the advanced classes from `jevlish/types`; they are kept out of the root entry point so the common API stays focused on verbs, question builders, and results.

## Errors

A `SenseError` means the expression itself is malformed or incomplete: an empty proposition, `.and()` before `.where()`, a branch awaited without `.whenUncertain()`, a scale with one level. Transport failures from the underlying SDK propagate as they are. A thrown error is a failed request, never evidence about the proposition; it does not become `uncertain`.