> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vainona.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Discover new options

> Find out what a choice judgment's escape option holds, get a proposal for the options it is missing, and review it before you create the version.

export const productName = "Vainona";

A choice judgment answers with one of its options, or with `none_of_the_above` when none of them fits. That escape option is where a new kind of complaint, a new abuse pattern or a new product question shows up first. Discovery reads what landed there and proposes the options your judgment is missing. It never changes the judgment: you review the proposal, edit it, and create the new version yourself.

Discovery is for choice judgments with fixed options. A `bool` or `score` judgment has no escape option; watch its [calibration report](/guides/measure-improve-tune) instead. A choice that [chooses among candidates](/guides/entity-matching) has one, but it means "no candidate matches", not a missing option, so discovery does not apply to it either.

## Know when to look: the escape alert

`escape_alert` is a setting of a choice judgment: the share of its answers over the last 7 days that were `none_of_the_above`, above which you want to know. It is off until you set it, and changing it creates no version.

<CodeGroup>
  ```ts TypeScript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  await ns.judgments.update("complaint_type", { escape_alert: 0.1 });
  ```

  ```python Python theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  ns.judgments.update("complaint_type", escape_alert=0.1)
  ```
</CodeGroup>

When the share rises above it, three things happen, and nothing else:

* **The judgment gets a warning.** `GET` on the judgment lists `taxonomy_drift` in `warnings`, with the share and when it rose. The dashboard shows it on the judgment's page. It clears when the share falls back.
* **One event.** The [events feed](/guides/events-feed), and every [webhook endpoint](/guides/webhooks) that asks for it, gets one `judgment.taxonomy_drift` per rise, not one per answer. Staying above sends nothing more.
* **Nothing changes on its own.** Your answers, options and bill stay as they are. You run discovery when you want to.

```json theme={"theme":{"light":"css-variables","dark":"css-variables"}}
{
  "code": "taxonomy_drift",
  "message": "12% of the last 7 days' answers were none_of_the_above, above the alert at 10%: run discover to see what they have in common",
  "escape_share": 0.12,
  "since": "2026-09-29T06:00:00Z"
}
```

The share needs at least 20 answers in the 7 days before it can raise the warning, so a quiet judgment's first escape isn't a drift. The alert takes a number above 0 and at most 1; `null` turns it off. A namespace that inherits the judgment from a [template](/guides/templates) follows the template's alert, and gets its own warning and event from its own answers.

## Turn on suggestions

