Skip to Content
ConceptsFail open, never fail unsafe

Fail open, never fail unsafe

A trust layer with no SLA that can take your agent offline is a trust layer that gets uninstalled. So every failure path in the gate proceeds, and says so. The exception is the one that matters: a verdict already known to block keeps blocking when the network is gone.

What happenedWhat the gate does
Registry unreachable, slow, or answering nonsensenotice, proceed
A response that does not parsetreated as unknownnever as clean
The server could not be identified from its confignotice, proceed, and name the reason
A cached flagged or disputed head, past its TTL, no networkstill blocks, up to 30 days
An unexpected crash anywhere in the gatenotice, exit 0
The hook exceeds its timeoutit is killed and the tool call proceeds, with no notice at all

The three rules underneath that table

1. The warn path must never emit a permission decision.

This is the single most important measured fact in the project. A PreToolUse hook that answers permissionDecision: "allow" grants the call — with no allowlist entry and no user grant, the tool ran. An early version of the SureX spec had the unknown path emitting allow, which would have auto-approved exactly the servers SureX knows nothing about: strictly worse than not installing it. The warn path now emits systemMessage alone, no decision field, which leaves Claude Code’s own permission flow in charge.

SureX has an opinion, not authority, on everything except a flag.

2. A malformed response degrades to unknown, never to clean.

parseVerdictHead() in the frozen contract validates every head before the gate acts on it, and an invalid one becomes a warn. clean is the only state that makes SureX silent, so anything that could produce it by accident would turn every glitch in the stack into a pass. The same rule runs one layer up: in the reviewer, a timeout, an HTTP 500, unparseable output or a single usable run out of two is unreviewable — never clean.

3. A miss may only be cached when the registry actually said so.

Found by running the chain end to end, not by reading the code. The SessionStart prefetch used to synthesise an unknown for every fingerprint the batch endpoint did not mention and cache it. A batch endpoint returning nothing therefore wrote eleven negative cache entries, and the hot path then served a flagged server out of the cache as unknown for the whole negative TTL — no lookup, no block. partitionBatchResponse() now returns answered and unanswered separately, and only answered is cached.

The timeout is a bypass, and there is no fail-closed opt-in. A PreToolUse hook that exceeds its timeout is killed, its stdout is discarded, and the tool call proceeds silently. That matches the posture above, but it also means anything that makes the gate slow disables enforcement. Budget the gate’s own network timeout well inside the hook timeout — which the numbers below do — and never treat the timeout as a control.

The budget, from the contract

SettingValueWhy
positiveTtlMs15 minHow long a head may be cached. The API sends the matching Cache-Control.
negativeTtlMs120 sA miss, and only when the registry actually said so.
flaggedGraceMs30 daysA cached flag keeps blocking with no network at all. A blip must not un-flag a server already known to be bad.
hookTimeoutSeconds10 sThe hook's own timeout. Exceeding it is a silent fail-open, so the budget below sits well inside it.
networkTimeoutMs1500 msThe hot-path lookup gives up here and proceeds.
batchNetworkTimeoutMs6000 msThe SessionStart prefetch, which nobody is waiting on.

The hot-path lookup gives up long before the hook does. The evidence fetch — the only network call that happens while blocking — gets its own 3 s budget, because at that point a human is about to read the message and a few hundred milliseconds is invisible.

What this costs you

Honestly stated: an offline gate is a gate that does not enforce anything it has not already seen. SureX’s answer is not to fail closed — it is to make the one case that must survive an outage survive it, and to make every other failure visible in the transcript rather than silent. The 30-day flagged grace window is that answer.

The largest knowingly-open gap is a different one: /v1/verdict responses are not signed. The gate makes an enforcement decision from an unsigned HTTP response. It is listed in the README’s “what we cut” section rather than left for someone to discover.

Last updated on