A Gateway Can Be Routed Around
Every control that sits in one place has the same weakness: the traffic that never went through it. Proving coverage is a different problem from enforcing policy, and most stacks only solve the first one.
Here is the question that decides whether an AI control layer survives an audit, and it is not about detection accuracy or latency.
How do you know every call went through it?
A gateway enforces policy beautifully on the traffic it receives. It has nothing at all to say about the traffic it did not. A developer who sets base_url back to the provider, a service deployed before the proxy config was standardized, a background job with its own credentials, a contractor's script: none of those appear in the gateway's records, because from the gateway's perspective they never happened. The record is complete with respect to itself and silent about everything else.
This is not a bug in gateways. It is a property of any control that lives in exactly one place.
Absence of evidence
The problem is that a clean gateway log and a bypassed gateway look identical from the outside. Both produce a tidy record of governed calls. One of them is a complete account of your AI usage and the other is a partial one, and nothing in the artifact distinguishes them.
An auditor will ask. The question takes the form "how do you know this is all of it," and "our gateway logs everything that goes through our gateway" is a tautology, not an answer. Under EU AI Act Article 12 the obligation is traceability of the system's operation, not traceability of the subset that happened to be routed correctly.
An in-process SDK has the mirror version of this weakness. It governs every call in the processes where it is installed and knows nothing about the ones where it is not.
Two witnesses
The answer is not a better single control. It is a second, independent observer, positioned so that the two see different things and their disagreement is detectable.
obsvr runs both. The SDK sits in-process and sees intent: which policy was in force, which rule matched, what the customer hook decided, what the prompt contained before redaction. The gateway sits at the network edge and sees the wire: the provider's raw response, exactly as returned, recorded with its own provenance tier rather than taking the SDK's word for it.
Each one covers the other's blind spot. Traffic that skips the SDK still crosses the gateway. Traffic that skips the gateway is still governed in-process. And because both emit signed events into the same chain, a call recorded by one and not the other is visible as a discrepancy rather than as nothing.
Proving the negative
Two witnesses still leave one hole: a period where a component was simply not running. Silence looks the same as an absence of activity.
The fix is that coverage is asserted rather than assumed. Each SDK instance sends a signed heartbeat carrying its identity and the policy it currently enforces. Those heartbeats are part of the record, so a gap in them is a positive fact about a window where enforcement was not attested, rather than an inference someone has to make from missing rows.
That is the difference between a log and evidence. A log tells you what it contains. Evidence has to also account for what it does not, and a chain where a deletion shows up as a deletion, and an unattested window shows up as a gap, does that. A flat table cannot, because a row that was never written and a row that was removed leave the same trace: none.
What to ask
Where the two witnesses disagree, and why that is the useful part
The value is not that two records exist. It is that they are produced from different vantage points, so a discrepancy carries information a single record cannot.
The SDK records what the application intended to send, after redaction, along with the decision that produced it. The gateway records what actually crossed the wire and what the provider actually returned, marked with its own provenance rather than inheriting the SDK's account of events. When those agree, you have corroboration. When they disagree, you have found something specific: a redaction that did not take effect, a client that was reconfigured, a response that differs from what the application believes it received.
A single-vantage system cannot produce that signal at all, because it has nothing to disagree with. This is the ordinary logic of dual controls, applied to a place the industry has mostly not applied it: it is why financial reconciliation compares two independently produced ledgers rather than reading one of them very carefully.
The uncomfortable version of this question
Turn it on us, because the same weakness applies and pretending otherwise would be exactly the failure this post is about.
obsvr's SDK governs the processes where it is installed, in the languages it ships, which today are TypeScript and Python. A Go service calling a provider directly is not covered. An application whose team never added the package is not covered. Auto-instrumentation removes the need to change call sites; it does not install itself. The gateway closes part of that, and the coverage heartbeats make an unattested window visible rather than silent, but neither one turns a control into something that covers code it was never put in front of.
What we will not do is describe that as complete coverage. Our own security documentation states the bypass surface plainly, including the case where an application simply never invokes the SDK, because a control layer that overstates its reach is producing false confidence, which is worse than a known gap someone can plan around.
What to ask
Whatever you run, ask the vendor how you would detect a call that bypassed it. If the answer describes how thoroughly the control logs what reaches it, the question has not been answered.
Then ask the follow-up: how would you know the control layer was running at all during some window last month? "There are no events from that period" is not an answer, because that is also what a quiet period looks like. Something in the record has to positively assert coverage, or absence stays ambiguous forever.
Coverage and enforcement are separate problems. A stack that solves only the second one produces an audit trail whose most important property, completeness, is the one thing it cannot demonstrate.