Skip to main content

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.

A quality gate is a named function that receives an agent’s output and returns a pass/fail verdict with an optional reason string. Gates are the core primitive in Pecta: they run on the very first evaluation with no baseline period, execute in parallel within a shared timeout budget, and stop as soon as one fails (fail-fast). Every gate runs inside your own process — there is no network call on the hot path.

How gates run

When you call engine.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.
engine.evaluate(ctx)

├─ gate: latency     ──► pass  (1 ms)
├─ gate: filesystem  ──► FAIL  (2 ms) ──► abort signal sent
├─ gate: pii         ──► aborted       (0 ms)

└─ EvaluationResult { passed: false, total_latency_ms: ~2 }
The 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 (default true) — as soon as one gate returns passed: false, the engine sends an abort signal to all other running gates and marks them as aborted in the result.
  • timeout (default 50 ms) — if the wall-clock budget expires before all gates complete, the engine aborts everything. Timed-out gates appear as failed in the result with reason pecta:timeout.
For RTB pipelines you can tighten the budget to 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 to result.gates:
{
  name: string;         // gate identifier, e.g. "filesystem"
  passed: boolean;
  reason?: string;      // present when passed is false or gate was aborted
  latency_ms: number;   // wall-clock time for this gate only
  skipped?: boolean;    // gate chose not to run; treated as pass
}
The top-level EvaluationResult:
{
  evaluation_id: string;   // unique ID per call
  agent_id: string;
  tool?: string;
  passed: boolean;         // true only if every gate passed or skipped
  gates: GateResult[];
  total_latency_ms: number;
  timestamp: string;       // ISO 8601 UTC
}
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

GateImportDescription
latencygates.latency({ maxMs })Fails if ctx.latency_ms exceeds the configured threshold.
schemagates.schema(zodSchema)Validates ctx.output against a Zod schema; exposes Zod issues in details.
filesystemgates.filesystem()Detects destructive commands (rm -rf), path traversal (../), and references to sensitive directories.
piigates.pii()Flags email addresses, SSN-shaped strings, and phone numbers in the output.
contentgates.content()Rejects empty output and AI refusal phrases that indicate a failed generation.

RTB (under gates.rtb)

GateImportDescription
tmaxGuardgates.rtb.tmaxGuard({ bufferMs })Skips all downstream gates when the OpenRTB tmax deadline is already exhausted, saving the remaining budget for bid submission.
impidMatchgates.rtb.impidMatch()Verifies that every bid.impid in the response matches an imp.id in the original request.
adomainVerifygates.rtb.adomainVerify()Rejects placeholder or malformed advertiser domain entries.
bidSanitygates.rtb.bidSanity({ maxFloorMultiple })Fails bids that are unrealistically far above the floor price (default 50×).
audienceSafetygates.rtb.audienceSafety()Blocks ad categories that violate COPPA or are mismatched with child-directed inventory.
bcatCompliancegates.rtb.bcatCompliance()Ensures response creatives do not appear in the request’s bcat blocked-category list.
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 a name string and a run function is a valid gate. Check the abort signal at the start of expensive operations.
const myGate = {
  name: "my.custom",
  run: async (ctx, signal) => {
    if (signal.aborted) return { passed: false, reason: "aborted" };
    // perform your check against ctx.output
    return { passed: true };
  },
};
run returns GateOutcome:
{
  passed: boolean;
  reason?: string;
  skipped?: boolean;
  details?: unknown;   // structured detail; never include user payloads
}
The engine merges in name and latency_ms before adding the result to EvaluationResult.gates.

Further reading