How gates run
When you callengine.evaluate(), the engine starts all configured gates simultaneously using Promise.all. A shared AbortController enforces the timeout budget (default 50 ms). If any gate fails and failFast is enabled (the default), the controller aborts immediately and remaining in-flight gates receive an abort signal and return without doing further work.
total_latency_ms reflects wall-clock time, not the sum of individual gate latencies, because gates run concurrently.
Fail-fast and timeout behaviour
Two configuration options control how the engine handles failures and slow gates:failFast(defaulttrue) — as soon as one gate returnspassed: false, the engine sends an abort signal to all other running gates and marks them as aborted in the result.timeout(default50ms) — if the wall-clock budget expires before all gates complete, the engine aborts everything. Timed-out gates appear as failed in the result with reasonpecta:timeout.
15 ms. For MCP proxy use cases, the default 50 ms gives gates enough room to do regex and schema checks comfortably.
Gate results
Each gate contributes one entry toresult.gates:
EvaluationResult:
passed is true only when every gate either passes or explicitly sets skipped: true. A single passed: false gate makes the entire evaluation fail.
Built-in gates
General
RTB (under gates.rtb)
RTB gates read standard OpenRTB fields from
ctx.input (the bid request) and ctx.output (the bid response). Pass tmaxMs and startedAt on the context to enable the tmaxGuard gate.Writing a custom gate
Any object with aname string and a run function is a valid gate. Check the abort signal at the start of expensive operations.
run returns GateOutcome:
name and latency_ms before adding the result to EvaluationResult.gates.