Behavioral Production Engineering · Steps 23–26Chapter 26 of 45

Why Did the Agent Fail? Build an Incident Forensics Pipeline

Page content

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.