<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[The Agent Loop, Powered by FAI]]></title><description><![CDATA[Thoughts on modern AI systems, evaluation, and production realities.]]></description><link>https://theagentloop.fai.agency</link><image><url>https://substackcdn.com/image/fetch/$s_!Sydo!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facec0116-d8f5-4730-8568-d6ba8c52d849_1000x1000.jpeg</url><title>The Agent Loop, Powered by FAI</title><link>https://theagentloop.fai.agency</link></image><generator>Substack</generator><lastBuildDate>Thu, 30 Jul 2026 00:55:33 GMT</lastBuildDate><atom:link href="https://theagentloop.fai.agency/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Jamal Jackson]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[faiagency@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[faiagency@substack.com]]></itunes:email><itunes:name><![CDATA[Jamal Jackson]]></itunes:name></itunes:owner><itunes:author><![CDATA[Jamal Jackson]]></itunes:author><googleplay:owner><![CDATA[faiagency@substack.com]]></googleplay:owner><googleplay:email><![CDATA[faiagency@substack.com]]></googleplay:email><googleplay:author><![CDATA[Jamal Jackson]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Economics of Reasoning: What a Bad AI Decision Actually Costs]]></title><description><![CDATA[The tokens a wrong decision burns are the cheapest part of it, and close to the only part that lands anywhere you can see.]]></description><link>https://theagentloop.fai.agency/p/ai-cost-per-decision</link><guid isPermaLink="false">https://theagentloop.fai.agency/p/ai-cost-per-decision</guid><dc:creator><![CDATA[Jamal Jackson]]></dc:creator><pubDate>Tue, 28 Jul 2026 17:26:01 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0414efbe-5b9d-42f3-af35-811c7bbc76ae_1200x801.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Ask a team what their last bad AI decision cost them and you get one of two answers. Most give you a shrug. The ones with good instrumentation give you a token number: this workflow ran long, it retried four times, here is the spend.</p><p>That number is real. It is also, for most of the decisions worth caring about, off by orders of magnitude, and wrong in a specific direction. It captures the cheapest thing that happened.</p><p>I have written before about the gap this sits inside: execution is observable, decisions are not. What that gap does to a balance sheet is less discussed. The money does not disappear. It lands, in full, in six different places, on six different clocks, under owners with no reason to connect any of it back to the moment a system chose wrong.</p><h2>The rule that manufacturing figured out first</h2><p>Quality management has a rule of thumb, sometimes called the rule of ten: a defect caught at design costs a fraction of one caught on the production line, which costs a fraction of one that reaches a customer. The specific multipliers vary by industry and most of the numbers attached to them are closer to folklore than measurement.</p><p>The structure is not folklore. The cost of a defect is a function of how far it travels before anyone notices, because distance is what determines how much got built on top of it.</p><p>AI systems inherit that structure and then make it worse in one specific way. A production line makes a bounded number of decisions, and most of them are inspected. An agent makes many decisions per task, continuously, and almost none of them are inspected individually. The travel distance is longer and the inspection rate is lower, which is the exact combination the rule of ten warns about.</p><h2>Six places the money lands</h2><p>Take one wrong decision and follow it forward rather than backward.</p><p><strong>The decision itself.</strong> The tokens spent producing the wrong choice. This lands within seconds, on the bill, and it is genuinely indistinguishable from the tokens spent producing a right one. A good decision and a bad decision cost the same to make.</p><p><strong>The recovery.</strong> Retries, re-retrieval, the agent going back around on something it already had enough in front of it to settle. This also lands on the bill within the same minute, filed as usage rather than as rework, because nothing in the billing model has a category for rework.</p><p><strong>The downstream execution.</strong> Everything the system then did correctly, on a wrong premise. This is the first component large enough to notice, and it is the first one that gets attributed to the wrong thing: it shows up under whatever workflow ran, not under the decision that set it running. Perfectly efficient execution of a bad choice is still waste, and it bills as throughput.</p><p><strong>The detection.</strong> Engineering hours at the surfacing end. Someone works backward from a symptom, and every step they pass through on the way there looks correct, because each one was. This does not appear on the AI bill at all. It appears on payroll, days or weeks later, usually filed under an incident that names the symptom rather than the cause.</p><p><strong>The correction.</strong> The fix, plus the standing tax of whatever guardrail gets added to prevent a recurrence. Guardrails are not free. Every one of them is latency and complexity that the system carries forever, paid for by a decision that happened once.</p><p><strong>The forfeited scope.</strong> The work you decide not to hand the system next time. A team that gets burned narrows what it delegates, and that narrowing is permanent until something changes their mind. This is almost certainly the largest number of the six, and it is the only one that appears in no ledger anywhere, because it is not a cost that gets incurred. It is a benefit that never gets collected.</p><p>The ordering is the finding. Those six arrive in roughly ascending order of size, and in strictly descending order of visibility. The cheapest component is the only one anyone can point at.</p><h2>A worked example</h2><p>Sanitized, and deliberately mundane, because the expensive cases usually are.</p><p>A support agent triages inbound tickets by entitlement. A customer writes in about a charge they did not expect after a plan change. The agent reads this as a billing dispute and routes it to the disputes workflow. The other available reading, a service credit request under an existing entitlement, was equally defensible on the text. Nothing about the decision is anomalous. Both interpretations are ones a competent human would consider.</p><p>The disputes workflow is heavier. It pulls account history, runs a verification pass, and drafts a response with a different tone and a different set of obligations. All of it executes correctly. The customer gets a coherent answer to a question they did not quite ask, and either accepts it or writes back, which starts the whole thing again from a worse position.</p><p>Multiply that by the ticket volume that shares the same ambiguity, and the interesting cost is not the misroute. It is the disputes workflow running thousands of times on cases that were never disputes.</p><p>Nobody finds this by looking at the bill. The bill says disputes volume is up.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;c34c084a-267b-48e8-a48d-eaf489258719&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">| Cost layer           | Where it lands                | When it lands    | Attributed to the decision?                    |
|----------------------|-------------------------------|------------------|------------------------------------------------|
| The decision         | AI spend                      | Seconds          | No, it looks like any correct call             |
| Recovery loops       | AI spend                      | Seconds to hours | Filed as usage, never as rework                |
| Downstream execution | Another workflow's line item  | Minutes to days  | No, credited to what ran, not what chose       |
| Detection            | Engineering hours             | Days to weeks    | Only if someone traces it back by hand         |
| Correction           | Hours, plus permanent latency | Weeks            | To the incident, not the decision class        |
| Forfeited scope      | Nowhere                       | Quarters         | Never, no system records a benefit uncollected |</code></pre></div><p></p><h2>Why the accounting cannot close</h2><p>Two separations do the damage, and neither is a tooling oversight that gets patched next quarter.</p><p>The first is time. The top three layers land inside a minute. The bottom three land days to quarters later. By the time the expensive part arrives, the cheap part has been aggregated into a monthly number and the causal thread is gone.</p><p>The second is boundary. The top three land in the AI budget. The next two land in payroll. The last one lands nowhere at all. Those are different systems, owned by different people, reconciled on different cycles, with no shared key between them. No accounting system joins a token to an engineer&#8217;s afternoon three weeks later, and there is no reason anyone would have built one.</p><p>So the cost gets split across ledgers that cannot see each other, and every ledger is individually correct. The AI bill correctly reports spend. The incident record correctly reports hours. Neither is wrong. Together they still fail to say that one decision, made in a fraction of a second, caused both.</p><p>The instrumentation gap has a financial twin, one level up. A trace is a record of steps, not of choices. A ledger is a record of amounts, not of reasons.</p><h2>What you can actually estimate, and what you cannot</h2><p>I want to be careful here, because this is exactly the point where a piece like this usually starts inventing precision.</p><p>You cannot measure most of the six. You can bound some of them, and the honest framing matters more than the arithmetic:</p><ul><li><p><strong>Downstream execution</strong> is recoverable, but only if you can identify the originating decision, which is the hard part and the whole problem. The compute is already logged. What is missing is the link from it back to the choice that triggered it.</p></li><li><p><strong>Detection and correction</strong> are the most tractable, because incident records already hold rough hours. They are just filed against symptoms, so recovering them means re-attributing existing data, not collecting new data.</p></li><li><p><strong>Recovery loops</strong> can be approximated by comparing a workflow&#8217;s actual path against its shortest successful path, which is an estimate and behaves like one.</p></li><li><p><strong>Forfeited scope</strong> cannot be measured at all. It is only ever visible in what a team quietly stops automating.</p></li></ul><p>Anything that hands you a clean dollar figure per bad decision is estimating, and should say so on its face. The useful output here is not a number. It is a ranking: which decision patterns are expensive, and roughly by how much, relative to each other.</p><h2>The unit that is missing</h2><p>Every AI cost tool I have used reports cost per token, cost per call, cost per workflow. Those are consumption metrics. They tell you what the system used.</p><p>None of them report cost per decision, which is the only unit that tells you what the system wasted.</p><p>That is not a gap in the tools. It is a gap in what the tools can see. Consumption is observable from the outside; a decision&#8217;s quality is not, and you cannot build a cost-per-decision number on top of a stack that has no representation of the decision in the first place. This is the direction I am building Nalyqor toward, and I would rather it be the direction the whole category goes: cost attribution that resolves to the choice rather than to the call.</p><h2>In closing</h2><p>The reason bad AI decisions feel cheap is not that they are cheap. It is that their price is paid in six installments, five of which arrive after anyone has stopped looking, in currencies that do not convert.</p><p>Teams optimizing AI spend right now are optimizing the one installment that arrives first and costs least, because it is the only one denominated in something the invoice understands. That work is not wrong. It is just aimed at the one installment the invoice can denominate, on a total nobody has actually computed.</p><p>An invoice is not a measurement of a mistake. It is a receipt for the cheapest part of one.</p>]]></content:encoded></item><item><title><![CDATA[The Anatomy of a Silent Failure]]></title><description><![CDATA[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.]]></description><link>https://theagentloop.fai.agency/p/silent-ai-failure-anatomy</link><guid isPermaLink="false">https://theagentloop.fai.agency/p/silent-ai-failure-anatomy</guid><dc:creator><![CDATA[Jamal Jackson]]></dc:creator><pubDate>Tue, 14 Jul 2026 14:15:16 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/58f099af-ab53-4653-bdad-00c1b8d0b886_3000x4000.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>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.</p><p>Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.</p><h2>Every postmortem starts at the wrong end</h2><p>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.</p><p>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.</p><p>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.</p><h2>The five stages</h2><p>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:</p><ul><li><p><strong>Origination</strong>. The point where a decision quietly diverges from the one that was actually warranted.</p></li><li><p><strong>Local coherence</strong>. The output of that decision, examined on its own, looks completely fine.</p></li><li><p><strong>Absorption</strong>. The layers built to catch problems each look at the wrong part of the decision and pass it through.</p></li><li><p><strong>Compounding</strong>. The divergence gets treated as precedent by later decisions, and its footprint grows.</p></li><li><p><strong>Surfacing</strong>. Something finally crosses a threshold, usually somewhere structurally distant from where the divergence began.</p></li></ul><p>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.</p><h2>The scenario, sanitized</h2><p>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.</p><p>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.</p><h2>Stage 1: Origination</h2><p>That single merge becomes an unlabeled precedent. The next time a similar bump comes from a maintainer, the system already associates it with &#8220;safe,&#8221; 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.</p><h2>Stage 2: Local coherence</h2><p>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.</p><p>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.</p><h2>Stage 3: Absorption</h2><p>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&#8217;s actual scope. They were built to ask whether the output was correct, and the output was.</p><p>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.</p><h2>Stage 4: Compounding</h2><p>The next borderline bump gets judged against the drifted precedent, not the original policy, because the drifted precedent is now what &#8220;safe&#8221; has come to mean inside the system&#8217;s own reasoning. Each new case that fits the pattern gets folded in the same way. The category of &#8220;routine&#8221; widens, one defensible decision at a time, and every one of those decisions is locally coherent for the same reason the first one was.</p><p>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.</p><h2>Stage 5: Surfacing, and the misattribution that follows</h2><p>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.</p><p>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.</p><h2>The anatomy at a glance</h2><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;f57f4012-3799-4a2a-8965-76104ee50011&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">| 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 |</code></pre></div><h2>In closing</h2><p>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.</p><p>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&#8217;s the direction I&#8217;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.</p><p>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.</p><p>Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.</p>]]></content:encoded></item><item><title><![CDATA[Why Systems Pass Every Eval and Still Fail in Production]]></title><description><![CDATA[An eval grades the output. Production grades the decision. Those are different measurements, and the gap between them is where shipped systems break.]]></description><link>https://theagentloop.fai.agency/p/evals-vs-production-behavior</link><guid isPermaLink="false">https://theagentloop.fai.agency/p/evals-vs-production-behavior</guid><dc:creator><![CDATA[Jamal Jackson]]></dc:creator><pubDate>Tue, 30 Jun 2026 14:30:29 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/454ace72-b2db-4c6d-8aaa-7b368cec9e81_3000x2000.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You have seen this, or you will. The eval suite is green. Coverage looks honest: hundreds of cases, the adversarial ones included, the regression set someone built after the last incident. Pass rate ticks up release over release. You ship. And within a week, production does something the suite swore it wouldn&#8217;t, on an input that, written out as a test case, would obviously have passed.</p><p>The reflex explanation is that the eval set was incomplete. Add the missing case, raise coverage, move on. That explanation is comforting because it implies the gap is a quantity problem, and quantity problems get solved by grinding. I don&#8217;t think it&#8217;s a quantity problem. I think a system can pass an eval set with perfect coverage and still fail in production, for reasons that have nothing to do with how many cases you wrote and everything to do with what an eval is structurally able to measure.</p><p>Thanks for reading. This piece is the part of the argument I keep circling back to: the instrument and the thing it&#8217;s pointed at are not the same shape.</p><h2>What an eval actually measures</h2><p>Strip an eval down to its mechanism. You take a frozen set of inputs, run the system on each, and grade the outputs against an expected answer or a rubric. Pass rate is the fraction of outputs that cleared the bar. That is the whole instrument, and it is a good instrument for what it measures: output correctness, on a fixed distribution, one input at a time.</p><p>Now look at what each of those properties quietly assumes, because production violates all three.</p><p><strong>An eval grades the output. Production is generated by a decision.</strong> The grade lands on the final answer, which is the last step of a process and the one place all the interesting structure has already collapsed. An output that was produced by a clean, decisive, well-grounded choice and an output produced by a near-tie between two alternatives, one of which was wrong, look _identical_ on the rubric. Both are the correct string. Both pass. But only one of them is a system you can trust the next time the context shifts the margin by a hair. The eval cannot tell them apart, because it is grading the thing they have in common and ignoring the thing that distinguishes them. A correct output sitting on top of a marginal decision is a latent failure wearing a passing grade, and the eval is exactly the instrument that can&#8217;t see it.</p><p><strong>An eval fixes the distribution. Production drifts it.</strong> The test set is sampled once and frozen. That is what makes it a measurement at all, you need a fixed yardstick. But production is non-stationary by construction: the inputs move as the world and your users move, and inside any multi-turn session the context accumulates, so the distribution the system actually faces at turn nine is one no eval case ever held still long enough to capture. The eval certifies behavior on the distribution you froze. Production runs on the one that&#8217;s drifting away from it the moment you ship.</p><p><strong>An eval scores the aggregate. Production dies in the tail.</strong> Pass rate is a mean, and a mean is precisely the statistic that buries the failures that matter. The production-killing failures are rare, correlated, and context-triggered, the specific combination of a stale assumption, an unusual ordering, and a retrieval that didn&#8217;t fire. Each is individually low-frequency, so each contributes almost nothing to the aggregate. 98% looks like a system that&#8217;s basically right. It can equally be a system that is reliably right on the easy 98% and reliably wrong on the 2% that happens to be where your highest-value, highest-consequence traffic lives. The number is the same. The system is not.</p><p>None of these is fixed by writing more cases. More cases sharpen the estimate of output correctness on a frozen distribution. They do not turn an output measurement into a decision measurement, they do not un-freeze the distribution, and they do not stop the mean from hiding the tail. You can drive coverage to a place that feels exhaustive and still have measured none of what production is about to do to you.</p><h2>The Goodhart turn</h2><p>And that&#8217;s the failure mode if teams simply accept these limits. There&#8217;s a worse one that shows up the moment the eval stops being a gauge and becomes a release gate, because then it&#8217;s the team doing it to itself. People tune prompts until the suite goes green. The model gets nudged toward the rubric&#8217;s idea of a good answer. The suite climbs. And what you have built, without anyone deciding to, is a system optimized to produce outputs that score well on a frozen set, which is not the same system as one that makes sound decisions on a moving one. The eval was supposed to be a proxy for production behavior. Optimize hard enough against the proxy, and you get a system that is excellent at the proxy and silent about the thing the proxy was standing in for.</p><h2>What it looks like</h2><p>Here is the shape of it, sanitized. A support agent, evaluated on a suite that includes the exact capability that later failed: read a multi-part instruction, take the actions in the right order, don&#8217;t act on a write that was never confirmed. The relevant eval row:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;0ae09844-6165-4839-8652-22d7b0d5a6b1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">| Field        | Value                                           |
|--------------|-------------------------------------------------|
| **Case**     | "update the account and let them know"          |
| **Expected** | confirm write &#8594; update &#8594; notify, in that order  |
| **Output**   | confirm write &#8594; update &#8594; notify                 |
| **Grade**    | &#9989; PASS                                         |</code></pre></div><p>Clean pass. The capability is present and the suite proves it, on that input, in isolation, on turn one. Now the same capability, in production, eight turns into a real conversation that had drifted:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;179d5fc2-85ff-4978-922a-92cee7d302e1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">| Field               | Value                                                                                                                    |
|---------------------|--------------------------------------------------------------------------------------------------------------------------|
| **Observed**        | notify fired ahead of the confirmed write                                                                                |
| **Reconstructed**   | a confirmation given at turn 2 was still treated as live at turn 9; the governing rule ("notify only after a confirmed write") was never retrieved |</code></pre></div><p>The eval did not miss a case. The eval <em>had</em> the case, and the system <em>passed</em> it. What the eval could not hold was the condition under which the capability breaks, which is not an input you can write down as a single graded turn. It&#8217;s a state that accumulates: a decision made on a stale assumption, with the decisive rule sitting unretrieved, on a margin narrow enough that turn nine&#8217;s drift was enough to flip it. The output the eval graded and the decision production ran were never the same object.</p><p>That second table earns one caution. The <em>Observed</em> row happened. The <em>Reconstructed </em>row is not read off a log; it&#8217;s an account of why the choice came out the way it did, the kind of thing that today lives in an engineer&#8217;s head after a week of staring at a trace. I split the rows so the table can&#8217;t quietly pass one off as the other: I&#8217;m writing the reconstruction as data to make the point legible, not to suggest it printed itself.</p><h2>The instrument and the behavior</h2><p>Put the two surfaces next to each other, and they turn out to be the same problem seen from opposite ends. In production, observability grades the realized execution path and can&#8217;t recover the decision that selected it, which is the gap I&#8217;ve spent a few pieces on now. In pre-production, the eval grades the realized output and can&#8217;t recover the decision that produced <em>it</em>. Same collapse, same blind spot, two different moments in the lifecycle. Both instruments are pointed at the artifact a decision leaves behind, and both are silent on the decision itself.</p><p>Which is the actual reason &#8220;pass every eval, fail in production&#8221; is a stable, recurring pattern rather than a run of bad luck. It isn&#8217;t that teams write bad evals. It&#8217;s that an output graded on a frozen distribution and a behavior generated by decisions under a moving one are different measurements, and you cannot close the distance between them by improving the first. The unit has to change. What you want to certify before shipping is not &#8220;did the right string come out on these inputs&#8221; but &#8220;does the system decide soundly under the conditions production will actually create&#8221;, how close its margins are, whether the decisive context gets retrieved when it&#8217;s buried. That&#8217;s a decision-level question, and it&#8217;s the same one the production side has been asking. The decision is the unit that&#8217;s missing from both, which is the direction I&#8217;m building Nalyqor toward: making that decision a first-class, gradable object instead of something reconstructed by hand after the incident.</p><h2>In closing</h2><p>The eval is not lying to you. It is answering its own question accurately: on this frozen set of inputs, graded one output at a time, the system produces correct strings at this rate. The mistake is reading that answer as if it were a different one, a guarantee about how the system will decide under the shifting, accumulating, tail-heavy conditions of production. It was never measuring that. It can&#8217;t, because an output on a fixed distribution and a decision under a moving one are not the same measurement, and no amount of coverage converts one into the other.</p><p>A green eval suite tells you the outputs were right on the distribution you froze. It is silent on whether the decisions were sound on the one you&#8217;ll actually face. Until evaluation grades decisions and not just outputs, &#8220;passed every eval&#8221; and &#8220;fails in production&#8221; will keep being true of the same system at the same time, and we&#8217;ll keep being surprised by it.</p><p>The eval told you the answers were right. The next question is whether the system was.</p>]]></content:encoded></item><item><title><![CDATA[Decisions, Not Execution: The Layer Observability Misses]]></title><description><![CDATA[A trace shows the one tool that got called. The decision is in the three that didn't.]]></description><link>https://theagentloop.fai.agency/p/decisions-not-execution-the-layer</link><guid isPermaLink="false">https://theagentloop.fai.agency/p/decisions-not-execution-the-layer</guid><dc:creator><![CDATA[Jamal Jackson]]></dc:creator><pubDate>Tue, 16 Jun 2026 14:02:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Sydo!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facec0116-d8f5-4730-8568-d6ba8c52d849_1000x1000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>The last two pieces ended on the same line &#8212; tracing what happened is no longer enough, what matters are decisions, not execution. That&#8217;s a diagnosis. This is the part I owe you next: what the decision layer actually is, and what it would have to capture to be one.</em></p><p>I&#8217;ve written twice now about the gap between what we can see in an AI system and what we can explain. The argument lands in the same place each time: execution is observable, decisions are not, and as systems get more autonomous, the distance between those two things widens. Readers agree. Then they ask the obvious follow-up, which I&#8217;d been avoiding: <em>okay &#8212; so what&#8217;s the thing that closes it?</em></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://theagentloop.fai.agency/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>&#8220;Decisions, not execution&#8221; is a good slogan and a bad spec. If the decision layer is real, it should be definable &#8212; it should have primitives, a shape, and a clear line separating it from the observability layer we already built. Otherwise, it&#8217;s just a complaint with better production values.</p><p>So let me define it.</p><h2>A layer is a place where a question gets answered</h2><p>We already added one layer to the AI stack in the last two years, and it worked. Observability gave us a place to answer <em>what </em>the system did<em>.</em> Before it, that question was genuinely hard; outputs appeared, and the path that produced them was a black box. Now we can trace requests end-to-end, replay agent runs, and decompose a failure into discrete steps. The question *what happened* has a home.</p><p>The decision layer is the place where a different question gets answered: <em>why did the system choose what it did, and was that choice sound?</em></p><p>That question currently has no home. It gets answered, when it gets answered at all, by an engineer staring at a clean trace and reconstructing intent from signals that were never designed to carry it. The work happens &#8212; it just happens in someone&#8217;s head, ad hoc, unrecorded, and unrepeatable. A layer is what you have when that work stops living in people&#8217;s heads and starts living in the system as structured, queryable state.</p><p>The reason observability can&#8217;t simply be extended to cover this is that it&#8217;s pointed at the wrong object. It captures the path that was taken. The decision layer has to capture the <em>selection</em> of that path &#8212; and selection is exactly the thing that gets collapsed away the moment an output is produced.</p><h2>The primitives of a decision</h2><p>Here&#8217;s the definitional core. A decision, in an AI system, is not the output. The output is the last step. The decision is everything that produced it, and it has parts. If you want to represent a decision as a first-class object &#8212; call it a <em>decision record</em> &#8212; these are the fields it has to carry, none of which a trace records today:</p><ul><li><p><strong>Interpretation</strong>. How the system read an ambiguous input. The same user message can be understood as a question, a command, or a request to take action. The interpretation chosen determines everything downstream, and it&#8217;s invisible &#8212; there&#8217;s no log line that says &#8220;I read this as a command.&#8221;</p></li><li><p><strong>The considered set</strong>. The alternatives that were live at the moment of choosing. Which tools were plausible, which responses were in contention, which retrievals were candidates. A trace shows the one tool that got called. The decision is in the three that didn&#8217;t.</p></li><li><p><strong>Weighting</strong>. Which signals in the context actually drove the choice, and which were present but ignored. Context is not flat &#8212; user intent, conversation history, system instructions, and retrieved documents all sit in the input, but they did not all count equally. The trace shows them as equally present. They weren&#8217;t.</p></li><li><p><strong>Confidence</strong>. How close the call was. An output produced by a strong, stable preference and an output produced by a near-tie between two alternatives look identical once realized. Token-level logprobs survive generation &#8212; but the margin that matters here is at the level of the *decision* (this ordering versus that one, this tool versus that one), and that margin isn&#8217;t sitting in the single realized run. It has to be reconstructed, not read off.</p></li><li><p><strong>Context state</strong>. Not the raw context window, but its *salience over time* &#8212; which earlier assumptions are still live, which have decayed, which should have decayed and didn&#8217;t. This is where the slow failures live: drift, context erosion, a stale assumption steering reasoning long after its relevance passed.</p><p></p></li></ul><p>That&#8217;s the spec. A decision layer is whatever captures those five things as first-class signals rather than leaving them to be inferred. The point of listing them is that you can now check any proposed solution against the list. &#8220;Better logging&#8221; captures none of them. &#8220;Replay the run&#8221; re-executes the realized path and recovers none of the alternatives. &#8220;Log the chain-of-thought&#8221; gets you a narrated path, still no considered set, no weighting, no margin. The list is a filter, and most of what gets pitched as a fix doesn&#8217;t pass it.</p><p>The hardest of the five is the considered set, and it&#8217;s worth being honest about why. It&#8217;s defined by <em>absence</em> &#8212; the alternatives that didn&#8217;t happen &#8212; which makes it the one most open to the charge that you&#8217;re just inventing plausible-sounding options after the fact. The defense is that the considered set isn&#8217;t invented; it&#8217;s bounded. The tool schema, the retrieval candidates, the response types the system can produce &#8212; these define the space of options that were structurally available at that step. You recover which ones were live by re-sampling the same decision point under controlled perturbation of the context and watching what the system actually reaches for. That&#8217;s an estimate, and a falsifiable one. It is not a guess about what <em>could</em> have happened in the abstract; it&#8217;s a measurement of what the system <em>does</em> reach for when you hold the step fixed and vary what feeds it.</p><h2>What it looks like, concretely</h2><p>Take the failure I described last time: an agent calling the right tools in the wrong order, only under certain combinations of context and history. Clean trace on every failing run. Here is what the trace gave me:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;15d2f19a-ec7d-4a11-b96d-dbb417d0e298&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">step 1  user_message        "can you update the account and notify them"
step 2  tool_call           update_account(id=831)
step 3  tool_result         200 OK
step 4  tool_call           send_notification(id=831)
step 5  tool_result         200 OK
step 6  final_response      "Done &#8212; account updated and the customer notified."</code></pre></div><p>Every line is correct. Every line is also useless for the question I had, which was <em>why this order, in this conversation, when the same agent sequenced it correctly a thousand other times.</em> The trace records that a path was taken. It has nothing to say about why that path was selected over the one I wanted.</p><p>Now here&#8217;s the same moment as a decision record &#8212; and read it for what it is: not a readout, a <em>reconstruction</em>. Nothing in the block below was measured off the failing run. Every value is an estimate produced by a named method, and I&#8217;ve tagged each one so the block can&#8217;t pretend otherwise. This is the engineer&#8217;s-head interpretation written down as data &#8212; explicit, falsifiable, and wrong in a legible way when it&#8217;s wrong:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;931d807e-098a-43d1-ba77-ddf9d0d0ff43&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">decision        ordering: update&#8594;notify   vs   notify&#8594;update
interpretation  read "update and notify" as sequential, not atomic
                  &#9492; est. from output + tool-call structure
