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

# Pecta built-in gates: complete reference

> Every gate Pecta ships out of the box, how to compose them in createEngine, and how the timeout budget and fail-fast behavior work together.

Gates are the core primitive in Pecta. Each gate is a single pass/fail check that runs against an agent's output before it reaches the user. You compose any number of gates when you call `createEngine`, and the engine runs all of them in parallel under a shared timeout budget. Fail-fast (the default) aborts remaining gates the moment one fails, keeping evaluation latency low.

## All built-in gates

| Gate                                                     | Category | What it checks                                                       |
| -------------------------------------------------------- | -------- | -------------------------------------------------------------------- |
| [`gates.latency`](/gates/latency)                        | General  | `ctx.latency_ms` exceeds a configurable `maxMs` threshold            |
| [`gates.schema`](/gates/schema)                          | General  | `ctx.output` matches a Zod schema you provide                        |
| [`gates.filesystem`](/gates/filesystem)                  | General  | Destructive `rm` commands, path traversal, and sensitive directories |
| [`gates.pii`](/gates/pii)                                | General  | Email addresses, SSN-shaped strings, and phone numbers in output     |
| [`gates.content`](/gates/content)                        | General  | Empty output and AI refusal/disclaimer phrases                       |
| [`gates.rtb.tmaxGuard`](/gates/rtb/tmax-guard)           | RTB      | Skips downstream gates when the OpenRTB `tmax` deadline is exhausted |
| [`gates.rtb.impidMatch`](/gates/rtb/impid-match)         | RTB      | Every `bid.impid` matches a request `imp.id`                         |
| [`gates.rtb.adomainVerify`](/gates/rtb/adomain-verify)   | RTB      | Placeholder or malformed advertiser domains                          |
| [`gates.rtb.bidSanity`](/gates/rtb/bid-sanity)           | RTB      | Bid price is not unrealistically far above the floor price           |
| [`gates.rtb.audienceSafety`](/gates/rtb/audience-safety) | RTB      | Child-directed inventory does not receive unsafe ad categories       |
| [`gates.rtb.bcatCompliance`](/gates/rtb/bcat-compliance) | RTB      | Response creative does not appear in the request `bcat` block list   |

## Composing gates

Pass a `gates` array to `createEngine`. The engine validates that every gate has a unique name and a `run` function, then returns an `Engine` object whose `evaluate` method you call for each agent output.

```typescript theme={null}
import { createEngine, gates } from "@pecta/core";
import { z } from "zod";

const engine = createEngine({
  gates: [
    gates.latency({ maxMs: 200 }),
    gates.schema(z.object({ answer: z.string().min(1) })),
    gates.filesystem(),
    gates.pii(),
    gates.content(),
  ],
  timeout: 50,   // total ms budget across all gates (default 50)
  failFast: true, // abort remaining gates on first failure (default true)
});

const result = await engine.evaluate({
  agent_id: "research-bot-v2",
  tool: "web.search",
  output: { answer: "The capital of France is Paris." },
  latency_ms: 120,
});

if (!result.passed) {
  const failures = result.gates.filter((g) => !g.passed && !g.skipped);
  console.error("blocked by:", failures.map((g) => g.name));
}
```

The return value is an `EvaluationResult`:

```typescript theme={null}
{
  evaluation_id: "V1StGXR8_Z5jdHi6B-myT",
  agent_id: "research-bot-v2",
  tool: "web.search",
  passed: false,
  gates: [
    { name: "latency", passed: false, reason: "latency 120ms exceeds 100ms threshold", latency_ms: 0.12 },
    { name: "schema",  passed: false, reason: "pecta:aborted: pecta:fail-fast", latency_ms: 0.01 },
    // ...
  ],
  total_latency_ms: 0.95,
  timestamp: "2026-05-07T14:32:00.000Z"
}
```

## Timeout budget

The `timeout` option (default `50` ms) is a wall-clock budget shared across all gates. When the budget expires, the engine fires an `AbortController` signal. Gates that check `signal.aborted` before doing expensive work return immediately; any gate that is still running when the timer fires has its result recorded as `passed: false` with `reason: "pecta:aborted: pecta:timeout"`.

<Warning>
  Setting `timeout` too low can cause gates to return aborted results even when the output is valid. Start with the default `50` ms and reduce only after profiling your gate set.
</Warning>

## Fail-fast behavior

When `failFast` is `true` (the default), the engine aborts the shared `AbortController` the instant a gate returns `passed: false`. Gates that have not yet returned will see `signal.aborted === true`. The engine still waits for every `Promise` to settle, but aborted gates complete almost immediately. Total evaluation latency is therefore dominated by the first failing gate, not the full gate set.

Set `failFast: false` if you want verdicts from every gate regardless of earlier failures — useful for auditing or debugging.

<Note>
  A gate that returns `skipped: true` is treated as passing. The `tmaxGuard` RTB gate uses this to opt out of evaluation when the OpenRTB deadline is already exhausted.
</Note>

## Custom gates

You can write your own gate and pass it alongside the built-in ones. See the [custom gates](/gates/custom) page for the full interface and a worked example.