Discovery sends a sample of your documents to a general-purpose LLM provider, the same one that [suggests parts](/guides/composite-judgments#suggested-parts), listed as a subprocessor in the data processing agreement. So it is **off by default**: an org admin turns on **Suggestions** in the organization's settings in the dashboard. Until then, `discover` is refused with `forbidden`.

## Run discovery

`POST /namespaces/{ns}/judgments/{name}/discover` with how far back to look (`window`, 7 days by default) and the most new options you want (`count`, 1 to 10, 5 by default):

```json theme={"theme":{"light":"css-variables","dark":"css-variables"}}
{"window": "7d", "count": 5}
```

<CodeGroup>
  ```ts TypeScript theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  let job = await ns.judgments.discover("complaint_type", { window: "7d", count: 5 });
  while (job.status === "running") {
    await new Promise((resolve) => setTimeout(resolve, 5_000));
    job = await db.jobs.get(job.id);
  }
  console.log(job.proposal);
  ```

  ```python Python theme={"theme":{"light":"css-variables","dark":"css-variables"}}
  import time

  job = ns.judgments.discover("complaint_type", window="7d", count=5)
  while job["status"] == "running":
      time.sleep(5)
      job = db.jobs.get(job["id"])
  print(job["proposal"])
  ```
</CodeGroup>

It answers `202` with a `discover` job, which:

1. **Samples the escape.** It takes the documents whose answer in the window is `none_of_the_above`, or whose `escape_p` is at or above the judgment's threshold on `none_of_the_above` if you set one, and samples up to 200 of them.
2. **Asks for options.** Each sampled document is compiled with the judgment's context recipe, exactly as it is judged, and the sample is cut to 100,000 tokens together. The LLM gets your question, your current options and the sample, and proposes up to `count` new options, each with a description and the sampled documents it covers.
3. **Tries them.** The current options plus the proposed ones are judged over the sample, as a [shadow report](/guides/measure-improve-tune) judges a new version. These shadow judgments are free and change no answer.

Discovery is free. Each call takes one of the judgment's `suggest_parts` calls for the day (20 per judgment and 50 per organization, together with suggested parts); past them it is `rate_limited`, with `details.limit` and when the allowance renews in `details.resets_at`. The call is taken when the job starts, and a busy model is waited out rather than failing the job.

## Read the proposal

When the job is `done`, its `proposal` is a new version's options, the current ones first:

```json theme={"theme":{"light":"css-variables","dark":"css-variables"}}
{
  "options": [
    {"value": "billing", "description": "Charges, invoices, refunds."},
    {"value": "delivery", "description": "Late, lost or damaged parcels."},
    {"value": "account_access", "description": "Locked out, password resets and two-factor codes that never arrive."},
    {"value": "subscription_cancel", "description": "Trying to cancel a subscription and being unable to."}
  ],
  "proposed": [
    {"value": "account_access", "description": "Locked out, password resets and two-factor codes that never arrive.", "absorbs": 71, "sample_ids": ["t_90412", "t_90388", "t_90377"]},
    {"value": "subscription_cancel", "description": "Trying to cancel a subscription and being unable to.", "absorbs": 44, "sample_ids": ["t_90401", "t_90356"]}
  ],
  "sampled": 200,
  "escape_documents": 1318,
  "unlabelled": 85
}
```

* **`escape_documents`** is how many documents in the window escaped; **`sampled`** is how many of them the job read.
* **`absorbs`** is how many sampled documents the proposed version answered with that option; **`sample_ids`** are the ones the LLM said the option covers. Open a few of them to see what the option really means.
* **`unlabelled`** is how many sampled documents the proposed version still answered `none_of_the_above`. A large number means the escape holds more than one new thing, or things no option should cover.

## Review before you create the version

The proposal is a draft. The review is where most of its value is, so don't accept it unedited.

We tested discovery on a public dataset of banking support questions: 20 kinds of question, 80 each, with three kinds removed from the options so that their questions escaped. Two of the removed kinds sat close to options that stayed, and one was unlike any of them. All three came back as proposed options, each covering almost exactly the escaped questions of its kind. The same run showed what the review is for:

* **Some proposals are a narrower case of an option you have.** Two of the five proposals were sub-topics of existing options: top-ups made with a phone wallet, under top-ups, and accounts for children, under accounts. Added as they were, they would have taken 73 and 39 of the 80 questions in their parent options. Fold a proposal like that into the parent option's description instead of adding it, or delete it.
* **A new option next to an old one won't take all of its documents.** About a quarter of the questions of each removed kind that had a close neighbour never escaped: they were answered with the neighbour. After the new option was active, one of them still lost about a quarter of its questions to its neighbour. Sharpen both descriptions so the line between them is clear, and read the shadow report when you activate.
* **The conditions were easy.** The removed kinds made up most of the escaped questions, and the dataset is public, so the model may have seen its categories before. A new kind that is a small part of your escape may not come back as its own option.

Then create the version with the options you settled on, as you create any version. Activating it runs the ordinary [shadow report](/guides/measure-improve-tune) over up to 1,000 of your documents, which shows what would change before anything does. In the dashboard, the judgment's **Discover** tab shows the proposal as an editable list of options, with the change to the definition beside it, and creates the version from what you edited.

## Limits

| | |
| - | - |
| `count` | 1 to 10 new options, 5 by default |
| Sample | up to 200 escape documents, 100,000 tokens together |
| Calls | 20 per judgment and 50 per organization a day, shared with suggested parts |
| `escape_alert` | above 0 and at most 1, or `null` (off); 7 days of answers, at least 20 |
| Judgments | choice judgments with fixed options; `bool`, `score` and a choice among a relation's candidates are refused with `invalid_request` |


## Related topics

- [Judgments](/concepts/judgments.md)
- [Propose options for what the escape option holds](/api-reference/judgments/propose-options-for-what-the-escape-option-holds.md)
- [Limits](/limits.md)
- [Create a judgment, or a new version of an existing name](/api-reference/judgments/create-a-judgment-or-a-new-version-of-an-existing-name.md)
- [Measure, improve, tune](/guides/measure-improve-tune.md)
