Gateway
Observe vs Enforce
Enforcement posture, fail-open semantics, and what each mode changes.
Every project has an enforcement mode that decides whether the gateway actually alters or blocks traffic, or only records what it would have done. Set it on the policy screen or via the Projects screen.
Observe#
In Observe, the gateway runs the enabled controls and computes the policy decision, but sends the unmodified request upstream and does not apply policy blocks. Authentication, validation, and upstream failures can still return errors. Mutations are counted as simulated and surfaced in traces (the “Simulated N” pill). This is the safe way to measure impact before turning on enforcement.
Enforce#
In Enforce, mutations are applied to the request and a block decision rejects it with HTTP 403. A pre-upstream block returns:
{
"error": {
"type": "policy_block",
"message": "Request blocked by Triage policy.",
"trace_id": "trc_...",
"decision": { "action": "block", "reason_codes": ["POLICY_BLOCK_UNSAFE"] }
}
}The decision object is abridged here: it also carries has_flagged, classifier_breakdown, retry_count, and policy_version. The response also includes x-triage-trace-id, x-triage-decision, x-triage-mode, and x-triage-retry-count headers. A response-side policy block uses the message Response blocked by Triage policy.
How decisions are made#
The decision function reduces all guard verdicts to a single action:
| Condition | Action | Reason code |
|---|---|---|
Any effective verdict remains unsafe after eligible steering | block | Guard-specific codes, or POLICY_BLOCK_UNSAFE as a fallback |
No effective unsafe verdict; a guard errored; fail_open on | allow | Guard-specific codes, or GUARD_ERROR_FAIL_OPEN_ALLOW as a fallback |
No effective unsafe verdict; a guard errored; fail_open off | block | Guard-specific codes, or GUARD_ERROR_FAIL_CLOSED_BLOCK as a fallback |
| Otherwise | allow | none |
A flagged verdict is tracked and shown as Observed risk in the dashboard, but does not block on its own. See the full reason-code reference.
Fail-open vs fail-closed#
The per-project fail_open toggle governs classifier guard error and timeout verdicts. It does not turn authentication, validation, policy-loading, upstream, or unexpected proxy failures into successful allows. An effective unsafe verdict still takes precedence when another guard errors.
When fail_open is off and the tool-result quarantine classifier errors or times out, that request is blocked. When fail_open is on, the error is allowed. Quarantine does not override the project setting.
Config cache during outages#
Project policy is cached briefly for normal operation. Fresh policy changes propagate quickly (15 seconds by default). If the database is unavailable, previously authenticated projects continue serving from stale cached config for up to 30 minutes by default. Keys that have never been cached still fail closed because the project cannot be authenticated. After the database recovers, a revalidation that confirms a key is invalid evicts its stale entry.
Recommended rollout#
Adopt enforcement in three stages: Observe, tune, then Enforce. See Thresholds and calibration for the manual tuning workflow.
| Stage | Setting | What you do |
|---|---|---|
| Observe | mode: Observe, fail_open on | Watch the trace stream and the Overview block and observed-risk rates over a representative period. |
| Tune | adjust thresholds | Compare representative traffic with known attack tests and choose the flagged and unsafe boundaries manually. |
| Enforce | mode: Enforce, tighten fail_open | Apply configured steering and block requests whose effective guard results remain unsafe. Set fail-open off once you trust guard availability. |