The Anatomy of a Silent Failure
A failure that never trips an alert still has a shape. Here is what it looks like, stage by stage, from the decision that caused it to the moment someone finally notices.
I have spent a few pieces on the shape of one gap: execution is observable, decisions are not, and the eval sitting between them turns out to be silent about the same thing at a different moment. What none of those pieces did was walk a single failure through its full life, from the decision that started it to the moment it finally became visible. That is what this piece does.
Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.
Every postmortem starts at the wrong end
When a production incident gets investigated, the investigation starts where the pain showed up: the timeout, the complaint, the number that finally moved. From there, someone works backward, hop by hop, until they find the step that first went wrong. That process is necessary, and it is also structurally backward. It starts at the one moment the failure was loud and reconstructs everything before it, which is exactly the part that was quiet.
A silent failure is not an event. It is a sequence, and most of that sequence happens while every dashboard stays green. If you only ever study the loud end, you learn what a failure looks like once it has already stopped being silent, which is the one part of its life that was never the hard part to see.
So run it the other direction. Start at the decision, and follow it forward through every stage that had to go right, for the system, for the failure to stay hidden that long.
The five stages
A silent failure has the same basic anatomy almost every time, regardless of which behavioral pattern it turns out to be. Five stages, in order:
Origination. The point where a decision quietly diverges from the one that was actually warranted.
Local coherence. The output of that decision, examined on its own, looks completely fine.
Absorption. The layers built to catch problems each look at the wrong part of the decision and pass it through.
Compounding. The divergence gets treated as precedent by later decisions, and its footprint grows.
Surfacing. Something finally crosses a threshold, usually somewhere structurally distant from where the divergence began.
None of this is exotic. It is the same mechanism whether the underlying pattern is drift, context erosion, or a stale assumption that never decayed. What changes is the content. The shape stays constant. Walking one case through all five stages is more useful than adding a sixth item to a list of failure types, so here is one, sanitized.
The scenario, sanitized
A CI pipeline has an agent that reviews routine dependency bumps. Patch-level version updates from a small set of trusted packages get auto-merged if the test suite passes. Anything else waits for a human. Ordinary, sensible policy.
Early on, the agent handles a minor-version bump, one step above what the policy actually covers, from a maintainer it already trusts. Tests pass, the diff is small, nothing looks wrong, and it merges. Nobody wrote that exception down anywhere. It just happened once, and it worked.
Stage 1: Origination
That single merge becomes an unlabeled precedent. The next time a similar bump comes from a maintainer, the system already associates it with “safe,” the interpretation it reaches for is the one that already worked, not the policy that was actually written. This is a decision problem before it is anything else: an interpretation forms, gets weighted into later reasoning, and nothing marks it as an exception rather than a rule. I have written before about the primitives a decision like this actually has: interpretation, the considered set, weighting, confidence, context state, and this is what it looks like when one of them quietly wins without ever being checked against the policy it was supposed to defer to.
Stage 2: Local coherence
Here is the part that makes this hard to catch: every individual merge, looked at by itself, is fine. Tests are green. The diff is small. Nothing about this specific decision is anomalous compared to the thousand other routine merges that really were routine. A reviewer glancing at any one of these commits would approve it without a second thought, because in isolation, it deserves that.
This is true of nearly every stage of a silent failure. It is never the decision itself that looks wrong. It is the pattern across many decisions, and no single decision carries the pattern.
Stage 3: Absorption
Everything built to catch a problem here is pointed at the wrong layer. The trace shows a merge that completed successfully, which is accurate. The test suite passed, which is also accurate. If there is an eval on this workflow, it almost certainly grades whether the merge was safe on that input, and this one was; the tests really did pass. None of these instruments were built to ask whether this decision matched the policy’s actual scope. They were built to ask whether the output was correct, and the output was.
This is the same collapse from a different angle each time: execution records what happened, not why it was chosen. An eval grades the output, not the decision that produced it. Here, that collapse means a policy exception gets treated as a policy success, three separate times, by three separate instruments, none of which were wrong about what they measured.
Stage 4: Compounding
The next borderline bump gets judged against the drifted precedent, not the original policy, because the drifted precedent is now what “safe” has come to mean inside the system’s own reasoning. Each new case that fits the pattern gets folded in the same way. The category of “routine” widens, one defensible decision at a time, and every one of those decisions is locally coherent for the same reason the first one was.
Nothing about this shows up as a spike. Merge volume looks normal, maybe even improves, since fewer borderline cases get flagged for review. An aggregate metric, watched for a threshold breach, is the wrong instrument for a slow directional shift that never crosses one.
Stage 5: Surfacing, and the misattribution that follows
Weeks later, a downstream service starts intermittently timing out. Nobody connects this to a dependency bump at first, because nothing about the incident points there. An on-call engineer spends the first few hours on the service itself: retry logic, connection pooling, recent deploys to that service specifically. Eventually, someone traces a changed default, a serialization behavior that shifted in a minor-version bump three weeks back, and finds it was auto-merged.
Here is the part worth sitting with. The natural fix, the one that gets shipped the same week, is usually a narrower rule: exclude this specific package, or require review for this specific maintainer going forward. That patches the symptom. It does not touch the mechanism, which was never about that package. It was an unlabeled precedent that will form again, around a different maintainer, the next time a bump gets treated as routine because an earlier one worked out. The investigation started at Surfacing and worked backward through a chain of individually valid steps, which is exactly the shape that makes it easy to fix the step you found and miss the pattern that produced it.
The anatomy at a glance
| Stage | What's visible | What's actually happening |
|-----------------|----------------------------------------------------------|-------------------------------------------------------------------------------------|
| Origination | A single decision, unremarkable in the trace | An interpretation forms and gets weighted without being checked against policy |
| Local coherence | Each individual output looks correct | The pattern lives across decisions, not inside any one of them |
| Absorption | Trace, tests, and evals all report healthy | Each instrument is grading the artifact, not the interpretation behind it |
| Compounding | Aggregate metrics stay flat or improve | The category the drifted precedent covers keeps widening |
| Surfacing | A symptom appears, structurally distant from the cause | Discovery starts at the symptom and reconstructs backward through valid-looking steps |In closing
The instinct, once a silent failure gets discovered, is to ask which check should have caught it. That question assumes the failure was a single missed detection, sitting at one layer, waiting for the right instrument to look at it. It usually was not. It was coherent at every stage because every instrument evaluated a different artifact than the one that actually failed. The better question is which stage the signal actually died at, and why that stage was structurally incapable of seeing it, because that is the question whose answer generalizes to the next failure instead of just patching this one.
That is also why I think the fix has to be something that can walk this anatomy after the fact, stage by stage, rather than something an engineer reconstructs from scratch under pressure each time. That’s the direction I’m building Nalyqor toward: not another alert at the point of surfacing, but a way to identify failures much closer to their point of origination.
A failure that never announces itself did not skip an announcement. It made it, quietly, at every one of these five stages, to instruments that were built to hear something else.
Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.

