# Filtering and ranking a list

> from, where, rankedBy, take, and the three buckets every item lands in.

`from(items)` starts an expression about a list. The same conditions `given` accepts filter it; a scale ranks it; `take` limits it. The model judges each item once. Partitioning, sorting, and limiting run locally.

## Filtering

`.where(condition)` states the filter. `.and()`, `.or()`, and `.unless()` refine it exactly as they do on a predicate, with the same three-valued logic. Each item is judged independently, and a false code predicate on an item drops it without a request for that item.

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


const result = await from(tickets)
  .seenAs((t) => ({ subject: t.subject, body: t.body }))
  .where((t) => t.status === "open")
  .and(reportsProblem)
  .unless(saysResolved);


result.accepted; // Ticket[]: the condition resolved to true, in input order
result.rejected; // Ticket[]: resolved to false
result.uncertain; // Ticket[]: did not meet the policy; unresolved, not rejected
result.evidence.requests.length; // one request per item that needed the model
```

The result has three buckets, and every item lands in exactly one:

* `accepted`: the condition resolved to true.
* `rejected`: it resolved to false.
* `uncertain`: the policy would not decide. These are not rejected. They are the items you have not yet made a decision about.

`evidence` covers the whole query: every request that went out and every judgment that was recorded, across all items.

## Ranking

`.rankedBy(scale, order)` adds a [Score](/Jevlish/guides/scales/) question for every item not rejected by code, in the same request as its semantic filter. After the filter resolves, scores are read only for accepted items and `accepted` is sorted by them. This avoids a second round trip, but an item the model later rejects or leaves uncertain was still scored. `order` is `"highest first"` (the default) or `"lowest first"`.

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


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


for (const { item, score, normalized } of queue.scored) {
  item.id; // an accepted ticket, highest disruption first
  score; // 0 .. disruption.top
  normalized; // 0 .. 1
}


// Ranking alone, with no filter, scores every item.
const byDisruption = await from(tickets).rankedBy(disruption, "lowest first");
byDisruption.accepted;
```

A ranked result adds `scored`: each accepted item with its `score` (0 to `scale.top`) and `normalized` score (0 to 1), in ranked order. An item whose score does not meet `policy.score.minConfidence` moves to `uncertain` even if its filter passed.

`from(items).rankedBy(scale)` with no `.where()` scores everything.

## Limiting

`.take(n)` keeps the first `n` of `accepted` after ranking. It does not reduce what is asked. To spend less, narrow the list in code first, or put a code predicate in `.where()` so rejected rows never leave the process.

## Projection and policy

`.seenAs(fn)` on `from` projects each item, the same as on `given`, and goes before `.where()`. `.withPolicy({...})` overrides thresholds either before or after the query is built.

## Inspecting before running

`.plan()` on a query reports `subjectCount`, `decidedByCode`, and the requests that would be sent, with notes describing the filter, ranking, and limit. See [Running and planning](/Jevlish/guides/running/).