HTTP 200. enabled: true. Zero Rows.
The configuration call returned HTTP 200. The long-running operation reported done. We read the configuration back, and
it said enabled: true.
Then we drove real traffic through it: a developer’s coding assistant, five prompts, against a hosted model. The audit log recorded the session. The request-and-response log, the one we had just enabled to capture what was asked and what came back, recorded this:
Audit log: 23 entries
R/R log: 0 rows. Not after 60s. Not after 90 minutes. Not ever.
No error. No warning. Every surface that could answer is this on? said yes.
Why we wanted it
The work was a usage proof for governing AI coding assistants inside an organisation: who used which model, when, from where, and how much. The audit log answers the first four. Only the payload log answers how much, because only it carries the token counts. Without it, governance of usage is a list of calls with no weight attached.
So the payload log was not a nice-to-have. It was the instrument the whole proof rested on, and it was silent.
How both were true at once
We spent five hours varying one thing at a time. Same project, same client, same models. Change the region the call goes to; change the region the logging is configured in; run a scripted call and a real session; wait.
The result, in one sentence: in our May measurement, the payload log fired only when the call’s region exactly matched the configured region, and that region was a single, direct region. Calls to the global endpoint, and to multi-region endpoints, were silently inert. Eight configurations landed zero rows, including one with logging enabled in four regions at once. The configurations that matched a direct region landed rows in about a second.
Two details made it worse than a gap:
- The configuration API accepts a config at any region you write it to, including regions where the model is not even served. Acceptance tells you the request was well-formed. It does not tell you the tap will ever fire.
- The main model the coding assistant used was served only at the global endpoint. Its traffic was structurally invisible to the payload log. Not misconfigured: unloggable, at that time, in any configuration.
A setting that says enabled is a statement about the setting. Whether anything is recorded is a different fact, and
only a row can establish it.
Re-measured on 4 November, before this went out: logging configured at the global endpoint only, one call to the global endpoint. A row landed in about a second. The global gap has closed for the model we probed; we have not re-run the multi-region cases. The May matrix stays as the record of what was true then. We believe the fix for the same reason we doubted the setting: a row appeared.
The instrument nobody thought to doubt
One more measurement from the same session. The coding assistant’s own local transcript recorded five model calls, one per prompt. The audit log recorded 23. The other 18 were the assistant’s internal sub-calls (titling the session, and other work it routed to other models), and they left no local trace at all.
So the three instruments disagreed in three directions. The local transcript was blind to most of its own compute. The payload log was blind to the main model entirely. Only the audit log saw every call, and it could not say how big any of them were. Each instrument was correct about what it saw. None of them saw the whole thing, and none of them said so.
What changed
The payload log is never read alone. Usage is computed by joining it onto the audit log, which records every call. Restricted to the global endpoint, that join returns 23 calls with no matching payload. The blind spot stops being an absence and becomes a count, with a region attached.
The limit is written into the governance guidance as a limit. The recommendation for governing assistant usage now states plainly that calls through the global and multi-region endpoints had no payload capture when we measured, and that “how much” for that traffic comes from the audit log’s call count and the developer-side transcript, each with its own blind spot named.
The working configuration is recorded with its evidence. The one that fires, a direct region matched on both sides, sits next to the eight that don’t, with probe times and the row counts they produced. The next person to set this up starts from the matrix, not from the acceptance code.
Every toggle has its off switch next to it. Enabling the logging and the audit configuration for the proof came with a symmetric disable step in the same script, and both were run when the proof was done. A control that can only be turned on is a control nobody can verify was turned off.
The part worth keeping
The documented behaviour holds for direct regional calls. Our traffic went somewhere else, and the configuration surface had no way to tell us.
The same holds for every control plane: configured and in effect are different claims, and the API that accepts the first is rarely in a position to confirm the second. The only confirmation is downstream, in the place the data is supposed to land.
The line that stays
Before you report that a control is on, go and find the thing it produced.
enabled: true is a claim. A row is evidence.