Every agent run leaves two kinds of evidence. One explains what happened. The other decides what may happen next. The stack keeps them apart on purpose and joins them on one id, so you can see which problem each part leaves untouched.
Traces, spans, token counts, latencies, prompt and response capture, evaluation reports. It reconstructs what an agent did, in what order, with what inputs, and how much of the context window it burned doing it. When an agent behaves strangely, this is the part that tells you why.
Budgets, policy verdicts, identity, approval ceremonies, hard ceilings. It sits in the request path and answers before the call happens: allowed, refused, or held for a human. Its output is not a chart, it is an action that did or did not occur, and a record that it was decided on purpose.
The control only decides what reaches it. A call that never went through a gateway or a policy point is decided by nothing, and it shows up in the record only if something on its host logged it. Route the agents through the stack before anyone relies on either half.
Take one concrete case: an agent enters a retry loop against a production API at two in the morning and spends four figures before anyone wakes up.
| The record alone | The control alone | Both, on one id | |
|---|---|---|---|
| At 02:00 | Records every call faithfully | Refuses the call that crosses the cap | Refuses it, and records why |
| At 09:00 | You can reconstruct exactly what happened | You know it was stopped, not why it started | Root cause and a bounded loss |
| The bill | Already spent | Capped at the budget | Capped, and attributable per run |
| The fix | A ticket for next sprint | A cap, without knowing the trigger | A cap now, the trigger fixed properly |
| The auditor | Logs, if retention was right | A signed decision record | Both, joined on one id |
The middle column is deliberately uncomfortable. The control alone is safe and opaque: you know an action was refused, and you cannot say what made the agent try. That is a worse place to debug from than most teams expect, which is why the stack keeps the record running beside the control.
The join is the only integration decision that really matters. If the trace, the spend line, the policy verdict and the outcome tag all carry the same run identifier, then the two halves compose: a refusal in the governance record links to the exact chain of calls that led to it, and a spike in the trace links to the budget that stopped it. If they do not, you have two logs and no way to join them.
In this stack the run id is the unit everything keys on, and the governance planes deliberately emit rather than hoard: policy decisions and quality runs export over OTLP when an endpoint is set, into whatever tracing backend you run, the gateway writes its own traces as Parquet, and every plane emits the same agent-event envelope. Governance data can sit in your tracing backend; the enforcement decision is made on the call.
If you already keep traces but have no enforcement, the shortest path to the other half is not a migration. Route model calls through one gateway, watch in shadow mode for a week, then turn on caps where the outliers are. Your traces keep working; they gain a spend line and a verdict per run.
The governance side is laid out in the agent governance guide, the money in FinOps for AI, and the defensive half in AI agent security. All of the tools are Apache-2.0, run on infrastructure you own, and export into the observability stack you already run, when an endpoint is set.
Observability reconstructs what an agent did: traces, token counts, latencies, evaluations. Governance decides what it may do next, in the request path, with a binding answer. One is a record you can question, the other is an action that did or did not happen.
Tracing alone leaves every insight arriving after the action and often after the invoice. Governance alone leaves you safe and opaque: you know an action was refused and cannot say what made the agent try. Most teams already have the first half, and the shortest path to the second is a gateway in shadow mode.
On one run identifier. If the trace, the spend line, the policy verdict and the outcome tag all carry the same id, a refusal links to the exact chain of calls that led to it. If they do not, you own two dashboards and an argument.
No. The governance planes here export over OTLP when an endpoint is set, into whatever backend you already run, and the gateway writes its own traces, so governance data lands in your observability stack rather than competing with it. What does not belong in a dashboard is the enforcement decision itself.
Four questions. Does it act in the path or after it? Is the answer binding, or can the agent proceed past a warning? What happens when it is unreachable, and is that choice documented? Can somebody who does not trust you verify its record?