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

# How it works

> The /v1/evaluate pipeline: resolve the collector from its API key, resolve the policy, run gates, run the detector rules, and reduce everything to a single status the caller enforces.

Every inspection goes through one runtime endpoint, `POST /v1/evaluate`. This page
explains what happens between the request and the verdict.

## 1. Authenticate and resolve the collector

The caller sends `Authorization: Bearer <api-key>`. TrustGuard verifies the key,
checks it is active and not expired, and resolves the
[collector](/trustguard/concepts/collectors) it belongs to. The collector is
**never** sent in the request body — it comes from the key.

A missing or invalid key returns `401`; an inactive/expired key is rejected
before any evaluation runs.

## 2. Resolve the policy

TrustGuard picks the [policy](/trustguard/concepts/policies) for this request:

* if the request's `consumer_id` has a **per‑consumer policy**, use it;
* otherwise use the collector's **default policy**.

If the collector has no matching policy, the request is **unguarded**: TrustGuard
returns `status: "allow"` with no findings. The policy's **Enforcement mode**
(Report vs Enforce) is read here — in **Report** mode every action below is
downgraded to a non‑blocking record.

## 3. Run gates

[Gates](/trustguard/concepts/policies#gates-match-before-you-detect) are
evaluated **before** any detector. Each gate matches request **attributes**
(consumer, model, collector, protocol, session) and takes an action:

| Gate action | Effect                                                                           |
| ----------- | -------------------------------------------------------------------------------- |
| **Block**   | The request is blocked and **detectors are skipped**. Returns `status: "block"`. |
| **Report**  | Records a finding and continues to detection.                                    |
| **Skip**    | Stops gate evaluation and proceeds to detection — no finding.                    |

All gates are evaluated and the most restrictive outcome wins.

## 4. Run the detector rules

For the request's `direction` (`input` or `output`), TrustGuard runs the
policy's matching **detector rules** — the same **Input** / **Output** phases
you configure on the [policy](/trustguard/concepts/policies). Rules are filtered
by direction and by their optional conditions, then split by capability:

The caller supplies `direction` on `/v1/evaluate`.
[TrustGate](/trustguard/integrations/gateway) sets it from the request/response
stage; [application](/trustguard/integrations/application) and other collectors
must set it explicitly (default `input` if omitted).

| Phase         | Detectors                                        | Execution                                                                                                                      |
| ------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
| **Detect**    | Every detection‑only detector                    | Run **concurrently**; results merged deterministically. They read the payload but never modify it.                             |
| **Transform** | Mutable detectors (today `data_loss_prevention`) | Run **sequentially** after detection. With the **Transform** action they rewrite the payload, producing `transformed_payload`. |

Each rule's action — **Monitor** (`report`), **Block**, or **Transform** — sets
the `outcome.action` on the findings it produces. A `block` rule also stops the
remaining detector chain.

File attachments (`payload.attachments`) are decoded once and shared with the
detectors that consume them (`doc_analyzer`, `url_analyzer`). Remote attachment
URLs are fetched server‑side under a strict SSRF guard (HTTPS only; loopback,
private, link‑local, CGNAT, and cloud‑metadata addresses blocked) and are
**never stored**.

## 5. Reduce to a status

Everything that fired is reduced to one top‑level `status`, most to least
restrictive:

```text theme={null}
block  →  transform  →  report  →  allow
```

In **Report** mode, blocks and transforms are downgraded, so the status never
exceeds `report`.

## 6. The response

```json theme={null}
{
  "status": "transform",
  "transformed_payload": { "input": "My email is [MASKED_EMAIL]" },
  "findings": [
    {
      "source": { "kind": "detector", "plugin": "data_loss_prevention", "detector_name": "PII masking", "policy_id": "…" },
      "signal": { "type": "pii", "confidence": 1.0 },
      "outcome": { "action": "transform" },
      "evidence": { "masked": 1, "entities": ["email"] }
    }
  ],
  "trace_id": "f1e2…",
  "request_id": "a9b8…"
}
```

| Field                     | Meaning                                                                                                         |
| ------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `status`                  | `allow` · `report` · `transform` · `block` — the reduced verdict. Advisory: the caller enforces.                |
| `transformed_payload`     | The rewritten payload, or absent/`null` if no Transform rule changed anything.                                  |
| `findings[]`              | One entry per gate or detector that fired. See the [Evaluate API](/trustguard/api/evaluate) for the full shape. |
| `trace_id` / `request_id` | Correlation IDs propagated through logs and telemetry.                                                          |

A detection is **always** `HTTP 200` — including a `block` status. Your
integration acts on `status` / `findings`; it never relies on TrustGuard to
reject the request.

## Failure behavior

If a detector hits an infrastructure error (an upstream provider is down, a
timeout, etc.), behavior follows your deployment's fail‑open / fail‑closed
setting:

* **Fail‑open** — TrustGuard drops that detector's result and the request still
  succeeds, so a TrustGuard issue never breaks your traffic.
* **Fail‑closed** — the request returns `500` so the caller can decide to hold
  traffic.

A structured **block** decision (from a gate or a Block rule) always applies
regardless of this setting. The default is **configured per deployment** — ask NeuralTrust which mode your environment uses.
