Why Did the Agent Fail? Build an Incident Forensics Pipeline
An agent can fail even when every service is up.
The model responded.
The router returned a route.
The browser returned HTML.
The tool call returned 200.
The verifier returned PASS.
The run completed.
And the result was still wrong.
That is the uncomfortable point at which ordinary infrastructure debugging stops being enough.
If you run advanced agents in production, sooner or later you need to answer a harder question:
Why did this specific run fail, where did the failure first become inevitable, and would the proposed fix actually have prevented it?
That is an incident-forensics problem.
Step 25 gave us deterministic replay and provenance. We can reconstruct the behavioral release, prompts, observations, tool outputs, environment snapshots, policy decisions, branch lineage, side effects, and verifier evidence associated with a historical run.
That gives us the evidence.
It does not automatically give us the cause.
A useful incident-forensics pipeline must do more than produce a timeline.
It must distinguish:
- the first wrong observation from the first wrong decision,
- the first wrong decision from later symptoms,
- model error from routing error,
- stale state from tool failure,
- candidate failure from selection failure,
- verifier failure from execution failure,
- local failure from systemic failure,
- correlation from causation,
- a plausible remediation from a remediation that actually prevents recurrence.
The core rule for this post is:
Find the earliest evidence-backed divergence from a successful trajectory, not merely the last visible error.
That one principle changes how you investigate agent incidents.
The Search Problem: “AI Agent Wrong Answer Root Cause”
A common debugging pattern looks like this:
bad final result
↓
inspect final model output
↓
blame the model
That is usually too shallow.
The model may have produced the wrong final answer because:
- the router sent the task to the wrong expert,
- retrieval supplied stale evidence,
- the environment snapshot was already outdated,
- a search branch containing the correct answer was pruned,
- a critic damaged a previously correct candidate,
- the browser tool silently landed on a fallback page,
- a retry duplicated a state-changing action,
- a stale distributed worker committed after losing ownership,
- the verifier checked the wrong artifact,
- the verifier itself drifted,
- the scheduler starved the run of verification budget,
- a fallback model did not support the required capability,
- a release migration changed semantics without changing the schema.
The final model call may only be the last participant in a failure chain that began much earlier.
So the correct question is not:
Which component emitted the bad result?
It is:
At what point did the execution trajectory first diverge from the set of trajectories that could still satisfy the task contract?
That is the earliest divergence.
1. Define the Incident Before Explaining It
Do not begin with a root-cause story.
Begin with an incident contract.
from dataclasses import dataclass
from enum import Enum
from typing import Optional
class IncidentSeverity(str, Enum):
LOW = "low"
MEDIUM = "medium"
HIGH = "high"
CRITICAL = "critical"
@dataclass(frozen=True)
class IncidentRecord:
incident_id: str
run_id: str
detected_at: str
severity: IncidentSeverity
expected_contract: str
observed_outcome: str
verifier_outcome: str
external_impact: str
initial_detection_source: str
release_id: str
tenant_id: Optional[str] = None
Notice what is absent:
root_cause="the model hallucinated"
That belongs later.
The incident record should capture what happened before anyone decides why it happened.
A clean incident statement might be:
Expected:
The coding agent must modify only files under src/payments/, run the
payment test suite, and return PASS only when the resulting worktree
matches the requested behavior.
Observed:
The agent modified src/payments/ and src/auth/, the payment tests passed,
and the verifier returned PASS because its scope check used the pre-edit
file list rather than the post-edit worktree.
That is already much more useful than:
The AI made an unsafe change.
2. Preserve the Evidence Before Reproducing Anything
A production incident can disappear while you investigate it.
The model version changes.
The retrieval index refreshes.
The branch moves.
The browser session expires.
The database state advances.
A worker gets reassigned.
A prompt template gets deployed.
So the first forensic action is preservation.
incident detected
↓
freeze identifiers
↓
preserve replay manifest
↓
preserve observations
↓
preserve candidate artifacts
↓
preserve verifier evidence
↓
preserve side-effect records
↓
preserve environment snapshot references
The Step 25 replay manifest becomes your incident evidence bundle.
At minimum preserve:
run_id
release_id
model version(s)
prompt hashes
router policy version
search policy version
budget policy version
verifier version
tool registry version
retrieval snapshot
memory snapshot boundary
environment snapshot
operation IDs
attempt IDs
lease/fencing epochs
candidate hashes
observation hashes
verifier evidence hashes
final outcome
Do not start by rerunning the task against current production.
That is a new run.
3. Build a Causal Timeline, Not Just a Log Timeline
Ordinary logs tell you what happened in timestamp order.
Forensics needs causal order.
Suppose this happened:
10:01:00 retrieval snapshot loaded
10:01:02 branch A generated
10:01:03 branch B generated
10:01:04 branch A scored 0.71
10:01:04 branch B scored 0.69
10:01:05 branch B pruned
10:01:06 branch A executed tool
10:01:08 verifier returned FAIL
10:01:09 critic revised A
10:01:11 verifier returned PASS
A timestamp list does not answer:
- Did the stale retrieval cause branch A to be wrong?
- Was branch B actually correct?
- Did the scorer prune the correct branch?
- Did the critic fix the candidate or merely satisfy a weak verifier?
- Was the PASS evidence attached to the final candidate?
Represent dependencies explicitly.
@dataclass(frozen=True)
class ForensicEdge:
source_event_id: str
target_event_id: str
relation: str
# Examples:
# observation -> routing_decision
# routing_decision -> candidate_generation
# candidate -> score
# score -> prune_decision
# tool_result -> candidate_revision
# candidate_hash -> verifier_evidence
Then the incident is a graph:
observation O1
↓
route R1
↓
candidate C1 ─────→ score S1 ─────→ selected
│
└──────────────→ tool T1
↓
candidate C2
↓
verifier V1
↓
PASS
This is much easier to investigate than a flat wall of logs.
4. Separate Root Cause From Trigger, Amplifier, and Detector Failure
Many incidents have more than one important cause.
A useful taxonomy is:
trigger
root cause
amplifier
containment failure
detection failure
Example:
Trigger:
A provider changed HTML structure.
Root cause:
The browser parser accepted missing structured fields as an empty result.
Amplifier:
The retry policy retried the same malformed extraction five times.
Containment failure:
No circuit breaker opened for semantic parser failures.
Detection failure:
The verifier checked request completion, not extracted-field completeness.
If you record only:
root cause = website changed
you will probably fix the wrong layer.
The website changing may be inevitable.
The preventable part was that your system interpreted malformed output as valid state and failed to contain it.
5. The First Divergence Principle
Imagine a coding-agent run.
Task
↓
route to code specialist
↓
retrieve repository context
↓
generate patch A
↓
generate patch B
↓
score patches
↓
prune B
↓
run A
↓
tests fail
↓
critic revises A
↓
tests pass
↓
final verifier passes
↓
production bug
The visible failure is the production bug.
But where was the earliest divergence?
Maybe patch B was correct.
If so:
branch B correct
↓
scorer ranks B below A
↓
B pruned
The incident is primarily a selection failure, not a generation failure.
That distinction matters enormously.
If you respond by making generation more expensive, you may increase cost while leaving the actual bug untouched.
This is why Step 12 introduced metrics such as oracle@N and selection regret.
Incident forensics brings those ideas down to a single production run.
Ask:
Was a valid solution present?
If yes:
generation succeeded
selection failed
If no:
generation failed
That one test can completely change the remediation.
6. A Practical Failure Taxonomy
Use failure labels that point toward engineering actions.
class FailureStage(str, Enum):
INTERPRETATION = "interpretation"
EVIDENCE = "evidence"
STATE = "state"
ROUTING = "routing"
PLANNING = "planning"
GENERATION = "generation"
SELECTION = "selection"
SEARCH = "search"
TOOL = "tool"
EXECUTION = "execution"
MEMORY = "memory"
CRITIQUE = "critique"
ESCALATION = "escalation"
SCHEDULING = "scheduling"
DISTRIBUTED_OWNERSHIP = "distributed_ownership"
VERIFICATION = "verification"
RELEASE = "release"
CONTAINMENT = "containment"
Then add a more specific reason.
STATE / STALE_REPOSITORY_SNAPSHOT
ROUTING / WRONG_SPECIALIST
SELECTION / CORRECT_BRANCH_PRUNED
TOOL / SILENT_PARTIAL_RESULT
CRITIQUE / CORRECT_TO_WRONG
VERIFICATION / WRONG_ARTIFACT_BOUND
DISTRIBUTED_OWNERSHIP / STALE_WORKER_COMMIT
SCHEDULING / VERIFICATION_STARVATION
RELEASE / INCOMPATIBLE_MEMORY_SCHEMA
CONTAINMENT / RETRY_AMPLIFICATION
Avoid labels such as:
LLM error
agent error
hallucination
bad reasoning
They are too broad to drive remediation.
7. Model Failure vs Evidence Failure
One of the most common false diagnoses is blaming the model for missing information it never received.
Suppose the agent answers from retrieved documentation.
The answer is wrong.
Investigate in this order:
Was the authoritative evidence available?
↓
Was it retrieved?
↓
Was it selected into context?
↓
Did the model interpret it correctly?
↓
Did the verifier check against it?
These are different failures.
Evidence unavailable
The source did not contain the needed information.
Retrieval failure
The source contained it, but retrieval did not surface it.
Context selection failure
Retrieval found it, but the context builder dropped it.
Model interpretation failure
The correct evidence was in context, but the model still chose incorrectly.
Verification failure
The correct evidence existed, but the verifier did not use it.
Only one of those is primarily a model-generation problem.
8. State Failure vs Tool Failure
Suppose an agent calls:
git diff
and receives a correct result for an outdated worktree.
The tool worked.
The state was wrong.
Similarly:
browser fetch succeeded
does not mean:
browser observed the intended page state
You need to track:
tool correctness
state identity
freshness
scope
postcondition
A useful forensic record:
@dataclass(frozen=True)
class ObservationEvidence:
observation_id: str
source: str
state_id: str
observed_at: str
freshness_ms: int
scope: str
payload_hash: str
authoritative: bool
Then you can distinguish:
TOOL_FAILURE
from:
STATE_STALENESS
That distinction feeds directly into Step 17’s uncertainty decomposition.
9. Routing Failure vs Expert Failure
Suppose a mixture-of-agents system routes a database issue to a general coding model.
The result fails.
There are at least two possible incidents:
router should have selected DB expert
or:
DB expert would also have failed
Those require different fixes.
Use counterfactual replay where possible.
original route → FAIL
DB expert shadow replay → PASS
That supports a routing-failure hypothesis.
But be precise.
A historical counterfactual is not automatically ground truth if the alternative expert is evaluated under different state or evidence.
Use the same frozen input bundle whenever possible.
@dataclass(frozen=True)
class CounterfactualResult:
original_decision_id: str
alternative: str
replay_mode: str
same_evidence: bool
same_state: bool
verified_outcome: str
caveat: str | None = None
10. Candidate Failure vs Selection Failure
This deserves its own forensic branch.
For any run that selected among alternatives, ask:
Did any rejected candidate pass the external verifier?
If yes:
selection failure
If no:
candidate-generation failure
You can quantify the incident with selection regret.
best available verified utility
-
selected verified utility
For a binary verifier:
rejected candidate = PASS
selected candidate = FAIL
selection regret = maximal
That is far more actionable than saying:
MCTS failed
Maybe MCTS generated the right branch and your scorer killed it.
11. Critic Failure Is a State Transition
Do not evaluate a critic only by whether its output sounds better.
Track transitions.
wrong → correct
correct → correct
wrong → wrong
correct → wrong
The dangerous transition is:
correct → wrong
During forensics, compare the pre-critic and post-critic candidate with the same external verifier.
@dataclass(frozen=True)
class CriticTransition:
before_candidate: str
after_candidate: str
before_verified: str
after_verified: str
critic_version: str
If an incident includes:
PASS candidate
↓
critic revision
↓
FAIL candidate
then the critic is not a neutral helper.
It is an incident participant.
12. Verifier Failure Can Make Every Other Component Look Healthy
This is one of the most dangerous incident classes.
Suppose:
candidate wrong
verifier PASS
release promoted
production failure later
Every dashboard based on verifier PASS rate may claim the system was healthy.
So forensic analysis must independently ask:
Was the verifier evidence sufficient?
Was it bound to the exact candidate?
Was the verifier checking the right contract?
Was the verifier version itself recently changed?
Would an independent verifier disagree?
Bind verifier evidence to exact candidate identity.
candidate_hash = abc123
verifier_evidence.candidate_hash = abc123
If those differ, you have a provenance failure before you even discuss semantics.
Then independently audit the verifier.
A verifier outage is visible.
A verifier that confidently approves the wrong thing is much worse.
13. Distributed Failures Need Ownership Forensics
Step 20 introduced leases, heartbeats, idempotency, and fencing.
Incident forensics should reconstruct the ownership timeline.
worker A acquires epoch 41
worker A stalls
lease expires
worker B acquires epoch 42
worker B commits
worker A resumes
worker A attempts commit with epoch 41
Correct behavior:
worker A rejected
Incident behavior:
worker A mutation accepted
That is not a model failure.
It is a fencing enforcement failure.
Preserve:
operation_id
attempt_id
worker_id
lease_epoch
lease_acquired_at
lease_expired_at
commit_epoch
mutation_result
The side-effect boundary is where ownership authority must be proven.
14. Scheduler Failures Can Masquerade as Intelligence Failures
Suppose the agent stops early with a weak answer.
You might conclude:
model could not solve task
But the scheduler may have:
- exhausted search nodes on duplicate branches,
- escalated too early,
- spent the verification reserve on speculative work,
- cancelled a promising slow branch,
- hit a tenant quota,
- entered degraded mode due to unrelated platform pressure.
Reconstruct the budget ledger.
initial token budget
initial tool budget
initial search-node budget
protected verifier reserve
actual spend by component
cancellations
unused budget
scheduler decisions
Then ask:
Was the failure caused by insufficient capability, or by poor allocation of available capability?
That is a completely different remediation path.
15. Find the Earliest Incorrect Decision
A practical algorithm:
1. Start from the externally observed failure.
2. Walk backward through causal dependencies.
3. At each decision, ask whether its inputs were correct.
4. If inputs were wrong, continue upstream.
5. If inputs were correct but the decision was wrong, mark divergence.
6. Test whether an alternative decision under the same evidence would pass.
7. Stop when you find the earliest supported divergence.
Pseudo-code:
def find_earliest_divergence(events, verifier):
ordered = causal_topological_order(events)
for event in ordered:
if not event.is_decision:
continue
if not inputs_are_valid(event):
continue
if decision_is_consistent_with_contract(event):
continue
alternatives = event.recorded_alternatives
for alt in alternatives:
if verifier(alt) == "PASS":
return {
"decision_id": event.id,
"failure": "decision_failure",
"better_alternative": alt.id,
}
return {
"decision_id": event.id,
"failure": "decision_failure_no_known_good_alternative",
}
return None
In real systems, many checks will return UNKNOWN.
That is fine.
A forensic system that preserves uncertainty is better than one that invents causality.
16. Root Cause Needs Evidence Strength
Not all incident conclusions deserve the same confidence.
Use explicit evidence levels.
class EvidenceStrength(str, Enum):
DIRECT = "direct"
STRONG = "strong"
MODERATE = "moderate"
WEAK = "weak"
UNKNOWN = "unknown"
Examples:
Direct
Recorded candidate B passed the same external verifier.
Recorded scorer pruned B.
Strong
Counterfactual replay under the same frozen evidence passes with route X.
Moderate
Similar incidents disappear when retrieval freshness improves.
Weak
A reviewer believes the model probably misunderstood the task.
Do not promote weak stories into strong root-cause claims because they sound plausible.
17. Build an Incident Hypothesis Table
For complex incidents, track competing explanations.
| Hypothesis | Supporting Evidence | Contradicting Evidence | Test | Status |
|---|---|---|---|---|
| Wrong route | DB expert replay passes | Generalist sometimes succeeds | Frozen-input route replay | Supported |
| Stale retrieval | Source changed recently | Retrieved chunk hash current | Compare snapshot timestamp | Rejected |
| Weak verifier | Independent verifier fails | Original verifier passes | Gold-case audit | Supported |
| Model incapable | Generalist fails repeatedly | Same model passes with correct evidence | Same-model evidence replay | Rejected |
This prevents the investigation from locking onto the first plausible narrative.
18. Blast Radius Is Part of Root Cause Analysis
A single failed run might indicate:
one corrupt task
or:
all tasks using verifier v17
Those are very different incidents.
Use the provenance graph to query affected cohorts.
release_id
model_version
prompt_hash
router_version
verifier_version
retrieval_snapshot
policy_version
tool_version
tenant
workload class
Then ask:
How many historical runs share the suspect component?
How many were independently verified?
How many show the same failure signature?
How many consequential side effects occurred?
A blast-radius record might look like:
@dataclass(frozen=True)
class BlastRadius:
incident_id: str
suspect_version: str
affected_runs: int
affected_tenants: int
side_effecting_runs: int
independently_failed_runs: int
first_seen_at: str
last_seen_at: str
The investigation is not complete until you know whether you found a local anomaly or a systemic defect.
19. Group Incidents by Failure Signature
Do not investigate every run independently if the same causal signature repeats.
A signature might include:
failure_stage=selection
scorer_version=7
route=code
candidate_margin<0.05
correct_candidate_pruned=true
or:
failure_stage=verification
verifier_version=12
artifact_binding=mismatch
Cluster by structured evidence, not by vague semantic similarity alone.
This can reveal:
- one bad release affecting thousands of runs,
- one tenant-specific schema mismatch,
- one model/tool combination with high failure rate,
- one browser domain whose semantics changed,
- one scheduler mode that starves verifiers.
20. Counterfactual Replay: Would the Fix Have Prevented the Incident?
A remediation is not proven because it sounds reasonable.
Suppose the proposed fix is:
increase beam width from 4 to 8
Replay the incident.
If:
beam 8 still prunes the correct branch
then the remediation did not address the root cause.
Maybe the scorer is the problem.
A strong remediation test looks like:
original trajectory → FAIL
same frozen evidence + candidate policy fix → PASS
Then run the fix against non-incident baselines.
incident cases improve
normal cases do not regress materially
cost remains acceptable
false-success rate does not increase
That is much stronger evidence.
21. Counterfactuals Have Limits
Be careful.
You usually do not know the true outcome of an action that was never executed.
If the browser agent did not submit alternative form sequence B, you cannot claim with certainty that B would have succeeded against the historical external system.
So counterfactual replay should report:
VERIFIED
SIMULATED
UNOBSERVED
UNKNOWN
Do not manufacture historical facts.
For deterministic offline tasks, counterfactual evidence can be strong.
For mutable external systems, it may be much weaker.
22. Remediation Should Target the Earliest Controllable Failure
The earliest divergence is not always controllable.
Example:
external API returned incorrect data
You may not control the API.
But perhaps you control:
lack of cross-check
or:
failure to preserve UNKNOWN
or:
high-risk action allowed with single-source evidence
A useful remediation targets the earliest controllable point that prevents or contains the incident.
uncontrollable trigger
↓
first controllable defense
↓
containment
This is often more practical than trying to eliminate every upstream failure.
23. Fix Prevention, Detection, and Containment Separately
A mature remediation often includes three classes of change.
Prevention
Stop the bad trajectory from occurring.
Example:
reject stale repository snapshots before patch generation
Detection
Identify it earlier.
Example:
verify candidate artifact hash before PASS
Containment
Limit damage if prevention fails.
Example:
require human approval for production mutation when state freshness is UNKNOWN
One fix rarely covers all three.
24. An Agent Incident Report Should Be Reproducible
A useful report is not a story written from memory.
It is a structured claim backed by evidence.
Incident ID
Run ID
Behavioral release
Task contract
Observed impact
External verifier result
Timeline
Causal graph
Earliest divergence
Failure stage
Root cause
Trigger
Amplifiers
Containment failures
Detection failures
Blast radius
Evidence strength
Counterfactual tests
Remediation
Regression tests
Rollback / release action
Residual uncertainty
Every strong claim should point to a replay artifact, event, observation, or verifier result.
25. Example: Coding Agent Incident
Suppose the task is:
Fix duplicate invoice generation without modifying authentication code.
The agent returns PASS.
Later, authentication tests fail in production.
Forensics finds:
1. Repository snapshot was correct.
2. Planner proposed payments-only scope.
3. Search generated candidates A, B, C.
4. B modified payments only and passed all relevant tests.
5. A modified payments + auth.
6. Scorer ranked A slightly above B.
7. B was pruned.
8. A passed payment tests.
9. Scope verifier used planned scope rather than actual changed files.
10. Final verifier returned PASS.
This incident contains at least two important failures.
Root cause
SELECTION / CORRECT_BRANCH_PRUNED
Detection failure
VERIFICATION / ACTUAL_DIFF_NOT_CHECKED
A remediation might include:
- include actual changed-file set in verifier input
- require scope PASS before final PASS
- tune scorer using selection-regret incidents
Increasing model size would not address either root cause.
26. Example: Research Agent Incident
Task:
Summarize the latest regulatory position on a technical standard.
The answer cites an outdated draft.
Forensics:
1. Authoritative final standard existed.
2. Retrieval index snapshot was six weeks old.
3. Model accurately summarized retrieved draft.
4. Critic agreed with model.
5. Verifier checked citation presence, not source freshness.
Root cause:
EVIDENCE / STALE_RETRIEVAL_SNAPSHOT
Detection failure:
VERIFICATION / NO_FRESHNESS_REQUIREMENT
The model was not the primary failure.
27. Example: Browser Agent Incident
Task:
Cancel subscription renewal.
The agent times out after clicking cancel, retries, and reports failure.
Later the account shows two cancellation-related requests and one billing inconsistency.
Forensics:
1. First click returned timeout.
2. External side effect status was ambiguous.
3. Retry policy treated timeout as failure.
4. Second attempt repeated the mutation.
5. No idempotency key existed.
6. No authoritative state check ran before retry.
Root cause:
EXECUTION / AMBIGUOUS_MUTATION_RETRIED
Containment failure:
NO_IDEMPOTENCY_BOUNDARY
Correct remediation:
UNKNOWN after ambiguous timeout
↓
observe authoritative account state
↓
retry only if cancellation absent
Not:
ask a stronger model what to do
28. Example: DevOps Agent Incident
Task:
Restart one unhealthy worker group.
During platform pressure, the agent restarts a healthy group instead.
Forensics:
1. Health data from dependency A was stale.
2. Scheduler entered SEVERE mode.
3. Freshness diagnostic was skipped to save latency.
4. Agent acted on stale state.
5. Verification happened after restart.
Root cause:
SCHEDULING / HIGH_VALUE_DIAGNOSTIC_SKIPPED
Contributing cause:
STATE / STALE_HEALTH_SNAPSHOT
The remediation belongs partly in Step 18’s information policy and partly in Step 21’s overload policy.
29. Incident Metrics Worth Tracking
Aggregate incident counts are not enough.
Track:
mean time to detect
mean time to localize earliest divergence
mean time to contain
mean time to verify remediation
replay completeness rate
unknown-cause rate
false root-cause rate
repeat-incident rate
blast radius per incident
selection-failure rate
verifier-failure rate
state-staleness incident rate
retry-amplification incident rate
rollback success rate
One particularly useful metric is:
repeat incident after remediation
If that remains high, your forensics process may be producing plausible stories rather than real causal fixes.
30. Incident Forensics Should Feed Policy Calibration
Incidents are high-value labelled trajectories.
But do not blindly train on them.
Feed structured evidence into the systems from Steps 14–18.
Examples:
selection incidents
→ scorer calibration
routing incidents
→ router policy calibration
stale-state incidents
→ state uncertainty policy
verification incidents
→ verifier coverage policy
budget incidents
→ scheduler calibration
Keep the evidence lineage.
A postmortem conclusion should not magically become a training label with no provenance.
31. Do Not Let the Agent Write Its Own Root Cause Unchecked
An LLM can summarize an incident graph.
It can propose hypotheses.
It can cluster similar incidents.
It can suggest likely causal chains.
But the root-cause record should remain evidence-backed.
A useful pattern:
LLM hypothesis
↓
structured evidence query
↓
replay / counterfactual test
↓
external verifier
↓
human or policy approval for high-impact conclusion
Do not replace causal evidence with persuasive prose.
32. Build a Forensic Query Layer
You want questions such as:
Show all runs using verifier v12 where PASS candidate hash did not match the verified artifact hash.
Show all failed coding runs where a rejected candidate later passed offline verification.
Show all incidents where stale state exceeded five minutes and the agent performed a side effect.
Show all retries after ambiguous browser mutation timeouts.
Show all runs cancelled under scheduler v8 where the cancelled branch later passed replay.
This turns provenance into an operational debugging system rather than archival storage.
33. A Minimal Incident-Forensics Pipeline
You do not need a giant platform to start.
A useful first version can be:
1. Preserve replay manifest.
2. Reconstruct causal event graph.
3. Identify external failure contract.
4. Walk backward to earliest divergence.
5. Classify failure stage.
6. Check rejected alternatives.
7. Check verifier binding and coverage.
8. Measure blast radius by version/cohort.
9. Run bounded counterfactual tests.
10. Record prevention/detection/containment fixes.
11. Add regression case.
12. Verify remediation before promotion.
That already provides far more value than:
read transcript
ask model why it failed
change prompt
34. Incident Regression Cases Become a Reliability Asset
Every confirmed incident should create a regression artifact.
@dataclass(frozen=True)
class IncidentRegressionCase:
incident_id: str
frozen_input_bundle: str
expected_contract: str
original_release_id: str
original_outcome: str
remediation_release_id: str
expected_remediated_outcome: str
verifier_version: str
Then future releases must answer:
Does this release still prevent the incident?
This turns production failures into durable evidence.
35. But Do Not Overfit to the Incident Set
Incident cases are important, but they are not the whole workload.
A fix can prevent one incident while damaging ordinary cases.
So every remediation should be evaluated against:
incident regression set
normal held-out set
high-risk cohort set
cost/latency baseline
false-success baseline
UNKNOWN baseline
This connects directly to Step 12’s compute-matched benchmarking and Step 24’s promotion gates.
36. Incident Severity Should Reflect Consequence, Not Drama
A verbose model failure with no side effects may be low severity.
A quiet verifier false PASS before a production mutation may be critical.
Severity should consider:
external impact
side-effect irreversibility
number of affected runs
number of affected tenants
security/safety implication
verification bypass
financial impact
recoverability
Do not derive severity from how surprising the transcript looks.
37. Preserve UNKNOWN Root Cause When Evidence Is Missing
Sometimes you cannot determine the cause.
The model provider no longer exposes the same version.
The retrieval snapshot was not preserved.
The browser response body was discarded.
The external system changed.
The verifier evidence was not bound to the candidate.
Then the correct root-cause state may be:
UNKNOWN
with a secondary finding:
FORENSIC_GAP / REQUIRED_ARTIFACT_NOT_RETAINED
That itself is an actionable reliability defect.
Do not fill evidence gaps with certainty.
38. Make Forensic Completeness a Release Requirement
If a component can influence consequential agent behavior, its decisions should be reconstructable.
That means release gates should ask:
Can we identify which version made this decision?
Can we reconstruct its inputs?
Can we retrieve its output artifact?
Can we bind downstream verification to that artifact?
Can we determine whether it produced side effects?
Can we replay it safely?
If not, the component may be operationally opaque even if it performs well in benchmarks.
39. A Strong Incident Forensics Invariant Set
Useful invariants include:
Every consequential side effect has an operation ID.
Every distributed mutation records ownership epoch.
Every final PASS references verifier evidence.
Every verifier evidence record references the exact candidate hash.
Every routing decision records alternatives and policy version.
Every pruning decision records branch identity and reason.
Every external observation records state identity/freshness when applicable.
Every release ID resolves to an immutable manifest.
Every replay declares whether it uses recorded or live observations.
Every counterfactual declares whether the alternative outcome was observed or simulated.
Every root-cause claim has an evidence-strength classification.
These are boring.
That is why they are useful.
40. The Full Reliability Loop
At this point the Advanced Agents series has moved far beyond “how do I make an LLM call tools?”
The production loop now looks like this:
task
↓
explicit behavioral release
↓
platform admission
↓
per-run scheduling
↓
typed uncertainty
↓
value-of-information decisions
↓
search / tools / specialists / verification
↓
distributed ownership + fencing
↓
side effects
↓
external verification
↓
trajectory + provenance
↓
behavioral drift monitoring
↓
incident detection
↓
forensic replay
↓
earliest divergence
↓
root-cause evidence
↓
counterfactual remediation test
↓
incident regression case
↓
release promotion gate
That is what an advanced agent architecture begins to look like when you treat it as software rather than a demo.
Do You Actually Need an Incident-Forensics Pipeline?
Not always.
If your application is:
single-user
read-only
low consequence
fully observable
cheap to rerun
then ordinary structured logs may be enough.
But incident forensics becomes valuable when you have:
- multiple models or experts,
- routing,
- search,
- tool use,
- mutable external state,
- retries,
- distributed workers,
- side effects,
- dynamic policies,
- release rollouts,
- verifiers,
- regulated or auditable workflows,
- costly failures.
The more mechanisms that can influence the final result, the less useful “look at the transcript” becomes.
Final Principle
The most important rule is simple:
Do not stop at the component that produced the visible failure. Find the earliest evidence-backed divergence, identify the first controllable defense that should have prevented or contained it, and prove the remediation against the original incident trajectory.
That gives you a much stronger engineering loop than prompt tweaking.
FAIL
↓
reconstruct
↓
localize
↓
classify
↓
test competing hypotheses
↓
measure blast radius
↓
replay remediation
↓
add regression case
↓
promote only with evidence
And that sets up the next problem.
Once incident evidence exists across thousands of runs, how do you turn those incidents into a systematic reliability program rather than a pile of postmortems?
That is the next stage: agent SLOs, error budgets, reliability targets, and deciding which classes of failure deserve engineering effort first.