# Routing policy

The routing policy is the single function that decides what happens to every submitted item. It runs server-side in `src/routes/api/public/items.ts` and reads its config from the item's project.

## Per-project config

| Field                   | Type      | Default                               | Purpose                                                       |
| ----------------------- | --------- | ------------------------------------- | ------------------------------------------------------------- |
| `auto_threshold`        | float     | `0.95`                                | At or above this confidence (and no risk flags), auto-approve |
| `review_threshold`      | float     | `0.70`                                | Below this confidence, always queue                           |
| `hard_block_flags`      | string\[] | `[]`                                  | Any flag here → immediate reject, no human                    |
| `escalate_flags`        | string\[] | `["escalate", "legal", "high_value"]` | Any flag here → senior reviewer                               |
| `force_review_flags`    | string\[] | `["pii", "new_user"]`                 | Any flag here → queue regardless of confidence                |
| `max_queue_age_minutes` | int       | `60`                                  | Items older than this auto-escalate                           |
| `reviewer_pool`         | uuid\[]   | all reviewers                         | Who can pick up items from this project                       |

## Decision order

The router evaluates rules in strict order. The first match wins:

```
1. hard_block_flags     → reject
2. escalate_flags       → escalate
3. force_review_flags   → queue
4. confidence < review_threshold → queue
5. confidence ≥ auto_threshold AND no flags → auto-approve
6. otherwise            → queue (middle band)
```

This ordering matters. Risk flags always beat confidence — a 0.99-confidence reply with a `pii` flag still goes to a human.

## Picking thresholds

The two thresholds carve confidence into three bands:

```
0.0 ─────── review_threshold ─────── auto_threshold ─────── 1.0
   queue (always)        queue (middle)        auto-approve
```

Choose them with this question in mind: *"How costly is a wrong auto-approval, and how costly is reviewer time?"*

* **Cost of wrong auto-approval is high** (payments, legal, customer-facing claims) → push `auto_threshold` up to 0.98+, accept a larger queue.
* **Cost of wrong auto-approval is low** (internal tagging, low-stakes categorization) → drop `auto_threshold` to 0.85, accept some auto-error in exchange for reviewer bandwidth.
* **Cost of reviewer time is high** (small team, expensive specialists) → raise `review_threshold` so the middle band is narrower.

See [Tuning thresholds](/hitl-docs/guides/tuning-thresholds.md) for the empirical approach.

## Risk flags vs. metadata

Risk flags drive routing. Metadata does not. If a field could *ever* change where an item is sent, it belongs in `risk_flags`. Everything else (analytics segments, internal ids, ab-test buckets) goes in `metadata`.

Good risk flags are short, namespaced, and stable:

```
pii            legal           high_value
new_user       trial_account   refund_request
content:nsfw   policy:unclear  region:eu
```

Avoid free-form sentences. The router does an exact string match.

## Time-based escalation

Items that sit in the queue longer than `max_queue_age_minutes` are automatically promoted to `escalate`. This protects against staffing gaps and ensures SLAs hold even when nobody is watching the queue. The original confidence and flags are preserved.

## Auditing the policy

Every routing decision writes a row to `item_routing_log` with the inputs (confidence, flags, project config snapshot) and the outcome. This is the source of truth for "why did this item end up where it did?" and the substrate for the [analytics](/hitl-docs/features/analytics.md) calibration view.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hitl-01.gitbook.io/hitl-docs/human-in-the-loop/routing-policy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
