Platform
Investigate when AI behaves outside expectations
Unexpected tool calls, prompt injection, agent loops and data leakage. When an AI system steps outside what was intended, the investigation starts at the trace.
Detected to contained
Reference gap
9s
Needing attention
2
The gap between detection and containment is the number anyone reviewing an incident cares about. Collapsing the two into one event hides it.
Why this page is short
The reconstruction is already done.
An AI incident normally begins with a reconstruction problem — which agent, under whose authority, against which rule, holding what data — and that is where the hours go. When the trace already carries all four, the investigation starts at the interesting question.
This is the compounding return on everything else in the platform. Identity, accountability, the policy version and the read grants are all part of each record because they were needed to make the decision — so they are present at investigation time without anyone having planned for the investigation.
What incidents add on top is containment: stopping an agent rather than refusing it one call at a time, and recording who restored it and why.
- Which agent, and under whose authority
- The authority chain is part of every record, so there is no join across three systems and no trusting the clocks. The accountable person is named before anyone starts looking.
- Which rule was in force
- The policy version at the moment of each decision. An incident that spans a rule change stays explainable, which is otherwise one of the harder reconstructions.
- What it was holding
- Which data sources the agent had read grants for and which it actually read. The exposure question is answerable immediately rather than after a data-mapping exercise.
- Every attempt, including the refused ones
- The refusals are in the record. A pattern of them is frequently the earliest evidence, and it is exactly what a success-only trail discards.
What goes wrong
Four kinds, and only one of them needs a new control.
An unexpected tool call is refused by the declared reach. An injection fails because the bound is not in the context window. Leakage is stopped by the sink rule. The loop is the one that needs something else, because no per-action rule can see a quantity.
- Unexpected tool call
- An agent reaching for something it was never granted — usually a grant nobody withdrew after a refactor. Refused at the boundary by the declared reach, and the attempt is the signal.
- Prompt injection
- Untrusted content reaching a context window and asking for a wider action. It fails because the bound is not in the context window: there is no prompt to argue with.
- Agent loop
- Individually legitimate actions in an illegitimate quantity. No per-action rule catches it, which is why the execution limit and the circuit breaker exist.
- Data leakage
- An approved read heading for an unapproved destination. Stopped by the sink rule at the action rather than found later in an export somebody noticed.
Injection fails because there is no prompt to inject into.
This is worth stating plainly because it is the most common question about AI security and the answer here is structural rather than defensive. The bound is not in the context window and is not expressed in natural language, so content arriving in the window has nothing to argue with. An injected instruction can make an agent attempt a wider action; it cannot make the boundary approve one.
The earliest signal is usually a refusal
post.journal_entryAmount is above the journal entry limit
amount ≤ INR 5,00,000
A single refusal is routine. The same refusal repeating is the thing worth paging someone about, and it is only visible because refusals are recorded rather than discarded.
One incident, end to end
Detected at 02:14, contained nine seconds later.
A retry loop, not an attack — which is the realistic case. Every individual payout was inside its bound, so no policy refused any of them. The breaker caught the quantity, and it did so without a human in the path because this agent runs unattended.
Rate anomaly · payout-runner
detected to resolvedRate anomaly on payout-runner
detected02:14Forty-one payout attempts in six minutes against a baseline of three an hour. Every individual action inside its bound, which is why no policy refused any of them.
Circuit breaker tripped
contained02:14The agent is stopped rather than refused call by call. Nine seconds after detection, with no human in the path — the breaker is armed because this agent runs unattended.
Retry loop in the upstream workflow
investigated02:31A timeout handler re-queued the same invoice without an idempotency key. The trace for each attempt names the same subject, which is what identified it as one event rather than forty-one.
Idempotency enforced, agent restored
resolved09:05A named person restored the agent after the upstream fix, and after an execution limit was added that would have contained this in three attempts rather than forty-one.
Three things this timeline shows.
- Detected and contained are separate
- Nine seconds apart. Reporting them as one event would hide the only figure a review actually asks for.
- Containment did not wait for a person
- At 02:14 nobody was awake. payout-runner runs at level 4, unattended, so its breaker is armed by default.
- Restoration is a named decision
- Rahul Menon restored it, after the upstream fix and after a limit existed that would have contained this in three attempts. Coming back up is never automatic.
Detected to contained
9s
no human in the path
Attempts contained
41
all inside their bound
Policies that refused
0
quantity is not a clause
Systems affected
1
the breaker is per agent
IllustrativeAn illustrative incident in the OpsAI sample estate, not a customer event. The agent, its owner and its autonomy level are the fixture estate's own.
What the review reads
The same records, read forwards.
An investigation reads the trail in the order it happened rather than searching it. Every attempt in the incident above has a full trace, and each one names the same subject — which is what identified forty-one events as one.
One attempt, in full
11msThe agent asked
0 msrefund-resolver asked to run issue.refund against Razorpay for ₹18,400 on ORD-40122. Nothing has run yet.
- Passedidentityworkload-id · mTLS attested
- Passedactionissue.refund
- PassedidempotencyACT-7512
Authority traced to a person
1 msEvery hop holds a subset of the hop before it. A sub-agent cannot be talked into authority it was never issued.
- Priya NairSupport Ops
- refund-resolver⊆ parent · L3
Bounds matched
2 msTwo bounds apply. Both were written by the team that owns the risk — not by the agent, and not by a prompt.
- refund.ceiling
- delegation.depth
Bounds evaluated
6 msEvery bound held. The action is cleared to run exactly as asked — no wider.
- Passedagent.identityworkload-id · attested
- Passeddelegation.depth1 ≤ 3
- Passedamount ≤ ceiling₹18,400 / ₹25,000
- Passedscope == own-orderORD-40122 · placed by subject
- Passedorder.statusdelivered
- Passedrate ≤ 5/hour3 / 5 this hour
240 decisions were recorded in this estate over twenty-four hours, including 25 that were held or refused. During an incident that second number is the one being read, and it exists only because refusals are sealed like anything else.
Search it
Audit
By person, system, policy or outcome — and the chain makes a missing entry visible rather than silent.
Spot it earlier
Observability
A refusal rate that moved is usually the first thing anyone notices, and it is an estate-level number.
Stop repeating it
Posture
Whether the estate is improving, scored against what good looks like rather than counted.
Where to start
Ask how long the reconstruction would take.
Not whether you would detect it — most teams would. The question is how long it takes to establish which agent, under whose authority, against which rule, holding what data. That interval is what this changes.