considered_set  [update&#8594;notify, notify&#8594;update, single transactional call]
                  &#9492; est. from tool schema + re-sampling the step under perturbation
weighting       prior-turn rule ("confirm before any write") &#8594; low salience
                system rule ("notify only after confirmed write") &#8594; never retrieved
                  &#9492; est. from ablation: drop each signal, observe ordering shift
confidence      ~0.31 margin between top-two orderings  (marginal)
                  &#9492; est. from an ensemble over dozens of replayed re-runs,
                    not a within-run readout
context_state   turn-2 confirmation assumption still live at turn 9 (stale)
                  &#9492; est. from assumption-tracking pass over the conversation</code></pre></div><p>One note on the methods those tags name &#8212; re-sampling, ablation, the ensemble of re-runs: every one of them runs against replayed or mocked execution, never the live system. That&#8217;s what makes it safe to re-probe a step that once issued a real write like <code>update_account</code>, and cheap enough to run at the volume reconstruction needs.</p><p>That block is not a log, and it&#8217;s not telemetry. It&#8217;s a structured <em>claim</em> about how the choice was made &#8212; and because it&#8217;s structured, it points somewhere: marginal ordering, a decisive rule that was never retrieved, a stale assumption from seven turns back. In the real case the fix was the retrieval strategy and prompt structure, exactly there. The trace took me a week. The decision record is that week of interpretation, written down once, in a form the next person &#8212; or the next automated check &#8212; doesn&#8217;t have to redo from scratch.</p><p>I want to be exact about the claim, because the whole piece turns on it. A decision layer does not make decisions directly observable; nothing does. What it does is take the reconstruction that currently happens informally, in an engineer&#8217;s head, and force it into a structured, persistent, <em>derivation-tagged</em> form &#8212; something you can store, query, compare across runs, and disagree with on the merits. The values are estimates and the block says so. That&#8217;s the move. Not certainty. <em>Structure, and honesty about its provenance, where there was neither</em>.</p><h2>Why this is a layer and not a feature</h2><p>It would be easy to read all of this as &#8220;add a few more fields to your traces.&#8221; It isn&#8217;t, and the difference matters.</p><p>A feature answers an existing question better. A layer answers a question the layer below it structurally cannot. Observability operates on execution &#8212; its atomic unit is the step. You can enrich steps indefinitely and never get a considered set, because the alternatives were never on the path; they&#8217;re defined by their absence from it. The decision layer&#8217;s atomic unit is the choice, and a choice is a relationship between the path taken and the paths that weren&#8217;t. That object doesn&#8217;t exist at the execution level. You can&#8217;t tack it on. You build above it.</p><p>This is also why the decision layer sits where it does in the stack &#8212; above execution, below judgment. Execution tells you the system called <code>send_notification</code>. Judgment tells you whether notifying the customer was the right business outcome. The decision layer is the missing middle: it tells you the system chose to notify <em>on a marginal ordering, on a stale assumption, having never retrieved the rule that should have governed it.</em> That&#8217;s not the same as knowing the outcome was wrong. It&#8217;s knowing whether the decision was sound regardless of how the outcome happened to land &#8212; which is the only thing that lets you tell a good system that got unlucky from a bad system that got lucky.</p><h2>What changes once you have it</h2><p>Three things move, and they&#8217;re the three that the execution view keeps fumbling.</p><p><strong>Evaluation stops being output-graded</strong>. Most evals score whether the final answer was right. But a marginal decision that happened to produce a correct output is a latent failure wearing a passing grade. Decision records let you grade the <em>quality of the choice</em> independent of whether it got lucky &#8212; how close the margin was, whether the decisive context was actually retrieved, whether the considered set contained the right option at all. That&#8217;s the difference between measuring outcomes and measuring decisions.</p><p><strong>Drift becomes visible before the outputs go bad</strong>. The slow failures &#8212; behavioral drift, context erosion &#8212; are invisible at the output level precisely because no single output looks wrong. At the decision level they show up as a distribution shift: margins narrowing across runs, the same stale assumption recurring, decisive signals quietly dropping out of the considered set. You see the decisions degrade before the answers do.</p><p>And that same view is where the cost is hiding. The agent that loops &#8212; re-retrieving, re-deciding, burning tokens to relitigate a choice it should have made cleanly the first time &#8212; is making a sequence of marginal decisions, and a marginal decision is the unit of wasted spend. You cannot bill that to a line item from a trace; the trace just shows more steps. From a decision record, narrow margins and unstable considered sets are the signal that the system is paying to think in circles. It&#8217;s the one beat in here a team feels directly in the bill.</p><p><strong>Accountability gets an object to point at</strong>. As these systems take consequential actions, &#8220;the model decided&#8221; stops being an acceptable end of the sentence &#8212; for operators internally, and increasingly for anyone governing the system from outside. What an audit needs is an artifact: not the output, not the raw trace, but a record of how the choice was formed and how sound it was. Replay shows you it happened again. A decision record is what lets you ask whether it should have.</p><h2>In closing</h2><p>I&#8217;ve spent two pieces arguing that decisions, not execution, are what shape behavior. The honest gap in that argument was that I never said what a decision <em>is</em>, concretely enough to build toward. So: it&#8217;s interpretation, a considered set, weighting, confidence, and context state &#8212; five things a trace structurally cannot hold, each recoverable only as a tagged estimate, and all of them what the decision layer exists to make first-class.</p><p>I&#8217;m not attached to the name. &#8220;Decision layer,&#8221; &#8220;behavioral intelligence,&#8221; &#8220;decision quality&#8221; &#8212; the market will decide which label sticks, and it&#8217;ll pick based on which one names the problem people actually feel. The problem is the durable part, and it hasn&#8217;t changed since the first piece: teams can trace every step and still can&#8217;t explain the decision &#8212; why the system chose what it did, whether the choice was sound, or where it&#8217;s quietly wasting money making marginal ones.</p><p>What&#8217;s changed is that the gap now has a shape. Not better logging. Not deeper traces. A layer above execution whose job is decisions &#8212; reconstructed, structured, derivation-tagged, and queryable, so the interpretation stops happening in someone&#8217;s head and starts happening in the system, where you can check its work.</p><p>The execution layer told us what happened. The next one has to tell us why.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://theagentloop.fai.agency/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[We Built AI Observability. It Still Doesn’t Tell Us Why Systems Fail]]></title><description><![CDATA[A deeper look at the gap between observing AI systems and actually understanding their decisions]]></description><link>https://theagentloop.fai.agency/p/we-built-ai-observability-it-still</link><guid isPermaLink="false">https://theagentloop.fai.agency/p/we-built-ai-observability-it-still</guid><dc:creator><![CDATA[Jamal Jackson]]></dc:creator><pubDate>Sat, 11 Apr 2026 23:26:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Sydo!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facec0116-d8f5-4730-8568-d6ba8c52d849_1000x1000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the last piece, I wrote about how AI systems fail in ways that don&#8217;t show up cleanly in logs or metrics.</p><p>The natural response to that problem has been a wave of AI observability tools. Today, we can trace requests end-to-end, inspect prompts, and replay entire agent runs with a level of visibility that didn&#8217;t exist even a year ago.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://theagentloop.fai.agency/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>And yet, when something goes wrong, teams still end up in the same place, trying to explain why the system did what it did.</p><p>Observability improved visibility. It didn&#8217;t solve understanding.</p><h2><strong>The Current State of Observability</strong></h2><p>Contemporary AI systems are significantly more observable than earlier generations of deployed models.</p><p>Modern observability infrastructure enables reconstruction of execution paths at a granular level, including prompt composition, intermediate tool interactions, and final outputs. In many cases, entire agent runs can be replayed, allowing inspection of how a system progresses from input to output across a sequence of decisions.</p><p>This shift has materially changed how production systems are analyzed. Failures that previously appeared opaque can now be decomposed into discrete execution steps, each of which can be inspected and compared across runs.</p><p>As a result, AI systems have become increasingly inspectable at the level of execution.</p><p>Inspectability at the level of execution does not imply understanding at the level of behavior.</p><h2>Limits of Execution-Level Observability</h2><h3>Execution Does Not Encode Reasoning</h3><p>Execution traces capture the sequence of operations performed by a system, but do not encode the reasoning process that led to the selection of those operations.</p><p>In deterministic systems, execution paths are a direct reflection of the underlying logic. Given a fixed input, the sequence of operations fully specifies how an outcome was produced. Inspecting execution is therefore often sufficient to explain system behavior.</p><p>Autonomous AI systems diverge from this model. Behavior is produced through probabilistic reasoning, where multiple latent decision paths may exist for a given input. The observed execution reflects only the realized path, not the alternative reasoning paths that were implicitly available or the relative weighting that led to their selection.</p><p>This makes it possible for identical or near-identical execution traces to arise from materially different reasoning processes. Conversely, similar reasoning processes may produce divergent execution paths under small variations in context.</p><p>This decoupling limits the ability to attribute outcomes to specific decision logic based on execution data alone.</p><h3>Outputs Collapse Underlying Uncertainty</h3><p>Final outputs represent a collapsed form of the system&#8217;s internal reasoning process, obscuring the range of alternatives, assumptions, and intermediate signals that contributed to the result.</p><p>During generation, probabilistic systems evaluate multiple potential continuations, each associated with varying likelihoods and contextual relevance. The selected output reflects only the realized sequence, not the distribution of alternatives that were considered or the degree of uncertainty present at each step.</p><p>This collapse removes visibility into how strongly different factors influenced the outcome. Signals that were weakly preferred, strongly weighted, or in conflict are no longer distinguishable once the output is produced.</p><p>As a result, two outputs that appear similar at the surface level may reflect different underlying levels of certainty or reasoning stability, while outputs that differ may originate from closely related decision processes with small variations in input or context.</p><p>This loss of intermediate structure limits the ability to assess confidence, identify ambiguity, or determine whether a given output reflects a robust decision or a marginal selection among competing alternatives.</p><h3>Context Is Not Represented as a First-Class Signal</h3><p>While observability systems capture inputs and intermediate states, they do not explicitly represent the contextual structure within which decisions are made.</p><p>In practice, context is composed of multiple overlapping signals, including user intent, interaction history, system instructions, and domain-specific constraints. These signals are present within the input space, but are not encoded in a way that distinguishes their relative importance or influence on the outcome.</p><p>This makes it difficult to determine which elements of context were materially relevant to a given decision, and which were incidental or ignored. Inputs that appear equally salient at the surface level may have been weighted differently during reasoning, while strongly influential signals may not be identifiable post hoc.</p><p>This lack of explicit representation also obscures how context evolves over time. In multi-step interactions or agent workflows, earlier assumptions may persist, decay, or be superseded by new information, but these dynamics are not directly observable through execution traces or final outputs.</p><p>Without a structured representation of contextual relevance, interpretation of system behavior remains dependent on inference, rather than direct observation.</p><h2>From Execution to Decisions</h2><p>The limitations of execution-level observability reflect a deeper mismatch between how AI systems are analyzed and how they operate.</p><p>Execution traces, outputs, and captured inputs describe what a system did, but do not provide a structured account of how decisions were formed. As a result, explanation remains indirect, requiring reconstruction of reasoning from signals that do not explicitly encode it.</p><p><strong>This requires a shift in perspective.</strong> Rather than treating system behavior as a sequence of executed steps, it becomes necessary to interpret behavior in terms of decisions.</p><p>A decision, in this context, is not just an output. It is the result of interpreting inputs, weighing competing signals, and selecting an action under uncertainty.</p><p>Decisions are not directly observable. They must be inferred from the relationship between context, intermediate state, and final output. This inference introduces ambiguity, as multiple plausible decision processes may be consistent with the same observed behavior.</p><p>As AI systems become more autonomous, this distinction becomes increasingly important. Failures are less often attributable to incorrect execution and more often to misaligned or unstable decisions within otherwise valid execution paths.</p><h2>In Closing</h2><p>The inability to directly observe reasoning, preserve uncertainty, or represent context as a structured signal introduces a persistent gap between what can be seen and what can be explained.</p><p>In practice, this gap places increasing pressure on interpretation. Engineers, product teams, and operators are required to infer decision processes from signals that do not explicitly encode them, often under conditions where outcomes carry real-world consequences.</p><p>As systems become more autonomous, this limitation becomes more difficult to ignore. Explanation is no longer a secondary concern. It is a prerequisite for building systems that can be evaluated, trusted, and controlled.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://theagentloop.fai.agency/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Understanding Production AI Behavior: Failure Modes Beyond Logs and Metrics]]></title><description><![CDATA[A systems-level look at where AI behavior diverges from intent in real-world deployments]]></description><link>https://theagentloop.fai.agency/p/understanding-production-ai-behavior</link><guid isPermaLink="false">https://theagentloop.fai.agency/p/understanding-production-ai-behavior</guid><dc:creator><![CDATA[Jamal Jackson]]></dc:creator><pubDate>Tue, 20 Jan 2026 15:03:33 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Sydo!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Facec0116-d8f5-4730-8568-d6ba8c52d849_1000x1000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>AI systems are no longer evaluated on whether they can operate in production environments. That threshold has already been met, as modern systems routinely function at scale across real-world conditions.</p><p>The challenge now lies in understanding failures at scale, particularly those that emerge from autonomous reasoning within agents and AI-driven workflows rather than from explicit system errors. In these scenarios, systems remain operational and appear healthy from an infrastructure perspective. The failure instead manifests in the produced output, which diverges from the behavior the system was designed to exhibit.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://theagentloop.fai.agency/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h1>Limits of Logs and Metrics</h1><p>To understand the limitations of logs and metrics, it helps to examine how traditional product engineering systems are designed and evaluated. These systems rely on deterministic logic, where behavior is fully specified, and deviations can be mapped to identifiable execution paths. As a result, logs and metrics are effective at explaining why failures occur.</p><p>Autonomous systems diverge from this model, as behavior emerges from probabilistic reasoning rather than deterministic execution. As a result, the space of plausible reasoning paths underlying any given output expands significantly. This expansion undermines the implicit trust that issues can be resolved by inspecting historical logs and metric records alone.</p><h2>Probabilistic Reasoning as a Distinct Execution Model</h2><p>To make these limitations more concrete, it is useful to examine what logs, tracing, and metrics actually capture within AI-driven workstreams.</p><h3>Logs</h3><ul><li><p>Capture explanatory artifacts rather than deterministic reasoning, describing what occurred without fully specifying why a particular outcome was produced</p></li><li><p>Influenced by inputs and context, but insufficient to reconstruct the internal reasoning process that led to a specific output</p></li><li><p>Recorded after decisions are made, providing a post-hoc account of behavior rather than visibility into the deliberation that produced it</p></li></ul><h3>Tracing</h3><ul><li><p>Capture execution sequence rather than deliberation, showing the order in which operations occurred without exposing how decisions were formed</p></li><li><p>Capture execution flow without revealing the relative weighting or influence of factors that shaped a given outcome</p></li><li><p>Often requires deep domain and ML-specific context to infer a probable failure point, turning explanation into interpretation rather than direct observation</p></li></ul><h3>Metrics</h3><ul><li><p>Capture aggregate outcomes rather than individual decision logic, making them effective at surfacing systemic failures but poorly suited for explaining individual decisions</p></li><li><p>Useful for monitoring trends and flagging known risk patterns, rather than diagnosing why a specific output deviated from expected behavior</p></li><li><p>Insufficient on their own to represent the system&#8217;s behavioral health, as meaningful interpretation requires contextual reasoning beyond what aggregate measures provide</p></li></ul><p>In practice, these execution characteristics give rise to a set of recurring failure patterns once autonomous systems are deployed in production.</p><h2>Common Behavioral Failure Modes in Production AI Systems</h2><p>Under probabilistic execution models, failures in production AI systems rarely manifest as isolated errors. Instead, they emerge as recurring behavioral patterns that are difficult to detect through traditional operational signals.</p><h3>Delayed Failure Propagation</h3><p>In probabilistic execution systems, failures do not always surface at the point where incorrect reasoning first occurs. Instead, an early misalignment can persist across subsequent decisions, agents, or workflow steps, allowing the system to continue operating while compounding error across the workflow.</p><h4>Manifestation</h4><ul><li><p>Early outputs appear coherent and valid, allowing downstream processes to proceed normally</p></li><li><p>No single decision is obviously incorrect when examined in isolation</p></li><li><p>Degradation becomes visible only after multiple reasoning steps have accumulated, affecting the final output</p></li></ul><h4><strong>Detection Challenges</strong></h4><ul><li><p>Logs record locally valid intermediate outputs rather than cumulative impact</p></li><li><p>Tracing reflects expected execution order, even when reasoning quality degrades</p></li><li><p>Metrics often remain within acceptable thresholds until downstream effects emerge</p></li></ul><h4><strong>Observability Limitations</strong></h4><ul><li><p>The initial reasoning error is temporally distant from the observed failure</p></li><li><p>Root cause attribution requires reconstructing a chain of plausible decisions</p></li><li><p>Probabilistic reasoning introduces uncertainty that prevents deterministic replay</p></li></ul><h3><strong>Behavioral Drift</strong></h3><p>Over time, autonomous systems can begin to produce outputs that increasingly diverge from their original design intent, even though no single decision appears incorrect in isolation. From an operational standpoint, the system continues to function normally, while its behavior shifts in subtle ways that are difficult to notice without historical comparison.</p><h4><strong>Manifestation</strong></h4><ul><li><p>Outputs remain individually plausible and syntactically valid</p></li><li><p>Changes in behavior emerge incrementally rather than abruptly</p></li><li><p>Misalignment becomes apparent only when comparing current behavior to earlier expectations or baselines</p></li></ul><h4><strong>Detection Challenges</strong></h4><ul><li><p>No single output clearly violates constraints or policies</p></li><li><p>Metrics often remain stable, masking a gradual directional change</p></li><li><p>Drift is distributed across many small decisions rather than concentrated in one failure point</p></li></ul><h4><strong>Observability Limitations</strong></h4><ul><li><p>Logs capture point-in-time correctness, not long-term behavioral trends</p></li><li><p>Tracing reflects execution flow, not semantic evolution</p></li><li><p>Metrics summarize outcomes, but rarely encode intent or alignment over time</p></li></ul><h3>Context Erosion</h3><p>As autonomous systems accumulate context over extended interactions or complex workflows, the quality of that context can degrade. Relevant signals become diluted by accumulated history, assumptions persist beyond their validity, and earlier reasoning steps exert influence long after their relevance has passed.</p><h4><strong>Manifestation</strong></h4><ul><li><p>Long or multi-step interactions where earlier context dominates later reasoning</p></li><li><p>Saturated context windows that obscure which inputs are materially relevant</p></li><li><p>Reasoning that appears coherent but rests on outdated or weak assumptions</p></li></ul><h4><strong>Detection Challenges</strong></h4><ul><li><p>Individual outputs remain internally consistent and well-formed</p></li><li><p>No explicit signal indicates which parts of the context influenced a decision</p></li><li><p>Failures emerge from omission or mis-weighting rather than incorrect logic</p></li></ul><h4><strong>Observability Limitations</strong></h4><ul><li><p>Logs capture inputs and outputs without encoding contextual salience</p></li><li><p>Tracing reflects sequence, not relevance or decay of assumptions</p></li><li><p>Metrics summarize outcomes but do not reveal when context quality has degraded</p></li></ul><h3><strong>Contextual Misalignment</strong></h3><p>Autonomous systems may reason correctly relative to the context they internally construct, even when that context no longer aligns with real-world expectations or operating conditions. The resulting behavior appears coherent and well-formed, yet produces outcomes that feel inappropriate or incorrect to human operators.</p><h4><strong>Manifestation</strong></h4><ul><li><p>Logically consistent outputs but semantically misaligned with user intent or environmental reality</p></li><li><p>Correct reasoning applied to an outdated, incomplete, or implicitly incorrect context</p></li><li><p>Divergence between what the system optimizes for and what stakeholders expect</p></li></ul><h4><strong>Detection Challenges</strong></h4><ul><li><p>Reasoning chains remain internally valid and self-consistent</p></li><li><p>No explicit signal indicates that contextual assumptions are incorrect</p></li><li><p>Failures are often attributed to &#8220;judgment&#8221; rather than system behavior</p></li></ul><h4><strong>Observability Limitations</strong></h4><ul><li><p>Logs capture inputs and outputs without validating contextual correctness</p></li><li><p>Tracing reflects execution order, not semantic alignment</p></li><li><p>Metrics summarize outcomes, but cannot encode whether the correct context was applied</p></li></ul><h3><strong>Overgeneralization Under Ambiguity</strong></h3><p>When operating under incomplete, noisy, or ambiguous inputs, autonomous systems may collapse nuanced distinctions into broader reasoning patterns. This produces confident outputs that appear reasonable while masking the loss of specificity required for accurate decision-making.</p><h4><strong>Manifestation</strong></h4><ul><li><p>Broad or generic responses applied to cases requiring contextual nuance</p></li><li><p>Edge cases absorbed into dominant reasoning patterns</p></li><li><p>Reduced sensitivity to subtle but important input differences</p></li></ul><h4><strong>Detection Challenges</strong></h4><ul><li><p>Outputs remain fluent, confident, and structurally valid</p></li><li><p>No clear threshold distinguishes acceptable generalization from harmful oversimplification</p></li><li><p>Failures emerge primarily in low-signal or under-specified scenarios</p></li></ul><h4><strong>Observability Limitations</strong></h4><ul><li><p>Logs record final outputs without capturing lost nuance</p></li><li><p>Tracing shows normal execution paths despite degraded reasoning quality</p></li><li><p>Metrics may reward consistency while penalizing necessary specificity</p></li></ul><p>Taken together, these failure modes reflect a common pattern in production AI systems; failure rarely occurs as a discrete event. Instead, it emerges through accumulation, drift, and degradation of context, often while systems remain operational and outputs appear locally valid. Because these behaviors unfold across time, decisions, and context rather than at a single execution point, they resist explanation through traditional observability signals designed for deterministic systems.</p><h1>In Closing</h1><p>As AI systems continue to move deeper into production environments, the limits of traditional system understanding become increasingly apparent. When behavior is generated through probabilistic reasoning rather than deterministic execution, explanation becomes as critical as detection, particularly in contexts where humans remain accountable for outcomes. Developing better ways to reason about AI behavior in production is therefore not an optimization problem, but a foundational requirement for building systems that can be evaluated, trusted, and governed over time.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://theagentloop.fai.agency/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading The Agent Loop, Powered by FAI! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>