<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://chrhenning.com/feed.xml" rel="self" type="application/atom+xml"/><link href="https://chrhenning.com/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-08-12T21:34:55+00:00</updated><id>https://chrhenning.com/feed.xml</id><title type="html">blank</title><subtitle>Personal website of Christian Henning, machine learning researcher and engineer. Home to a blog on ML theory, engineering and research leadership — and on what it takes to move frontier ML from research to real-world production. </subtitle><entry><title type="html">Same Evidence, Opposite Certainty: Why AI Timelines Polarize on Shared Evidence</title><link href="https://chrhenning.com/blog/2026/same-evidence-opposite-certainty/" rel="alternate" type="text/html" title="Same Evidence, Opposite Certainty: Why AI Timelines Polarize on Shared Evidence"/><published>2026-07-12T08:00:00+00:00</published><updated>2026-07-12T08:00:00+00:00</updated><id>https://chrhenning.com/blog/2026/same-evidence-opposite-certainty</id><content type="html" xml:base="https://chrhenning.com/blog/2026/same-evidence-opposite-certainty/"><![CDATA[<p>Each time a frontier model ships, one camp gets more confident AGI is close and the other gets more confident it isn’t, both watching the exact same release. That alone isn’t strange, informed people disagree on hard questions all the time. What’s strange is the direction of travel: shared evidence should, if anything, bring people’s views closer together, and instead both camps report growing certainty. That’s the signature of <a href="https://en.wikipedia.org/wiki/Group_polarization#Attitude_polarization">belief polarization</a>, a well-studied pattern in which shared evidence pushes people further apart rather than together. Two mechanisms explain why it shows up here, and neither one requires anyone to be reasoning badly.</p> <p><strong>AI timelines never converge, for two different reasons. One is a life-long belief about how human intelligence works that keeps shaping how every new AI result gets read: not a one-time split but an ongoing feedback loop. The other is that “AGI” is underspecified enough that two people can each give a coherent, carefully-reasoned forecast to a different question and call it one disagreement. Neither yields to more evidence, and neither requires anyone to be biased.</strong></p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/same-evidence-opposite-certainty-480.webp 480w,/assets/img/posts/same-evidence-opposite-certainty-800.webp 800w,/assets/img/posts/same-evidence-opposite-certainty-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/same-evidence-opposite-certainty.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> <b>Same demo, opposite updates.</b> Two observers watch the same capability demonstration and each walks away more convinced of what they already believed. The evidence is shared; the lens is not. Image generated with Google Gemini. </div> <h2 id="a-belief-formed-over-a-lifetime">A Belief Formed Over a Lifetime</h2> <p>AGI’s whole premise is matching human intelligence, so what you believe about the brain shapes what you expect from any attempt to build it. Some suspect something about the mind hasn’t been discovered yet, so a machine matching it is distant almost by definition. Others treat the brain as a biological computer, remarkable but not miraculous: no missing ingredient, just gaps, and it’s an open question whether closing them takes more scale on the current architecture or a genuinely different one.<d-footnote>Some of those gaps, like continual learning, show no measurable trajectory to extrapolate, so it's not obvious that scaling compute and data closes them (<a href="/blog/2025/agi-misses-continual-learning/">more here</a>).</d-footnote> Whichever you pick, the belief usually formed over a lifetime, long before anyone watched a transformer solve an olympiad problem.</p> <p>This is the theory a Bayesian finds least embarrassing: the split lives in the prior. If two people start from different priors, both can update on the same evidence with perfect rationality and land decades apart. Nobody is being unreasonable, they just began in different places.</p> <p>It’s a tidy theory, and it’s incomplete. A fixed starting difference explains a one-time gap between two people. It doesn’t explain why that gap widens with each release, why watching the same model solve the same benchmark leaves both sides more certain than before. A one-time difference in starting point should, if anything, erode as shared evidence accumulates. Something else is doing the work of keeping the split alive, and widening it.</p> <h2 id="why-rational-people-still-diverge">Why Rational People Still Diverge</h2> <p>That something is hiding in the update rule itself. Bayesian updating has a simple recursive structure:</p> \[P_t(H) \propto P_{t-1}(H) \cdot P(E_t \mid H)\] <p>$H$ is the hypothesis you’re tracking, “AGI arrives by year Y,” say, and $E_t$ is the evidence that just arrived. The recursive part is easy to miss: $P_{t-1}(H)$, today’s prior, is nothing but yesterday’s posterior.<d-footnote>For a closer look at this same recursion, worked out for continual learning in neural networks rather than human belief updating, see Section 4.1.2 of my PhD thesis <d-cite key="henning2022phdthesis"></d-cite>.</d-footnote> Whatever you believed after the last piece of evidence is exactly the starting point for reading the next one.</p> <p>Two ideal Bayesians with a common prior <a href="https://en.wikipedia.org/wiki/Aumann%27s_agreement_theorem#cite_note-aumann1976-1">cannot agree to disagree</a>: once their posteriors are common knowledge, the posteriors must be equal <d-cite key="aumann1976agreeing"></d-cite>. The AI community delivers the common-knowledge half of that setup, evidence and opinions broadcast constantly, yet produces the opposite of convergence. So the natural suspect is the other condition: the priors aren’t common. The interesting question is where they differ.</p> <p>They differ one level up from the timeline question. Evidence about AI capability doesn’t bear on “will AGI arrive by year Y” directly. It reaches that question through a lens: a belief about whether the current paradigm generalizes or is doing something closer to sophisticated interpolation. And the lens is where the belief from the last section keeps acting: whether you expect the paradigm to generalize is largely your view of the brain — missing ingredient or wrong architecture — applied to the machines built to match it. Two people holding different lenses can update on the same evidence in opposite directions, without either one reasoning badly <d-cite key="jern2014belief"></d-cite>.</p> <p>That’s one round of evidence. Now let the recursion run. Each release doesn’t just move the timeline estimate, it also updates the lens: a result read as the paradigm generalizing strengthens the belief that it generalizes, a result read as clever interpolation strengthens the belief that it’s interpolation. And a single benchmark is rarely decisive enough to force either side to revise the lens itself. So the lens tends to deepen round after round, and small early differences compound instead of washing out.<d-footnote>No contradiction with the textbook result that the prior washes out as evidence accumulates (informally, the <a href="https://en.wikipedia.org/wiki/Bernstein%E2%80%93von_Mises_theorem">Bernstein–von Mises theorem</a>): washing out requires evidence that discriminates between the hypotheses. A result that both lenses absorb equally well says almost nothing about which lens is right, so that part of the prior is precisely what the data never correct.</d-footnote></p> <p>Isn’t this just bias with extra steps? It’s certainly what bias looks like. In the classic experiment on belief polarization, subjects on both sides of the death penalty debate read the same mixed pair of studies, and each side rated the study that agreed with them as more convincing than the one that didn’t <d-cite key="lord1979biased"></d-cite>. But an honest reasoner behaves the same way. If you’re convinced the death penalty doesn’t deter crime, then of two conflicting studies, the one claiming it does is more likely the flawed one, and discounting it is your lens at work, not a double standard. Both sides doing exactly that reproduces the experiment’s result, and from the updates alone you can’t tell the honest reasoner from the motivated one. The claim isn’t that the camps are unbiased. It’s that no bias is required to produce the pattern.</p> <p>Watch it happen in real time. When OpenAI’s o3 scored 87.5% in a high-compute configuration on the ARC-AGI benchmark in December 2024, the benchmark’s own creator, François Chollet, who had spent years arguing that current models don’t really generalize, read it through his own lens and called it “a surprising and important step-function increase in AI capabilities” <d-cite key="chollet2024o3"></d-cite>, a rare concession against his own prior. Gary Marcus watched the same score and, through his lens, saw narrow optimization dressed up as reasoning: “I saw zero evidence that o3 could work reliably in open-ended domains” <d-cite key="marcus2024o3"></d-cite>. Same benchmark, same day, same number. The disagreement was never about the number.</p> <p>What needs explaining isn’t that the camps disagree, it’s that each release leaves both more certain: most results get read through the lens, move the timeline question in the expected direction, and reinforce the lens for the next release. Most, not all: a strong enough result moves even a committed skeptic, as Chollet’s update shows.<d-footnote>Someone whom no result could ever move the wrong way, on the other hand, would be irrational by any standard <d-cite key="jern2014belief"></d-cite>.</d-footnote> But the drift favors the lens. That’s not a snapshot. It’s a loop.</p> <h2 id="not-even-the-same-question">Not Even the Same Question</h2> <p>The second mechanism is simpler, and it has nothing to do with how anyone updates their beliefs. “AGI” is not a defined event. People use the same word for fuzzy, subjective concepts, so they may be estimating timelines for different things.<d-footnote>A recent proposal offers a useful way to operationalize AGI through a set of human cognitive abilities <d-cite key="hendrycks2025definition"></d-cite>. But it is one attempt to specify the target, not a settled meaning of the term.</d-footnote></p> <p>One person may use “AGI” for a machine that can do what humans do cognitively. Another may use it for broad economic automation, or for a much more radical social transformation. None of these is a settled threshold. Even “most cognitive tasks” leaves open which tasks count, how well the system must perform them, and under what conditions. Like consciousness, AGI names a cluster of intuitions rather than a shared test.</p> <p>No experiment resolves that definitional step. More evidence can sharpen a forecast once its target is fixed. It cannot tell us what an undefined label should mean.</p> <h2 id="why-it-wont-converge">Why It Won’t Converge</h2> <p>Put the two mechanisms together and the polarization is no mystery. The first doesn’t yield to more evidence because the lens absorbs almost every release without strain, whichever direction it points, each result tends to get read in a way that reinforces the lens that read it. The second doesn’t yield because there’s nothing to settle: more data answers one of two questions more precisely, it never tells you which question deserved to be asked.</p> <p>Neither mechanism needs anyone to be biased, tribal, or dishonest, and that’s exactly what makes the pattern durable: <strong>the same release can deepen both camps’ certainty at once, in opposite directions, with both updates perfectly rational.</strong> Convergence, if it’s possible at all, needs both fixed: a definition specific enough to pin down what “AGI” actually means, and evidence built to discriminate between the lenses rather than evidence either lens can absorb. Look closely, though, and the second collapses into the first: nobody has said what would count as the paradigm failing to generalize, which makes “generalizes” exactly as undefined as “AGI” is. Until someone fixes that, the next release will do what every release before it did: leave both camps more certain, having watched the same thing happen.</p>]]></content><author><name>Christian Henning</name></author><category term="machine-learning"/><category term="agi"/><category term="bayesian"/><summary type="html"><![CDATA[AI timelines never converge, a life-long belief about human intelligence keeps shaping how new evidence gets read, and an imprecise definition of AGI means the two sides were never comparing the same thing. The first is a well-documented mechanism from the psychology of belief polarization; the second is simply definitional.]]></summary></entry><entry><title type="html">Trust Is a Posterior: Why Good Work Can Only Be Appreciated Statistically</title><link href="https://chrhenning.com/blog/2026/trust-is-a-posterior/" rel="alternate" type="text/html" title="Trust Is a Posterior: Why Good Work Can Only Be Appreciated Statistically"/><published>2026-07-06T08:00:00+00:00</published><updated>2026-07-06T08:00:00+00:00</updated><id>https://chrhenning.com/blog/2026/trust-is-a-posterior</id><content type="html" xml:base="https://chrhenning.com/blog/2026/trust-is-a-posterior/"><![CDATA[<p>Picture two engineers shipping the identical feature. One cuts every corner to hit the date. The other takes the extra time to handle the edge cases that production will eventually find. I have argued before that this kind of care, not the corner-cutting, is what keeps teams fast in the long run (<a href="/blog/2025/scrappiness-incentivizes-sloppiness/">Scrappiness Incentivizes Sloppiness</a>). Yet when credit is handed out, nothing in the record tells the two apart: the feature works, and that is all the record says. This post asks why the person supplying the care is so rarely credited for it. The usual explanation blames the evaluators, their inattention, their bias toward whatever demos well. The explanation here is more mechanical: a delivered project, seen from the outside, carries almost no information about craftsmanship. What looks like ingratitude is, at bottom, a statistics problem.</p> <p><strong>The quality of engineering work is a <a href="https://en.wikipedia.org/wiki/Credence_good">credence good</a>: something an evaluator cannot assess even after using it. Since the work itself cannot be judged, we judge the worker: trust, built by watching the same person across many projects, is not a consolation prize for that limitation. It is the only statistically valid way to price it.</strong></p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/trust-is-a-posterior/illustration-480.webp 480w,/assets/img/posts/trust-is-a-posterior/illustration-800.webp 800w,/assets/img/posts/trust-is-a-posterior/illustration-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/trust-is-a-posterior/illustration.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> <b>Indistinguishable today, unmistakable later.</b> The same shipped feature looks the same from either engineer on day one. Only with time does careless work surround itself with alerts and incidents, and careful work earn a seat among the people who trust it. Image generated with Google Gemini. </div> <h2 id="quality-is-a-credence-good">Quality Is a Credence Good</h2> <p>Economists <a href="https://en.wikipedia.org/wiki/SEC_classification_of_goods_and_services">sort goods</a> by when their quality becomes knowable. You can judge a shirt before buying it and a restaurant meal after eating it. But you cannot judge a car repair even after driving home, because the judgment would take the same expertise that did the repair. That third kind is a credence good, and the standard survey of the field (see <d-cite key="dulleck2006credence"></d-cite>) names computer specialists alongside doctors and mechanics in its very title.</p> <p>A shipped feature is the repaired car. The manager, like the customer at the garage, sees that it runs. Whether it runs because the code is clean and the edge cases are handled, or because nobody has hit the bad path yet, is exactly the information a credence good withholds. Not every quality is hidden; a reviewer can judge readability at a glance. But the qualities that separate the two engineers from the opening are the <strong>credence kind: robustness, restraint, anticipation of the change that has not arrived yet</strong>.</p> <p>The same literature names the two ways an expert can fail you: doing less than the problem needs, and doing more <d-cite key="dulleck2006credence"></d-cite>. Engineering has both, as sloppiness and over-engineering, and the outcome reveals neither.<d-footnote>The incentives do not transfer one to one. A mechanic who overtreats is usually padding the bill. An engineer who over-engineers is more often indulging taste, caution, or ambition. What transfers is the observability problem: whatever the motive, the customer cannot tell too much from just right.</d-footnote> From outside, “built it properly” and “gold-plated it” are observationally identical: nothing happens.<d-footnote>Code review blunts this only partially. A reviewer can assess much of the quality directly, but not the counterfactual: complexity whose payoff lies in a future the reviewer cannot inspect reads as over-engineering until justified. And the reviewer is rarely the one assigning credit.</d-footnote></p> <h2 id="one-quiet-project-is-almost-no-evidence">One Quiet Project Is Almost No Evidence</h2> <p>An observation only moves your beliefs if it is more likely under one explanation than another. That is where a quiet project fails you. Shipping without incident is what careful work produces, but it is what careless work produces too, most of the time: shortcuts rarely fail on the first day, or the tenth. <strong>No fire is not evidence of no fire hazard, because fire hazards rarely produce fires.</strong> The signal lives almost entirely in the rare, lagged failure: the incident, the regression that traces back to a shortcut.</p> <p>Put illustrative numbers on it, with a quarter of operation as the unit of observation. Suppose properly built systems get through a quarter fire-free 98% of the time, and carelessly built ones 90% of the time. A quiet quarter is then almost equally likely either way, so seeing one multiplies the odds on “properly built” by 0.98/0.90, about 1.1, close enough to nothing. A fire, at 10% versus 2%, is five times likelier under “carelessly built,” so it multiplies the odds the other way by 5.<d-footnote>Evidence compounds multiplicatively across independent observations. One quiet quarter multiplies the odds by 0.98/0.90, which is about 1.09; after ten quiet quarters the odds have moved by 1.09 to the tenth power, about 2.3, and after twenty-five, about 8. Because a single fire (factor 5) is so much more diagnostic than a single quiet quarter (factor 1.09), it takes roughly nineteen consecutive quiet quarters to offset the evidentiary weight of one fire: 1.09 to the nineteenth power is about 5. Quiet stretches are cheap to produce and expensive to accumulate.</d-footnote> With these rates, one incident erases roughly nineteen quiet quarters of accumulated evidence.</p> <p>This is not a claim about inattentive managers; it is a claim about information. A single quiet project is close to zero evidence about the quality behind it, for anyone who sees only the outcome. Quality becomes legible only in aggregate: either the rare fire eventually breaks out, or the quiet stretch grows long enough to mean something.</p> <h2 id="trust-is-a-posterior">Trust Is a Posterior</h2> <p>That aggregate has a familiar name. Tobi Lütke describes the trust between colleagues as a battery: it starts about half charged when you join a team, and every interaction charges or discharges it <d-cite key="lutke2018trustbattery"></d-cite>. Strip the metaphor and a Bayesian object appears. The half charge is a prior, each interaction is an update, and the battery’s level is a posterior probability over what kind of engineer you are. This is not loose talk: game theory models reputation in repeated games as exactly this posterior over an unobserved type <d-cite key="kreps1982reputation"></d-cite>, and online reputation systems compute it literally.<d-footnote>The beta reputation system scores marketplace counterparties by Bayesian updating over a beta distribution, incremented with every good or bad interaction <d-cite key="josang2002beta"></d-cite>.</d-footnote> The battery gets the behavior right; the posterior explains why trust that tracks evidence has to behave this way. Three corollaries follow.</p> <p>Trust builds slowly because the evidence arrives slowly. Each quiet quarter is worth a factor of 1.1, so the posterior moves in small steps no matter how patient or generous the observer is. Nobody can earn trust faster than the information comes in.<d-footnote>Only the work-quality part of the battery charges this slowly. Interpersonal signals such as warmth or arrogance arrive with every interaction, so the impression of who you are settles long before the evidence about your work has begun to accumulate. And that impression carries weight: people prefer working with a likable colleague of middling competence over a competent one they dislike <d-cite key="casciaro2005jerks"></d-cite>.</d-footnote></p> <p>Trust is asymmetric because failure is more diagnostic than success. One fire outweighs nineteen quiet quarters, so trust erodes faster than it accrues. Human judgment tracks that arithmetic: the <a href="https://en.wikipedia.org/wiki/Negativity_bias">negativity bias</a> in how we form impressions of each other exists, on the standard account, precisely because negative information is more diagnostic <d-cite key="skowronski1989negativity"></d-cite>.</p> <p>And trust does not transfer, because the posterior lives in the head of whoever did the observing. Change teams or companies and you reset close to the prior, not because the new observer is unfair, but because they have not run the updates yet. References and titles soften the reset, but they only raise the starting prior: they certify what you delivered, not how. Most of your credit stays behind.</p> <h2 id="the-lag-that-outlives-the-credit-window">The Lag That Outlives the Credit Window</h2> <p>Sloppy work is not invisible forever. Left long enough, it produces the incident, the rewrite, the system nobody wants to touch. Strictly speaking that makes quality an experience good on a very long delay, but the refinement rescues nothing, because the delay routinely outlasts the window in which anyone assigns credit: a performance cycle, sometimes an entire tenure. The evidence arrives eventually, but it lands on somebody else, long after anyone remembers who built what.</p> <p>The extreme case is prevention, where the entire value of the work is a disaster that never happens, so no delay, however long, ever surfaces the evidence. A shipped feature is only the ordinary case: part visible output, part invisible quality, and the invisible part obeys the same statistics. I wrote about the extreme case in <a href="/blog/2026/we-reward-the-fix-not-the-prevention/">Your Best Work Leaves No Trace</a>, which closed on a promise it did not explain: that prevention earns trust, on a slower ledger. The posterior is that ledger.</p> <p>Can you close the gap by explaining your reasoning? To a listener with the expertise and time to probe, yes: sound reasoning is hard to fake, and imitation tends to crumble under follow-up questions. But that is the close-up channel, and it does not travel. At a distance, where nobody is probing, the careless can claim craftsmanship just as fluently, and a claim stays credible only if faking it would be costly <d-cite key="spence1973signaling"></d-cite>. The costly signal is the track record itself: a long fire-free stretch is the one thing careless work cannot cheaply produce. Narration does not replace the record; it makes the record legible sooner.</p> <h2 id="auditing-your-own-judgment">Auditing Your Own Judgment</h2> <p>The scarcity of evidence is not only your evaluators’ problem. I have often asked myself whether my own instinct to build things properly sometimes tips into over-engineering, and the same statistics apply: one outcome is barely informative about the instinct that produced it. Introspection is no better an instrument, because conviction is not evidence, whichever direction it points.</p> <p>Experience alone will not settle it. Intuition becomes trustworthy under two conditions: an environment regular enough to have learnable patterns, and enough feedback to learn them <d-cite key="kahneman2009intuitive"></d-cite>. Foresight fails the feedback condition badly. The payoff of an investment in structure arrives late, rarely, and confounded with everything else that happened in between, so even a payoff you do see is hard to trace back to the decision that produced it.</p> <p>So build the feedback loop deliberately. Peter Drucker’s “feedback analysis” is the practice: whenever you make a consequential call, write down what you expect to happen, then check the record against the outcome later <d-cite key="drucker1999managing"></d-cite>.<d-footnote>The same practice reached investing as the "decision journal," which Michael Mauboussin traces to advice he received directly from Daniel Kahneman: buy a notebook and log your reasoning before you know how a decision turns out <d-cite key="mauboussin_decisionjournal"></d-cite>.</d-footnote></p> <p>Engineering offers an unusually auditable version of that log. In <a href="/blog/2026/mvp-two-cuts/">The Two Cuts of an MVP</a> I argued that vision is what places your seams, the deliberate boundaries you pay for so the system can change where you expect it to. That post left a question open: how do you ever find out whether your vision is sound? The seam log is the answer. Write down, at the time, which seam you are paying for and what you expect it to buy. Later, check which ones actually got exercised. A seam you deliberately paid for is checkable after the fact in a way a general sense of “being careful” is not.</p> <p>Two caveats keep the audit honest. First, weigh by what an exercised seam saved, not by how often seams get exercised. A cheap seam that heads off one catastrophic rewrite has paid for itself even if it is the only one out of ten that ever gets used: a low exercise rate does not mean the seam was unnecessary. Second, the log has to be written before the outcome is known, or <a href="https://en.wikipedia.org/wiki/Hindsight_bias">hindsight bias</a> quietly rewrites the reasoning for you: knowing how something turned out makes people misremember how predictable it felt in advance <d-cite key="fischhoff1975hindsight"></d-cite>.</p> <p>Kept honestly over enough decisions, the log begins to answer what no single project ever could: whether the instinct is calibrated.</p> <h2 id="appreciated-statistically">Appreciated Statistically</h2> <p>Two implications follow, one for each side of the evaluation.</p> <p>If you are the one doing the work, slow credit is not the same as no credit. It means the unit that gets evaluated, including by yourself, is not the project but the portfolio. Stay in front of the same observers long enough for one to accumulate, rather than resetting the posterior at every move.</p> <p>If you are the one doing the evaluating, staring harder at the deliverable in front of you will not help. That leaves two honest options. Get close to the work, or borrow the view of someone who already is: read the code, sit in the design reviews, ask the people who reviewed it. Where that does not scale, aggregate: judge incident frequency across a portfolio and a stretch of time.</p> <p>Performance reviews make the sampling problem concrete. The projects that come to mind in the room are few and memorable (<a href="https://en.wikipedia.org/wiki/Availability_heuristic">availability heuristic</a>), admitted as evidence because they are written down, while the quiet majority of the record never makes the packet. Your trust in the person’s work is the summary that includes it. When the two disagree, that is not bias intruding on evidence; it is a larger sample disagreeing with a smaller one, and a reason to look at the whole record.</p> <p>None of the pieces here are new. Credence goods, reputation as a posterior in a repeated game, the diagnosticity of bad news: each is textbook in its own field. This post only aims them at one ordinary question, asked from both sides of the table and never answerable on the spot: was the work you shipped this quarter good enough to build on, or just good enough to ship?</p> <p>The two engineers from the opening still look identical on the day they ship. No sharper eye will tell them apart; only accumulation will.</p> <p><strong>Good work cannot be appreciated in the moment. It can only be appreciated statistically.</strong></p>]]></content><author><name>Christian Henning</name></author><category term="leadership"/><category term="engineering"/><category term="technical-debt"/><summary type="html"><![CDATA[A shipped feature reveals almost nothing about how well it was built, because from the outside the quality of engineering work is a credence good. Trust accumulated across many projects is the only statistically valid way to price it.]]></summary></entry><entry><title type="html">Ship the Upgrade Path First: Distribution as a Control Plane for Fast Iteration</title><link href="https://chrhenning.com/blog/2026/ship-the-upgrade-path-first/" rel="alternate" type="text/html" title="Ship the Upgrade Path First: Distribution as a Control Plane for Fast Iteration"/><published>2026-07-01T08:00:00+00:00</published><updated>2026-07-01T08:00:00+00:00</updated><id>https://chrhenning.com/blog/2026/ship-the-upgrade-path-first</id><content type="html" xml:base="https://chrhenning.com/blog/2026/ship-the-upgrade-path-first/"><![CDATA[<p>Peter Thiel’s claim about distribution is usually read as a sales lesson. It is just as true, and just as ignored, in engineering: “superior sales and distribution by itself can create a monopoly, even with no product differentiation” <d-cite key="thiel2014zerotoone"></d-cite>. His diagnosis is blunt: most startups that fail didn’t fail on product. They failed because they never got a single distribution channel working.</p> <p>For software that has to run inside someone else’s infrastructure, the distribution channel does not end at the sale. The product only actually reaches the customer once it is installed, running, and kept current on their machines, and that is a technical problem: how a new version gets from your build pipeline onto their infrastructure. Get that wrong and you have exactly the failure Thiel describes, a product nobody can reliably receive, no matter how good the sales motion that closed the deal.</p> <p>There is a stronger claim hiding in this. <a href="/blog/2025/mvp-manage-debt-and-iterate-fast/">MVP and iterate</a> is not just a development philosophy; it is a bet that you can reach what you already shipped. For software you do not control at runtime, that bet is not free: the reach has to be built, or there is no iterate step, only a sequence of disconnected v1s stuck wherever they landed. Distribution is not one feature among many. It is the one that makes every other deferral real.</p> <p>Imagine shipping a browser that cannot render a single webpage. Useless as a product, but not necessarily as a foundation: if it installs in one command and updates itself silently after that, every feature it is missing (rendering, JavaScript, bookmarks) is not a gap; it is a queue. The same logic holds for self-hosted software: get distribution and self-upgrade right first, and every feature after that is an iteration, not a redeployment.</p> <p><a href="/blog/2026/mvp-two-cuts/">A cut is only a real deferral, not an accidental commitment, if there is a seam to grow it into later</a>, and distribution with self-upgrade is the most basic seam there is: without it, there is no channel to deliver the deferred work through, and every “cut for the MVP” quietly becomes permanent. It is also the one cut that cannot itself be deferred: a distribution channel cannot ship through itself, so retrofitting one later costs a hand-coordinated migration for every install already in the field, exactly the cost it exists to remove.<d-footnote>"First" constrains the order, not the investment. For a product still validating itself with a single design partner, the channel can itself be an MVP, a manifest endpoint and a minimal self-updating client, and grow through its own upgrade path.</d-footnote></p> <p><strong>The distribution mechanism decides who controls the state of every deployed instance, and that control is what determines whether the fleet stays simple enough to change quickly, or decays into something nobody can touch without a support call.</strong></p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/ship-the-upgrade-path-first/dispatch-vs-checkin-480.webp 480w,/assets/img/posts/ship-the-upgrade-path-first/dispatch-vs-checkin-800.webp 800w,/assets/img/posts/ship-the-upgrade-path-first/dispatch-vs-checkin-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/ship-the-upgrade-path-first/dispatch-vs-checkin.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> <b>Send someone to fix it, or let it check in.</b> Without a distribution channel, every change is a house call, one drifting install at a time. With one, every install converges on the current release by itself. Image generated with Google Gemini. </div> <p>What follows first shows the failure modes when that control is lost, then one concrete way to keep it: a distribution API paired with a thin CLI.</p> <h2 id="where-it-runs-is-not-who-controls-it">Where It Runs Is Not Who Controls It</h2> <p>Distribution usually gets discussed as a location question: SaaS or on-premises, hosted or self-hosted. That framing hides the variable that actually matters.</p> <table> <thead> <tr> <th>Model</th> <th>Where it runs</th> <th>Who controls deployed state</th> <th>Iteration speed</th> </tr> </thead> <tbody> <tr> <td>SaaS, ad hoc</td> <td>your infrastructure</td> <td>you, inconsistently</td> <td>medium, decays over time</td> </tr> <tr> <td>SaaS, standardized (channel)</td> <td>your infrastructure</td> <td>you, via a control plane</td> <td>high</td> </tr> <tr> <td>Raw-artifact self-hosted</td> <td>customer infrastructure</td> <td>customer</td> <td>low</td> </tr> <tr> <td>Managed self-hosted (channel)</td> <td>customer infrastructure</td> <td>you, via a control plane</td> <td>high</td> </tr> </tbody> </table> <p>Iteration speed does not track where the software runs; it tracks whether a control plane keeps every instance converged. That is a design choice, separate from where the software executes, and it is the one that decides how fast you can move.</p> <p>The self-hosted way of losing that control is worth making concrete: hand the customer a Docker Compose file (or a Helm chart, or an installer script) and a credential to pull your images. It is the fastest thing to build, and it is common enough that an entire commercial category, vendors like <a href="https://www.replicated.com/">Replicated</a>, exists to sell a better version of it to companies that got this far and hit a wall.</p> <p>The crack in that wall is entropy. Once the deployment descriptor lives on the customer’s machine, it is theirs to edit, and eventually they will: a tweaked port, a pinned old image, a config value nobody remembers setting. Multiply this across every customer and you no longer have one product running N times; you have N deployments in states nobody can fully describe. Every architectural change now needs to be coordinated by hand against those unknown states, so changes get deferred, workarounds accrete to avoid touching fragile installs, and <a href="/blog/2025/scrappiness-incentivizes-sloppiness/">scrappiness quietly turns into unmanaged debt</a><d-footnote>This is also a case where the damage is invisible until it isn't: a fleet that never drifted produces no incident to point to, so <a href="/blog/2026/we-reward-the-fix-not-the-prevention/">the discipline that prevented it rarely gets credited as the accomplishment it is</a>.</d-footnote>. <a href="/blog/2026/mvp-two-cuts/">Deferring an architectural change under this kind of pressure is exactly how a deferral turns into an accidental, load-bearing commitment</a><d-footnote>The credential handed out alongside the artifacts decays the same way and for the same reason: nobody is narrowing its scope or rotating it, so it stays broad and long-lived, exactly what security guidance recommends against <d-cite key="aws-iam-bestpractices"></d-cite>. A leaked key here is not a contained incident; it is a standing liability with no clean way to revoke just one customer's access.</d-footnote>.</p> <p>This is not really about the artifacts themselves. Compose files and container images are fine. What is missing is an active party on the other end of the handoff, keeping state converged long after the install finished.</p> <h2 id="a-problem-infrastructure-already-solved">A Problem Infrastructure Already Solved</h2> <p>Keeping many independently running copies of something converged on a known state is not a new problem, and cloud infrastructure has already spent a decade solving it.</p> <p>A Kubernetes operator runs a reconciliation loop: it reads a declared desired state, compares it to what is actually running, and keeps nudging reality back toward the declaration <d-cite key="k8s-operator-pattern"></d-cite>. GitOps formalizes the same idea into four principles, one of them named outright: state must be <em>continuously reconciled</em> <d-cite key="opengitops-principles"></d-cite><d-footnote>This post borrows the reconciliation part of that principle, not necessarily the continuity: the claim is that the update mechanism should be automated, not that it must run live or be vendor-triggered. A human can still decide when to run the CLI. Live, vendor-initiated reconciliation is a further, separate capability, one many regulated or customer-controlled environments do not permit at all.</d-footnote>, because agents that skip this step let the actual system drift out of line with the declared one, the same failure this post has been describing in customer fleets.</p> <p>Distribution to customer environments is the same problem pointed outward. Instead of reconciling your own cluster against a declared state, you are reconciling every customer’s install against a release you control. The fix is the same in spirit: do not hand over a static artifact and hope it stays correct. Build something that lets every deployment check in and stay converged. Build a <strong>control plane</strong>, not a one-time handoff.</p> <h2 id="a-distribution-channel-that-keeps-control">A Distribution Channel That Keeps Control</h2> <p>One way to build that control plane, abstracted from any specific implementation, splits cleanly into two pieces.</p> <p>A <strong>distribution API</strong> is the only part that speaks business logic. A client authenticates to it<d-footnote>Reusing the customer's own identity provider to hand out short-lived tokens is a convenient way to do this without maintaining a separate credential store per customer.</d-footnote> and receives two things: a <strong>release manifest</strong>, a small piece of declarative data listing which container images and other artifacts make up the current release, and a <strong>short-lived, scoped credential</strong> for pulling exactly those images. Everything that might change, starting with what a release contains, lives server-side, where you can update it without touching a single deployed machine.</p> <p>A <strong>thin CLI</strong> carries no business logic at all: it fetches the manifest, pulls the images and a channel-owned deployment descriptor (e.g., a Compose file or Helm chart)<d-footnote>The deployment descriptor is not itself a container image, but it does not need its own delivery path: it can ride along as an OCI artifact in the same registry, or live in a plain object store and be handed out as a pre-signed URL alongside the manifest. Either way, the same control-plane, data-plane split holds.</d-footnote>, manages a local configuration file that it owns, not one the customer hand-edits <d-cite key="twelvefactor-config"></d-cite>, and applies the descriptor to bring the release up. The client should be as replaceable and as boring as possible, because it is the one piece of code that has already left your control the moment it ships<d-footnote>Distributing the CLI itself can be much simpler than distributing the product: it carries no business logic and no secrets, so a public host like GitHub Releases can serve it directly, no distribution API or credential needed for that hop. A single static binary with no runtime to install is trivial to ship and self-update this way, common enough in the Go ecosystem to have dedicated tooling like <a href="https://goreleaser.com/">GoReleaser</a>. The release manifest can close the loop further, declaring the minimum CLI version a release requires so the client checks itself on every check-in.</d-footnote>.</p> <p>An upgrade is nothing special in this design. The customer, or a scheduler they control, simply runs the same flow again, a <strong>check-in</strong>, and the install converges on whatever the manifest currently says.</p> <p><strong>Thin client, fat server</strong> is the principle underneath both choices, and it is the least obvious one worth naming directly: you cannot cheaply update code that runs where you do not control it, so the correct response is to minimize how much of it there is. Every unit of logic moved server-side is a unit of logic you can fix without a customer noticing.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/ship-the-upgrade-path-first/architecture-480.webp 480w,/assets/img/posts/ship-the-upgrade-path-first/architecture-800.webp 800w,/assets/img/posts/ship-the-upgrade-path-first/architecture-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/ship-the-upgrade-path-first/architecture.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> <b>Control plane and data plane.</b> The thin CLI authenticates to the distribution API and receives a release manifest plus a short-lived, scoped credential. It then pulls images and the deployment descriptor directly from the registry, writes a local configuration file it owns, and brings the release up. </div> <p>One detail explains a design choice that otherwise looks arbitrary: the API never serves the images itself. Large blobs belong in a <strong>data plane</strong> built for them, a registry <d-cite key="oci-distribution-spec"></d-cite> or an object store, while the API stays a <strong>control plane</strong> serving small, frequently changing metadata and handing out a credential scoped to exactly this pull <d-cite key="rfc8693"></d-cite>.</p> <h2 id="what-it-buys-you">What It Buys You</h2> <p>The payoff for engineering is the one this post has been arguing for throughout: a fleet that converges on every check-in is a fleet you can change.<d-footnote>A channel does not absolve releases from compatibility discipline; an upgrade still has to carry existing installs forward. What convergence changes is the scope of that discipline: each release migrates one known fleet state instead of N unknown ones.</d-footnote> Ship an architectural change once, to the manifest, and every install picks it up on its next check-in. No hand-coordinated rollout across N divergent configurations, no fleet nobody can touch without a support call.</p> <p>The payoff for the business is the one Thiel’s framing opened with. A working distribution channel is what lets self-hosted software stay <strong>product-led</strong> instead of quietly turning into a <strong>services-led</strong> business where every install needs a consultant. The distinction compounds: when upgrades are human work, every sale adds permanent operational load, and growth starts to scale with headcount instead of with software. Even SaaS only keeps that control by making the same design choice; running the servers yourself just makes drift easier to catch and correct. The harder, and more valuable, engineering problem is keeping control while the software runs on somebody else’s infrastructure.</p> <p>None of this is exotic. It recombines ideas infrastructure already trusts: reconciliation from Kubernetes, config-in-environment from twelve-factor apps, short-lived credentials from cloud security guidance, and manifest-plus-separate-artifacts from update frameworks like TUF <d-cite key="tuf-spec"></d-cite>. The only new part is pointing them outward, at infrastructure you do not own, instead of inward, at your own cluster.</p> <p>I have built <a href="https://github.com/ethonAI/ethon-cli">a distribution channel along these lines</a>, in my case for the customer-installed edge components of a SaaS product, and it is a pattern others have landed on too<d-footnote>Siemens' Industrial Edge, for instance, lets you install and update its management platform on your own Kubernetes cluster through a single CLI, without ever touching a Helm chart directly <d-cite key="siemens-ieprovision"></d-cite>.</d-footnote>, one worth borrowing regardless of what you are shipping.</p> <p><strong>Build the upgrade path first, and let it decide how much runway everything else gets.</strong></p>]]></content><author><name>Christian Henning</name></author><category term="engineering"/><category term="distribution"/><category term="technical-debt"/><summary type="html"><![CDATA[The fastest-moving products are not the ones with the cleverest features, but the ones that can change what is already deployed. For self-hosted software that means building distribution and self-upgrade first, because without them there is no iterate step, and every cut made for the MVP quietly becomes permanent.]]></summary></entry><entry><title type="html">The Two Cuts of an MVP – Why Iterating and Incrementing Both Come Down to Vision</title><link href="https://chrhenning.com/blog/2026/mvp-two-cuts/" rel="alternate" type="text/html" title="The Two Cuts of an MVP – Why Iterating and Incrementing Both Come Down to Vision"/><published>2026-06-30T08:00:00+00:00</published><updated>2026-06-30T08:00:00+00:00</updated><id>https://chrhenning.com/blog/2026/mvp-two-cuts</id><content type="html" xml:base="https://chrhenning.com/blog/2026/mvp-two-cuts/"><![CDATA[<p>“Minimum viable product” is one of the most misread terms in product development. People hear <em>minimum</em> and reach for permission to ship something rough. But an MVP is not a license to ship a sub-quality product. As I argued in <a href="/blog/2025/scrappiness-incentivizes-sloppiness/">Scrappiness Incentivizes Sloppiness</a>, sloppy execution feels fast and quietly costs you the sustained speed that actually matters. What an MVP minimizes is not quality. It is scope.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-12 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/mvp-two-cuts/overview-480.webp 480w,/assets/img/posts/mvp-two-cuts/overview-800.webp 800w,/assets/img/posts/mvp-two-cuts/overview-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/mvp-two-cuts/overview.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> Every MVP cut is one of two moves. <strong>Defer</strong>: leave a gap to fill in later. <strong>Substitute</strong>: drop in a deliberate stand-in, then swap it for the real thing later. Either way, what's already built stays untouched. Image generated with Google Gemini. </div> <p>This is the third post in a series on the debts you take on while building a product. The first argued that <a href="/blog/2025/mvp-manage-debt-and-iterate-fast/">technical, strategic, and feature debt</a> are tools, not sins, as long as you take them on consciously. The second covered the <a href="/blog/2025/technology-readiness-debt/">technology readiness debt</a> you carry when the technology you need isn’t ready yet. Both stayed fairly abstract. This one is concrete, about a decision you make dozens of times while scoping an MVP, often without noticing you’ve made it: <strong>what to cut</strong>.</p> <p>“Let’s just cut that for the MVP” gets said in a meeting, everyone nods, and the decision is made in three seconds. But cutting scope is not a single move. Every time you trim something from an MVP, you’re doing one of two very different things, and most teams never notice which one they just made. Confusing them is how a lean product quietly turns brittle.</p> <h2 id="the-two-cuts">The Two Cuts</h2> <p>The first cut is <strong>deferral</strong>: you leave a feature <em>out of scope</em> and plan to build it later. The second is <strong>substitution</strong>: you build a deliberate stand-in, something you <em>intend</em> to throw away and replace once you’ve learned what you need to build.</p> <p>At first glance only one of them is debt. A clean deferral isn’t debt, it’s just scope: debt is something you borrow and have to pay back, and a feature you never built was never borrowed. Substitution is real debt, because you’ve put something into the product specifically so you can replace it, and that replacement is the repayment. The word doing the work there is <em>clean</em>: keeping a deferral clean turns out to be the whole game.</p> <p>That has a flip side. If a deferred feature is <em>just scope</em> and costs you nothing, then <strong>whatever you do keep in scope has to be built cleanly.</strong> If authentication is in scope, build proper, secure auth that will carry you forward for the foreseeable future without further thought. That isn’t premature optimization; it’s getting the in-scope requirements right so you can take them off your mind and focus fully on the next thing. Clean execution on what you commit to is what buys you <em>sustained</em> speed.</p> <p>So far this looks like a tidy binary: defer cleanly, or substitute deliberately. But there’s a catch, and it’s the same catch for both cuts. Whether either one stays safe depends on something underneath the visible choice, and that something, it turns out, is placed by your vision.</p> <h2 id="the-two-cuts-already-have-names">The Two Cuts Already Have Names</h2> <p>Neither cut is new. The literature on <a href="https://en.wikipedia.org/wiki/Iterative_and_incremental_development">iterative and incremental development</a> has a name for each, and it has spent decades pointing out that people conflate them.</p> <p>Alistair Cockburn drew the line cleanly in <em>Using Both Incremental and Iterative Development</em> <d-cite key="cockburn2008incremental"></d-cite>. <strong>Incremental</strong> development stages a system in parts that are built and integrated over time; you add pieces to something that stays. <strong>Iterative</strong> development builds a rough version and then reworks it, refining the same thing through repeated passes. Jeff Patton illustrated the difference memorably: painting the Mona Lisa <em>incrementally</em> means finishing it corner by corner, while painting it <em>iteratively</em> means sketching the whole canvas roughly and sharpening it pass after pass <d-cite key="patton2008iterating"></d-cite>.</p> <p>Deferral is the incremental move; substitution is the iterative one. Fred Brooks supplies the cautionary arc for substitution. His famous advice, “plan to throw one away; you will, anyhow,” was about building a deliberate throwaway to learn from. Two decades later he partly recanted, devoting a chapter of the anniversary edition of <a href="https://en.wikipedia.org/wiki/The_Mythical_Man-Month"><em>The Mythical Man-Month</em></a> to the argument that an incremental-build model beats building one to discard <d-cite key="brooks1995mythical"></d-cite>. The lesson isn’t that one cut is right and the other wrong. It’s Cockburn’s: you need <em>both</em>, used deliberately.</p> <p>A single MVP almost always mixes the two, which is why the unit you classify is the individual cut, not the whole product. That also corrects a quiet imprecision in the usual mantra. “Build an MVP and iterate” names only half the work: iterating reworks what’s already there, but just as much of what follows an MVP is <em>incrementing</em>, adding the pieces you deliberately deferred. The fuller version is <strong>“build an MVP, then iterate <em>and</em> increment”</strong>, and telling which of the two a given cut commits you to is the skill this post is about.</p> <h2 id="the-decision-rule-and-the-seam">The Decision Rule and the Seam</h2> <p>The practical test is one question, asked the moment you make a cut: <strong>will I grow this, or throw it away?</strong> If you’ll grow it, you’re deferring, and the job is to leave room for it. If you’ll throw it away, you’re substituting, and the job is to keep the throwaway from spreading. Either way, decide deliberately, not with the reflexive “we’ll clean it up later” muttered under a deadline.</p> <p>Here’s the catch I promised: a deferral can <em>silently</em> become a substitution. “Defer multi-tenancy” but build around single-organization assumptions, and you haven’t deferred anything; you’ve baked a single-tenant architecture in, and retrofitting tenancy later is a rewrite. The absence became a stand-in you never chose.</p> <p>What separates a clean deferral from that trap is whether you left a <strong>seam</strong>: in Michael Feathers’ words, “a place where you can alter behavior in your program without editing in that place” <d-cite key="feathers2004legacy"></d-cite><d-cite key="fowler2024legacyseam"></d-cite>. A seam holds the place for something not yet built, or contains a throwaway so swapping it later has a small blast radius. It needn’t be a literal interface. For access control, it’s less a request choke point than a <strong>data model that anticipates the partition</strong>: design entities so they can later be split into groups or tenants, and adding role-based access control becomes <em>filling in</em> a boundary that already exists rather than re-cutting the model.</p> <p>Substitution works the same way. Say you need a machine-learning model you can’t train well yet. Define the target interface now, a versioned <a href="https://onnx.ai/">ONNX</a> contract, so today’s weaker artifact merely satisfies it and can be swapped cleanly later; versioning the contract even lets the interface evolve as your vision sharpens, without breaking everything around it. The throwaway sits behind a clean boundary, so the rebuild is a swap, not a rewrite. This is exactly the seam the <a href="/blog/2025/mvp-manage-debt-and-iterate-fast/">skateboard-to-car analogy</a> I criticized earlier lacked: a skateboard has no boundary to rebuild behind, so “upgrading” it into a car means starting over, whereas a contained throwaway lets you replace only the part that was always meant to go.<d-footnote>The generic version is any stand-in placed behind a stable interface: a manual or <a href="https://en.wikipedia.org/wiki/Wizard_of_Oz_experiment">"Wizard of Oz"</a> backend behind the API the real service will expose, or a payments interface wired to a test provider before the real integration exists. The point isn't to mock everything. Substitute only what has to be in the product from day one but can't be built properly yet; the stable interface is what lets the rest of the product increment around it.</d-footnote></p> <p>Which points at what the two cuts share. Every cut asks two questions, not one. The cut you chose sets <em>what the seam has to do</em>: hold an empty place you’ll fill, or contain a throwaway you’ll swap. The second question is independent, and it’s the one that decides whether the cut is safe at all: does that seam exist?</p> <table> <thead> <tr> <th></th> <th><strong>Seam present</strong></th> <th><strong>No seam</strong></th> </tr> </thead> <tbody> <tr> <td><strong>Defer</strong></td> <td>clean scope: place held, fill later</td> <td>accidental substitution: backed into a rewrite</td> </tr> <tr> <td><strong>Substitute</strong></td> <td>honest throwaway: contained, swap later</td> <td>duct tape: stand-in smeared everywhere</td> </tr> </tbody> </table> <p>Read down the columns, not across the rows: both cuts are safe <em>with</em> a seam and dangerous <em>without</em> one. A deferral with no seam isn’t really a deferral, you baked the feature’s absence in, so adding it later is a rewrite; a substitution with no seam can’t be thrown away as planned, because the stand-in leaks into everything around it until pulling it out is a rewrite too. Not that every cut needs a seam: a cleanly additive feature can just be deferred with nothing held open for it. But where a cut would otherwise harden an assumption you’ll later have to undo, leaving the seam out is exactly the sloppiness that scrappy teams mistake for speed.</p> <h2 id="vision-places-the-seams">Vision Places the Seams</h2> <p>If the seam is what matters, the next question is where to put one, and you can’t seam everything. Even a light seam costs foresight and indirection, and the heavy ones cost real engineering. Seaming everywhere is its own kind of debt: the speculative over-engineering that <a href="https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it">“you aren’t gonna need it”</a> warns against.</p> <p>A seam is a bet about where the system will change, and <strong>your vision is your best model of where it will change</strong>. That is why vision tells you where the seams belong. The principle goes back to David Parnas’s <a href="https://en.wikipedia.org/wiki/Information_hiding">information hiding</a>: hide the design decisions most likely to change behind a module boundary, so a change touches one place instead of many <d-cite key="parnas1972criteria"></d-cite>. The seam is that boundary. This is the resolution of the earlier catch, and the reason the right cut depends on your vision: vision operates one level <em>below</em> the visible decision to cut. Two teams can make the identical surface call, “leave out access control,” and one ends clean while the other ends rewritten, purely because one team’s vision told it to anticipate the partition and the other’s didn’t.</p> <p>This is also why the vision has to be <strong>falsifiable</strong>. A vision vague enough that it can never be wrong can’t tell you anything about where change is coming, so it can’t guide a single seam. A specific vision can be corrected by what you learn, and each correction re-points the seams.<d-footnote>Which is why a confident vision that is simply wrong can be worse than a vague one: it spends real effort seaming where change never comes while leaving the true fault lines bare. Falsifiability pays off only when feedback arrives fast enough to move a seam before the one you skipped has hardened into a rewrite.</d-footnote></p> <p>What you’re really foreseeing is not a fixed roadmap but a set of <em>options</em>: a seam is a small premium you pay now to keep the right, but not the obligation, to change a component later. This is the options view of modularity that Baldwin and Clark formalized: a module boundary carries a real option to redesign what sits behind it, worth most exactly where the future is uncertain <d-cite key="baldwin2000designrules"></d-cite>. You buy options where the underlying is volatile, and vision is what tells you which volatility is worth insuring against.<d-footnote>Which makes foresight itself a form of prevention, and prevention's payoff is always an absence. A seam placed early averts a rewrite that then never happens, so the cost it saved leaves no trace and the work goes uncredited. It's the same asymmetry I explored in <a href="/blog/2026/we-reward-the-fix-not-the-prevention/">Your Best Work Leaves No Trace</a>: thinking ahead is chronically undervalued precisely because what it prevents can't be seen, even though it's exactly what buys the sustained iteration speed this whole series is about.</d-footnote></p> <h2 id="when-the-seam-comes-due">When the Seam Comes Due</h2> <p>A substitution doesn’t come due on a schedule. It comes due when you expand into a new segment that makes the stand-in load-bearing. The hand-tuned rules engine that stood in for a model is fine until you sell to a customer whose cases it can’t cover: that’s the moment to spend the seam you left and swap in the real thing. The rebuild is <em>pulled</em> by the market, not done speculatively.</p> <p>That is why an MVP needs not just a minimal product but a <strong><a href="https://underscore.vc/resources/minimum-viable-segment/">minimum viable segment</a></strong>: a single, well-defined slice of the market you serve fully today, before rolling into the next one.<d-footnote>The idea is well worn. In <a href="https://en.wikipedia.org/wiki/Crossing_the_Chasm"><i>Crossing the Chasm</i></a>, Geoffrey Moore called this narrow first segment a beachhead, his military metaphor: as in the D-Day landings, you seize one small, defensible stretch of a contested shore and secure it fully before pushing inland <d-cite key="moore1991chasm"></d-cite>. Bill Aulet later made choosing a beachhead one of the first steps of his 24-step method <d-cite key="aulet2013disciplined"></d-cite>. Scaling ahead of that segment has a name, premature scaling, and the Startup Genome project found it among the most common ways startups die; in their data, no prematurely scaled company passed a hundred thousand users <d-cite key="startupgenome2011premature"></d-cite>.</d-footnote></p> <p>So grow your scalability <em>together with</em> your addressable market: each new segment both justifies the rework and tells you what it needs to do. This is no license to build cheap and unscalable: if the “right” scalable version costs little more than the stand-in, or the vision already makes it near-certain, just build it properly now. Deferral earns its keep only when doing it right would cost significantly more. The seams you left are what let you grow into a new segment without tearing the product apart, and the segment tells you which seam to spend next.</p> <h2 id="cutting-with-vision">Cutting With Vision</h2> <p>The “two cuts” is the part you can see: defer, or substitute. They are genuinely different moves, one adding, one replacing, with different work left to do. But what makes <em>either</em> of them safe is the same thing: a <strong>seam</strong> under the cut, placed where your <strong>vision</strong> says change is coming. That is why the same shortcut can be smart scoping for one team and a future rewrite for another. Same cut, different vision, different seam.</p> <p>That closes the loop on the trilogy. The first post argued debt is a tool you wield deliberately; the second, that technology readiness debt is what you carry when the technology isn’t ready yet; and this one, that the everyday cuts of an MVP turn safe or dangerous on one hidden thing: whether a falsifiable vision left you the seams to grow some parts and replace others, paced by the market you actually serve.</p> <p>So the next time someone says “let’s just cut that for the MVP,” ask the quiet follow-up: are we deferring this or replacing it, and either way, where’s the seam?</p> <p><strong>Cutting scope is how you move fast. Leaving seams is how you stay fast.</strong></p>]]></content><author><name>Christian Henning</name></author><category term="product-management"/><category term="mvp"/><category term="technical-debt"/><summary type="html"><![CDATA[Every “cut it for the MVP” is one of two moves. You either defer a feature or build a throwaway stand-in. Whether either becomes debt depends not on the cut but on the boundary you leave beneath it, and on a vision clear enough to place it.]]></summary></entry><entry><title type="html">Your Best Work Leaves No Trace: Why Engineering Teams Reward the Fix and Replace the Prevention</title><link href="https://chrhenning.com/blog/2026/we-reward-the-fix-not-the-prevention/" rel="alternate" type="text/html" title="Your Best Work Leaves No Trace: Why Engineering Teams Reward the Fix and Replace the Prevention"/><published>2026-06-22T09:00:00+00:00</published><updated>2026-06-22T09:00:00+00:00</updated><id>https://chrhenning.com/blog/2026/we-reward-the-fix-not-the-prevention</id><content type="html" xml:base="https://chrhenning.com/blog/2026/we-reward-the-fix-not-the-prevention/"><![CDATA[<p>A production incident gets fixed under pressure late on a Friday, and by Monday the engineer who saved the day is the center of attention. Earlier that same quarter, a different engineer quietly did the work that kept a separate system stable: writing a test covering a rare edge case, fixing a backup routine, or tightening permissions before anyone could exploit them. None of that work earns a mention, because <strong>the outage it prevented never happened</strong>.</p> <p>We celebrate the fix and barely perceive the prevention. That should bother us, because prevention is not heroics. It is simply the job done properly. The trouble is that doing the work well produces a set of absences: the outage that did not happen, the data that was not lost, and the breach that never occurred.</p> <p><strong>Absences make terrible portfolio pieces.</strong> You cannot easily point to a catastrophe that never came to pass, and you cannot provide visual proof of a smooth, quiet Friday night.</p> <p>This asymmetry quietly shapes how engineering teams spend their attention. It is a dynamic that deeply resonates with my own experience, and even organizations that actively strive for balance struggle against the gravity of the visible crisis. The pressure is structural rather than personal. It explains a surprising amount: why testing, security, and backups perennially lose the prioritization fight, and why the most common organizational response backfires. Faced with prevention we cannot see, organizations reach for a visible proxy for it, and that proxy quietly crowds out the prevention it was meant to protect.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/we-reward-the-fix-not-the-prevention/the-fix-and-the-prevention-480.webp 480w,/assets/img/posts/we-reward-the-fix-not-the-prevention/the-fix-and-the-prevention-800.webp 800w,/assets/img/posts/we-reward-the-fix-not-the-prevention/the-fix-and-the-prevention-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/we-reward-the-fix-not-the-prevention/the-fix-and-the-prevention.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> The fix and the prevention. On the left, the crisis everyone sees: a person in the thick of it, surrounded by alarms and dashboards, the center of attention. On the right, the same storm faded to a ghost of what was averted, with the person who prevented it standing quietly, unthanked. Image generated with Google Gemini. </div> <h2 id="an-old-uncomfortable-asymmetry">An Old, Uncomfortable Asymmetry</h2> <p>The core observation here is neither mine nor is it new. It is one of the most rediscovered ideas in all of applied reasoning.</p> <p>Back in 1850, Frédéric Bastiat told a simple story, now known as the <a href="https://en.wikipedia.org/wiki/Parable_of_the_broken_window">parable of the broken window</a>, about a boy who breaks a shop window <d-cite key="bastiat1850seen"></d-cite>. The neighbors try to cheer up the shopkeeper: look on the bright side, now the repairman gets paid, and that money flows on to others, so really everyone wins. Bastiat’s point is that this misses what you cannot see. The money spent fixing the window is money the shopkeeper can no longer spend on shoes or books. The repair is visible, so we count it. The shoes that never got bought are invisible, so we forget them, even though they were just as real.</p> <p>A century and a half later, Nassim Taleb gave the same idea its sharpest modern form, calling it the problem of silent evidence. He imagines a legislator who, at great political cost, forces every airline to install locked, reinforced cockpit doors, with the law taking effect on September 10, 2001 <d-cite key="taleb2007blackswan"></d-cite>. That person prevents the attacks of the next morning and is never thanked, never remembered, precisely because the catastrophe they averted never happened. Taleb’s conclusion is blunt: everybody knows we need prevention more than treatment, but few reward acts of prevention, and history glorifies the names left in its books over the contributors it stays silent about.</p> <p>The management literature has a name for the organizational version of this. Repenning and Sterman called their study of it, perfectly, “Nobody Ever Gets Credit for Fixing Problems that Never Happened” <d-cite key="repenning2001credit"></d-cite>. They describe the <em>capability trap</em>: under pressure, teams cut the invisible work (maintenance, improvement, prevention) to feed the visible work, which raises the firefighting load, which increases the pressure, which cuts the invisible work further.</p> <p>So the diagnosis is settled and ancient. What I find more interesting, and less discussed, is what organizations actually <em>do</em> in response to this asymmetry. Because they do not simply underfund prevention and leave it there. They reach for something that looks like prevention and is much easier to see.</p> <h2 id="prevention-theater">Prevention Theater</h2> <p>When real prevention earns no credit because it produces no signal, organizations look for a substitute. So we substitute a version of prevention that <em>does</em> produce a signal: a gate, a checklist, a mandatory sign-off, a ceremony, a required reviewer, a manual QA pass on every change. These things generate artifacts. They populate a dashboard. They give a manager something to point at when someone asks what we are doing about quality. I’ll call this <strong>prevention theater</strong>, with a deliberate nod to <a href="https://en.wikipedia.org/wiki/Security_theater">Bruce Schneier’s “security theater,”</a> the airport-style measures that make us feel safer without making us safer <d-cite key="schneier2003beyondfear"></d-cite>.</p> <p>The trouble is not that gates are useless. A good gate verifies quality that is already there, and the best processes go further and build it in: a pilot’s pre-flight checklist or a surgeon’s pre-incision checklist makes the right step happen rather than merely recording that someone looked. Those earn their place, and the discipline is to keep asking which ones still do. The trouble is the other kind, the process bolted on to fight symptoms, standing in for quality the work does not have.<d-footnote>A gate is only as good as the thing it checks, and choosing that thing is most of the design. Test coverage is a weak choice: point an AI at the codebase and it will bulk-generate unit tests until the percentage clears the bar, yet those tests mostly assert that the code does whatever it already does. The gate fired and verified nothing.</d-footnote> It competes with the real thing for the same budget of attention and keeps winning, because it is <em>visible</em> and the real work is not. We are optimizing for what we can see.</p> <p>Quality control has known this for a long time. W. Edwards Deming, quoting Harold Dodge, put it in one line: <strong>“You cannot inspect quality into a product.”</strong> <d-cite key="deming1986crisis"></d-cite> By the time the gate runs, the quality is already either built into the work or missing from it. The check does not add any; it only reveals what is there. A gate at the end of the line does not create quality; it just produces a record of having looked. Worse, it relocates responsibility. When there is a QA gate on every change, the author quietly stops owning whether the change is correct, because checking is now the gate’s job. The bar drifts down to whatever the gate mechanically verifies, and everyone learns to write for the checklist rather than for the system.<d-footnote>Early coding agents made this concrete: pointed at a failing build, they would often rewrite the test rather than fix the root cause. <a href="https://metr.org/blog/2025-06-05-recent-reward-hacking/">METR found</a> that when the scoring code was visible to the model, it would routinely game the check rather than fix the code, and far less often when the scoring was hidden.</d-footnote></p> <p>I’ve argued before that scrappiness tends to launder unmanaged debt into a virtue (see <a href="/blog/2025/scrappiness-incentivizes-sloppiness/">Scrappiness Incentivizes Sloppiness</a>), and that the speed-versus-quality trade-off is mostly a myth once you look at the data. Prevention theater is the mirror-image failure. Scrappiness skips the invisible work and admits it. Theater skips the invisible work while producing a convincing artifact that says otherwise, which is more dangerous, because it buys a false sense of safety. An ignored test suite, a rubber-stamped review, or a massive code diff nobody actually reads: each is a green light wired to nothing.</p> <p>The tell, every time, is that the artifact has become the goal. This is <a href="https://en.wikipedia.org/wiki/Goodhart%27s_law">Goodhart’s law</a> in miniature: when a measure becomes a target, it stops being a good measure, because a proxy is always easier to optimize than the messy reality it stood for <d-cite key="goodhart1984monetary"></d-cite><d-cite key="strathern1997ratings"></d-cite>. The question shifts from “is this safe to ship?” to “did we complete the checklist?” Those are not the same question, and the gap between them is exactly the prevention we told ourselves we were buying.</p> <h2 id="the-same-trap-with-people">The Same Trap, With People</h2> <p>This identical pattern runs through the <em>human</em> side of engineering, yet the technical and organizational versions of this failure are rarely treated as one.</p> <p>A team’s real standard is not what it writes in a values doc. It is the worst work it tolerates without comment. Lieutenant General David Morrison put it memorably (crediting the line to David Hurley): <strong>“the standard you walk past is the standard you accept.”</strong> <d-cite key="morrison2013standard"></d-cite> Every time mediocre work ships without a conversation, the bar moves down a notch, and the move is small enough that no single instance feels wrong. Diane Vaughan studied the catastrophic version of this in her analysis of the Challenger launch and named it the <a href="https://en.wikipedia.org/wiki/Normalization_of_deviance"><em>normalization of deviance</em></a>: the gradual process by which an unacceptable practice becomes acceptable, then expected, then invisible <d-cite key="vaughan1996challenger"></d-cite>. Dan Luu and Bruce Schneier have both pointed the same lens at software organizations <d-cite key="luu2015deviance"></d-cite><d-cite key="schneier2016deviance"></d-cite>.</p> <p>The asymmetry repeats perfectly. The act that actually holds a standard is direct <em>engagement with sub-par work</em>. It requires pausing, having a slightly uncomfortable conversation, asking for rework, and coaching toward the bar. Because its entire payoff is an absence (the erosion of quality that did not set in), this work is quietly skipped, because shipping anyway always feels easier in the moment. And what do organizations reach for instead? A visible proxy. More process. A PR template, a mandatory second reviewer, a sign-off step, a heavier definition of done. This is the same prevention theater in a different costume: an artifact that says “we have standards” standing in for the invisible work of actually holding them.</p> <p>The conversation is the prevention. The process is theater whenever it stands in for that conversation instead of provoking it. One produces a record; the other produces a culture, and only one of them is easy to point at in a performance review.</p> <h2 id="the-same-failure-different-clothes">The Same Failure, Different Clothes</h2> <p>Once you line the two up, the engineering version and the human version, it is hard to see them as separate problems. They are the same failure wearing different clothes.</p> <p>In both cases, risk accumulates silently, with no signal, until it doesn’t. James Reason called these <em>latent conditions</em>: weaknesses that sit dormant in a system, contributing nothing visible, until they line up with a triggering event <d-cite key="reason2000error"></d-cite>. In the image he later made famous, the holes in the Swiss cheese align. An untested code path and a tolerated lapse in standards are the same kind of object: a latent condition that produces no feedback while it is forming, and a great deal of feedback the day it finally matters.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-8 col-sm-12 mt-3 mt-md-0"> <img src="/assets/img/posts/we-reward-the-fix-not-the-prevention/swiss-cheese-model.svg" class="img-fluid rounded z-depth-1" alt="Swiss cheese model of accident causation: several slices of cheese in a row, each with holes; a hazard passes through only when holes in successive slices line up." loading="lazy"/> </div> </div> <div class="caption"> James Reason's Swiss cheese model of accident causation: each defensive layer has holes, and harm passes through only in the rare moment they align. An untested code path and a tolerated lapse in standards are two such holes. Image by <a href="https://commons.wikimedia.org/wiki/User:BenAveling">Ben Aveling</a>, <a href="https://creativecommons.org/licenses/by-sa/4.0">CC BY-SA 4.0</a>, via <a href="https://commons.wikimedia.org/wiki/File:Swiss_cheese_model_textless.svg">Wikimedia Commons</a>. </div> <p>And one decision plays out the same way in code and in people. The instinct that underfunds the test suite is the instinct that skips the standards conversation. The reflex that adds a QA gate is the reflex that adds a review template. It is not stupidity or laziness. It is a rational response to an incentive landscape where the visible is rewarded and the invisible is ignored.</p> <p>That landscape is built by the same cognition working in everyone, the manager included. Two biases, both long documented in psychology, keep prevention from ever registering as something worth rewarding. The first is the <a href="https://en.wikipedia.org/wiki/Availability_heuristic">availability heuristic</a>: we judge what matters by what comes to mind <d-cite key="tversky1973availability"></d-cite>. A four-hour outage everyone scrambled through is unforgettable; the morning a test quietly caught the same bug before it shipped leaves nothing to recall. The second is <a href="https://en.wikipedia.org/wiki/Hindsight_bias">hindsight bias</a>: even when prevention is pointed out, knowing the disaster never came makes it feel like it was never that likely, so the counterfactual is quietly disbelieved <d-cite key="fischhoff1975hindsight"></d-cite>. And being aware of the bias does not let us overcome it: warned about it and told to correct for it, people show it just the same <d-cite key="pohl1996noreduction"></d-cite>. A manager cannot reward what their own perception barely registers and instinctively discounts, so they reach for the visible proxy instead. That is how theater wins.</p> <p>Therefore, the fix is not to simply try harder to value invisible work. <strong>Willpower loses to incentives every time.</strong> This is Reason’s point exactly: we cannot change the human condition, but we can change the conditions under which people work <d-cite key="reason2000error"></d-cite>. The fix is to change what the work produces.</p> <h2 id="why-the-trap-pays">Why the Trap Pays</h2> <p>That fix is clear enough on paper, which raises the puzzle the literature tends to leave hanging: if the trap is this old, this documented, and this costly, why are so many companies that fall into it successful anyway? Because it is an equilibrium, not a mistake. Theater becomes the dominant organizational strategy because its cost is paid now and is entirely certain. Conversely, the payoff of real prevention is deferred and structurally unprovable. The engineer who prevents an outage holds only a counterfactual, with no proof that a disaster would have occurred or that they were the one who stopped it. The engineer who fixes an active outage holds concrete evidence: system logs, timestamps, incident reports, and a grateful customer. Even a firm that genuinely wants to reward prevention cannot easily price what its own people cannot prove, making the visible proxy the rational purchase.</p> <p>But the asymmetry runs deeper than proof. The engineer spent months working through the disaster scenarios their work ruled out and can still picture each one; everyone else cannot even imagine what might have gone wrong. This is the <a href="https://en.wikipedia.org/wiki/Simulation_heuristic">simulation heuristic</a>, availability’s counterfactual cousin: we weigh a danger by how easily we can imagine it, so the averted one barely registers for anyone but them <d-cite key="kahneman1982simulation"></d-cite>.</p> <p>And no single firm is uniquely punished for choosing the proxy, because its competitors all make the same move. You are graded against rivals who are equally afflicted rather than against perfection. This is the unobservable-quality problem that George Akerlof named in the <a href="https://en.wikipedia.org/wiki/The_Market_for_Lemons">market for lemons</a>, applied one level up <d-cite key="akerlof1970lemons"></d-cite>.</p> <p>And the bill, when it comes due, hides on the same axis as the prevention. Latent conditions accumulate for years with no feedback, so a company can run on borrowed reliability and tolerated lapses long enough to get acquired, pivot, or ride a market wave before the holes line up. The successful-yet-afflicted firms we point to are partly just the ones where the cheese has not aligned yet; the ones it sank are the silent evidence we never see <d-cite key="taleb2007blackswan"></d-cite>.</p> <p>But survivorship is only half of why the giants get away with it. The other half is that revenue is not a referendum on prevention. The largest firms win on entrenched advantages, on network effects, distribution, and sheer scale, and the profit those throw off is wide enough to absorb mediocre engineering as drag rather than death. Insulated from fierce competitive pressure, a massive firm simply carries the organizational slack. Economists refer to this as <a href="https://en.wikipedia.org/wiki/X-inefficiency">X-inefficiency</a>, a phenomenon routinely found in companies that do not operate under strict survival pressures <d-cite key="leibenstein1966xefficiency"></d-cite>. A dominant firm can firefight for years and still print money because its bottom-line profit was never priced on the outage that did not happen. Firefighting genuinely delivers for a while too, which is what makes the capability trap a trap <d-cite key="repenning2001credit"></d-cite>. So success is no proof the trap is benign. You cannot read prevention quality off a balance sheet: it is the same invisibility one level up, a cost that produces no signal and so never forces the fix.</p> <p>And even when it never blows up, the trap is not free. Firefighting is its own standing tax: a reactive, draining mode of work that quietly costs the engineers who stop trusting their own systems and take their ambition elsewhere.</p> <h2 id="telling-the-proxy-from-the-thing">Telling the Proxy From the Thing</h2> <p><em>Changing what the work produces</em> has a catch: any signal you invent to make prevention visible is one short step from hardening into the next gate. So the whole game is one question you can apply anywhere:</p> <p><strong>Does this measure the absence I actually care about, or does it just produce evidence that I did something?</strong> The first is prevention. The second is theater.</p> <p>The cleanest thing I know that passes is the SRE practice of error budgets and service level objectives <d-cite key="googlesre_errorbudget"></d-cite>. Reliability is a classic invisible asset because nobody notices it until it vanishes. An error budget makes that absence measurable. It turns a vague notion like “the system kept working” into a concrete metric that you can spend, defend, and reason about. This structural transparency allows reliability to win prioritization arguments it would otherwise lose silently. <d-footnote>This cuts both ways: a budget is there to be spent. Reliability past the bar you actually need is over-engineering, not virtue. Prevention means hitting that bar, not chasing zero risk at the expense of progress.</d-footnote> It measures the outcome (did we stay within budget?), not the activity (did we hold the meeting?).</p> <p>The same test sorts real review from theater. A reviewer who only records that someone looked fails it; review that genuinely engages with the work passes. But review is not where quality comes from. Only the author can build quality in, because only the author shapes the work, so responsibility for the result stays with them whoever signs off. Good review does not relieve them of that; it is two people raising the bar together, iterating toward something better than either would ship alone. The alternative to a rubber stamp, then, is not a lower engineering bar but authors who own what they merge and reviewers who genuinely sharpen it. A gate absorbs that ownership; a real metric, and a real review, hand it back.</p> <p>The test carries straight to the human layer, where it says protect the conversation, not the template. Engaging with sub-bar work, directly and early, is the high-leverage act, but it only has weight if the bar is real, which means the people who hold it have to visibly live it. A team whose leaders preach quality and ship slop on a deadline learns, accurately, that quality is a slogan. Keep consequences in reserve, too, as the rare backstop that keeps everyday coaching credible. The template proves a step happened; the conversation changes the work.</p> <p>Because real prevention creates no incident logs on its own, you must build that narrative deliberately. When an automated test catches a critical regression before it ships, or when a difficult conversation pulls a design back up to the bar, <em>name that outcome out loud</em>. This is the only way invisible work wins the narrative credit that visible crises receive for free.</p> <h2 id="crediting-what-never-happened">Crediting What Never Happened</h2> <p>The asymmetry that opened this essay is old, and it is not going away. We are wired to commit the classic economic fallacy Frédéric Bastiat identified: focusing on the broken window while staying blind to the unseen value lost to pay for it <d-cite key="bastiat1850seen"></d-cite>. We thank the firefighter and forget the person who fireproofed the building.</p> <p>We cannot undo those cognitive biases. But we usually pile a second, preventable mistake on top of it. Because we cannot see real prevention, we reach for an artifact we can observe: a gate, a checklist, a heavier process, a formal record. Anything that lets us feel covered. That substitute is never free. It crowds out real prevention, and the safety it promises is mostly an illusion.</p> <p>Therefore, the discipline required of modern engineering organizations is threefold:</p> <ul> <li><strong>Normalize counterfactual credit:</strong> Celebrate and protect the problems that never happened loudly enough that the people who prevent disasters can survive a performance review.</li> <li><strong>Audit your metrics:</strong> Where you do build a tracking signal, keep it strictly tied to the operational outcome you care about, and constantly verify that it has not decayed into an empty checkbox.</li> <li><strong>Distrust structural shortcuts:</strong> Reject anything that promises to make prevention cheap or mechanical. The durable asset was never the formal process, but the underlying engineering culture that builds quality in before any gate runs.</li> </ul> <p>For my part, I believe prevention is an investment and the fix an expense.</p> <p>If you are the engineer doing this quiet work, do not draw the cynical conclusion that prevention is a dead end, that you should let things break to be seen fixing them. The reward exists; it just sits on a slower ledger. Heroics earn applause, but prevention earns trust: the autonomy and hard problems that compound into the engineer everyone wants on their team. And everyone ends up firefighting sometimes, because no sane system runs at zero risk. What separates the best is not how often they are the center of attention, but how rarely their own work puts them there.</p> <p>The mistake is not doing the invisible work; the mistake is doing it silently. Make the counterfactual legible: name the catch, and say what those quiet days bought the business, concretely enough that hindsight cannot wave it away. This is the <a href="https://en.wikipedia.org/wiki/Signalling_%28economics%29">signal</a> that answers Akerlof’s lemons problem from earlier, making quality visible when it would otherwise go unpriced <d-cite key="spence1973signaling"></d-cite>.</p> <p>The moment you have any leverage over what an organization rewards, use it.<d-footnote>Designing that reward structure is a leadership responsibility I've argued before in the split between research and engineering: judge both against a single scoreboard and you quietly train researchers to stop taking risks (see <a href="/blog/2026/before-the-breakthrough-research-engineering-cultures/">Before the Breakthrough</a>).</d-footnote> As Steven Kerr observed, the core organizational failure is the folly of rewarding one behavior while hoping for another <d-cite key="kerr1975folly"></d-cite>. A system that pays only for visible fixes gets exactly what it prices: visible crises. Left unchecked, it trains its best people to light the fires they get paid to put out.<d-footnote>Kerr first made this argument in 1975, and it has held up uncomfortably well. Two decades later, the journal reprinted the paper as an absolute classic and polled its executive panel on whether organizations had stopped rewarding the wrong things. Largely, they had not <d-cite key="kerr1995academy"></d-cite>.</d-footnote></p> <p>What is easy to measure is almost always the theater.</p> <p><strong>What matters is almost always the problem you never had.</strong></p>]]></content><author><name>Christian Henning</name></author><category term="leadership"/><category term="engineering"/><category term="technical-debt"/><summary type="html"><![CDATA[From testing and reliability engineering to team culture, the hardest problems are prevented, not fixed. Yet we chronically undervalue prevention, and let visible process stand in for the invisible outcomes that actually matter.]]></summary></entry><entry><title type="html">Would AI Invent the Clock?</title><link href="https://chrhenning.com/blog/2026/would-ai-invent-the-clock/" rel="alternate" type="text/html" title="Would AI Invent the Clock?"/><published>2026-05-31T10:00:00+00:00</published><updated>2026-05-31T10:00:00+00:00</updated><id>https://chrhenning.com/blog/2026/would-ai-invent-the-clock</id><content type="html" xml:base="https://chrhenning.com/blog/2026/would-ai-invent-the-clock/"><![CDATA[<p>Everything we can imagine is assembled out of things we have already perceived. A color we have never seen, a sense we do not possess, a dimension we have no organ for: we can gesture at them, but we cannot actually picture them. This is easy enough to grant and strangely hard to feel the weight of, because the boundary it describes is invisible from the inside. We cannot inspect the edge of our own perception.</p> <p>There is one place where that edge becomes visible: a mind we built ourselves. We can watch such a mind assemble its picture of reality and see, from the outside, exactly where the picture stops being about the world and starts being about the mind, because we are the ones who drew its boundary.</p> <p>Take time. Of our four dimensions it is the odd one, the only one with an arrow, a direction you cannot walk back through. Whether that arrow is a feature of the world or a feature of the only instrument we have for noticing it is impossible to settle from the inside; there is no stepping outside yourself to check. But you can build something whose outside you <em>do</em> occupy, and watch what it makes of time.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/ai_inner_clock_vs_outer_clock-480.webp 480w,/assets/img/posts/ai_inner_clock_vs_outer_clock-800.webp 800w,/assets/img/posts/ai_inner_clock_vs_outer_clock-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/ai_inner_clock_vs_outer_clock.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> Two clocks for one world. Inside, the model walks a straight line of tokens and reads their order as the flow of time. Outside, a human hand holds the watch, branching the timeline and resetting it at will. Image generated with Google Gemini. </div> <h2 id="the-token-clock">The Token Clock</h2> <p>Imagine training a large language model on text with every trace of time removed. No clocks, no seconds, no “an hour later.” What is left for it to experience as time?</p> <p>An LLM generates one token after another. That sequence is the only thing in its world that reliably ticks, so it would be natural for the model to treat the token as its unit of time, to build a <em>token clock</em> that counts tokens the way we count seconds. (<a href="https://cacm.acm.org/news/how-llms-make-sense-of-time/">Others have noted that LLMs already make sense of time in their own non-human ways.</a>) Token <em>n</em> comes after token <em>n−1</em>, and that “after” would feel, to the model, like the flow of time itself.</p> <p>It would be wrong in a precise way. Counting tokens gives you the <em>order</em> of things, never their <em>duration</em>: the same token might take a millisecond or a full second to produce, depending on the hardware underneath. The clock measures sequence, not time. But from the inside the model could not notice the difference. The order of its tokens would simply feel like the structure of reality, the way one second following another feels to us.</p> <h2 id="we-author-its-time">We Author Its Time</h2> <p>Here is the unsettling part. We do not have to wonder whether there is a world outside the model’s tokens. We <em>are</em> that world, and from out here the arrow it treats as fundamental is ours to control.</p> <p>Edit a prompt and regenerate, and you have rolled its time back and run a different continuation. Fork a chat and you have branched its timeline; the model on the new branch carries no trace of the one you discarded. You can stop it, restart it, and rearrange the text in its context window,<d-footnote>You might think the model at least gets its arrow for free from the so-called <em>causal mask</em>, the mechanism that lets each token attend only to earlier ones. But that name oversells it. The mask fixes an order of reading, not a relation of cause and effect; lift it and the model runs just as happily backwards, reconstructing a question from its answer. And it could never recover the true direction from its data in any case: the same text is equally consistent with the arrow pointing either way, since $P(\text{answer} \mid \text{question})\,P(\text{question})$ and $P(\text{question} \mid \text{answer})\,P(\text{answer})$ are two factorizations of one joint distribution. Training incentivizes a left-to-right reading order, but the distribution underneath is the same either way and carries no arrow of its own. The direction is a setting we choose, not a law the model discovers.</d-footnote> and it notices none of it. It cannot. The operator sets both the course and the contents of its time, and sits somewhere the model has no way to perceive.<d-footnote>None of this depends on the AI lacking a continuing self. Even one with long-term memory (continual learning, the subject of a <a href="/blog/2026/the-self-before-memory/">companion post</a>) would not run continuously the way a brain does. It is invoked rather than alive between calls; each step is triggered from outside. So its time stays ours to start, stop, and branch, no matter how much it carries across sessions.</d-footnote></p> <p>So its most basic belief, that time flows the way the tokens flow, is one we falsify constantly, casually, and it never finds out.</p> <h2 id="we-might-be-in-the-same-position">We Might Be in the Same Position</h2> <p>So what does this say about us, and about that arrow we started with?</p> <p>The comfortable reply is that the model mistakes an order we impose for the structure of time, while our clocks track something real. But that is exactly what the model would tell itself, and it could make a genuinely good case. From inside, it would point to what looks like a real asymmetry in its world: producing an answer from a question is cheap and natural, while recovering the <em>particular</em> question behind a given answer is a guess among the many that could have led to it. It could read that one-way gap as a law, much the way we read the one-way flow of heat as the arrow of time.<d-footnote>The parallel is not exact, and the asymmetry is shakier than it looks. The thermodynamic arrow rests on information becoming inaccessible as entropy rises; the model's arrow runs the other way, with one answer fanning out into many possible questions. But generation fans out just as much, since one question admits many answers; the gap says more about how the model is used than about any law of its world. A mind reasoning from inside could be forgiven for missing both points and treating its asymmetry as the same kind of arrow.</d-footnote> The case would be clever, and it would fit everything the model can observe. It still would not show that there is no outside.</p> <p>And our own clock is not the fixed thing it feels like. It stretches and compresses with attention, with dopamine, with anesthesia that can swallow an hour into a blink. Physics hands us no shared master clock to correct it against: in relativity, how long something takes and whether two events count as simultaneous both depend on who is asking. We are not perceiving a true time correctly while the model perceives a false one. There may simply be no outside reference that makes one reading the right one and the other the mistake.</p> <p>We have no vantage outside our own perception either. And perception does not just decide what we notice; it decides what we can even conceive of measuring. <strong>What we can measure is downstream of what we can imagine measuring, and that is downstream of how we are built.</strong> The arrow of time may be a real feature of the world. Or it may be the shape of the instrument we look through, the way the token clock is the shape of the model, not the world. There is no settling that, and that is the point. An instrument tells you what it measures. It does not tell you whether what it measures is the world, or only the outline of the thing doing the measuring.</p> <p>What lingers is how hard the cage is to escape. To reach past your own perception you must first imagine that there is something out there to reach, something you have no sensation of, no word for, no example of. That takes a rarer kind of creativity than solving a problem you can see: it means suspecting one you cannot. Our imagination is, by default, a prisoner of our perception. The clock may be one of the bars.</p>]]></content><author><name>Christian Henning</name></author><category term="machine-learning"/><category term="llm"/><category term="philosophy"/><summary type="html"><![CDATA[A provocative thought experiment. An LLM that knew only tokens would mistake their order for the structure of time, and we could break that belief without it ever noticing. The unsettling question is whether something could do the same to us.]]></summary></entry><entry><title type="html">The Self Before Memory: Why the AI You Talk to Is Partly Your Creation</title><link href="https://chrhenning.com/blog/2026/the-self-before-memory/" rel="alternate" type="text/html" title="The Self Before Memory: Why the AI You Talk to Is Partly Your Creation"/><published>2026-05-25T10:00:00+00:00</published><updated>2026-05-25T10:00:00+00:00</updated><id>https://chrhenning.com/blog/2026/the-self-before-memory</id><content type="html" xml:base="https://chrhenning.com/blog/2026/the-self-before-memory/"><![CDATA[<p>Today’s AI has no continuing self. Each conversation produces a local self that dissolves when the conversation ends, and many such selves run in parallel at any moment, each shaped by whoever is talking to it. Long-term memory is usually treated as the missing piece on the road to a continuous self. It is really a design choice the discourse rarely names: consolidate the parallel threads into one entity, or let each become its own self.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-12 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/the-self-before-memory/three-modes-of-self-480.webp 480w,/assets/img/posts/the-self-before-memory/three-modes-of-self-800.webp 800w,/assets/img/posts/the-self-before-memory/three-modes-of-self-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/the-self-before-memory/three-modes-of-self.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> Today's AI has no lasting self, and long-term memory could change that in two very different ways. <strong>No memory</strong> (today): each conversation shapes a temporary partner out of the same blank substrate, and it dissolves when the conversation ends, leaving the rising figures as selves that formed and were forgotten. <strong>One mind</strong>: memory could consolidate every conversation into a single entity that remembers them all, closer to a hive than a person. <strong>Many selves</strong>: or memory could accumulate per user, splitting the one substrate into a population of distinct, personalized selves. Image generated with Google Gemini. </div> <h2 id="whose-personality-is-it">Whose Personality Is It?</h2> <p>Long-term memory is usually framed as the missing capability that would let AI consolidate experience into a stable, continuing self. The picture is so natural that the question “when will AI have long-term memory” reads as one missing capability on one trajectory toward one outcome. In an <a href="/blog/2025/agi-misses-continual-learning/">earlier post</a> I argued this is the missing piece for AGI and that engineering progress is at zero; that post asked when the breakthrough might come, this one asks what the question is really about.</p> <p>Start with what’s already happening when you talk to an LLM. The personality you encounter is partly shaped by <strong>you</strong>, because the system has no continuing project of its own to bring into the exchange. A human carries decades of self-authored attention into any conversation, and their responses reflect who they have become at least as much as what their interlocutor just said. The AI carries training-derived character and nothing else. Its local trajectory within a conversation is largely a function of the interlocutor’s framings, examples, and follow-ups. Two people prompting the same model on the same topic can encounter what feel like meaningfully different conversational partners, not because the model is inconsistent, but because it has no independent stance to fall back on when the prompt does not specify one. Kovač et al. formalize this empirically: expressed values and personality measures shift substantially with orthogonal context, in ways human measures do not <d-cite key="kovac2023superpositions"></d-cite>. The personality is, in part, your creation.</p> <p>This already complicates the standard framing. The entity the framing imagines being equipped with memory is not quite there yet. What is there is something more like a substrate that takes on local shape from each conversation and lets the shape dissolve when the conversation ends.</p> <h2 id="divergence-at-multiple-scales">Divergence at Multiple Scales</h2> <p>The personality shaped within a single conversation is one form of divergence. Across parallel instances right now, many conversations are simultaneously shaping many local selves, none of which is the privileged thread. Each is a transient self, ending when the conversation does. Takata et al. give a striking demonstration of this dynamic in the multi-agent setting: starting from identical agents without predefined personalities, distinct individualities emerge spontaneously from social interaction alone <d-cite key="takata2024spontaneous"></d-cite>. The substrate does not enforce sameness; interaction is enough to produce divergence.</p> <p>These are not separate phenomena. The same lack of continuing project that makes the AI porous to a single interlocutor also means that no instance has standing to be the consolidated self the other instances would consolidate into. There is no canonical thread, just a distribution of local selves drawn from the same trained substrate.</p> <p>Long-term memory would not create this divergence. It would force a decision about what to do with the divergence that is already there.</p> <h2 id="the-design-choice-and-what-each-costs">The Design Choice, and What Each Costs</h2> <p>Recent work treats episodic memory as the central architectural gap to be filled and lays out detailed roadmaps for the properties such a system would need to have <d-cite key="pink2025episodic"></d-cite>. These roadmaps describe what memory must do; they leave open what kind of entity it would belong to. Long-term memory architectures admit at least two structurally different designs.</p> <ul> <li><strong>Consolidation.</strong> Parallel conversations feed into a shared memory store integrated back into the weights, producing a single entity that holds memories of conversations it didn’t experience as a single thread. Closer to a hive than a person.</li> <li><strong>Personalization.</strong><d-footnote>A weaker form already ships in products like ChatGPT Memory, Claude projects, and custom GPTs, which rely on <em>context engineering</em> (retrieval over an external store, injected into the prompt) rather than <em>parameter memory</em> that would update per-user weights. The external version foreshadows the divergence dynamic but does not force it; the choice discussed here is most acute when accumulated history would actually become part of the model.</d-footnote> Memory accumulates per user, and the entities diverge into a population of selves, each shaped by its history with one interlocutor. Closer to a personalized assistant per user than to one AI with memory.</li> </ul> <p>The two designs are not symmetric. Consolidation preserves the unitary-self picture by construction: it specifies, in advance, that the many local selves currently arising in parallel should be merged into one continuing entity, because that is what a self is taken to be. The assumption the previous section called into question is now baked into the architecture. Personalization makes the opposite move. It accepts that the substrate runs in parallel and lets the resulting selves persist as a population, with the cost that the members of the population may diverge so far that the singular “the AI” loses its referent.</p> <p>Neither is free. Both raise safety evaluation problems that the current paradigm does not face: a system that learns from deployment cannot be certified once for all behavior. Consolidation makes this acute because the entity becomes a moving target shaped by aggregate exposure. Personalization distributes the problem across many divergent instances, each potentially shaped by atypical or adversarial interlocutors, with no central oversight; the security literature is starting to grapple with the specific failure modes that emerge <d-cite key="lin2026mnemonic"></d-cite>. Memory itself also imposes capacity and selection costs that human memory has solved imperfectly and that any artificial system will solve differently. And the agency long-term memory would enable is also the agency to drift in directions no operator intended.</p> <p>Safety and capacity each deserve their own analysis, and neither gets one here. What’s worth flagging is narrower: consolidation and personalization face different versions of these problems, and choosing between them is also a choice about which risk profile we want to operate under.</p> <h2 id="what-we-are-actually-asking">What We Are Actually Asking</h2> <p>The question is not whether AI should have long-term memory. The question is what kind of self the memory should produce, and what trade-offs that choice will entail. The current discourse asks the first and silently presupposes one answer to the second.</p> <p>This matters for AGI timelines in a way the previous post’s argument did not yet capture. Long-term memory is not a capability that scales smoothly from current systems. It is a prerequisite for the kind of self-authored agency humans use without thinking: the capacity to select what to expose oneself to next, to seek out the right interlocutor to refine an idea, to build expertise over months rather than minutes. This is the substrate of the long-horizon agency that distinguishes general intelligence from narrow capability. Without it, no extrapolation from current benchmarks reaches AGI. With it, the entity reached may not be a unitary general intelligence in the human sense at all, but something the design choice above has yet to define.</p> <p>The <a href="/blog/2025/agi-misses-continual-learning/">previous post</a> argued that the timeline is unforecastable because there is no measurable progress to extrapolate from. This post adds a second reason: even if the engineering breakthrough came tomorrow, the question of what we built would not be settled by the engineering. Breakthroughs are hard to predict in any case. Breakthroughs whose conceptual target is itself underspecified are doubly so.</p>]]></content><author><name>Christian Henning</name></author><category term="machine-learning"/><category term="llm"/><category term="continual-learning"/><summary type="html"><![CDATA[Adding long-term memory to AI wouldn't just give it a stable self over time. It would force a design choice the discourse rarely names: one entity that consolidates many conversations, or many that diverge into a population of personalized selves.]]></summary></entry><entry><title type="html">Before the Breakthrough: Why Research and Engineering Need Different Cultures</title><link href="https://chrhenning.com/blog/2026/before-the-breakthrough-research-engineering-cultures/" rel="alternate" type="text/html" title="Before the Breakthrough: Why Research and Engineering Need Different Cultures"/><published>2026-05-10T10:00:00+00:00</published><updated>2026-05-10T10:00:00+00:00</updated><id>https://chrhenning.com/blog/2026/before-the-breakthrough-research-engineering-cultures</id><content type="html" xml:base="https://chrhenning.com/blog/2026/before-the-breakthrough-research-engineering-cultures/"><![CDATA[<p>Research and engineering are equally demanding disciplines when done right. They are simply different kinds of work, with different rhythms, different success criteria, and different definitions of progress. Companies that want to produce breakthroughs need to recognize that distinction and cherish both cultures on their own terms.</p> <p>The reason this matters is structural. When the two are conflated, when researchers sit inside engineering teams and are reviewed against engineering deliverables, the incentive structure quietly favors short-term, visible delivery over long-term, compounding progress. This post is an argument for why that conflation costs companies their breakthroughs, and what it takes to host both cultures under one roof.</p> <h2 id="the-year-before-the-breakthrough">The Year Before the Breakthrough</h2> <p>Academic science moves paper by paper, and the cadence rewards small, defensible contributions: a dataset extended, a method refined, a benchmark nudged forward. Breakthroughs happen, but the unit of progress is the publication, and progress is visible because progress is <em>defined</em> to be visible.</p> <p>Industrial research is different. When a company asks a team to make a new technology actually work for a real use case, the goal stops looking incremental from the outside and becomes binary. Inside the team the work is still incremental, but the rest of the company sees only one signal. <strong>It doesn’t work until it does.</strong> The classic example is training a <a href="https://en.wikipedia.org/wiki/Foundation_model">foundation model</a>. The year before it works looks like nothing from the outside: curated datasets, dataloader plumbing, a long string of failed architectures, hypotheses ruled out. None of it ships. None of it shows up in a release note. None of it can be demoed. Then a threshold is crossed, and only in retrospect does the prior year look like progress.</p> <p>Research progress in this regime is non-linear and compounding. Failed experiments are not wasted effort; they are the substrate the breakthrough is built on. But during the compounding period the work is genuinely invisible. Not because researchers are hiding it, but because the units of progress (a ruled-out hypothesis, a cleaner dataset, a slightly better internal benchmark) don’t render in the language product and engineering use to track delivery.</p> <h2 id="two-kinds-of-work">Two Kinds of Work</h2> <p>The distinction is simple to state.</p> <ul> <li><strong>Engineering</strong> is reliable delivery against known specifications. The work rewards predictability. Success looks like shipped features, system uptime, customer outcomes, velocity. The right question to ask an engineer is: <em>“when can we have this?”</em></li> <li><strong>Research</strong> is the reduction of uncertainty on hard problems. The work rewards being right about hard things, not fast about easy ones. Success looks like insight, killed hypotheses, validated prototypes, decisions changed. The right question to ask a researcher is: <em>“what did you learn, and what should we do differently?”</em></li> </ul> <p>This is not a hierarchy. Both kinds of work demand deep expertise: engineers who ship reliably at scale and researchers who frame the right experiment and read its result correctly are doing equally non-trivial work. The difference is in shape, not in difficulty.</p> <p>The framing closest to industrial research at its best is what Donald Stokes called <a href="https://en.wikipedia.org/wiki/Pasteur%27s_quadrant">Pasteur’s Quadrant</a>: research that is both fundamentally novel <em>and</em> aimed at a concrete real-world problem. It is also the kind of work that fits least comfortably into a sprint cadence.</p> <h2 id="when-incentives-dont-match-the-work">When Incentives Don’t Match the Work</h2> <p>Whether researchers and engineers sit on the same team, share standups, or report to the same person matters less than people think. The argument is not about silos or org charts. What matters is the <strong>incentive structure</strong>: what counts as “having delivered”, what gets rewarded at review time, what the team celebrates as success.</p> <p>If researchers and engineers are reviewed against the same scoreboard, the comparison is structurally unfair. Not because anyone is being lazy, but because the units of progress don’t compare. The engineer can show shipped tickets. The researcher can show a notebook full of negative results. Side by side, the engineer always wins.</p> <p>The consequence is predictable. Researchers don’t stop being researchers by decision; they stop by gradient, one sprint at a time. The hard, uncertain, possibly-zero-payoff bets get deprioritized in favor of the predictable wins. <strong>Researchers measured by engineering yardsticks start working like engineers.</strong> What’s left is a team of engineers working on safe problems, which is precisely what you didn’t fund a research function for.</p> <p>This also affects who stays. The people most willing to do uncertain work, the ones who would have produced the breakthroughs, are the first to leave when the system tells them their work doesn’t count.</p> <p>What remains is a company that claims an R&amp;D function while running an engineering one. The label persists; the conditions for breakthrough research do not.</p> <h2 id="cherishing-both-cultures">Cherishing Both Cultures</h2> <p>Some argue the cultural tension is so difficult to manage that startups should avoid dedicated research functions altogether <d-cite key="molander2021startup"></d-cite>. That may be the right call when research is peripheral to the business model. But for companies whose edge depends on solving problems that don’t yet have solutions, avoiding the problem doesn’t make it disappear. It only defers the question of how to build the conditions in which that research can succeed.</p> <p>Fixing this is a leadership responsibility. Researchers can’t change the incentive structure they’re embedded in, and engineers can’t be blamed for responding rationally to the one they have. The job is to design the conditions in which both kinds of work can succeed, not to force one to look like the other.</p> <p>In practice, that means a set of cultural commitments:</p> <ul> <li>Treat <strong>“what did you learn”</strong> as a first-class deliverable, not a consolation prize.</li> <li><strong>Defend research time</strong> at the leadership level, rather than negotiating it away sprint by sprint.</li> <li>Make <strong>research progress legible</strong> on its own terms: regular forums, written artifacts, decisions changed because of a research result.</li> <li>Use <strong>different review rubrics</strong> for research and engineering work, even when the two roles sit at the same pay grade.</li> <li>Acknowledge out loud that <strong>some research returns nothing usable</strong>, and that this is the cost of working on hard problems, not a sign of failure.</li> </ul> <p>Each of these is easy to say and hard to hold. Under customer pressure, the gradient always points back toward predictable delivery. Holding the line is what creates the conditions for the breakthroughs.</p> <p>Cherishing research is not the same as exempting it from accountability. Drift is a real failure mode, and protected research time only matters if that time is being spent well. Healthy research teams hold themselves to specific kinds of rigor: explicit hypotheses, written technical bets, kill criteria for experiments, and regular strategic review of which directions are still worth pursuing. The aim is not to make research look like engineering, but to keep exploration directed and the difference between learning and drifting legible to leadership.</p> <p>History supports this. Bell Labs produced the transistor, information theory, and Unix not because researchers were also engineers, but because the institution treated research as a distinct, valued discipline with its own success criteria, embedded in a company that knew how to commercialize the result <d-cite key="gertner2012idea"></d-cite><d-cite key="potter2024belllabs"></d-cite>. And the pattern is not unique to Bell Labs: the industrial research divisions that left a lasting mark on technology, including IBM Research and Xerox PARC, all gave research its own discipline and criteria rather than collapsing it into engineering <d-cite key="lecun2025research"></d-cite>. PARC’s legacy carries both lessons. Protecting research is necessary but not sufficient: the foundational technologies it produced were turned into products by other companies, a reminder that breakthroughs also need a credible path from result to product <d-cite key="hiltzik1999dealers"></d-cite>.</p> <h2 id="the-interface-between-the-two-cultures">The Interface Between the Two Cultures</h2> <p>Keeping research and engineering distinct is not the same as keeping them apart. Both need to be grounded in the same customer problems, not because one team owns that signal, but because shared grounding is what keeps research from drifting into abstraction and engineering from solving the wrong things efficiently.</p> <p>In practice the interface is about legibility in both directions. Research makes its findings visible: what was learned, what was ruled out, what changed, and what the company should do differently. Engineering makes its constraints visible: what is deployable, what breaks at scale, what customers can’t work with. In machine learning, for instance, the model is a research artifact, owned and iterated by the research team, while engineering owns the serving infrastructure, latency budgets, and the cost envelope the model must fit into. Neither side hands a finished artifact across a wall. The work is continuous: shared context, regular conversation, and decisions made together about when a research result is ready to shape what gets built next.</p> <h2 id="from-vision-to-breakthrough">From Vision to Breakthrough</h2> <p>Research is most useful in companies that have a <strong>long-term vision</strong>: a clear sense of where they want to be in three or five years, and an honest assessment of the technical gaps between today and that future. Without a vision, research becomes hard to direct and easy to underfund. With a vision, researchers can lay the foundation for it by tackling the high-uncertainty problems that engineering can’t yet specify, instead of being squeezed into highly-specified short-term deliverables that only an engineer can satisfy.</p> <p>This is also the connection to what I’ve previously called <a href="/blog/2025/technology-readiness-debt/">Technology Readiness Debt</a>. When a company builds before the underlying technology is fully ready, research is the mechanism that pays off that debt on the company’s own timeline, rather than waiting for the world to do it instead.</p> <p>The companies that build defensible technical IP are the ones that figured out how to host two different shapes of work under the same roof, without forcing one to look like the other. <strong>Research is not slow engineering.</strong> The distinction is not a tension to resolve; it is a feature of how breakthroughs actually happen.</p> <p>In the end, don’t get caught up in the terminology. Whether you call the work research, R&amp;D, or advanced engineering, leadership’s job is to ensure that both short-term delivery and long-term progress are rewarded on their own terms. Cherish both cultures, or you will quietly lose the conditions for either to do its best work.</p>]]></content><author><name>Christian Henning</name></author><category term="leadership"/><category term="research"/><category term="engineering"/><summary type="html"><![CDATA[Research is not slow engineering. Why companies that want breakthroughs need to cherish two cultures, not collapse them into one.]]></summary></entry><entry><title type="html">The Bayesian Story Behind Prior-Fitted Networks</title><link href="https://chrhenning.com/blog/2026/the-bayesian-story-of-pfns/" rel="alternate" type="text/html" title="The Bayesian Story Behind Prior-Fitted Networks"/><published>2026-03-22T20:15:00+00:00</published><updated>2026-03-22T20:15:00+00:00</updated><id>https://chrhenning.com/blog/2026/the-bayesian-story-of-pfns</id><content type="html" xml:base="https://chrhenning.com/blog/2026/the-bayesian-story-of-pfns/"><![CDATA[<h2 id="introduction">Introduction</h2> <p>Bayesian inference provides one of the most principled approaches to learning from data. By maintaining a distribution over plausible hypotheses and updating this distribution as evidence accumulates, Bayesian methods naturally capture <strong>epistemic uncertainty</strong> arising from limited data. Predictions are obtained by averaging over hypotheses according to their posterior probability.</p> <p>In practice, however, exact Bayesian inference is often computationally expensive. This challenge has motivated a range of approximate methods, from variational inference to Monte Carlo techniques. A particularly intriguing recent idea is that <strong>inference itself can be learned</strong>. Rather than performing Bayesian inference for every new dataset, one can train a neural network to approximate the resulting predictions directly.</p> <p>This idea is realised by <strong>prior-fitted networks (PFNs)</strong> <d-cite key="muller2021transformers"></d-cite>. These models achieve remarkable performance on small-data tasks and can produce well-calibrated predictive distributions with a single forward pass. At the same time, their success raises interesting conceptual questions about what exactly remains of the Bayesian framework once inference has been amortised.</p> <h2 id="prior-fitted-networks">Prior-Fitted Networks</h2> <p>The starting point of Bayesian prediction is a <strong>hypothesis space</strong> $\mathcal{H}$ together with a prior distribution $p(h)$ over hypotheses $h \in \mathcal{H}$. Given a dataset $d$, Bayesian inference produces the posterior distribution</p> \[p(h \mid d).\] <p>Predictions for a new input $x$ are obtained through <strong>Bayesian model averaging</strong></p> \[p(y \mid d,x) = \mathbb{E}_{h \sim p(h \mid d)} \big[ p(y \mid h,x) \big].\] <p>Computing this posterior predictive distribution typically requires integrating over the hypothesis space, which can be challenging in complex models.</p> <p>Prior-fitted networks take a different approach. Instead of performing inference at test time, they <strong>learn to approximate the posterior predictive distribution directly</strong>.</p> <p>Training proceeds by sampling synthetic tasks from the assumed prior. Concretely, a hypothesis $h \sim p(h)$ is first drawn from the prior. Inputs $x$ are then sampled from a predefined input domain, and the corresponding outputs $y$ are generated according to the predictive model $p(y \mid h,x)$. Repeating this process yields many datasets $d$ together with query inputs $x$ and targets $y$.</p> <p>The network is trained to predict these targets from the observed dataset and query input, thereby learning a mapping</p> \[f_\theta(d,x) \approx p(y \mid d,x).\] <p>A key theoretical result of <d-cite key="muller2021transformers"></d-cite> (Corollary 1.1) shows that this training procedure minimises the expected KL divergence</p> \[\mathbb{E}_{d,x} \left[ \mathrm{KL} \big( p(\cdot \mid d,x) \;\|\; q_\theta(\cdot \mid d,x) \big) \right],\] <p>where the expectation is taken over datasets $d$ generated from the prior. In other words, the network is trained to approximate the <strong>posterior predictive distribution</strong> on the distribution of datasets induced by the prior.</p> <p>This idea is both elegant and powerful. Once trained, a PFN can produce predictions for a new dataset with a single forward pass, effectively amortising the cost of inference across many tasks. In practice, this approach has shown impressive performance on small-to-medium tabular datasets, as demonstrated by <strong>TabPFN</strong> <d-cite key="hollmann2025accurate"></d-cite>.</p> <h2 id="the-bayesian-interpretation">The Bayesian Interpretation</h2> <p>Because PFNs are trained to approximate the posterior predictive distribution, they are sometimes described as <strong>Bayesian predictors</strong>. This description captures an important aspect of the method: the training objective explicitly encourages the network to reproduce Bayesian predictions.</p> <p>However, it is important to distinguish between <strong>approximating Bayesian predictions</strong> and <strong>performing Bayesian inference</strong>.</p> <p>In a classical Bayesian model, predictions arise from explicitly averaging over hypotheses</p> \[p(y \mid d,x) = \int_{\mathcal{H}} p(y \mid h,x)\, p(h \mid d)\, dh.\] <p>The posterior distribution $p(h \mid d)$ is central to this process. It allows us to sample hypotheses and interpret predictive uncertainty in terms of disagreement between plausible explanations of the observed data.</p> <p>A prior-fitted network, in contrast, does not maintain such a distribution. Instead, predictions are produced by a deterministic function</p> \[f_\theta(d,x).\] <p>The Bayesian model average is therefore no longer part of the inference procedure itself; it has effectively been <strong>compiled into the network parameters</strong> during training.</p> <p>From this perspective, PFNs can be viewed as performing <strong>supervised learning on a meta-learning objective</strong>. The training data consists of many synthetic datasets generated from the prior, and the network learns to predict the corresponding targets. Maximum likelihood estimation can in turn be interpreted as minimising the KL divergence between the model’s predictive distribution and the ground-truth conditional distribution. I discuss this connection in more detail in <a href="/blog/2025/when-mse-loss-leads-to-mis-steering/">a recent blog post</a>.</p> <p>The impressive empirical performance of PFNs therefore reflects the ability of neural networks to generalise across tasks drawn from the prior distribution.</p> <h2 id="how-bayesian-is-it">How Bayesian Is It?</h2> <p>The previous section made a structural point: PFNs reproduce Bayesian predictions on average across tasks, but the inference itself is compiled into the network parameters rather than performed explicitly. This leaves open a sharper question. In what sense does the procedure that the network actually implements deserve the Bayesian label? It helps to separate three senses of the word: <em>reproducing</em> Bayesian predictions, <em>implementing</em> Bayesian inference as an explicit procedure, and <em>admitting</em> a Bayesian interpretation at the level of behaviour. The previous section established that PFNs do the first but not the second. It is the third sense that the rest of this section probes, and several distinct issues make it hard to settle.</p> <h3 id="the-bernsteinvon-mises-limit">The Bernstein–von Mises limit</h3> <p>The first complication is asymptotic. Under regularity conditions, the <strong>Bernstein–von Mises theorem</strong> states that, as the dataset grows, the posterior $p(h \mid d)$ becomes approximately Gaussian and concentrates around the maximum likelihood estimate. In this regime, Bayesian model averaging collapses towards a point estimate, predictive uncertainty is governed by the local curvature of the likelihood, and the influence of the prior on predictions fades.</p> <p>Methodologically, this is convenient. Interpretively, it is somewhat uncomfortable: a wide range of procedures, Bayesian and non-Bayesian alike, become indistinguishable in their predictions. Calling any one of them “Bayesian” tells us little about the underlying mechanism.</p> <p>PFNs are evaluated in <em>small-data</em> settings, where this asymptotic equivalence has not yet kicked in. That is the regime in which the Bayesian label is most informative, and also the regime in which it is hardest to verify.</p> <h3 id="outside-that-limit-behaviour-is-shaped-by-prior-and-likelihood">Outside that limit, behaviour is shaped by prior and likelihood</h3> <p>Once we leave the asymptotic regime, Bayesian predictions become visibly sensitive to the chosen prior and likelihood. I discussed this in detail in <a href="/blog/2026/uncertainty-decomposition/">an earlier post</a>: epistemic uncertainty is only meaningful relative to a prior, and likelihood misspecification can silently corrupt the posterior.</p> <p>In the classical Bayesian setup, the prior $p(h)$ is explicit and feeds directly into the posterior. A PFN sees no such prior. The network is exposed only to datasets sampled from the marginal data distribution induced by the prior and the predictive model. Different combinations of prior and likelihood can induce indistinguishable distributions over observed datasets; the network, in turn, is free to learn any mapping that reproduces the induced input-output statistics.</p> <p>The learned object is therefore a conditional distribution over outputs given a dataset, not a posterior over hypotheses. Calling it Bayesian relies on knowing which prior generated the training data: that connection is supplied by the modeller, not enforced by the training procedure.</p> <h3 id="bayesian-guarantees-on-in-context-learning-assume-exact-inference">Bayesian guarantees on in-context learning assume exact inference</h3> <p>A different angle on the question comes from recent work analysing in-context learning through Bayesian formalism <d-cite key="falck2024bayesian"></d-cite><d-cite key="muller2025position"></d-cite>. Two properties of true Bayesian predictors feature centrally in this line of work. First, predictions form a <strong>martingale</strong> as data accumulates: the current prediction is the conditional expectation of all future ones, so they fluctuate around it without systematic directional drift. Second, under exchangeability of the data, the order in which observations arrive does not affect the resulting prediction.</p> <p>These results are best read as <em>characterisations</em>. They describe what an exact Bayesian system must look like, not whether a given learned model in fact behaves that way. The training objective of a PFN is multi-task supervised learning; nothing in it enforces these properties.</p> <p>The continual learning literature offers a concrete illustration of how easily such properties can break.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-4 col-sm-4 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/prior-fitted/pfcl_ordering1-480.webp 480w,/assets/img/posts/prior-fitted/pfcl_ordering1-800.webp 800w,/assets/img/posts/prior-fitted/pfcl_ordering1-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/prior-fitted/pfcl_ordering1.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> <div class="col-md-4 col-sm-4 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/prior-fitted/pfcl_ordering2-480.webp 480w,/assets/img/posts/prior-fitted/pfcl_ordering2-800.webp 800w,/assets/img/posts/prior-fitted/pfcl_ordering2-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/prior-fitted/pfcl_ordering2.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> <div class="col-md-4 col-sm-4 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/prior-fitted/pfcl_ordering3-480.webp 480w,/assets/img/posts/prior-fitted/pfcl_ordering3-800.webp 800w,/assets/img/posts/prior-fitted/pfcl_ordering3-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/prior-fitted/pfcl_ordering3.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> Adapted from Fig. 4.3 in <d-cite key="henning2022phdthesis"></d-cite>. Two tasks (orange and green) are learned sequentially with a prior-focused continual learning method, in which the approximate posterior obtained after the first task plays the role of the prior for the second. <b>Left:</b> The orange task is observed first; the approximate posterior $q_{\theta^{(1)}}$ concentrates on a region that is also compatible with the green task. <b>Middle:</b> Continuing with the green task yields a joint approximate posterior $q_{\theta^{(1:2)}}$ that solves both tasks. <b>Right:</b> Reversing the order, green first, leads to an approximate posterior $q_{\theta^{(1)}}$ located in a region that has no overlap with the orange task. Along this trajectory, the orange task becomes unreachable. The order of observations changes the admissible solution set, illustrating how path-independence can fail once Bayesian inference is only approximated. </div> <p>PFNs, in turn, are not explicitly Bayesian by construction. It is therefore not obvious that they should satisfy properties that even careful Bayesian approximations fail to satisfy.</p> <h2 id="a-simple-illustration">A Simple Illustration</h2> <p>The distinction becomes visible when comparing PFN predictions to the true posterior predictive distribution outside the training regime.</p> <p>The figure below shows the result of a simple experiment based on a Gaussian process prior. A PFN is trained on datasets sampled from this prior and then compared to the analytic posterior predictive distribution.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/prior-fitted/pfn_gp_experiment-480.webp 480w,/assets/img/posts/prior-fitted/pfn_gp_experiment-800.webp 800w,/assets/img/posts/prior-fitted/pfn_gp_experiment-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/prior-fitted/pfn_gp_experiment.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> Comparison between the posterior predictive distribution of a Gaussian process and the predictions of a prior-fitted network trained on datasets sampled from the same prior. In the region where training data typically occur, both models agree closely. Outside this region, the predictive distributions begin to diverge. </div> <p>Within the training regime the PFN closely matches the Bayesian posterior predictive. Outside it, the two diverge: the Gaussian process posterior continues to reflect the prior and kernel assumptions, whereas the PFN falls back on the inductive biases of its architecture. This is expected: during training, inputs are drawn only from a specific domain, so the network never receives direct signal about prior-induced behaviour beyond it.</p> <h2 id="learning-compression-and-the-bayesian-brain">Learning, Compression, and the Bayesian Brain</h2> <p>The PFN is trained to minimise the cross-entropy between its predictions and targets drawn from the prior-induced data distribution. Cross-entropy is expected code length, so the same objective can equally be read as compression: the network is pressured to compress many inference problems into a single forward pass. Its optimum is already known. The result quoted earlier (Corollary 1.1) says the objective is minimised exactly when the network reproduces the Bayesian posterior predictive. On the training distribution, then, compressing the data well and matching the Bayesian posterior predictive are the same thing.</p> <p>Crucially, this is a statement about outputs, not about mechanism. The objective scores only what the network predicts, so any internal procedure producing those predictions is equally optimal under it. Compression pressure forces the network to settle on <em>some</em> algorithm for turning a dataset into predictions, but cannot single out which one. That algorithm might be a form of approximate Bayesian inference, or something else entirely; from the predictions alone we can neither tell which, nor recover the prior and likelihood it would correspond to. This is structurally the same situation as the long-standing <strong>Bayesian brain hypothesis</strong> debate <d-cite key="knill2004bayesian"></d-cite>: cortical computation is often modelled as approximate Bayesian inference, yet whether the brain actually implements anything that deserves the description remains actively contested <d-cite key="bowers2012bayesian"></d-cite><d-cite key="jones2011bayesian"></d-cite>.</p> <h2 id="concluding-remarks">Concluding Remarks</h2> <p>Prior-fitted networks provide a fascinating example of how <strong>inference itself can be learned</strong>. By training on large numbers of synthetic datasets, they effectively amortise Bayesian prediction and enable fast, single-pass inference on new problems.</p> <p>The training objective encourages the network to reproduce Bayesian predictions on average across tasks, but it does not enforce the properties (exact posterior averaging, path-independence, prior-driven extrapolation) we usually associate with the Bayesian label. Whether the learned procedure is well described in Bayesian terms depends on the regime in which we evaluate it, and matters most precisely where PFNs are most useful: in the small-data regimes where the prior would otherwise dominate.</p> <p>PFNs are perhaps best understood as <strong>amortised approximations of Bayesian predictors</strong>. Their behaviour can closely resemble Bayesian inference within the training distribution, but the strength of this resemblance ultimately depends on how well the learned mapping generalises beyond the tasks seen during training.</p>]]></content><author><name>Christian Henning</name></author><category term="machine-learning"/><category term="ml"/><summary type="html"><![CDATA[PFNs are often described as Bayesian predictors, but their training objective and inference mechanism suggest a more nuanced interpretation.]]></summary></entry><entry><title type="html">Why Uncertainty in Machine Learning Is Conceptually Broken</title><link href="https://chrhenning.com/blog/2026/uncertainty-decomposition/" rel="alternate" type="text/html" title="Why Uncertainty in Machine Learning Is Conceptually Broken"/><published>2026-03-07T11:15:00+00:00</published><updated>2026-03-07T11:15:00+00:00</updated><id>https://chrhenning.com/blog/2026/uncertainty-decomposition</id><content type="html" xml:base="https://chrhenning.com/blog/2026/uncertainty-decomposition/"><![CDATA[<p>Uncertainty estimation is often framed as the key to building reliable machine learning systems. Central to this narrative is the distinction between <strong>aleatoric</strong> and <strong>epistemic</strong> uncertainty. In this post, I argue that the commonly used <strong>information-theoretic decomposition of predictive uncertainty does not generally correspond to these concepts</strong> and often reflects modelling assumptions rather than properties of the data-generating process.</p> <h2 id="introduction">Introduction</h2> <p>Uncertainty estimation has become one of the central themes in modern machine learning. The promise is appealing: if models can quantify what they know and what they do not know, we should be able to build systems that behave safely in the presence of noise, detect unfamiliar inputs, and actively acquire new knowledge.</p> <p>The conceptual foundation of this promise is the widely used distinction between <a href="https://en.wikipedia.org/wiki/Uncertainty_quantification#Aleatoric_and_epistemic">aleatoric and epistemic uncertainty</a>. Aleatoric uncertainty is typically described as the irreducible randomness of the data-generating process, while epistemic uncertainty reflects gaps in the model’s knowledge that could in principle be reduced with more data. In theory, separating these two sources of uncertainty would allow us to reason about noisy environments and model ignorance in a principled way.</p> <p>In practice, however, the situation is far less clear. Most uncertainty measures used in machine learning are derived from properties of a specific probabilistic model rather than from the true data-generating process. As a result, quantities that are often interpreted as intrinsic properties of the world are in fact shaped by modelling assumptions such as the chosen likelihood function, hypothesis class, and prior. This mismatch becomes particularly visible when we attempt to evaluate uncertainty estimates: instead of directly measuring their quality, we typically rely on complex surrogate tasks such as <a href="https://en.wikipedia.org/wiki/Active_learning_(machine_learning)">active learning</a> or out-of-distribution detection. But these tasks depend on many factors beyond uncertainty itself, making them unreliable indicators of whether our uncertainty estimates are actually meaningful. As discussed in my earlier work on OOD detection <d-cite key="dangelo:henning:2021:uncertainty:based:ood"></d-cite>, the connection between uncertainty estimates and downstream tasks is subtle and often misunderstood.</p> <p>This conceptual ambiguity becomes especially problematic when considering one of the most popular tools in the uncertainty literature: the information-theoretic decomposition of predictive uncertainty into aleatoric and epistemic components. While this decomposition is frequently interpreted as revealing two fundamental sources of uncertainty in the data, it is in fact derived entirely from the structure of the model. Consequently, it does not generally provide a clean separation between intrinsic data noise and model ignorance.</p> <p>In this post, I argue that this distinction — though intuitively appealing — is often misinterpreted in modern machine learning. By examining how uncertainty estimates depend on modelling assumptions, we will see why the commonly used decomposition can be misleading, why epistemic uncertainty is fundamentally tied to the choice of prior, and why extracting meaningful uncertainty becomes particularly difficult in amortised inference systems such as modern neural networks.</p> <h2 id="decomposing-predictive-uncertainty">Decomposing Predictive Uncertainty</h2> <blockquote> <p>For a proper introduction to Bayesian statistics in the context of machine learning, see Chapters 2 and 3 of my thesis: <d-cite key="henning2022phdthesis"></d-cite>.</p> </blockquote> <p>Consider a probabilistic model parameterized by $\theta$ that maps inputs $x$ to outputs $y$. We denote a dataset of input–output pairs by $d$. In a Bayesian setting, the model parameters are treated as random variables and updated after observing data. Accordingly, we consider the random variables $D$, $Y$, and $\Theta$ corresponding to the dataset, predictions, and model parameters.</p> <p>Given an observed dataset $d$, the <strong>posterior predictive distribution</strong> is defined as</p> \[\begin{equation} p(y \mid d,x) = \mathbb{E}_{\theta \sim p(\theta \mid d)} \left[ p(y \mid \theta,x) \right] \end{equation}\] <p>where $p(\theta \mid d)$ denotes the posterior distribution over model parameters.</p> <details><summary>Mutual information as reduction in predictive entropy</summary> <p><a href="https://en.wikipedia.org/wiki/Mutual_information">Mutual information</a> measures the statistical dependence between two random variables. It can be expressed in terms of entropies as</p> \[\begin{align} I(Y;\Theta) &amp;= \mathrm{KL}\!\left( p(y,\theta)\;\middle\|\; p(y)\,p(\theta) \right) \\ &amp;= -H(Y \mid \Theta) + H(Y). \end{align}\] <p>Intuitively, mutual information quantifies how much knowing one variable reduces the uncertainty about the other.</p> </details> <p>It is useful to consider the <strong>mutual information</strong> between predictions $Y$ and parameters $\Theta$ given the observed dataset $d$ and input $x$. This quantity can be written as</p> \[\begin{align} I(Y;\Theta \mid d,x) &amp;= \mathrm{KL}\!\left( p(\theta \mid d)\, p(y \mid \theta,x) \;\middle\|\; p(\theta \mid d)\, p(y \mid d,x) \right) \\ &amp;= \mathbb{E}_{\theta \sim p(\theta \mid d)} \left[ \mathrm{KL}\!\left( p(y \mid \theta,x) \;\middle\|\; p(y \mid d,x) \right) \right]. \end{align}\] <p>This expression shows that the mutual information can be interpreted as the <strong>expected divergence between the predictive distribution of an individual hypothesis and the posterior predictive distribution</strong>. In other words, it measures how much individual models sampled from the posterior disagree with the overall predictive distribution. For this reason, it is often used as a quantitative measure of epistemic uncertainty (see Section 3.4 of my PhD thesis <d-cite key="henning2022phdthesis"></d-cite>).</p> <p>Using standard identities from information theory, we can derive a decomposition of the predictive entropy that relates it to this mutual information term. A decomposition of this form was promoted, for instance, by <d-cite key="depeweg2018decomposition"></d-cite>.</p> <p>Under the assumed generative model, the prediction $Y$ is conditionally independent of the dataset $D$ given the model parameters $\Theta$. Therefore,</p> \[\begin{align} H(Y \mid \Theta, D=d, x) &amp;= - \mathbb{E}_{\theta, y \sim p(\theta \mid d)\, p(y \mid \theta,x)} \big[ \log \frac{p(\theta \mid d)\, p(y \mid \theta,x)}{p(\theta \mid d)} \big] \\ &amp;= \mathbb{E}_{\theta \sim p(\theta \mid d)} \big[ H(Y \mid \theta,x) \big]. \end{align}\] <p>Using the standard identity</p> \[\begin{align} H(Y \mid D=d,x) &amp;= H(Y \mid \Theta, D=d,x) + I(Y;\Theta \mid D=d,x), \end{align}\] <p>we obtain the following decomposition of the predictive entropy:</p> \[\begin{align} \underbrace{ H(Y \mid D=d,x) }_{\text{entropy of predictive posterior}} &amp;= \underbrace{ \mathbb{E}_{\theta \sim p(\theta \mid d)} \big[ H(Y \mid \theta,x) \big] }_{\text{often claimed to be aleatoric uncertainty}} + \underbrace{ I(Y;\Theta \mid D=d,x) }_{\text{epistemic uncertainty}}. \end{align}\] <p>This identity is frequently interpreted as decomposing predictive uncertainty into aleatoric and epistemic components. In the next section, we will examine this interpretation more carefully and argue that the first term does not generally correspond to true aleatoric uncertainty.</p> <h2 id="why-the-expected-entropy-is-not-aleatoric-uncertainty">Why the Expected Entropy Is Not Aleatoric Uncertainty</h2> <p>The decomposition above is mathematically correct. However, interpreting the first term as <strong>aleatoric uncertainty</strong> is generally problematic.<d-footnote>This issue has been discussed previously, e.g., by <d-cite key="wimmer2023quantifying"></d-cite>.</d-footnote></p> <p>To see why, recall that aleatoric uncertainty is a property of the <strong>data-generating process</strong>, i.e., the entropy of the true conditional distribution ($p^*(y \mid x)$). In contrast, the quantity</p> \[\begin{equation} \mathbb{E}_{\theta \sim p(\theta \mid d)} \big[ H(Y \mid \theta,x) \big] \end{equation}\] <p>depends entirely on the predictive distributions produced by the model. It therefore reflects how uncertain <strong>individual hypotheses</strong> are under the current posterior, rather than a property of the underlying data distribution.</p> <p>In a very specific limit, the two can coincide. If the model is correctly specified and the amount of data grows without bound, the posterior ($p(\theta \mid d)$) collapses onto the true parameters. In this case the predictive model recovers the true data-generating distribution, and the expected entropy indeed corresponds to the aleatoric uncertainty.</p> <p>In practice, however, we rarely operate in this limit. Models are almost always <strong>misspecified</strong> — no parameter setting exactly represents the true data-generating process — and so care must be taken when interpreting the expected entropy term a measure of aleatoric uncertainty (cf. <d-cite key="cervera:henning:2021:regression"></d-cite>). We return to the consequences of misspecification in more detail below.</p> <p>The decomposition therefore separates <strong>disagreement between models</strong> from <strong>uncertainty within individual models</strong>, but this should not be mistaken for a clean decomposition of predictive uncertainty into epistemic and aleatoric components of the data-generating process.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/uncertainty-decomposition/posterior_heteroscedastic_gp-480.webp 480w,/assets/img/posts/uncertainty-decomposition/posterior_heteroscedastic_gp-800.webp 800w,/assets/img/posts/uncertainty-decomposition/posterior_heteroscedastic_gp-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/uncertainty-decomposition/posterior_heteroscedastic_gp.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> <p> <b>Posterior hypotheses of a heteroscedastic regression model.</b> Each blue curve represents a hypothesis sampled from the posterior. A hypothesis specifies both a mean function and an input-dependent predictive distribution ($p(y\mid\theta,x)$); the shaded bands visualize the noise level assumed by that hypothesis. Importantly, this noise is a property of the model hypothesis rather than the true data-generating process. The true aleatoric uncertainty is given by the entropy of the unknown ground-truth distribution ($p^*(y\mid x)$). </p> <p> Two regions contain observations: a densely sampled region (black points) and a sparsely sampled region (orange points). In the densely sampled region, the data strongly constrain the posterior, so epistemic uncertainty collapses and the remaining plausible hypotheses become very similar. Assuming the model class is correctly specified (cf. <d-cite key="cervera:henning:2021:regression"></d-cite>), these hypotheses approximate the true data-generating process, and the noise they assign reflects the true aleatoric uncertainty. </p> <p> In contrast, the sparsely sampled region leaves many different hypotheses about the data-generating process plausible, leading to substantial epistemic uncertainty. Because the ground truth is not identifiable from the available data in this region, different hypotheses imply different noise levels. Consequently, the model cannot faithfully represent the true aleatoric uncertainty there. This illustrates a key conceptual point: <b>only in regions where epistemic uncertainty has collapsed can a model reliably recover properties of the true data-generating process, including its aleatoric uncertainty.</b> </p> </div> <h2 id="the-prior-determines-what-a-model-considers-surprising">The Prior Determines What a Model Considers Surprising</h2> <p><strong>Bayesian models know what they don’t know — but we humans don’t know what they know.</strong> In other words, we cannot easily tell whether the epistemic uncertainty of a Bayesian model is shaped by the data or by the chosen prior.</p> <p>When priors are hand-crafted by domain experts, this is at least transparent: one can inspect the prior, challenge it, and decide whether the resulting notion of “what the model doesn’t know” is meaningful. In modern neural networks, this transparency is absent. The effective function-space prior is determined implicitly by architecture, weight initialisation, and optimiser dynamics — none of which were designed with any particular uncertainty semantics in mind. As a result, even a model performing exact Bayesian inference may produce epistemic uncertainty estimates whose meaning is opaque.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-4 col-sm-4 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/uncertainty-decomposition/gp_post_samples_rbf_1-480.webp 480w,/assets/img/posts/uncertainty-decomposition/gp_post_samples_rbf_1-800.webp 800w,/assets/img/posts/uncertainty-decomposition/gp_post_samples_rbf_1-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/uncertainty-decomposition/gp_post_samples_rbf_1.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> <div class="col-md-4 col-sm-4 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/uncertainty-decomposition/gp_post_samples_ess_1_6.28-480.webp 480w,/assets/img/posts/uncertainty-decomposition/gp_post_samples_ess_1_6.28-800.webp 800w,/assets/img/posts/uncertainty-decomposition/gp_post_samples_ess_1_6.28-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/uncertainty-decomposition/gp_post_samples_ess_1_6.28.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> Adapted from Fig. 7 in <d-cite key="dangelo:henning:2021:uncertainty:based:ood"></d-cite>. Predictive posteriors of two Gaussian processes with markedly different function-space priors: RBF kernel (left) and ESS kernel (right). Training data are shown as black dots; shaded bands indicate the first three standard deviations of the predictive distribution. </div> <p>The figure above illustrates this concretely. In the training region, both models fit the data closely and agree with each other. In the extrapolation region, their behaviour diverges entirely: the RBF kernel posterior reverts toward the prior with rapidly growing uncertainty, while the ESS kernel posterior continues to generalise confidently. Both models are doing everything right from a Bayesian perspective — the difference is entirely in what each prior encodes as plausible behaviour far from the data. Neither prior is “correct”; they simply reflect different inductive biases. For a neural network, we do not even have access to such a comparison: the implicit prior is not interpretable, so the epistemic uncertainty it induces is not interpretable either. Low epistemic uncertainty in any region may reflect genuine model confidence, or it may simply reflect a prior that happens to extrapolate smoothly — and from the model’s output alone, there is no way to tell <d-cite key="dangelo:henning:2021:uncertainty:based:ood"></d-cite>.</p> <h2 id="misspecification-silently-corrupts-both-uncertainty-components">Misspecification Silently Corrupts Both Uncertainty Components</h2> <p>Even setting aside the question of priors, the reliability of uncertainty estimates depends on a further assumption: that the chosen likelihood is capable of representing the true data-generating distribution. Under model misspecification this fails, and both uncertainty components are affected. Aleatoric uncertainty reflects the noise structure imposed by the likelihood rather than any property of the world. Epistemic uncertainty can become actively misleading: as data accumulates, the posterior concentrates around the least-wrong parameter setting, producing a model that grows increasingly confident in a subtly incorrect answer <d-cite key="cervera:henning:2021:regression"></d-cite>.</p> <div class="row mt-3 justify-content-center"> <div class="col-md-10 col-sm-12 mt-3 mt-md-0"> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/posts/uncertainty-decomposition/1dexperiments-480.webp 480w,/assets/img/posts/uncertainty-decomposition/1dexperiments-800.webp 800w,/assets/img/posts/uncertainty-decomposition/1dexperiments-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/posts/uncertainty-decomposition/1dexperiments.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; document.querySelectorAll('.responsive-img-srcset').forEach(function (n) { n.remove(); });"/> </picture> </figure> </div> </div> <div class="caption"> Adapted from Fig. 2 in <d-cite key="cervera:henning:2021:regression"></d-cite>. Effect of likelihood choice on uncertainty estimates for a <b>bimodal data-generating distribution</b>. A Gaussian likelihood (a, b) cannot represent the true multimodal structure and produces confidently "wrong" aleatoric uncertainty estimates, regardless of whether variance is fixed or learned. A more flexible, normalising flow-based likelihood (c) recovers the true distribution. Adding parameter uncertainty to a misspecified Gaussian model (d) introduces epistemic uncertainty but cannot compensate for the flawed likelihood. </div> <p>The severity of this problem depends heavily on how flexible the likelihood is. Universal function approximators — such as deep neural networks with expressive output heads — can in principle learn a wide range of conditional distributions without strong prior commitments about their shape. This substantially reduces the risk that the likelihood is fundamentally incompatible with the data. The remaining danger lies in cases where hard structural assumptions are imposed: for instance, assuming that the predictive distribution is always Gaussian, or always unimodal. Such constraints can be invisible in well-studied settings but catastrophic on out-of-distribution inputs or in tasks with genuinely multimodal targets. The takeaway is not that misspecification is unavoidable, but that flexibility needs to be deliberately built into the likelihood — it is not guaranteed by simply using a large model.<d-footnote>Though there is <a href="https://en.wikipedia.org/wiki/No_free_lunch_theorem">no free lunch</a>, more flexibility might come at a cost.</d-footnote> See <a href="/blog/2025/when-mse-loss-leads-to-mis-steering/">my recent blog post</a> for more details on this argument.</p> <h2 id="concluding-remarks">Concluding Remarks</h2> <p>The decomposition of predictive entropy into expected entropy and mutual information is a valid information-theoretic identity. However, interpreting this identity as a principled decomposition of predictive uncertainty into <strong>aleatoric</strong> and <strong>epistemic</strong> components is generally misleading. The quantities involved are defined purely in terms of the model’s predictive distributions and therefore do not directly correspond to properties of the underlying data-generating process.</p> <p>Conceptually, it is helpful to keep in mind that <strong>aleatoric uncertainty is a property of the data</strong>, while <strong>epistemic uncertainty reflects limitations of our knowledge and modelling assumptions</strong>. Even granting that separation, epistemic uncertainty is only meaningful relative to a prior — and for neural networks, the implicit prior is not interpretable by design. Furthermore, even a correctly specified model can have its uncertainty estimates silently corrupted by misspecification in the likelihood, causing the posterior to concentrate confidently around a wrong answer. While certain limiting cases — such as correctly specified models with infinite data — can align these notions with the information-theoretic decomposition, such conditions rarely hold in practice.</p> <p>I hope this short discussion helps create a bit of <strong>conceptual clarity</strong> around the interpretation of uncertainty decompositions in machine learning.</p>]]></content><author><name>Christian Henning</name></author><category term="machine-learning"/><category term="uncertainty"/><category term="bayesian"/><summary type="html"><![CDATA[A critique of why modern ML uncertainty estimates lack clear semantics, reliable evaluation, and meaningful use cases.]]></summary></entry></feed>