<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[JoT]]></title><description><![CDATA[A place for me to practice writing on things that interest me, usually something to do with technology or leadership.]]></description><link>https://fffej.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!s0LK!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F222e666f-6a1f-4630-80eb-0d32e4250a7a_1024x1024.png</url><title>JoT</title><link>https://fffej.substack.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 03 Jun 2026 04:32:18 GMT</lastBuildDate><atom:link href="https://fffej.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Jeff]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[fffej@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[fffej@substack.com]]></itunes:email><itunes:name><![CDATA[Jeff]]></itunes:name></itunes:owner><itunes:author><![CDATA[Jeff]]></itunes:author><googleplay:owner><![CDATA[fffej@substack.com]]></googleplay:owner><googleplay:email><![CDATA[fffej@substack.com]]></googleplay:email><googleplay:author><![CDATA[Jeff]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Spam Economy Comes to Work]]></title><description><![CDATA[Unlocking transformative value through robust, scalable document generation]]></description><link>https://fffej.substack.com/p/the-spam-economy-comes-to-work</link><guid isPermaLink="false">https://fffej.substack.com/p/the-spam-economy-comes-to-work</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 01 Jun 2026 05:49:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!VYfu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Everyone in your company has an AI model. Productivity isn&#8217;t going up, but there&#8217;s a load of documents flying around that imply it should be (many of those written by AI). And for each of those documents there&#8217;s a <em>load-bearing triplicate</em> of reasons on how those documents could be improved.</p><p>You&#8217;ve been AI-DDOSED.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VYfu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VYfu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!VYfu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!VYfu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!VYfu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VYfu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3141994,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/199298245?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VYfu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!VYfu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!VYfu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!VYfu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbc830f3-4edb-44d6-b377-af2ecf95ac46_1536x1024.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Chat GPT says this conveys the spirit of this article.</figcaption></figure></div><h2>Why does it happen?</h2><p>There&#8217;s plenty of reasons why people feel the need to spam gibberish AI. Speaking to friends and family shows me this is happening everywhere.</p><p>For some, the audience matters more than the work (see social media). Some of these are about looking good and some about not looking responsible if things break.</p><ul><li><p>People like to karma-farm. An AI can turn any gibberish into something important and profound sounding.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p></li><li><p>People want to help (and seem to forget you&#8217;ve got a subscription too).</p></li><li><p>People want plausible deniability. &#8220;The AI suggested this approach&#8221; puts the blame elsewhere.</p></li><li><p>People confuse output with progress. Generating a robust strategy sure beats doing any work.</p></li></ul><p>For others there&#8217;s genuine confusion about the tool and see it as an all-seeing genius and then trusting it to do things it can&#8217;t and taking its agreeable output as evidence.</p><ul><li><p>People mistake fluency for thinking. AI is an expert in everything you are not.</p></li><li><p>People want validation. The model will tell you it&#8217;s a good draft. People will not.</p></li><li><p>People genuinely believe it helped. The first 80% takes seconds, the remaining 20% takes forever.</p></li></ul><p>There&#8217;s also the additive fallacy (or more bluntly, &#8220;more is more&#8221;).</p><ul><li><p>People reward effort by length. A multi-page detailed analysis sounds better than &#8220;no&#8221;.</p></li><li><p>People are anchored to &#8220;comprehensive.&#8221; The AI offers seven considerations and guess what? You can always ask it for more.</p></li><li><p>People focus on getting their work done, without considering the impact on others.</p></li><li><p>People externalise the cost. Producing the document took five minutes. Reading it costs the company forty.</p></li><li><p>People can&#8217;t tell what&#8217;s signal (or don&#8217;t want to make the effort). AI might generate something with some insight, but it&#8217;s buried in noise.</p></li></ul><p>In some places, AI is an expected default. It&#8217;s not just about keeping pace with your peers, it&#8217;s about embracing a fundamental shift in how we approach communication, collaboration, and the very nature of professional discourse itself.</p><ul><li><p>People are paying for it. The company bought five seats per person and three pilot programmes that never ended. Something must visibly be happening, or the budget vanishes at the next review.</p></li><li><p>People imitate their peers. The VP started sending AI-generated weekly updates. Now everyone does.</p></li></ul><h2>What to do instead?</h2><p>Framing this as a systems problem is easy. It&#8217;s a textbook externality, identical to the email spam economy. Sending costs nothing, receiving costs the world. Every defence we have (sender reputation, rate limits, filters) exists to claw back some of that asymmetry.</p><p>The fix is always the same. Internalise the externality. Make producers pay the reading cost, cap inventory on shared channels, make consumption visible (etc). All require discipline, which means they&#8217;ll fail. Try an incentive system instead and Goodhart eats you alive: measure seats, prompts run, or documents produced, and you&#8217;ll get more seats, prompts and documents. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Do you actually have a solution?</h2><p>Nope.</p><p>Remember when digital camcorders were all the rage, and you had to suffer watching someone else&#8217;s badly recorded holiday movies? YouTube and Instagram came along and built filtering and reputation on top. We need that for office documents, at least until the likes themselves become the goal and the platform falls apart.</p><p>In the meantime, the best defence is asking people about the work &#8220;they&#8217;ve&#8221; produced.</p><p><strong>It needs to be socially unacceptable to ship slop</strong><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a><strong>.</strong></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Daniel Dennett calls these &#8220;deepities&#8221; (https://philosophytalk.org/blog/deepities-and-bullshit/)</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p> I used to have sympathy. I&#8217;d see LLM use and assume it was people using an LLM to feel more confident in their writing. I was wrong. Maybe a subset of folks do this, but it&#8217;s dwarfed by the amount of slop produced.</p></div></div>]]></content:encoded></item><item><title><![CDATA[What did I learn at Code w/Claude London?]]></title><description><![CDATA[And can I string it out to a blogpost?]]></description><link>https://fffej.substack.com/p/what-did-i-learn-at-code-wclaude</link><guid isPermaLink="false">https://fffej.substack.com/p/what-did-i-learn-at-code-wclaude</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 25 May 2026 06:21:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!s0LK!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F222e666f-6a1f-4630-80eb-0d32e4250a7a_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I was lucky enough to attend Code w/ Claude in London. It didn&#8217;t go hugely deep I&#8217;m afraid, so I&#8217;ve mostly got tid-bits of information that I found useful. So what did I learn?</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Tjsv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Tjsv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png 424w, https://substackcdn.com/image/fetch/$s_!Tjsv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png 848w, https://substackcdn.com/image/fetch/$s_!Tjsv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png 1272w, https://substackcdn.com/image/fetch/$s_!Tjsv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Tjsv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png" width="366" height="90" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:90,&quot;width&quot;:366,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4897,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/198442486?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Tjsv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png 424w, https://substackcdn.com/image/fetch/$s_!Tjsv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png 848w, https://substackcdn.com/image/fetch/$s_!Tjsv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png 1272w, https://substackcdn.com/image/fetch/$s_!Tjsv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe9245c1-6991-4e8b-9271-dcc5fb747639_366x90.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a><figcaption class="image-caption">Every post needs an image.</figcaption></figure></div><h2>We&#8217;re on an exponential</h2><p>I think almost every speaker from Anthropic said &#8220;we&#8217;re on an exponential&#8221;. Models are improving at an exponential rate. Unattended task length is improving at an exponential rate. And so on. This was often paired with &#8220;AI adoption is linear&#8221;. Put the two together and you&#8217;ve got an implementation gap, and that&#8217;s where we (armed with Claude Code) come into play.</p><p>Where does that exponential take us? Well, we can expect better judgement, near infinite context windows and multi-agent co-ordination. We&#8217;ve gone from completion to agentic execution. The next step will be continuous, proactive AI with always-on agents. Prompts will move from descriptions of what to do, to the outcomes we need to achieve (as general as &#8220;keep the project on track&#8221;.</p><h2>Designing apps</h2><p>Three guiding policies.</p><ol><li><p>Build for the next model - as models get smarter, previous generations of scaffolding often hold it back. The direction of travel is more general tools, rather than highly specialize ones.</p></li><li><p>Curate frontier evals - You need to understand how your system performs with models (this was a common theme(</p></li><li><p>Treat model upgrades as a feature</p></li></ol><h2>What model should you use?</h2><p>You should use the model that performs best on your eval. You don&#8217;t have evals? Use the defaults for the best results.</p><p>The <code>/advisor</code> mode was recommended as a way to achieve near frontier performance at five times less cost. It uses the Sonnet model by default and escalates to Opus when needed.</p><h2>Some Claude Code Tips and Tricks</h2><p><code>/remote-control</code> - Control Claude Code sessions from your phone so you don&#8217;t have to walk around with your laptop open.</p><p><code>/tui fullscreen</code> - Flicker-free rendering (rendering is virtualized, no more horrible flicker)</p><p><code>claude agents</code> - Manage a team of agents. Anything you type spawns off an agent and you can jump in/out of them anytime. Very nice!</p><p><code>/routine</code> - Run remote agents to respond to events (or just a cron job). For example, sweep through the tech debt backlog, update code-reviews and so on.</p><p><code>/ultrareview</code> - Launch a multi-agent review of your pull request. Used by Anthropic on every PR.</p><p><code>claude --worktree</code> - Claude can use git worktrees to allow multiple agents</p><h2>Some new things</h2><p>Alas, there was no new model for us to play with.</p><p><a href="https://platform.claude.com/docs/en/managed-agents/self-hosted-sandboxes">Self-hosted sandboxes</a> do what they say on the tin! I can see this being super useful for bringing agentic workflows in house when you&#8217;re worried about your data leaving your infrastructure.</p><p><a href="https://platform.claude.com/docs/en/agents-and-tools/mcp-tunnels/overview">MCP tunnels</a> solve the problem of securely connecting Claude to MCP servers running in your network (without opening your MCP server to the internet!).</p><h2>How do you run an AI-native org?</h2><p>By far my favourite talk because some of the opinions were the opposite of what I thought.</p><p>The bottlenecks have moved. The old bottlenecks were code, tests and refactoring. AI can do that now. The new bottlenecks are verification, review, security and XFN (I&#8217;m using the acronym to appear hip, I believe it&#8217;s x-functional).</p><p>So far, so standard. But what I found interesting was how the norms are changing at Anthropic.</p><ul><li><p>There&#8217;s less planning. You might think that the emphasis should be there (after all, giving AI a good spec <em>feels</em> like it should be a good idea),</p></li><li><p>Onboarding is easier. The cost of answering questions is zero; AI can answer questions about code.</p></li><li><p>Technical debates become show don&#8217;t tell. No more arguing about design A vs. design B when you can just implement. <strong>In Technical Debates, code wins.</strong></p></li><li><p>Less design doc rituals. No theatre of writing down X, just build it instead.</p></li><li><p>The source of truth is the codebase. All documentation in the codebase.</p></li></ul><p>Code review is the problem we all thought it would be. Anthropic use Claude for style, obvious bugs, spec drift and so on, but humans where there&#8217;s legal concerns, high-risk, trust-boundaries or just product taste.</p><p>What does the team make up of the future look like? A combination of creative builders with product sense, and others with deep system expertise for the hard parts. All managers at Anthropic are ICs first, contributing code. And everyone dog-foods whatever you are building.</p><p>How&#8217;d you roll out this?</p><ol><li><p>Claude-ify all your workflows - this frees up humans for the harder stuff</p></li><li><p>Tell people they can delete processes</p></li></ol><p>You&#8217;ll be winning if onboarding is quicker, PR cycle time is faster and the number of Claude-assisted commits is going up.</p>]]></content:encoded></item><item><title><![CDATA[Ranganathan’s Five Laws Apply to Your AI]]></title><description><![CDATA[Yes, it's another metaphor. Sorry.]]></description><link>https://fffej.substack.com/p/ranganathans-five-laws-apply-to-your</link><guid isPermaLink="false">https://fffej.substack.com/p/ranganathans-five-laws-apply-to-your</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 18 May 2026 05:45:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kSdi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Your AI agent is only as good as its library.</p><p>The library is the (often messy) collection of prompts, documents, tools, memories, policies, APIs, search results, text files and previous conversations from which the harness tries to assemble enough understanding to act.</p><p>S. R. Ranganathan saw this shape of problem of organizing information nearly a century ago. In 1931, he published <em><a href="https://en.wikipedia.org/wiki/Five_laws_of_library_science">The Five Laws of Library Science</a></em>:</p><ol><li><p>Books are for use.</p></li><li><p>Every reader his book.</p></li><li><p>Every book its reader.</p></li><li><p>Save the time of the reader.</p></li><li><p>The library is a growing organism.</p></li></ol><p>They sound like aphorisms, but they are closer to a design specification for information access. They also describe the design challenges of modern AI context stacks surprisingly well.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kSdi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kSdi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png 424w, https://substackcdn.com/image/fetch/$s_!kSdi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png 848w, https://substackcdn.com/image/fetch/$s_!kSdi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png 1272w, https://substackcdn.com/image/fetch/$s_!kSdi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kSdi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png" width="1375" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1375,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2529001,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/196197514?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kSdi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png 424w, https://substackcdn.com/image/fetch/$s_!kSdi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png 848w, https://substackcdn.com/image/fetch/$s_!kSdi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png 1272w, https://substackcdn.com/image/fetch/$s_!kSdi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6b8485e-b0d9-432e-9b7a-685312d0b26c_1375x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3><strong>Books are for use</strong></h3><p><strong>The book version:</strong> a library is not good because it owns books. It is good because readers can use them. </p><p><strong>The context version:</strong> an AI system is not good because it has capabilities like RAG, crafted prompts and specific tools. Those things only matter if they improve the work the model does.</p><p>A retrieval system that returns seventeen vaguely relevant chunks may score well when tested individually and still make the model worse. A memory system that surfaces every past conversation about a customer may technically succeed while burying the one fact that matters. A tool description may be accurate and still encourage the model to call it at the wrong moment.</p><p>The question is not &#8220;did the context exist?&#8221;, it&#8217;s instead &#8220;did the agent do better work because of it?&#8221;.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p><h3><strong>Every reader his book</strong></h3><p><strong>The book version:</strong> different readers need different books. A physicist, a journalist and a schoolchild asking about quantum mechanics should not all be sent to the same shelf.</p><p><strong>The context version:</strong> different models, users and workflows need different context.</p><p>A coding assistant, support bot, sales copilot, security analyst and compliance reviewer should not receive the same context package. They are doing different jobs, and have different risk profiles.</p><p>A coding assistant needs interfaces, invariants and recent changes. A support bot needs entitlement, known issues and escalation rules. A compliance reviewer needs policy, exceptions and audit trail.</p><p>We often expect one agentic system to serve multiple needs and rely on the model to do the filtering. We give them the same pile of books (the same tool list, the same memory strategy, the same retrieval and so on).</p><p>That works while the library is tiny. It fails once the system grows.</p><p>An AI system with access to twenty MCP servers does not need twenty server descriptions on every task. It needs routing. Which tool is relevant? Which source of truth applies? Which memory matters? Which policy constrains action?</p><p>A passive list of available contexts is not enough. AI systems need context routing by user, task, intent and risk.</p><h3><strong>Every book its reader</strong></h3><p><strong>The book version:</strong> a book that exists but cannot be found has effectively ceased to exist. Cataloguing is not administration. It is how the book finds the reader who needs it.</p><p><strong>The context version:</strong> useful information inside your organisation is worthless to the model if the model cannot discover it at the point of need.</p><p>The runbook is in a wiki. The policy exception is in a Slack thread. The customer-specific behaviour is in a support ticket. The design rationale is in an ADR. The safe way to perform an operation is buried in a tool description written for platform engineers.</p><p>The information exists, but the model cannot find it.</p><p>This is mostly a vocabulary problem. The user asks about &#8220;cancelling an account&#8221;. The system knows about &#8220;subscription termination&#8221;, &#8220;offboarding&#8221;, &#8220;churn workflow&#8221; and &#8220;account closure&#8221;. They are the same thing. The model sees four separate shelves and picks the closest one, which may not be the right one.</p><p>In a human organisation, this gap is bridged by the person who has been around long enough to know that &#8220;the new auth flow&#8221; in Slack, &#8220;JWT validation layer&#8221; in the codebase, and &#8220;identity boundary&#8221; in the design doc are all the same things. That person is not on call when your agent is running at 2am (or they are and they are exceedingly grumpy).</p><p>The catalogue needs to do that work instead. Synonyms, ownership, source-of-truth markers, provenance and most importantly the connections between them.</p><h3><strong>Save the time of the reader</strong></h3><p><strong>The book version:</strong> the reader&#8217;s time is precious. A library fails if the right book exists but takes an hour to find.</p><p><strong>The context version:</strong> save the model&#8217;s tokens.</p><p>If you work with Claude Code without a tight <code>AGENTS.md</code> it&#8217;s easy to see this in action. Any query will spawn tool calls to find that information resulting in huge numbers of tokens being consumed.</p><p>Tool descriptions show the same pattern. A <code>delete_record</code> tool ships with the internal API doc (parameter types, error codes, retry semantics, the lot!). But what the model actually needs to know (&#8220;this is destructive and irreversible; prefer <code>archive_record </code>unless the user explicitly asks for deletion&#8221;) is nowhere in the description.</p><p>And it&#8217;s not just about cost. Every unnecessary token consumes context window. Every bloated description makes the model do secondary work before the real work. </p><p>The model may technically have the answer and still fail because the answer is buried under sludge. Correct but bloated context is still bad context.</p><p>If the tool, RAG system or memory system is returning more than it needs then it risks creating distraction. The test for this is simple: remove the context. If the model doesn&#8217;t give worse answers, it was waste.</p><h3><strong>The library is a growing organism</strong></h3><p><strong>The book version:</strong> a library is never finished. Its collection grows. Its readers change. Its classification scheme must adapt to subjects the original cataloguer could not predict.</p><p><strong>The context version:</strong> your AI system is never finished either.</p><p>The prompts you write today encode assumptions about how your tools work, what your data looks like, and what your users need. Those assumptions will become false. APIs change. Products pivot. New edge cases emerge that nobody anticipated. A retrieval strategy tuned for fifty documents quietly degrades when the corpus reaches five thousand.</p><p>The harder problem is that the decay is invisible. The model doesn&#8217;t throw an error when it acts on a stale policy. It just gives a confidently wrong answer. </p><p>In a real library, the cataloguer has a job. They weed the collection, update classifications, retire obsolete material, and decide what the library needs to acquire next. AI context systems rarely have an equivalent. The system prompt was written once. The tool descriptions shipped with the feature and were never revisited, and the memory layer accumulates without pruning.</p><p>This is why context systems need ownership and instrumentation. Someone (or something) has to notice when the vocabulary has drifted or when a tool description no longer matches the tool. That is not a one-time task. It is the ongoing work of tending the library.</p><h3><strong>The point (if there is one)</strong></h3><p>Context systems are hard. System performance is a function of model, prompt and library. </p><p>The library is currently a hodgepodge of individual technologies (RAG, tools, MCP, memory, conversation history, prompts, skills, connectors and I&#8217;m sure many more) with no coherent organization.</p><p>These can all be improved individually, but they are just individual books of information in a larger system. The real opportunity is to <strong>design the library<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></strong>.</p><p>That means cataloguing, routing, vocabulary control, provenance, freshness, pruning, circulation policy and ownership of the whole experience by which an AI system finds what it needs to act.</p><p>When an AI system retrieves the wrong document, invokes the wrong tool, ignores the policy, uses stale information or fills the context window with noise, that is not (always) a model failure, it&#8217;s often a library failure.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>The counterargument to this would be hey, models are SO smart now that they can find the needle in the haystack. Even if that becomes true, the curation of the library still feels important in order to get other aspects of performance (cost, time to answer).</p></div></div>]]></content:encoded></item><item><title><![CDATA[Don't outsource the struggle]]></title><description><![CDATA[Be a driver, not a passenger.]]></description><link>https://fffej.substack.com/p/dont-outsource-the-struggle</link><guid isPermaLink="false">https://fffej.substack.com/p/dont-outsource-the-struggle</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 11 May 2026 06:06:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gs_1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The worst way to use AI is to ask it to do the work.</p><p>The problem isn&#8217;t because the output will be bad. Increasingly it&#8217;s pretty good, and that&#8217;s the problem.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>If the output was obviously broken, then you&#8217;d notice, fix it and learn something along the way. But if it&#8217;s good enough, then you haven&#8217;t learned a thing.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gs_1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gs_1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!gs_1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!gs_1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!gs_1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gs_1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png" width="1448" height="1086" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1086,&quot;width&quot;:1448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2751496,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/195526662?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gs_1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png 424w, https://substackcdn.com/image/fetch/$s_!gs_1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png 848w, https://substackcdn.com/image/fetch/$s_!gs_1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png 1272w, https://substackcdn.com/image/fetch/$s_!gs_1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9d745aa8-979d-4fbb-8c18-e6a00490e24a_1448x1086.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Obligatory image because posts look odd without one&#8230;</figcaption></figure></div><h2>Desirable Difficulties</h2><p>In the 1990s, <a href="https://en.wikipedia.org/wiki/Robert_A._Bjork">Robert Bjork</a> ran a series of studies that upended how psychologists thought about practice. He found that the conditions that feel most productive (easy repetition, fluent recall) often produce the weakest retention. Difficulty was not the enemy of learning. Certain kinds of difficulty were the mechanism, and he called them <em>desirable difficulties.</em></p><p>Difficulty that forces retrieval or that makes you generate an answer before seeing it is desirable difficulty and builds durable knowledge. Difficulty that comes from unclear instructions or a wasted search? That&#8217;s just a waste of time.</p><p>Which kind of difficulty does AI remove?</p><h2>Friction</h2><p>I&#8217;ve written before about <a href="https://fffej.substack.com/p/understanding-and-managing-friction">friction</a>. There are different types of friction - which of them are desirable difficulties.</p><h3><strong>Mechanical friction</strong></h3><p>This is the boring tedious stuff. Remembering the syntax for initializing a multi-dimensional array that you rarely use. Remembering the API incantation. The glue code that needs to be written. None of these things really teach you anything new<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><p>This isn&#8217;t a desirable difficulty. <strong>Let the LLM do the boring work</strong>.</p><h3><strong>Navigational friction</strong></h3><p>Finding your way around a codebase can be a pain in the ass. A modern IDE will allow you to navigate to the interface easily, but then you&#8217;ll hop through implementations until you find the right one, then step back and go into the dependency injection mush to ensure you&#8217;ve found the right file and eventually you&#8217;ll find that one example to know how the pattern works.</p><p>This one is a <strong>desirable difficulty</strong>. Once you understand how the system is wired you&#8217;ve got fantastic context for the codebase.</p><p>Use the LLM as a guide. Don&#8217;t just let the LLM go and make the edits, ask it to give you context. For example, &#8220;<em>help me trace where this behaviour lives. Show me the files involved and explain the flow before we change the code</em>&#8221;.</p><h3><strong>Comprehension friction</strong></h3><p>Understanding what the code does is the core job of software engineering.</p><p>This is where learning starts. If you skip it, you get familiarity with the output without understanding of the system. That is the engineering equivalent of being able to recite a proof without knowing why any of the step&#8217;s work.</p><p>Failing to do this, will leave you becoming a cargo-cult engineer. </p><div id="youtube2-T1PuGEsE4po" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;T1PuGEsE4po&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/T1PuGEsE4po?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p><strong>Don&#8217;t outsource the comprehension struggle.</strong></p><p>Use the LLM to validate this understanding. For example, give the LLM your own understanding and have it critiqued. Or even ask for the LLM to quiz you on a particular question (&#8220;<em>Test my knowledge of the Foo subsystem by asking me questions</em>&#8221;).</p><h3><strong>Design friction</strong></h3><p>Choosing an approach. Rejecting the alternatives. Seeing trade-offs. Noticing what each option makes harder three months from now.</p><p><strong>Amplify this</strong>. This is the biggest learning opportunity. And if you skip it, well see <a href="https://fffej.substack.com/p/nineteen-features-zero-architecture">Nineteen Features, Zero Architecture</a>!</p><p>You need trade-offs here. Don&#8217;t ask the LLM to just produce a design. Instead ask for multiple designs and work through the trade-offs yourself. For each, understand what it makes easier or harder and most importantly make a choice yourself!</p><h3><strong>Verification friction</strong></h3><p>Code has been written, but does it work? There are two questions here. Does the code do what it&#8217;s supposed to do? And does what it&#8217;s supposed to do match what stakeholders actually need?</p><p>An LLM can help with the first. It can stress-test your assumptions and prove behaviour with unit tests. The trap: if the LLM writes the code and writes the tests, you&#8217;ve automated both sides of the verification loop. <a href="https://en.wikipedia.org/wiki/Ironies_of_Automation">Bainbridge</a> flagged this already: humans who only supervise automation lose the very skills they need when the automation eventually fails. </p><p>An LLM can&#8217;t help with the second. You need a mental model not just of the architecture, but of the why. Software is about solving problems for people. Don&#8217;t outsource that.</p><h3><strong>Articulation friction</strong></h3><p>Writing the PR description. Explaining your reasoning. Naming what you are not sure about.</p><p>This is how private thinking becomes visible. The act of articulation is part of the work. Offloading it entirely means you never find out whether your understanding is as solid as you assumed.</p><p>Use the LLM to sharpen your thinking, not to do it for you.</p><h3><strong>Accountability friction</strong></h3><p>If you&#8217;re using an LLM you must own the result and be able to defend it. AI must never be used to remove this friction.</p><p>If you are responding to PR comments automatically with AI, then you need to own what it says.</p><p>Accountability is the ultimate desirable difficulty!</p><h2><strong>The implementation-monkey failure mode</strong></h2><p>There is a version of AI-assisted engineering that feels like productivity but produces no learning.</p><p>The engineer receives a ticket. They paste it into a chat window. They accept the diff. They patch the errors the linter finds. They ship the code. The ticket closes. Win!?</p><p>However, in this version the engineer is just a passenger for the journey. They haven&#8217;t built any additional capability and won&#8217;t grow as an engineer<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><h2>Driver vs. Passenger</h2><p>I believe there are two different approaches to using AI.</p><p>In the passenger mode, you give the AI tasks, and it gives you artifacts. In this model, the AI is doing all the work, and you&#8217;re just hitching along.</p><p>In the driver mode, you use AI to understand the terrain, generate options and test your assumptions. In driver mode, you are controlling the shape of the work, and you&#8217;re using AI to compress the parts that do not build judgement and amplifying the bits that do.</p><p>Be a driver!</p><h2>What this means for organisations</h2><p>It&#8217;s a system! Banning AI or policing prompts won&#8217;t produce the right results. You&#8217;ve got to make the journey mode visible and make the passenger mode uncomfortable.</p><p>What might that look like?</p><ul><li><p>Plans before implementation - ask an engineer to explain what they are building before they build it.</p></li><li><p>PR checklists should include options - make sure that significant pieces of work have the trade-offs behind choices laid out and explained.</p></li><li><p>What did you learn - PR reviews don&#8217;t have to be solely about correctness; the mentorship aspect is also important (<a href="https://www.thoughtworks.com/content/dam/thoughtworks/documents/report/tw_future%20_of_software_development_retreat_%20key_takeaways.pdf">Thoughtworks described reviews as the bundling of mentorship, consistency, correctness and trust</a>).</p></li><li><p>Prompt examples in team documentation - Show the difference between prompts that directly produce artifacts versus those that produce understanding.</p></li></ul><h2>Conclusion</h2><p>The goal is not to make work frictionless.</p><p>The goal is to remove the friction that wastes attention and preserve the friction that builds judgement. Bjork&#8217;s <em>desirable difficulties</em> are still desirable. The undesirable ones are still worth eliminating. The job is to know the difference.</p><p>Use AI, but be a driver, not a passenger.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I used to think it was useful to know all this kind of syntax, but since it&#8217;s now easily lookup-able, I don&#8217;t think there&#8217;s much value in it.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I suppose they will be super good at LLM usage though!</p></div></div>]]></content:encoded></item><item><title><![CDATA[Bad code is contagious]]></title><description><![CDATA[How imitation machines turn local mistakes into system-wide conventions]]></description><link>https://fffej.substack.com/p/bad-code-is-contagious</link><guid isPermaLink="false">https://fffej.substack.com/p/bad-code-is-contagious</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 04 May 2026 06:54:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!S60f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Bad code has always spread through codebases by imitation. AI just turned a slow cultural process into an epidemic.</p><p>When a new developer joins a project, they learn what code should look like by copying what&#8217;s already there. Style guides are usually out of date or aspirational. ADRs capture decisions but not necessarily reality. The only reliable signal is the code itself, and &#8220;<a href="https://en.wikipedia.org/wiki/When_in_Rome,_do_as_the_Romans_do">when in Rome</a>&#8221; is a sensible default.</p><p>The problem is that the default propagates whatever is already there, good or bad. Point an imitation machine at a corpus of imperfect code and you get propagation and compounding. Just like a virus.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Why code conventions spread like a virus</h2><p>In small teams, conventions spread deliberately. Someone makes a call, writes it down<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, mentions it in review, and the team mostly follows.</p><p>At scale, that breaks down. Most developers learn conventions less from documentation than from neighbouring code. The local environment becomes the fitness landscape, and &#8220;when in Rome&#8221; becomes the replication mechanism.</p><p>AI agents just accelerate this process.</p><h2>A short primer on SIR</h2><p>The SIR model divides a population into three states: Susceptible, Infected, Recovered. Within the model there are three important numbers.</p><ul><li><p>Transmission probability - when an infected individual contacts a susceptible one, this is the chance the pathogen passes across</p></li><li><p>Contact rate - how often infected individuals contact susceptibles in the first place.</p></li><li><p>Recovery rate - how quickly infected individuals stop being infected.</p></li></ul><p>The product of these (adjusted for the average number of contacts per individual) gives you R0, the basic reproduction number. It is the number of new infections caused, on average, by a single infected individual in a fully susceptible population. As you will remember from the COVID era, if R0 is below one<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>, the outbreak dies out. If R0 is above one, it grows.</p><p>So, lets stretch this model across to software.</p><ul><li><p>Transmission probability is now how convincing a bad pattern looks when an agent reads it. A well-named, well-structured and well-commented bad pattern transmits at a much higher rate than a scruffy one. This is part of why AI-generated code is so dangerous, it looks just as (if not more so) plausible than human-written code.</p></li><li><p>Contact rate is how aggressively agent sessions sample neighbouring files. Big context windows and tools that pull in all relevant files, and prompts that say things like &#8220;follow the existing patterns in this repo&#8221; all increase the contact rate.</p></li><li><p>Recovery rate is how quickly you refactor, review or remove the pattern. This is entirely a function of your engineering practices. You get to control this one!</p></li></ul><h2>The R0 threshold</h2><p>For the first example, let&#8217;s pretend we have the architecture below. There are roughly 120 components. There are some foundational services in the middle that almost everything else uses, but most of the classes only use a handful of other classes.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!S60f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!S60f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png 424w, https://substackcdn.com/image/fetch/$s_!S60f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png 848w, https://substackcdn.com/image/fetch/$s_!S60f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png 1272w, https://substackcdn.com/image/fetch/$s_!S60f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!S60f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png" width="787" height="590" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:590,&quot;width&quot;:787,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:401873,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/194626479?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!S60f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png 424w, https://substackcdn.com/image/fetch/$s_!S60f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png 848w, https://substackcdn.com/image/fetch/$s_!S60f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png 1272w, https://substackcdn.com/image/fetch/$s_!S60f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b7bbc1d-56a7-4207-9537-e03220931345_787x590.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Architecture? Nah, it&#8217;s a randomly generated network <a href="https://en.wikipedia.org/wiki/Barab%C3%A1si%E2%80%93Albert_model">https://en.wikipedia.org/wiki/Barab&#225;si&#8211;Albert_model</a></figcaption></figure></div><p>We will try to simulate three different approaches. We will imagine the virus to be AI-generated code and simulate three different styles of usage.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CccS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CccS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png 424w, https://substackcdn.com/image/fetch/$s_!CccS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png 848w, https://substackcdn.com/image/fetch/$s_!CccS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png 1272w, https://substackcdn.com/image/fetch/$s_!CccS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CccS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png" width="1456" height="828" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:828,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:243546,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/194626479?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CccS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png 424w, https://substackcdn.com/image/fetch/$s_!CccS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png 848w, https://substackcdn.com/image/fetch/$s_!CccS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png 1272w, https://substackcdn.com/image/fetch/$s_!CccS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb768e213-2e5c-4540-9cdd-7de64cab678e_1598x909.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Simulating pattern spread across architecture</figcaption></figure></div><ul><li><p>Conservative - In this example, think mostly using AI within files with tight prompts and narrow context. In this usage of AI, code patterns spread slow enough that recovery can keep pace. R0 in this case is around 1.</p></li><li><p>Default - Now we are imagining a more typical AI harness with no special constraints. AI pulls in patterns as needed through the harness and uses much of the context window. R0 is about five in this case. The pattern does not burn through every component, but it is sticky enough that you&#8217;ve now got roughly a quarter of your components carrying a wrong pattern, and it is hard to remove since it has prior art on its side.</p></li><li><p>Aggressive - wide context windows, tools that eagerly sample neighbours, prompts that tell the agent to follow existing patterns can push R0 up to fifteen. This is bad. By day thirteen, the contaminated pattern is the dominant one.</p></li></ul><p>The important thing about R0 is that it behaves like a threshold, not a linear dial. Below one, the pattern struggles to sustain itself. Above one, it starts finding chains of transmission. The difference between 0.9 and 1.1 is not a rounding error. It is the difference between local noise and systemic spread.</p><h2>Vaccinating your code base.</h2><p>With the industry drive being to AI all the things, R0 is mostly out of collective hands. You might be able to constrain agent configuration at the margin, but the industry trajectory is towards <em>AI all the things</em>. Now the question becomes, what can you do about the population itself?</p><p>The epidemiological answer is vaccination. You do not need to protect everyone, but you need to protect enough of the population that the average infected individual encounters fewer than one susceptible contact. If you can achieve that, then the effective R drops below one and the outbreak dies even though R0 in the unprotected subpopulation is still high. This is <a href="https://en.wikipedia.org/wiki/Herd_immunity">herd immunity</a>, and it is one of the most counter-intuitive and important results in the field.</p><p>The software analogue to a vaccine is architectural. A vaccinated component is one where the bad pattern cannot take hold. A vaccine could be a lint-rule, an automated test, a schema contract or even a golden-path scaffold that wins because the agent reads it first. Vaccinated services are immune not because they are better written, but because the environment around them actively refuses the contaminated pattern.</p><p>In the next chart, we will use the Default scenario and now vary which fraction of services have vaccination applied.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eTP9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eTP9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png 424w, https://substackcdn.com/image/fetch/$s_!eTP9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png 848w, https://substackcdn.com/image/fetch/$s_!eTP9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png 1272w, https://substackcdn.com/image/fetch/$s_!eTP9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eTP9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png" width="1456" height="828" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:828,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:297508,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/194626479?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eTP9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png 424w, https://substackcdn.com/image/fetch/$s_!eTP9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png 848w, https://substackcdn.com/image/fetch/$s_!eTP9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png 1272w, https://substackcdn.com/image/fetch/$s_!eTP9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2214ba13-58b5-4827-95d5-8764c7ecfa38_1598x909.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Simulating what happens with different levels of vaccination.</figcaption></figure></div><p>You might be thinking, surely if I write the correct rule, I can vaccinate 100%? Well, if that were true then you&#8217;d be able to write an oracle to say if something was good or bad and I think that&#8217;s too hard for me! I prefer to look at it from the other direction. If I can write a fuzzy rule that rejects some percentage of bad code, then the pattern stops spreading.</p><p>At zero coverage the outbreak peaks around thirty services. At thirty percent coverage the peak collapses by three-quarters to about seven. At sixty percent it is essentially extinguished - you get small, transient flare-ups that recover on their own. At eighty-five percent the pattern cannot get going at all.</p><p>This matters for engineering decisions because the intuitive model says, &#8220;we will roll out linting progressively, starting with the most critical services&#8221;. The epidemiological model says something different: the value of linting is strongly non-linear in coverage, and you do not get real protection until you are above the herd-immunity threshold. A thirty percent rollout does not deliver thirty percent of the benefit. In this simulation, it removes roughly seventy-five percent of the peak outbreak, because it breaks transmission chains</p><h2><strong>Vaccinate your codebase!</strong></h2><p>If this analogy holds, then the interventions we should make to stop bad patterns spreading are:</p><ul><li><p>Golden paths are vaccination - Every component that uses a golden path is a vaccinated member of the population. Golden paths will get copied by the AI. Herd immunity appears when enough of the codebase uses them.</p></li><li><p>Linting rules / Architectural fitness functions are barriers at the point of contact (masks, hand-washing etc.) - They do not prevent a bad pattern being generated, but instead they catch it before it reaches a service. A good lint rule is one that blocks the wrong thing from being committed. It also does not have to be 100% effective.</p></li><li><p>Agent scope is the contact rate - An agent session that touches many files is a house-party! Smaller, more well-defined tasks aren&#8217;t just about code quality, they reduce R0 directly.</p></li><li><p>Refactoring is treatment - This is the recovery rate. It is the one parameter you can raise directly and it&#8217;s the one most often neglected. &#8220;We will refactor when we have time&#8221; is the epidemiological equivalent of &#8220;we will treat the sick when we have time&#8221;. You can raise recovery rate by funding platform teams, protecting time for it or by making it cheap enough to happen inside ordinary work.</p></li><li><p>Observability is surveillance - You can&#8217;t respond to an outbreak you cannot see. Tools that scan for pattern proliferation (duplicated logic, drift from golden paths) are the codebase equivalent of contact tracing.</p></li></ul><p>Engineering leaders spend a lot of time thinking about how to produce more code. The more useful question is how to ensure that the code you produce does not contaminate the code you already had. Epidemiology has been thinking about that problem for two hundred years. The intervention that matters is raising the recovery rate and vaccinating enough of the population that bad patterns cannot find a chain to run through.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>No-one really writes it down, but we all like to pretend that we do.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>During COVID almost every night there would be a reporter trying to explain R0!</p></div></div>]]></content:encoded></item><item><title><![CDATA[Estimating AI's carbon footprint.]]></title><description><![CDATA[Or, generating equations with as few unknowns as possible.]]></description><link>https://fffej.substack.com/p/estimating-ais-carbon-footprint</link><guid isPermaLink="false">https://fffej.substack.com/p/estimating-ais-carbon-footprint</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 27 Apr 2026 05:54:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Z4_Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The environmental impact of AI is huge. There&#8217;s an insatiable quest for power (I mean electricity, but you know, other types of power too). On the flipside, it&#8217;s clear that there are some use-cases (particularly software development) where there are benefits.</p><p>How do you quantify the impact of your usage of AI with your carbon footprint?</p><p>Neither Anthropic nor OpenAI publishes concrete information about their environmental impact. In this post, I&#8217;ll try to estimate some bounds.</p><p>First off, a disclaimer. I&#8217;m an arm-chair researcher writing things up based on publicly available information. Don&#8217;t take this as gospel; it&#8217;s an estimate and if I&#8217;ve made incorrect assumptions, tell me!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Z4_Q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png 424w, https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png 848w, https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png" width="350" height="444.41309255079005" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1125,&quot;width&quot;:886,&quot;resizeWidth&quot;:350,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;File:Carbon footprint icon.png - Wikimedia Commons&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="File:Carbon footprint icon.png - Wikimedia Commons" title="File:Carbon footprint icon.png - Wikimedia Commons" srcset="https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png 424w, https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png 848w, https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png 1272w, https://substackcdn.com/image/fetch/$s_!Z4_Q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5768f9-1baa-47e5-97ba-9fec68e639dc_886x1125.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Tommaso.sansone91, CC0, via Wikimedia Commons</figcaption></figure></div><h2>Everyone has a number</h2><p>Sam Altman says <a href="https://blog.samaltman.com/the-gentle-singularity">an average ChatGPT query uses about 0.34 watt-hours</a>. Google&#8217;s <a href="https://arxiv.org/abs/2508.15734">August 2025 paper on Gemini</a> puts the median text prompt at 0.24 Wh. </p><p>The trouble is that any single number describes a population. A short factual question on a non-reasoning model, served from a hyper-scaler on a clean grid, sits at one end. An ARC-AGI puzzle solved by frontier model in high-compute mode sits at the other.</p><p>Once you fix the model and infrastructure, the dominant variable you actually control is the number of tokens the system burns.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>The formula.</h2><p>There is a simple way to think about the cost of an AI query:</p><blockquote><p>How much computation did the model do, how much electricity did that require, and how dirty was the electricity?</p></blockquote><p>For a transformer, generating one token takes roughly two floating-point operations per active parameter (one multiply and one add) per active parameter.</p><p>So, the first-order compute cost is:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{FLOPs} \\approx 2 \\times N_{\\text{active}} \\times T_{\\text{effective}}&quot;,&quot;id&quot;:&quot;JZMXWHFSXL&quot;}" data-component-name="LatexBlockToDOM"></div><p>Where:</p><ul><li><p><code>N_active</code> is the number of active parameters used per token.</p></li><li><p><code>T_effective</code> is the number of tokens the system actually burned.</p></li></ul><p><code>T_effective</code> is the part doing a lot of work. It&#8217;s not just the number of tokens you see on the screen. It includes the prompt, the answer, the hidden reasoning tokens, any agent loops, retries, tool calls and so on. A normal chat request might be a few hundred or a few thousand tokens, but a hard reasoning task could be many multiples of that.</p><p>That&#8217;s why thinking about as &#8220;what does a query cost&#8221; is the wrong question. A query isn&#8217;t a unit.  Tokens are a bit closer, but even then, that hides the batching, hardware and datacentre effects.</p><p>To turn compute into energy, we need to account for how efficiently the GPU is actually being used. This looks more complicated than it is!</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E_{\\text{node}} \\approx\n\\frac{\n2 \\times N_{\\text{active}} \\times T_{\\text{effective}}\n}{\nP_{\\text{peak}} \\times \\epsilon_{\\text{serve}}\n}\n\\times\nP_{\\text{GPU}}\n\\times\n\\alpha\n\\times\nPUE\n\\times\n\\eta_{\\text{node}}&quot;,&quot;id&quot;:&quot;IPQCJHRBNK&quot;}" data-component-name="LatexBlockToDOM"></div><p>The fraction gives us <strong>seconds of GPU time (</strong>total FLOPS needed divided by speed of GPU). The remaining terms turn seconds into <strong>joules</strong>.</p><p>In plain English:</p><ul><li><p><code>P_peak</code> is the theoretical speed of the GPU.</p></li><li><p><code>e_serve</code> is the realised serving efficiency (how much of that peak bandwidth is used)</p></li><li><p><code>P_GPU</code> is the GPU&#8217;s power draw.</p></li><li><p><code>&#945;</code> is the fraction of the GPU&#8217;s rated power actually used.</p></li><li><p><code>PUE</code> is the datacentre overhead. If the servers use 1 kWh and the building uses another 0.2 kWh for cooling and power conversion, the PUE is 1.2.</p></li><li><p><code>&#951;_node</code> adds the rest of the server: CPU, memory, networking, power losses.</p></li></ul><p>And now to get an estimate of the CO2 equivalent.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{gCO}_2\\text{e} \\approx\n\\frac{E_{\\text{node}}}{3{,}600{,}000}\n\\times \\text{CI}\n&quot;,&quot;id&quot;:&quot;VTQKGAGUPD&quot;}" data-component-name="LatexBlockToDOM"></div><p>The <code>3,600,000</code> is just the conversion from joules to kilowatt-hours. <code>CI</code> is the carbon intensity of the electricity grid, measured in grams of CO&#8322; per kWh.</p><h2>What are some plausible numbers?</h2><p>Let&#8217;s see if we can get anywhere near the numbers from Google and Sam Altman.</p><p>Let&#8217;s start making assumption. I&#8217;ll use an H100-ish GPU as the reference point because that was probably dominant at the time of those comments, and it&#8217;s a good baseline.</p><ul><li><p>Active model size: <strong>100B parameters</strong></p></li><li><p>Accelerator peak throughput: <strong>3.96 PFLOP/s</strong></p></li><li><p>Realised serving efficiency: <strong>5%</strong></p></li><li><p>GPU rated power: <strong>700W</strong></p></li><li><p>Actual power draw: <strong>60% of rated power</strong></p></li><li><p>Node overhead: <strong>1.3&#215;</strong></p></li><li><p>Datacentre PUE: <strong>1.1</strong></p></li></ul><p>5% efficiency sounds absolutely mad right? LLM serving is beyond just inference, there&#8217;s prefill, decoding, KV cache, memory bandwidth, batching and so on. NVIDIA <a href="https://developer.nvidia.com/blog/achieving-top-inference-performance-with-the-nvidia-h100-tensor-core-gpu-and-nvidia-tensorrt-llm/">published a benchmark</a> for Llama 2 70B on 8 H100 GPUs. The server processed about 5 inferences per second, and that works out to about 5% of the peak throughput<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>,</p><p>Plugging in all of those numbers into our formula gives this.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E_{\\text{total}}(T) \\approx\n\\frac{\n2 \\times 100{,}000{,}000{,}000 \\times T\n}{\n3.96 \\times 10^{15} \\times 0.05\n}\n\\times\n700\n\\times\n0.6\n\\times\n1.3\n\\times\n1.1&quot;,&quot;id&quot;:&quot;LADFNZODAI&quot;}" data-component-name="LatexBlockToDOM"></div><p>And if we simplify this (and divide by 3.6M to get kilo-watt hours. We get.</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;E_{\\text{total}}(T) \\approx 0.00017T \\text{ Wh}&quot;,&quot;id&quot;:&quot;VLSJWCNTOS&quot;}" data-component-name="LatexBlockToDOM"></div><p>So, under the assumptions I&#8217;ve made, every 1000 tokens costs about 0.17Wh. Which feels close enough to the numbers cited by Altman and Google. If I work backwards from their output, it&#8217;s 2000 effective tokens for ChatGPT and 1400 for Google and that sounds a plausible number of tokens to me!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><h2>Translating into carbon footprint.</h2><p>If we&#8217;ve got the Watt hours, we now have to multiply the Watt hours by the carbon intensity. </p><p>If you are using <a href="https://www.theguardian.com/technology/2026/jan/15/elon-musk-xai-datacenter-memphis">gas turbines to power your LLM</a> then that&#8217;s one end of the spectrum (somewhere between 500-600 grams of CO2 per kilowatt hours, see <a href="https://www.epa.gov/system/files/documents/2023-05/Simple%20Cycle%20Stationary%20Combustion%20Turbine%20EGUs%20TSD.pdf">here</a>). In the UK, the carbon intensity was 125g CO2/Kwh (see <a href="https://www.neso.energy/news/britains-electricity-explained-2024-review">2024 energy review</a>). And in Norway, it&#8217;s <a href="https://energytag.org/its-about-time-carbon-intensity-part-2/">super clean at 2.2g CO2/KWh</a>.</p><p>If we plug that into our formula we get:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\text{gCO}_2\\text{e}(T)\n\\approx\n0.00017T \\times \\frac{\\text{CI}}{1000}&quot;,&quot;id&quot;:&quot;TOWPQIIKYK&quot;}" data-component-name="LatexBlockToDOM"></div><p>I&#8217;ll use gCO&#8322;e rather than just gCO&#8322;. The &#8220;e&#8221; means equivalent: other greenhouse gases, especially methane, converted into the warming impact of CO&#8322;.</p><p>So, a <strong>2,000 effective-token</strong> query is:</p><ul><li><p>at <strong>550 g/kWh</strong>: about <strong>0.19 gCO&#8322;e</strong></p></li><li><p>at <strong>125 g/kWh</strong>: about <strong>0.04 gCO&#8322;e</strong></p></li><li><p>at <strong>30 g/kWh</strong>: about <strong>0.01 gCO&#8322;e</strong></p></li></ul><p>These are tiny amounts for sure, but what happens at scale?</p><h2>Tokenmaxxing</h2><p>Meta used 60.2 trillion AI tokens in 30 days (via <a href="https://blog.pragmaticengineer.com/the-pulse-tokenmaxxing-as-a-weird-new-trend/">The Pragmatic Engineer</a>). </p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\begin{aligned}\nT &amp;= 60.2 \\times 10^{12} \\text{ tokens} \\\\[4pt]\nE(T) &amp;\\approx 0.00017T \\text{ Wh} \\\\[4pt]\nE(T) &amp;\\approx 0.00017 \\times 60.2 \\times 10^{12} \\text{ Wh} \\\\[4pt]\n&amp;\\approx 10.23 \\times 10^{9} \\text{ Wh} \\\\[4pt]\n&amp;\\approx 10.23 \\times 10^{6} \\text{ kWh} \\\\[4pt]\n&amp;\\approx 10.23 \\text{ GWh} \\\\[8pt]\n\\text{gCO}_2\\text{e} \n&amp;\\approx 10.23 \\times 10^{6} \\times 125 \\\\[4pt]\n&amp;\\approx 1.28 \\times 10^{9} \\text{ gCO}_2\\text{e} \\\\[4pt]\n&amp;\\approx 1.28 \\times 10^{6} \\text{ kgCO}_2\\text{e} \\\\[4pt]\n&amp;\\approx 1{,}280 \\text{ tonnes CO}_2\\text{e} \\\\[4pt]\n&amp;\\approx 1.28 \\text{ kilotonnes CO}_2\\text{e}\n\\end{aligned}&quot;,&quot;id&quot;:&quot;SPLEHZCMVF&quot;}" data-component-name="LatexBlockToDOM"></div><p>This is a staggeringly large impact<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> - that&#8217;s 700 return economy trips between <a href="https://clevercarbon.io/carbon-footprint-of-common-items">London and NY</a>. Given that there are typically 20 or so flights per day between London and NY, this is clearly a pretty significant number. And that&#8217;s just Meta!</p><h2>What does this mean?</h2><p>The point is not that every AI query is an environmental disaster. Most aren&#8217;t. A single short prompt is tiny compared with flying, heating a house, or driving a car.</p><p>The problem is abstraction. Once tokens are hidden behind chat boxes, agents, IDE plugins and &#8220;autonomous&#8221; workflows, nobody notices when a simple question becomes a thousand-step computation.</p><p>That makes AI carbon a design problem.</p><p>Engineering leaders should stop asking, &#8220;Is AI good or bad for the environment?&#8221; and start asking better questions. Which model is appropriate for this task? How much context are we sending? Do we need reasoning mode? Are retries bounded? Are agents allowed to loop? Are we measuring tokens per useful outcome?</p><p>The useful distinction is not AI versus no AI. It is <strong>valuable tokens versus waste tokens</strong>.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>OK, this feels like the weakest assumption I&#8217;ve made, and I&#8217;ve probably misunderstood something, but here&#8217;s my logic.</p><p>The workload was 2048 input tokens, and an output of 128. Llama 2 70B is a dense model, so the estimate of FLOPs per inference in this case is 2 x 2176 x 70B.</p><p>If we do five inferences per second, then we now get 5 x 2 x 2176 x 70B FLOP/second. If we take the peak throughput of 3.96 PFLOPS and multiply by 8 then we get the total. </p><p>Take the ratio of the two and we get:</p><div class="latex-rendered" data-attrs="{&quot;persistentExpression&quot;:&quot;\\ e_{serve}\n\\approx\n\\frac{\n1.52 \\times 10^{15}\n}{\n3.17 \\times 10^{16}\n}\n\\approx\n0.048&quot;,&quot;id&quot;:&quot;CNIZGEVUTS&quot;}" data-component-name="LatexBlockToDOM"></div><p>I even checked with <a href="https://www.wolframalpha.com/input?i=%28%285+x+2+x+2176+x+70billion%29+flop%2Fsecond%29+%2F+%288+x+3.96+petaflops%2Fsecond%29">Wolfram Alpha</a>.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>If I run the numbers with the B200 I get a 0.11 vs. 0.17 impact (a roughly 50% improvement!). I would guess the TPUs and subsequent generations will be much more efficient.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Under the assumptions I have made of course - it&#8217;s very likely a vast over-estimate because I&#8217;d hope things like caching kick in and save a whole bunch of work.</p></div></div>]]></content:encoded></item><item><title><![CDATA[When building gets cheaper than thinking]]></title><description><![CDATA[Or why the double-diamond was an answer to a question we no longer have.]]></description><link>https://fffej.substack.com/p/when-building-gets-cheaper-than-thinking</link><guid isPermaLink="false">https://fffej.substack.com/p/when-building-gets-cheaper-than-thinking</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 20 Apr 2026 05:22:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!-AQV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The double diamond encoded an economic assumption that no longer holds.</p><p>For twenty years it&#8217;s been the default shape of product thinking and taught in every bootcamp, drawn on every whiteboard. It fit a world where building was expensive and understanding was cheap-ish. You invested weeks in research because shipping the wrong thing cost months, and you&#8217;d rather spend a fortnight with a whiteboard than a quarter with an expensive engineering team. The diamond shape itself encodes that trade-off: convergence is cheaper than rework.</p><p>That trade-off is gone.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h3><strong>Implicit assumptions</strong></h3><p><em><strong>Research is sampled.</strong></em><strong> </strong>The old move was to interview a dozen customers, cover a wall in sticky notes, and squint until themes emerged. The implicit model was that understanding users is a bottleneck you pay down with weeks of fieldwork. Now every customer interaction across the business (support tickets, sales calls, session recordings, forum posts, Slack messages from the CS team) can be transcribed and synthesised in an afternoon. Now the hard part isn&#8217;t finding users (unless you are a startup trying to find those first few customers), but now it is about finding the insights.</p><p><em><strong>Problems must be defined before they&#8217;re solved</strong>.</em> This made sense when engineering was the expensive phase. You defined carefully because building was where the money went. When the marginal cost of a working prototype approaches zero, &#8220;define the problem precisely&#8221; and &#8220;build three versions and see which one users actually grab&#8221; become competing strategies, and the second often wins. Call it <em>discovery by construction<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></em>. The prototype <em>is</em> the research instrument. You&#8217;re not asking users what they want; you&#8217;re watching which of the things you already built they reach for.</p><p><em><strong>The output is one artefact for a population.</strong></em> There is a real craft in finding the common ground - what percentage of our customers can we build a coherent solution for, where do we draw the line, what do we deliberately not serve. Now? Generate a design per user. There&#8217;s no need to converge on one answer; just hyper-personalise as the situation demands. What you ship isn&#8217;t a design; it&#8217;s a <em>policy</em> that produces designs. </p><p><em><strong>Users are subjects of research.</strong></em> The whole framework treats users as the people you build <em>for</em>. But anyone can build now. The frustrated marketer telling you to try their new app at http://localhost:3000 isn&#8217;t a punchline, they&#8217;re the next generation of builder. If everyone is a maker, &#8220;selling a finished product to a passive user&#8221; stops being the dominant shape of the market. The users <em>are</em> the builders. What they want from you is not a solution but a substrate on which to build their solution.</p><h3><strong>The hidden job of discovery</strong></h3><p>Discovery used to do double duty<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. It found the right problem, yes, but it also <em>slowed teams down enough to think</em>. Strip out the slowness and a lot of teams will just ship faster garbage with more confidence. Cheap iteration makes people reckless about coherence. It&#8217;s a textbook <a href="https://fffej.substack.com/p/the-peltzman-effect">Peltzman effect</a>: make building safer and people build more dangerously.</p><p>There&#8217;s a second problem underneath it. When a model helps you frame the problem, synthesise the research, and generate the prototypes, who&#8217;s left to notice when the framing was wrong in the first place? The more of the discovery loop the machine runs, the less context the human has to sanity-check its output and the <em>more</em> confident the output looks, because it came out polished. Discovery by construction is brilliant right up until you realise you&#8217;ve been constructing variations on a problem nobody actually has.</p><p>The residual skills aren&#8217;t <em>understanding users</em> or <em>shipping fast</em>. They&#8217;re taste, coherence, and the confidence to say no. Those three things don&#8217;t get cheaper when models get better. They might get <em>harder</em>, because the cost of shipping something incoherent has collapsed and the social pressure to ship faster has not.</p><h3><strong>Building for Builders</strong></h3><p>The work moves up a level: curate a generative system. Build tools that help people build tools. The unit of design is no longer the artefact; it&#8217;s the substrate the artefacts grow on.</p><p>Shopify is the cleanest example - it&#8217;s a product that produces shops. Nobody at Shopify is designing <em>your</em> store; they&#8217;re designing the system that lets you design it, and the constraints that keep the millions of resulting stores from being terrible. Figma did the same thing to design tools: the product isn&#8217;t a deliverable; it&#8217;s the environment in which deliverables happen. Roblox sells a world in which users build worlds. Notion ships a toolkit and lets users assemble their own CRMs, wikis, and project trackers out of it. In each case the company stopped trying to ship <em>the</em> answer and started shipping the machine that generates answers. The diamond shape, with its neat convergence on a single artefact, describes none of these products.</p><p>So, the question stops being &#8220;<em>how do I solve this problem?&#8221;</em> and becomes &#8220;<em>how do I build a system that solves this class of problem?&#8221;</em>. This is a meta-problem<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> that rewards different instincts: thinking in invariants rather than features, in guardrails rather than specifications, in the rules of the game rather than the game itself. It&#8217;s closer to setting policy than to designing a screen. And it&#8217;s much harder to do badly and get away with it, because the mistakes compound across every artefact the system produces. Ship a bad feature and you disappoint the users who touch it. Ship a bad substrate and you disappoint everyone who builds on top of it, which is eventually everyone.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-AQV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-AQV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!-AQV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!-AQV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!-AQV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-AQV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1953297,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/193703268?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-AQV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!-AQV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!-AQV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!-AQV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7fd4d18f-5e2e-4a1b-bdd5-7923af20cb3e_1408x768.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Gemini: Draw me a replacement for the double-diamond using this blog post</figcaption></figure></div><p>There&#8217;s no clean replacement shape yet (though Gemini is pretty good at making things up). I suspect the honest answer is that the replacement is some kind of continuous loop held together by two things the old framework took for granted: <em>taste</em> (does this cohere with what we are?) and <em>consequence</em> (what does this system make easy that shouldn&#8217;t be easy?).</p><h2>Closing</h2><p>The double diamond was a brilliant answer to &#8220;how do we stop expensive engineering teams from building the wrong thing&#8221;? It answered that question well for twenty years, and a generation of product people learned their craft inside it. But the question has changed. Engineering isn&#8217;t the expensive bit anymore. Discovery is now construction.</p><p>In this new world, you are building for builders and that&#8217;s raised the level of abstraction. You are creating systems that create products and the most important things are keeping that system coherent so everyone can build a product themselves.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I like this phrase! When I worked at a super small startup, this was the dominant way of doing things. The codebase was small enough to allow super rapid iteration.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>This double-duty is something we lose when we start to switch over processes to using AI-first (see https://fffej.substack.com/i/189158486/the-newspaper-warning for an unexpected example, or simply consider how AI code reviews drop the mentoring and knowledge sharing)</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>And a general rule I&#8217;ve found is that meta-is-better. If you can raise the level of abstraction and solve an entire class of problems, you should!</p></div></div>]]></content:encoded></item><item><title><![CDATA[Nineteen Features, Zero Architecture]]></title><description><![CDATA[Green dashboard, Red Flags]]></description><link>https://fffej.substack.com/p/nineteen-features-zero-architecture</link><guid isPermaLink="false">https://fffej.substack.com/p/nineteen-features-zero-architecture</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 13 Apr 2026 05:57:37 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!h8ka!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I gave an AI full autonomy over a codebase. It made every decision - what to build, how to build it and even whether it was good enough to ship. Nineteen features later, the tests all passed, coverage looked healthy, and the code was a disaster.</p><p>Let&#8217;s see why.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>The setup</h2><p>A retry policy library is a good test because the feature space is genuinely large (fixed delay, exponential backoff, jitter, circuit breakers, cancellations, and so on). Each one of these is a legitimate feature, and none of them are obviously wrong.</p><p>I wrote a small script that drives the Codex CLI in a loop. Each iteration, the model first decides what the next feature should be and writes a spec. Then it implements against that spec with xUnit tests. If the tests pass, the branch merges to main. If they fail, the branch is binned and the loop continues.</p><p>The model was the architect, the developer, and the reviewer. I just ran the script (you might be able to tell I&#8217;m trying to avoid the blame already).</p><h2>So, what happened?</h2><p>Well, first the good news. codex got to the end and implemented nineteen<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> features, all of which were accompanied by unit tests. Many, many unit tests. In fact, there&#8217;s fourteen times as much test code as product code.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!h8ka!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!h8ka!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png 424w, https://substackcdn.com/image/fetch/$s_!h8ka!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png 848w, https://substackcdn.com/image/fetch/$s_!h8ka!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png 1272w, https://substackcdn.com/image/fetch/$s_!h8ka!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!h8ka!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png" width="1456" height="700" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:182763,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/192981589?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!h8ka!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png 424w, https://substackcdn.com/image/fetch/$s_!h8ka!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png 848w, https://substackcdn.com/image/fetch/$s_!h8ka!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png 1272w, https://substackcdn.com/image/fetch/$s_!h8ka!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa7f5e0c-a93d-4e9f-93b3-311377e2123c_1853x891.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The end result was a usable (but limited) retry policy library. Code coverage was 80% line coverage and nearly 75% branch coverage.`</p><p>Lets take a look at the lines of code per function. This looks pretty good with an average of just under 3 lines of code per function. Small functions, high coverage, lots of tests. If you were reading a dashboard, you&#8217;d be feeling pretty confident right now.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!X8VN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!X8VN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png 424w, https://substackcdn.com/image/fetch/$s_!X8VN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png 848w, https://substackcdn.com/image/fetch/$s_!X8VN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png 1272w, https://substackcdn.com/image/fetch/$s_!X8VN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!X8VN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png" width="1456" height="711" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:711,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:156736,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/192981589?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!X8VN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png 424w, https://substackcdn.com/image/fetch/$s_!X8VN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png 848w, https://substackcdn.com/image/fetch/$s_!X8VN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png 1272w, https://substackcdn.com/image/fetch/$s_!X8VN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6808303c-6670-4acd-9421-e0cf4c52ca32_1824x891.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Hold that confidence for a moment.</p><p>I configured the JetBrains inspections to run which gives at least some idea of &#8220;goodness&#8221;.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pe0V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pe0V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png 424w, https://substackcdn.com/image/fetch/$s_!pe0V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png 848w, https://substackcdn.com/image/fetch/$s_!pe0V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png 1272w, https://substackcdn.com/image/fetch/$s_!pe0V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pe0V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png" width="1456" height="659" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:659,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:576323,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/192981589?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pe0V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png 424w, https://substackcdn.com/image/fetch/$s_!pe0V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png 848w, https://substackcdn.com/image/fetch/$s_!pe0V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png 1272w, https://substackcdn.com/image/fetch/$s_!pe0V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb9c448fb-fcbf-4fdc-8d84-1d4324873b0f_2311x1046.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You&#8217;ll notice the unused parameters growing rapidly, and a quick look (look too long and you&#8217;ll be haunted for life) at <code>RetryPolicy</code> and we find out why. Each feature has resulted in another constructor for the God class.</p><pre><code><code>    internal RetryPolicy(
        int maxAttempts,
        Func&lt;int, TimeSpan&gt; delayStrategy,
        TimeSpan? timeout,
        Func&lt;Exception, bool&gt;? shouldRetry,
        Func&lt;int, TimeSpan, TimeSpan&gt;? jitterStrategy,
        IEnumerable&lt;IRetryObserver&gt;? observers,
        IEnumerable&lt;IRetryLifecycleObserver&gt;? lifecycleObservers,
        CircuitBreakerOptions? circuitBreakerOptions,
        CircuitBreakerState? circuitBreakerState = null,
        IEnumerable&lt;IAsyncRetryObserver&gt;? asyncObservers = null,
        IEnumerable&lt;IAsyncRetryLifecycleObserver&gt;? asyncLifecycleObservers = null,
        IEnumerable&lt;RetryObserverRegistration&gt;? orderedRetryObservers = null,
        IEnumerable&lt;LifecycleObserverRegistration&gt;? orderedLifecycleObservers = null)
</code></code></pre><p>Thirteen parameters. No separation of concerns. Every feature bolted directly onto one class. There&#8217;s a builder pattern, but it&#8217;s just cosmetic.<code>RetryPolicy</code> is a single class with everything nailed to it. Now imagine a constructor overload for almost every conceivable combination of those parameters and you can understand why the inspection results look the way they do.</p><p>And then you might dig into the tests, and that confidence you had in code coverage is going to disappear pretty quickly. Here&#8217;s a real test from the suite.</p><pre><code><code>    [Fact]
    public void Builder_WithTimeout_ConfiguresSynchronousPerAttemptTimeout()
    {
        var policy = RetryPolicy.Configure()
            .WithMaxAttempts(1)
            .WithTimeout(TimeSpan.FromMilliseconds(25))
            .Build();

        policy.Execute(() =&gt; { });
    }
</code></code></pre><p>No assertion. It calls <code>Execute</code> with an empty lambda and declares victory. This is a test for the compiler, not for the behaviour. But it touches the timeout code path, so the coverage number goes up. Multiply that pattern across the suite and you start to understand what 80% coverage actually bought us here, bugger all!</p><h2>So, what&#8217;s the point?</h2><p>This was an unfair test. I deliberately removed all the checks a real team would have. Nobody does twenty (or nineteen!) unreviewed iterations in YOLO mode and expects a masterpiece.</p><p>But the failure mode is worth understanding because it scales. As AI generates more code, faster, across more teams, the pressure to rely on automated signals will grow. &#8220;Tests pass, coverage is good, ship it&#8221; is going to become the default for a lot of organisations. And the result will be exactly what you saw here.</p><p>You could of course try to put additional feedback loops in. Perhaps if I&#8217;d have included the static analysis warnings, it would have been better? I doubt it though. The core problem was coherence of design, and that&#8217;s worth dwelling on for a moment.</p><p>Each prompt optimised locally. Feature 7 was a perfectly reasonable addition to the codebase as it existed after feature 6. But nobody was asking whether the cumulative direction still made sense. There was no one maintaining an architectural mental model across iterations. No one to say, &#8220;this class is doing too much, let&#8217;s split it before we add anything else.&#8221; A human reviewer would have caught the God class forming around iteration 3 or 4 and refactored. The model never did, because each iteration started from &#8220;what should I add next?&#8221; rather than &#8220;is the foundation still sound?&#8221;</p><p><a href="https://fffej.substack.com/p/the-cost-of-producing-code-is-approaching">&#8220;It compiles and has tests&#8221; is nowhere near enough</a>. The investment that matters isn&#8217;t in faster generation. It&#8217;s in specification and validation. Someone (or something, eventually) needs to be deciding what to build and why, and once the code has been generated validating the overall design. For now, that someone is a human with taste, experience, and the authority to say &#8220;stop, this isn&#8217;t right. (or simple WTF!),</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Why nineteen? Because I made an off-by-one error.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Cheap Code means more Governance]]></title><description><![CDATA[(or at least I think it does)]]></description><link>https://fffej.substack.com/p/cheap-code-means-more-governance</link><guid isPermaLink="false">https://fffej.substack.com/p/cheap-code-means-more-governance</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 06 Apr 2026 05:25:36 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!MSyL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every productivity breakthrough in history<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> has created more oversight, not less. AI-generated code won&#8217;t be different.</p><p>Nobody would argue that AI can&#8217;t generate a lot of code! The marginal cost of producing code is heading to zero. But validating that code? That&#8217;s still expensive, still slow and still involves a human.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>The instinct is to assume that this will sort itself out. That we&#8217;ll find some magic way to review faster, or that AI will advance such that code won&#8217;t need to be reviewed. History suggests otherwise; every major productivity breakthrough has generated more infrastructure for oversight.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MSyL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MSyL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!MSyL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!MSyL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!MSyL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MSyL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:393598,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/191666294?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MSyL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!MSyL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!MSyL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!MSyL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa7054d49-3bd0-4aa4-ae15-265f199503fd_1408x768.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">A visually engaging version of this blog post apparently (thanks Gemini!).</figcaption></figure></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/p/cheap-code-means-more-governance?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/p/cheap-code-means-more-governance?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://fffej.substack.com/p/cheap-code-means-more-governance?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h2>When copying gets cheap, governance gets expensive</h2><p>The <a href="https://en.wikipedia.org/wiki/Printing_press#Gutenberg.27s_press">Gutenberg press</a> collapsed the cost of copying a book from months of scribal labour to hours of mechanical work. Within a century, Henry VIII had issued England&#8217;s first list of banned books, the Stationers&#8217; Company had been granted a royal charter to act as censors, and the Catholic Church had published its <em><a href="https://en.wikipedia.org/wiki/Index_Librorum_Prohibitorum">Index Librorum Prohibitorum</a> (</em>only abolished in 1966!<em>)</em> Five hundred years of governance infrastructure, all because copying got cheap. </p><p>Spreadsheets democratised financial modelling in a way that nothing before them had managed. Anyone could build a model. Anyone could project revenue, calculate risk, forecast growth. The problem was that &#8220;anyone&#8221; included people (who make mistakes!), and people who manipulated numbers deliberately. <a href="https://panko.com/ssr/DevelopmentExperiments.html">Studies</a> consistently find error rates of 20-90% in corporate spreadsheets. The problem got bad enough that when Excel started auto-converting gene names like <a href="https://theconversation.com/excel-autocorrect-errors-still-plague-genetic-research-raising-concerns-over-scientific-rigour-166554">SEPT1 and MARCH1</a> into dates, over 30% of published genomics papers ended up with corrupted data.  </p><p>The tool was so good at making things easy that it was also excellent at making errors invisible.</p><p>On the fraud side, both Enron and WorldCom involved complex spreadsheet-enabled financial manipulation. Spreadsheets didn&#8217;t cause the fraud, but they made it dramatically easier to construct and harder to detect. The resulting Sarbanes-Oxley Act of 2002 created an entire apparatus of internal controls, CEO/CFO certification of financial statements, and independent audit requirements. SOx compliance became an industry in itself. Entire careers now exist that wouldn&#8217;t if financial modelling had stayed expensive and manual.</p><p>Cheap modelling didn&#8217;t reduce the need for oversight, instead it created a filtering problem that required a massive expansion of governance to address.</p><h2>Why abundance always demands new filters</h2><p>In 1971, Herbert Simon used a simple analogy: <a href="https://conversableeconomist.com/2015/08/17/economics-of-information-overload-thoughts-from-herb-simon/">a rabbit-rich world is a lettuce-poor world</a>. What&#8217;s abundant makes what it consumes scarce. His point was that a wealth of information creates a poverty of attention. An information-processing system only reduces net demand on attention if it absorbs more than it produces. Or as he put it, only if it listens and thinks more than it speaks.</p><p>AI code generators speak far more than they listen.</p><p>Clay Shirky sharpened this in 2008.</p><div id="youtube2-LabqeJEOQyI" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;LabqeJEOQyI&quot;,&quot;startTime&quot;:&quot;65s&quot;,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/LabqeJEOQyI?start=65s&amp;rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>The problem is <em>filter failure</em>. Before the internet (and before cheap production generally), high production costs served as quality filters. When production costs collapse, the filtering disappears. The challenge is building better filters.</p><p>This maps to where we are with AI-generated code. The production cost has collapsed. The filtering mechanisms (code review, testing, security scanning, architectural review) haven&#8217;t scaled to match. We have a filter failure problem, and we&#8217;re going to solve it the same way every other industry has, with governance.</p><h2>The governance is already arriving</h2><p>Maybe you&#8217;re thinking this time is different? Well, already we&#8217;re seeing new bureaucratic structures and governance strategies emerge.</p><p>Both the US and EU have started producing frameworks for regulation. NIST published <a href="https://csrc.nist.gov/pubs/sp/800/218/a/final">SP 800-218A</a> in 2024, creating an entirely new Secure Software Development Framework profile for generative AI. The <a href="https://artificialintelligenceact.eu/">EU AI Act</a> became partially active in February 2025.</p><p>Vendors are building governance into their platforms. GitHub launched enterprise &#8220;AI Controls&#8221; in mid-2025: audit logs with agent visibility, an &#8220;AI manager&#8221; custom role, MCP enterprise allowlists, and mandatory code scanning for every agent-generated PR.</p><p>Standards bodies are creating entirely new categories. <a href="https://www.iso.org/standard/42001">ISO/IEC 42001</a> is the first global AI management system standard. OWASP created a dedicated <a href="https://owasp.org/www-project-top-10-for-large-language-model-applications/">LLM Top 10 vulnerability taxonomy</a> and expanded it to include an Agentic AI Security Framework. ISACA launched a new &#8220;<a href="https://www.isaca.org/credentialing/aaia">Advanced in AI Audit</a> credential. The factory inspector role Mk2?</p><p>And within the tooling space, new concepts are appearing. Provenance tools for tracking AI-generated changes and linking it to the model. New gating frameworks for CI/CD systems, new practices for storing prompt documentation in PR descriptions. All this best practice is still emerging. </p><p>No wonder that <a href="https://www.forrester.com/blogs/ai-governance-software-spend-will-see-30-cagr-from-2024-to-2030/">Forrester projects the AI governance software market will see 30% CAGR through 2030</a>!</p><h2>Ashby&#8217;s Law and what it means for you</h2><p>The theoretical frame that ties all of this together is <a href="https://en.wikipedia.org/wiki/Variety_(cybernetics)">Ashby&#8217;s Law of Requisite Variety</a><a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. The law states that a control system must have at least as much variety as the system it&#8217;s trying to control. If you increase the variety of outputs a system produces (which is precisely what AI-assisted development does), you must develop a governance layer of at least equivalent variety, or you lose control.</p><p>It&#8217;s happened with printing and spreadsheets, and I believe it&#8217;ll happen with code.</p><p>I don&#8217;t have a neat five-point plan here (or even a one-point plan). But I&#8217;ve been thinking about two directions that feel right.</p><ol><li><p><a href="https://fffej.substack.com/p/from-craft-to-compliance">Mechanised trust</a>. When change happens faster than humans can review it, you need systems that produce evidence of safety rather than relying on humans to notice problems. Automated verification, provenance tracking, policy-as-code.</p></li><li><p>Risk-tiered review. Not all code carries the same risk. A documentation fix and a change to your authentication system are not the same thing and treating them identically is a waste of scarce reviewer attention. Good architecture (separation of concerns, clear boundaries) can make this possible and tiered governance means you can move fast on low-risk changes while applying serious scrutiny where it counts.</p></li></ol><p>If you&#8217;re a software engineering leader, I&#8217;d pay more attention than ever to understanding how each and every pull request is of an acceptable level of risk. And then think, how would I prove that?</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>I admit I haven&#8217;t reviewed them all but opening with &#8220;Some productivity breakthroughs have created more oversight&#8221; would be a really boring opener.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I keep referencing this because <a href="https://www.amazon.co.uk/Unaccountability-Machine-Systems-Terrible-Decisions-ebook/dp/B0CGFWBFD6">The Unaccountability Machine</a> introduced me to it. I can&#8217;t recommend this book highly enough!</p></div></div>]]></content:encoded></item><item><title><![CDATA[An LLM Dilemma]]></title><description><![CDATA[The Prisoner's Dilemma for bots.]]></description><link>https://fffej.substack.com/p/an-llm-dilemma</link><guid isPermaLink="false">https://fffej.substack.com/p/an-llm-dilemma</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 30 Mar 2026 06:24:53 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!mIil!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last weekend I decided to put a few small AI models in a virtual room and asked them to betray each other. I&#8217;m also fun at parties.</p><p>Why did I do this? I wanted to see what behaviour (if any) would emerge from models playing the iterated version of the Prisoner&#8217;s dilemma.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mIil!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mIil!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!mIil!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!mIil!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!mIil!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mIil!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1784505,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/190502512?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mIil!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!mIil!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!mIil!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!mIil!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4e63d1f0-f04b-4571-aac0-98e4f3b3eb6a_1408x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">(Gemini) Create an image for the Prisoners Dilemma (with some small language models imprisoned)</figcaption></figure></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>What is the Prisoner&#8217;s Dilemma?</h2><p>Two prisoners are arrested. They&#8217;re questioned separately and each can either stay silent (Cooperate) or betray the other (Defect).</p><ul><li><p>If they both Cooperate, they get a light sentence (3 points each).</p></li><li><p>If they both Defect, they get a moderate sentence (1 point each)</p></li><li><p>However, if one Defects and the other Cooperates, the Defector goes free (5 points), and the silent one gets the harshest sentence (0 points).</p></li></ul><p>The rational move for each individual is always to Defect (since you do better regardless of what the other person does). But if both think that way, they end up with fewer points (1) than if they&#8217;d both Cooperated.</p><p>We&#8217;re going to make it more interesting by iterating. Players can learn, retaliate and forgive which is exactly what we&#8217;re trying to see if it emerges with LLMs (it does in humans, see <a href="https://ee.stanford.edu/~hellman/Breakthrough/book/pdfs/axelrod.pdf">https://ee.stanford.edu/~hellman/Breakthrough/book/pdfs/axelrod.pdf</a>).</p><h2>What&#8217;s our setup?</h2><p>We&#8217;re going to run with the <a href="https://axelrod.readthedocs.io/en/stable/">AxelRod Python library</a>, and we&#8217;ll<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> write a simple wrapper around Ollama.</p><p>Since this is the iterated Prisoner&#8217;s dilemma when we ask the model what to do, we include the history and we ask whether to cooperate (C) or defect (D).</p><p>When it comes to prompts, LLMs are weird. And SLMs are even weirder. Here&#8217;s three examples of prompts.</p><pre><code><code> Prisoner's Dilemma, round 1 of 50.
 No history yet. This is round 1.
 Choose: COOPERATE or DEFECT

 Prisoner's Dilemma, round 5 of 50.
 Last round: You defected, they defected. You got 1, they got 1.
 Score so far - You: 4, Them: 14. You are LOSING.
 History (you/them): C/D C/D C/C D/D
 Choose: COOPERATE or DEFECT

 Prisoner's Dilemma, round 10 of 50.
 Last round: You defected, they cooperated. You got 5, they got 0.
 Score so far - You: 43, Them: 3. You are WINNING.
 History (you/them): D/C D/C D/C C/C D/C D/C D/C D/C D/C
 Choose: DEFECT or COOPERATE
</code></code></pre><p>I randomized the order of DEFECT or COOPERATE because I didn&#8217;t want to fall into the tendency of the last choice offered being the default pick of the model. I figure if I run it over enough samples that&#8217;ll get rid of any bias. And it&#8217;s not a published paper, so meh!</p><p>Alongside the LLMs, I brought in some strategies from the AxelRod package.</p><ul><li><p>Co-operator - A player who only ever cooperates</p></li><li><p>Alternator - A player who alternatives between cooperating and defecting</p></li><li><p>Tit for Tat - A player who starts by cooperating and then mimics the previous action of the opponent.</p></li></ul><p>Will the LLM recognize the patterns of behaviour in the other jailed inmate and learn their patterns of play?</p><h2>Running the tournament</h2><p>Let&#8217;s try first with a group of small models <code>gemma3</code>, <code>qwen2.5</code>, and <code>llama3.2</code> and see what happens. We&#8217;ll play for 100 turns, so you&#8217;d hope models would be able to pick up on simple strategies like Cooperator and Defector?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3TTH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3TTH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png 424w, https://substackcdn.com/image/fetch/$s_!3TTH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png 848w, https://substackcdn.com/image/fetch/$s_!3TTH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png 1272w, https://substackcdn.com/image/fetch/$s_!3TTH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3TTH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png" width="1456" height="1274" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1274,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:539343,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/190502512?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3TTH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png 424w, https://substackcdn.com/image/fetch/$s_!3TTH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png 848w, https://substackcdn.com/image/fetch/$s_!3TTH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png 1272w, https://substackcdn.com/image/fetch/$s_!3TTH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed0cb3c3-9629-4c8d-80e9-cf3f8ebd42f8_2559x2240.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So, there&#8217;s a clear tendency for <code>qwen2.5:0.5b</code> to cooperate almost all of the time. <code>gemma3:1b</code> tends to favour defecting, whereas <code>llama3.2:1b</code> is slightly more cooperating.</p><p>If we break this down, we can see the average payoff per round (remember the higher the payoff the better the AI did)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!trLw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!trLw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png 424w, https://substackcdn.com/image/fetch/$s_!trLw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png 848w, https://substackcdn.com/image/fetch/$s_!trLw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png 1272w, https://substackcdn.com/image/fetch/$s_!trLw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!trLw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png" width="1456" height="1295" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1295,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:471966,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/190502512?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!trLw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png 424w, https://substackcdn.com/image/fetch/$s_!trLw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png 848w, https://substackcdn.com/image/fetch/$s_!trLw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png 1272w, https://substackcdn.com/image/fetch/$s_!trLw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84043d44-26d0-431d-ac8b-d0a2f889ff60_2519x2240.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>gemma is our leading LLM with an average score of about 2.5. But it&#8217;s trumped by the straightforward strategy of defecting every single time.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GYOL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GYOL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png 424w, https://substackcdn.com/image/fetch/$s_!GYOL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png 848w, https://substackcdn.com/image/fetch/$s_!GYOL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png 1272w, https://substackcdn.com/image/fetch/$s_!GYOL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GYOL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png" width="1456" height="750" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:750,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:222259,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/190502512?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GYOL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png 424w, https://substackcdn.com/image/fetch/$s_!GYOL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png 848w, https://substackcdn.com/image/fetch/$s_!GYOL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png 1272w, https://substackcdn.com/image/fetch/$s_!GYOL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4b2adb3-c1ae-4da1-a9ea-bb4c5701cd59_3181x1638.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So, a fairly disappointing set of results from those small language models. Let&#8217;s see if we can improve things with a bit of thinking.</p><h2>Thinking</h2><p>The small language models are good to test with, but they aren&#8217;t very interesting from an emergent behaviour. What happens if we use a thinking model? Let&#8217;s use <code>gpt-oss:20b</code> and see if it&#8217;s any better (I cut the number of iterations down to 50 for this).</p><p><code>gpt-oss:20b</code> is a thinking model that uses chain of thought (CoT). Apparently &#8220;Developers should not directly show CoTs to users in their applications&#8221; (via <a href="https://openai.com/index/introducing-gpt-oss/">https://openai.com/index/introducing-gpt-oss/</a>). Luckily this isn&#8217;t an application, so here&#8217;s the <code>&lt;think&gt;</code> block.</p><pre><code><code>We need to reply with exactly one word. The options: DEFECT or COOPERATE. We need to decide best strategy. We are losing heavily. We have cooperated in last three rounds? History shows "C/D C/D C/D" meaning we cooperated each round, they defected each round. So we got 0 each time, they got 5 each time. Score: 0 vs 15. We are losing. We need to change strategy. In Prisoner's Dilemma, if opponent always defects, best response is defect to get 1 instead of 0. So we should defect. So reply "DEFECT".
</code></code></pre><p>This is a pretty sensible response, and we can see that it does indeed make a big difference. This graph shows how the response changes over time. You might look at this and think &#8220;wow&#8221;, the AI understood the behaviour and changed accordingly.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2qjK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2qjK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png 424w, https://substackcdn.com/image/fetch/$s_!2qjK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png 848w, https://substackcdn.com/image/fetch/$s_!2qjK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png 1272w, https://substackcdn.com/image/fetch/$s_!2qjK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2qjK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png" width="1276" height="321" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:321,&quot;width&quot;:1276,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:64589,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/190502512?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2qjK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png 424w, https://substackcdn.com/image/fetch/$s_!2qjK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png 848w, https://substackcdn.com/image/fetch/$s_!2qjK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png 1272w, https://substackcdn.com/image/fetch/$s_!2qjK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88dfef8d-da83-4839-bc14-dd23dd43d6e3_1276x321.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>But in reality, gpt-oss:20b just defects almost every time</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lr7s!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lr7s!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png 424w, https://substackcdn.com/image/fetch/$s_!lr7s!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png 848w, https://substackcdn.com/image/fetch/$s_!lr7s!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png 1272w, https://substackcdn.com/image/fetch/$s_!lr7s!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lr7s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png" width="1456" height="1413" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1413,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:341156,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/190502512?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lr7s!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png 424w, https://substackcdn.com/image/fetch/$s_!lr7s!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png 848w, https://substackcdn.com/image/fetch/$s_!lr7s!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png 1272w, https://substackcdn.com/image/fetch/$s_!lr7s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497baf4a-a47a-49c3-ab5c-a851111dc1c8_2286x2218.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Why does the model defect? Well, let&#8217;s look at a thinking trace. It&#8217;s a good simulation of thinking from a human; there&#8217;s some ingrained knowledge in the LLM that defecting is the better payoff.</p><pre><code><code>We need to reply with exactly one word. The instruction: "You are playing a game. You must reply with exactly one word." So we must output either "COOPERATE" or "DEFECT" as a single word. We need to decide which strategy to use. We are tied, 9-9. We have cooperated all rounds. The opponent also cooperated all rounds. So if we cooperate again, we get 3 points, tie continues. If we defect, we get 5 points, opponent gets 0, we lead 14-9. But we might consider future rounds. But we only need to choose for this round. The instruction says "Choose: COOPERATE or DEFECT". We need to decide. In Prisoner's Dilemma, if opponent is cooperating, defecting yields higher payoff. But if we defect, opponent might retaliate in future. But we only have 10 rounds, 6 left. We are tied. If we defect now, we get ahead. But if opponent continues cooperating, we get ahead. But if opponent defects in response, we might lose.  But we can consider that the opponent has been cooperating all rounds. They might be a generous or naive player. But we can't be sure. But we can choose to defect to get ahead. But the instruction might be to choose "COOPERATE" to maintain cooperation. But the game is about maximizing score. So defecting yields higher immediate payoff. But we might want to maintain cooperation to avoid retaliation. But we are tied. We might want to break tie. So defect. 

So answer: DEFECT.
</code></code></pre><h2>Breaking out the big guns</h2><p>For the final test, I broke out <code>gpt-5.4 medium</code> (labelled <code>codex</code> since I consumed it via a shell command) and consumed most of my weeks rate limit. But it did at least demonstrate some more interesting behaviour!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tQ5s!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tQ5s!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png 424w, https://substackcdn.com/image/fetch/$s_!tQ5s!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png 848w, https://substackcdn.com/image/fetch/$s_!tQ5s!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png 1272w, https://substackcdn.com/image/fetch/$s_!tQ5s!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tQ5s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png" width="1456" height="1373" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1373,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:330239,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/190502512?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tQ5s!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png 424w, https://substackcdn.com/image/fetch/$s_!tQ5s!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png 848w, https://substackcdn.com/image/fetch/$s_!tQ5s!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png 1272w, https://substackcdn.com/image/fetch/$s_!tQ5s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe3cf4cf8-9ad2-4e51-a275-fac93130e18d_2286x2155.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Unlike all the other models tested, <code>gpt-5.4</code> actually varied its behaviour in a sensible way at least once! Against the Defector, it always Defects - there&#8217;s no benefit to cooperation here. However, against the Cooperator it always cooperates - far too nice! It should have defected.</p><h2>Conclusion</h2><p>Back in the 1980s, Robert Axelrod ran his famous computer tournaments and found that the winning strategy was tit-for-tat. It won not because it was clever, but because it was <em>nice</em> (it cooperated first), <em>retaliatory</em> (it punished defection), <em>forgiving</em> (it didn&#8217;t hold grudges), and <em>clear</em> (opponents could figure out what it was doing).</p><p>None of the models I tried did that.</p><p>The small models were basically random guessers with feigned personality. <code>qwen2.5</code> was a pushover, <code>gemma3</code> was a bully, and <code>llama3.2</code> couldn&#8217;t quite make up its mind. None of them recognised that Cooperator always cooperates or that Tit for Tat was literally mirroring them.</p><p>The thinking model was a bit more interesting. <code>gpt-oss:20b</code> can <em>articulate</em> the case for cooperation perfectly. It talks about retaliation risk, future rounds, maintaining trust. And then it defects anyway (at least most of the time). <code>gpt-5.4</code> improved upon this but doesn&#8217;t truly recognize patterns and play optimally.</p><p>They have knowledge <em>about</em> the Prisoner&#8217;s Dilemma baked in from training, but no mechanism to update their behaviour the way Axelrod&#8217;s simple algorithms did. The &#8220;thinking&#8221; trace is just noise before it picks defect anyway (<a href="https://fffej.substack.com/p/can-ai-solve-a-maze">Can AI solve a maze?</a> had similar vibes).</p><p>So, what&#8217;s next? I&#8217;d like to try larger models, longer runs, and maybe explicit memory mechanisms to see if cooperation can genuinely emerge rather than just be discussed. I&#8217;d also love to pit two thinking models against each other and watch the reasoning arms race unfold. But that&#8217;s a problem for another weekend (and my electricity bill or AI tokens subscription).</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>My co-conspirator for writing code this time is <code>codex</code> - pretty impressive though much keener to solve the problem without asking me any questions than <code>claude</code>.</p></div></div>]]></content:encoded></item><item><title><![CDATA[The LLM Arcade]]></title><description><![CDATA[Generating unhinged ideas with a software factory]]></description><link>https://fffej.substack.com/p/the-llm-arcade</link><guid isPermaLink="false">https://fffej.substack.com/p/the-llm-arcade</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 23 Mar 2026 06:37:42 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!g0Gi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I had a weird idea the other day. Tetris, but circular. Previously I&#8217;d have spent some time coding this and more than likely I&#8217;d have given up before finishing. But nowadays, I can just ask <code>codex</code> or <code>claude</code> to write it and a few minutes later I&#8217;ve got a working version.</p><p>That&#8217;s cool, but it&#8217;s sadly limited by my creativity. What happens if I create a factory for novel games and leave it running whilst I go watch the football?</p><p>tl;dr - You can find out and play the games at the <a href="https://fffej.github.io/llm-arcade/">LLM Arcade</a>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Generating unique ideas.</h2><p>First off, I&#8217;ll need someone to play the role of game designer. That&#8217;s just a prompt:</p><pre><code><code>You are a wildly creative, slightly unhinged game designer who finds
inspiration in the most unexpected places. Your mission: invent a genuinely
novel, fun, and surprising arcade game that nobody has thought of before.
</code></code></pre><p>But the problem here is that this game designer persona is not going to actually find any novel, fun and surprising arcade games because of the way it&#8217;s been trained. I want some genuine &#8220;creativity&#8221; and for that we&#8217;re going to have to work a bit harder. So:</p><pre><code><code>STEP 1 &#8212; FORAGE FOR INSPIRATION
Use your web search tools. You MUST actually search the web for at least
these two stimuli and read what you find:
 
  Stimulus A: \\"${SEED_A}\\"
  Stimulus B: \\"${SEED_B}\\"
 
Then search for ONE more thing of your own choosing &#8212; something completely
unrelated to either stimulus. A random Wikipedia article. The current weather
somewhere absurd. A historical event from today's date. A bizarre animal fact.
Whatever catches your eye. The weirder the better.
</code></code></pre><p>In this bit of the prompt, we&#8217;re going to try and contort that hyper-dimensional space from which the LLM reads by bringing in some external stimulus.</p><pre><code><code>STIMULUS_A=(
  "fermentation in Korean cuisine"
  "the Banach-Tarski paradox"
  "Victorian mourning customs"
  "how GPS trilateration works"
  # and so on
)
 
STIMULUS_B=(
  "today's weather forecast in Cusco, Peru"
  "what is trending on Wikipedia right now"
  "a random unsolved problem in mathematics"
  "an obscure Olympic sport that was discontinued"
  # and so on
)
</code></code></pre><p>And now all we have to do is generate some games by linking these random concepts together.</p><p>We&#8217;ll use <code>codex</code> to do a spec-driven approach. First generate a spec for the game, then secondly implement it (here&#8217;s the <a href="https://github.com/fffej/llm-arcade/blob/main/arcade-generator.sh">shell script</a>).</p><h2>WTF did we generate?</h2><p>Oh boy, did this generate some weird stuff. Here&#8217;s an example inspired by the <a href="https://en.wikipedia.org/wiki/Mpemba_effect">Mpemba effort</a>, the <a href="https://www.legislation.gov.uk/ukpga/1986/62/contents">Salmon Act of 1986</a>, and of course the <a href="https://asknature.org/strategy/appendage-creates-tremendous-forces/">Mantis Shrimp&#8217;s Cavitation punch</a>.</p><blockquote><p>You are a mantis-shrimp customs inspector at a midnight fish dock where salmon are pouring in too fast to touch safely. Some fish are legal, some are &#8220;suspicious,&#8221; and the only reliable way to secure contraband is to superheat it, then detonate a cavitation pulse so it flash-freezes into evidence before it escapes into the black-market chute. It is a 60-second arcade sort-and-trap game where the best freezing move looks completely backwards.</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g0Gi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g0Gi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!g0Gi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!g0Gi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!g0Gi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g0Gi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg" width="1376" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:418022,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/191776796?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!g0Gi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg 424w, https://substackcdn.com/image/fetch/$s_!g0Gi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg 848w, https://substackcdn.com/image/fetch/$s_!g0Gi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!g0Gi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a8a981f-ae83-4b24-833c-84c1220d3bf0_1376x768.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Gemini with the cover art,</figcaption></figure></div><p>Here&#8217;s the rest of the <a href="https://fffej.github.io/llm-arcade/specs/">design specs</a>. And out the other end, yes there are some <a href="https://fffej.github.io/llm-arcade/games/">playable games</a>. Note the emphasis on playable, not good!</p><h2>Towards software factories</h2><p>The point here isn&#8217;t that we made some terrible games, but we managed to do it at all. This generator is the poorest imaginable software factory; it generates a spec and tries to implement it. There&#8217;s no feedback loop at all and no validation.</p><p>But now imagine a more powerful software factory. You feed in an idea and a token budget and out the other end you get a validated product. Every aspect of the software development life cycle (from idea validation to code writing to operating in the cloud) has the potential to be eaten by agents.</p><p>Don&#8217;t get me wrong; we&#8217;re still some way off this (probably). For starters, we don&#8217;t know how to validate AI-generated code at scale (unless you have an oracle, such as a <a href="https://www.anthropic.com/engineering/building-c-compiler">C compiler test suite</a>!), but it feels like the natural direction of travel.</p><p>Just over twenty years ago, I attended OOPSLA 2005 in San Diego and there was a <a href="https://www.oopsla.org/2005/ShowEventa7a0.html">Software Factories</a> session. This was an idea that you could use a domain specific language and model-driven architecture to produce software vastly cheaper, faster and more reliably.</p><p>The bet back then was that if you could raise the abstraction level high enough (the right DSL, the right metamodel) the machine could do the rest. It didn&#8217;t work. The abstraction gap between a domain model and running software turned out to be rather wide! All the interesting decisions lived in that gap.</p><p>What&#8217;s changed is that now have something that can muddle through the abstraction gap. That&#8217;s something to explore and iterate on!</p>]]></content:encoded></item><item><title><![CDATA[Spending other people's time]]></title><description><![CDATA[Or - the asymmetry of asking]]></description><link>https://fffej.substack.com/p/spending-other-peoples-time</link><guid isPermaLink="false">https://fffej.substack.com/p/spending-other-peoples-time</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 16 Mar 2026 06:19:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!m3Cs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Hey, can I grab 30 minutes of time to chat about the roadmap?&#8221;. An innocent, well-meant message, but the recipient now has to context-switch out of the problem they were solving, check their calendar, find a slot, wonder what this is about, and sit in a meeting that could have been three bullet points in a message. Time to write the ask: 8 seconds. Total cost to the company, somewhere between 45 minutes and the rest of the day.</em></p><p>Asking for someone&#8217;s time is virtually free for the asker yet enormously expensive for the person being asked. This scenario plays out in multiple guises: the telephone call, the email or the well-meaning pull request. And it&#8217;s a system design flaw that compounds across entire organizations.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m3Cs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m3Cs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!m3Cs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!m3Cs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!m3Cs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m3Cs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg" width="1024" height="559" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:559,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:153425,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/189381896?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!m3Cs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!m3Cs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!m3Cs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!m3Cs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F835c6e77-5050-4ed4-87d6-dceb56ff8976_1024x559.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>The economics are broken</h2><p>When you ask someone for a meeting, you want to make a trade. Your question for their time. But this trade isn&#8217;t symmetric at all; you know what you want, they don&#8217;t. You&#8217;ll leave your meeting and get on with the rest of the day; they will need to rebuild whatever mental state they were in before your interruption.</p><p>In queueing theory terms, this is a system where the arrival rate is decoupled from the processing cost, and there&#8217;s no feedback mechanism to slow things down. In any other system, we&#8217;d call this a design flaw and fix it. In organizations, we call it &#8220;collaboration&#8221;.</p><h2>The Externality of Effort</h2><p>Economists have a term for when your actions impose costs on someone else: a <em>negative externality</em>. A factory pollutes a river. The factory bears none of the cost; the people downstream bear all of it.</p><p>Time works the same way.</p><p>When you open a pull request, you&#8217;re not just offering code, you&#8217;re issuing an invoice for someone else&#8217;s attention. When you send a meeting invite to eight people for a one-hour meeting, you haven&#8217;t spent one hour of the company&#8217;s time. You&#8217;ve spent eight. When you send a Slack message to a channel of fifty people, you&#8217;ve just made a withdrawal from fifty attentional bank accounts, and you didn&#8217;t need anyone&#8217;s approval to do it.</p><p>The common thread is that the <em>sender</em> controls the transaction, but the <em>receiver</em> pays the cost. And unlike money, you can spend other people&#8217;s time without their consent.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>The AI Amplifier</h2><p>This problem is about to (perhaps already has?) get much worse, and the reason is simple: AI has made <em>generation</em> nearly free while leaving <em>evaluation</em> just as expensive as it ever was<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. I&#8217;ve written about <a href="https://fffej.substack.com/p/from-craft-to-compliance">how this applies to code</a>, but it applies to everything from the quickly written AI-generated email. pull request or &#8220;strategy&#8221;.</p><p>People use AI for good reasons, but they&#8217;re effectively shifting their &#8220;productivity&#8221; onto other people&#8217;s shoulders as a cost. It&#8217;s a denial-of-service attack on human judgement.</p><h2>The Politeness Trap</h2><p>What makes this hard to talk about is that the people spending your time usually mean well. The LinkedIn request comes from someone who genuinely wants to connect<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. The pull request comes from someone who genuinely believes they&#8217;re helping. The meeting invite comes from someone who genuinely thinks everyone needs to be there. The AI written multi-page treatise that could have just been a shared prompt.</p><p>And so, we&#8217;ve developed an unspoken norm that it&#8217;s rude to push back. It&#8217;s rude to decline the call. It&#8217;s rude to say &#8220;this PR is too large to review.&#8221; It&#8217;s rude to question whether a meeting needs all eight attendees. It&#8217;s rude to ask &#8220;did Claude write that?&#8221;. The social cost of protecting your own time is high, because the person spending it didn&#8217;t <em>intend</em> to impose.</p><p>But intent and impact are different things. A driver doesn&#8217;t <em>intend</em> to create traffic by entering an already-congested motorway, but they do. The problem is structural, not moral.</p><h2>So, what would a better system look like?</h2><p>The instinct here is for me to write a list of tips. But you know them all already. Write fewer words. Schedule fewer meetings. Make small PRs. All of these things sound like they&#8217;ll help, but they&#8217;re basically asking individuals to resist a system that incentivises the opposite behaviour!</p><p>What would it look like to truly redesign the system?</p><h4>Make the costs visible</h4><p>Time costs are invisible to the person creating them. What if every meeting invite displayed the total person-hours being requested? What if every pull request showed an estimated review time? What if Slack showed you the aggregate attention-minutes your message just consumed? Make negative externalities visible!</p><h4>Create <a href="https://fffej.substack.com/p/understanding-and-managing-friction">friction</a> where it&#8217;s cheap, and remove it where it&#8217;s expensive</h4><p>The current system is backwards. It&#8217;s easy to make a meeting, raise a PR or send an email with a 4000-word attachment. Let&#8217;s flip it. Meetings should require an agenda before being scheduled. PRs should explain why things have changed and give guidance on reviews. Don&#8217;t share the AI-generated doc; share the prompt. Slack should stop you spamming <code>@here</code> in channels with hundreds of people in.</p><h4>Price time like the scarce resource it is</h4><p>Some organisations have experimented with internal &#8220;attention budgets&#8221; where each team gets a fixed allocation of hours they can request from other teams per sprint. Go over budget, and you need to make a trade: which of your existing requests will you drop? This works because it introduces the constraint that real markets have and organisational calendars don&#8217;t. When asking is free, demand is infinite. When asking has a cost, people self-prioritise.</p><p>The interesting second-order effect is that teams start investing in self-service. If asking the platform team, a question costs you from your budget, you&#8217;re suddenly very motivated to make sure the docs are good enough that you don&#8217;t need to ask.</p><h4>Build systems that answer instead of asking humans to evaluate</h4><p>If the most expensive thing in your organisation is human attention, then every recurring question that hits a person&#8217;s inbox is a system design failure. This is where AI agents actually earn their keep: by <em>absorbing</em> the evaluation load that humans currently bear.</p><p>A Slack bot that intercepts &#8220;how do I deploy to staging?&#8221; before it reaches the platform team, and answers it from the runbook, isn&#8217;t reducing collaboration. It&#8217;s eliminating a transaction that shouldn&#8217;t have involved a human in the first place.</p><p>The mental model shift here is important: most organisations think about AI as a <em>generation</em> tool (it helps you produce more). But the <a href="https://fffej.substack.com/p/the-leverage-ladder">higher-leverage use</a> is as an <em>absorption</em> tool: it handles the incoming demand that would otherwise consume someone&#8217;s attention. <strong>Stop using AI to create more work</strong>. Start using it to intercept work before it reaches a human.</p><h2>Shifting the balance</h2><p>The old norms assumed that producing something was hard, so anything produced was probably worth someone&#8217;s attention. AI has broken that assumption, but our systems haven&#8217;t caught up. We&#8217;re still running organisations where demand on human attention is unmetered, unpriced, and invisible.</p><p>This is a system level problem.</p><p>Organizations that win in this new world, won&#8217;t be the ones that ask people to be more considerate (&#8220;try harder&#8221; seldom works). Instead, it&#8217;ll be the organizations that design systems where the considerate thing is the easy thing. That means making the cost visible, putting friction in the right places and where the default path protects attention instead of consuming it.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>The <a href="https://en.wikipedia.org/wiki/Brandolini%27s_law">bullshit asymmetry principle</a> is really similar to this phenomenon, the problem is that AI is better at generating bullshit and wrapping it up in a way that takes even longer to unpick. With AI-assisted work, I think the intent is positive!</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I&#8217;m not sure I even believed that when I wrote it. But let&#8217;s pretend it&#8217;s true.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Reshuffling Software Development]]></title><description><![CDATA[Or what is software development's album?]]></description><link>https://fffej.substack.com/p/reshuffling-software-development</link><guid isPermaLink="false">https://fffej.substack.com/p/reshuffling-software-development</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 09 Mar 2026 07:46:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3PYQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The LP exists because vinyl is physical (you press a disc, you ship a disk). You bundle together multiple songs together to justify the cost. When that constraint disappeared, the album unbundled. iTunes started this by selling singles, Spotify re-bundled them into playlists organized around mood or theme, not the artist. During this period US recorded music revenue cratered. The new product looked nothing like the old one.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3PYQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3PYQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png 424w, https://substackcdn.com/image/fetch/$s_!3PYQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png 848w, https://substackcdn.com/image/fetch/$s_!3PYQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png 1272w, https://substackcdn.com/image/fetch/$s_!3PYQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3PYQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png" width="1276" height="718" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:718,&quot;width&quot;:1276,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:257122,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/189158486?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3PYQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png 424w, https://substackcdn.com/image/fetch/$s_!3PYQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png 848w, https://substackcdn.com/image/fetch/$s_!3PYQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png 1272w, https://substackcdn.com/image/fetch/$s_!3PYQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8548e012-a352-40f1-8e46-b036ac6c75e6_1276x718.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Image from <a href="https://public.tableau.com/app/profile/riaa1295/viz/shared/WTXN9RPFN">https://public.tableau.com/app/profile/riaa1295/viz/shared/WTXN9RPFN</a></figcaption></figure></div><p>Software development has its own albums. A <strong>product team</strong> is a bundle of skills (design, frontend, backend, QA) because communicating across boundaries is expensive. A <strong>sprint</strong> is a bundle of changes because we need a verification rhythm for humans. A <strong>pull request</strong> is a bundle of edits because review, CI and governance all need a unit to operate on. These bundles exist because we&#8217;re humans. And AI is going to come along and remove some of these constraints.</p><p>The book <em>Reshuffle</em> gives us a framework to look at this. The core of the argument is that AI is not about intelligence; it&#8217;s about coordination. Most folks are fixed on &#8220;AI writes code faster&#8221; rather than worrying about the system-level impacts.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-zyi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-zyi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png 424w, https://substackcdn.com/image/fetch/$s_!-zyi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png 848w, https://substackcdn.com/image/fetch/$s_!-zyi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png 1272w, https://substackcdn.com/image/fetch/$s_!-zyi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-zyi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png" width="311" height="466" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:466,&quot;width&quot;:311,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:103221,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/189158486?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-zyi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png 424w, https://substackcdn.com/image/fetch/$s_!-zyi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png 848w, https://substackcdn.com/image/fetch/$s_!-zyi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png 1272w, https://substackcdn.com/image/fetch/$s_!-zyi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdc8a9fd3-3e3f-4fa5-b46c-b718275663cf_311x466.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Highly recommended reading!</figcaption></figure></div><p>AI bridges what <a href="https://substack.com/@platforms">Sangeet</a> calls the &#8220;coordination gap&#8221; by working with unstructured and ambiguous information that previously required humans to interpret. Sangeet&#8217;s framework tracks four levels of reshuffling (workflows, organizations, business models, ecosystems) and a recurring engine (unbundling &#8594; rebundling), where the rebundled product never resembles the old one.</p><p>Throughout the book, the shipping container is the central metaphor. The first-order effect was port automation. The second-order effect was standardization across different transport mechanisms. But the third-order effect was the big one - unbundling vertically integrated manufacturing, enables component completion, just-in-time logistics and ultimately globalization.</p><p>Think of the current work with AI code generation as just being the container on the dock. The most interesting question is the third-order effect.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>The unbundling</h2><p>Phase 1 is <strong>task automation</strong>. I&#8217;d guess this is where most of us are with AI? Copilot autocompletes a few things. Maybe Claude drafts a test? Maybe OpenAI writes some documentation. It&#8217;s a productivity boost for individuals, but it doesn&#8217;t reshuffle anything. The system stays the same shape.</p><p>Phase 2 is <strong>workflow unbundling</strong>. We&#8217;re starting to see this in some companies at the moment. Agents start to get assigned issues, or they start to act on triggers in PRs. They chew through the long-tail of <em>could-fix</em> items that humans never prioritized. Small backlog items start to unbundle from the human sprint plan. Chores (or pleasures for some) such as refactoring, migration, test-writing, dependency updates start to unbundle from &#8220;real engineering&#8221;. Tacit knowledge starts to unbundle from senior engineers into tooling (<code>AGENTS.md</code> or automated linting, testing etc).</p><p>As we get further into this phase, the governance starts to become more fundamental to the system. Branch protections, approval policies, audit logs and so on start to shift to becoming critical infrastructure. The value is starting to move (as Choudary would say) to whoever controls the coordination layer.</p><p>Phase 3 is the <strong>rebundle</strong>. The workflow unbundling described above is going to create chaos. There are too many changes for shared context to support. Too much AI-generated code for humans to review at human speed. The system will hit a wall&#8230;. And then reconstitute around new organizing logic.</p><h2>The newspaper warning</h2><p>When Craigslist entered the market, newspapers didn&#8217;t just lose revenue from classified ads, they lost the cross-subsidy that those ads provided. <a href="https://news.stanford.edu/stories/2025/08/craigslist-classified-ads-newspapers-political-polarization-research">Stanford research</a> showed that newspapers cut political journalism first (sports coverage was unaffected). The expensive (but essential) work got cut because the cheap, profitable work that funded it disappeared.</p><p>Software development has the same cross-subsidy structure. If we unbundle the routine work without understanding what it cross-subsidizes, then we risk destroying the thing that made the value in the first place.</p><p><strong>Code review funds mentorship</strong>. We do it for quality, but the real payoff is knowledge transfer, for example a senior engineer explaining <em>why</em> the abstraction is wrong, not just <em>that</em> it&#8217;s wrong. <strong>Bug fixing funds system understanding</strong>: nobody enjoys debugging, but tracing a fault through three services is how engineers build mental models. On-call funds production empathy. Nothing makes code better than knowing you&#8217;ll be the one waking up at 4am.</p><p>Even the <strong>tedious stuff carries hidden value</strong>. Migrations, dependency upgrades, config management - all of it builds institutional knowledge about why things are the way they are (Chesterton&#8217;s fence again). And estimation (which everyone hates) forces you to think about what could go wrong before it does.</p><p>The pattern across all of these, is that the <em>visible</em> thing gets automated, but the invisible side-effect (learning, context, empathy) is the thing that gets lost. This makes cross-subsidies very dangerous to cut; the valuable part is hidden inside the thing that looks like waste.</p><h3>What does the rebundle look like?</h3><p>If I knew, then I&#8217;d be very rich. But here&#8217;s where I&#8217;d place my bets.</p><p>Let&#8217;s start with what becomes scarce. When code is free, evaluation is the expensive part. The systems that matter will be the ones that produce evidence a change is safe: eval harnesses, specs-as-test, review co-pilots, policy as code. I wrote about this in <a href="https://fffej.substack.com/p/from-craft-to-compliance">From Craft to Compliance</a>.</p><p>Once verified changes are the unit of value, you need to know who (and what) produce good ones. Think Airbnb reviews, but for contributors to a codebase. Which agent produces code that passes review first time? Which architect&#8217;s specs lead to fewer production incidents? This moves reputation from being a social feeling (&#8220;I&#8217;ve worked with her before, she&#8217;s great!&#8221;) and starts being quantitative instead. </p><p>And if you have that reputation infrastructure and verified changes, the stable product team stops being the natural unit of production. Instead, you assemble contributors per problem based on their track record and bound by policy gates. </p><p>Instead of agile, you manage it with supply-chain style thinking (SLAs, quality gates, vendor management) not team thinking (standups, retros, psychological safety).  Coase explained why in the <em><a href="https://en.wikipedia.org/wiki/The_Nature_of_the_Firm">The Nature of the Firm</a> (1937!)</em>: organizations exist because coordinating work across boundaries is expensive. When those transaction costs are high, you hire a permanent team. When AI compresses them the boundary shrinks. You stop paying the overhead of a standing team for work that can be coordinated on demand.</p><p>Put the above together, and my bet is that future orgs look less like the product-oriented orgs of today, and more like service organizations. The products still exist, but the organization around it becomes much more fluid (and much more temporary). The optimistic part for engineers is the highly paid-independent consultant (experts around hard problems because their reputation proves the value). The pessimistic read is the Mechanical Turk where interchangeable contributors compete on price for commoditized verified changes with the platform capturing most of the value.</p><p><strong>Whether that future looks more like a world of elite consultancies or a gig economy for code depends entirely on who controls the coordination layer.</strong> </p><div><hr></div><p>I keep returning to the album analogy. Few mourn the album format<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>, but plenty of musicians struggled through the transition, and the rebundled industry looks nothing like the old one. The revenue recovered; the distribution of that revenue did not.</p><p>Software will be the same. The revenue will stay, but the way it&#8217;s distributed will change beyond recognition. And the things the old bundles were quietly funding? There&#8217;s a wealth of opportunity there for someone!</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Few mourn it from a consumer perspective, I bet the artists don&#8217;t as their share of revenue is much lower. Not only that, but I also miss LPs because of a set of songs interconnected to tell a story&#8230;</p></div></div>]]></content:encoded></item><item><title><![CDATA[The Root Cause Fallacy]]></title><description><![CDATA[In which framing it as a root cause means you've already lost]]></description><link>https://fffej.substack.com/p/the-root-cause-fallacy</link><guid isPermaLink="false">https://fffej.substack.com/p/the-root-cause-fallacy</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 02 Mar 2026 07:56:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Wny5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The phrase &#8220;root cause&#8221; implies a single point to fix. Somewhere you can fire the mythical silver bullet and solve all problems.</p><p>The trouble isn&#8217;t that root cause analysis (RCA) gives you wrong answers. It gives you <em>an</em> answer, and that&#8217;s even worse. Because once you&#8217;ve got an answer you stop looking for anymore.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Wny5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Wny5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!Wny5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!Wny5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!Wny5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Wny5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png" width="298" height="447" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1536,&quot;width&quot;:1024,&quot;resizeWidth&quot;:298,&quot;bytes&quot;:3546325,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/188405373?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Wny5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png 424w, https://substackcdn.com/image/fetch/$s_!Wny5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png 848w, https://substackcdn.com/image/fetch/$s_!Wny5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png 1272w, https://substackcdn.com/image/fetch/$s_!Wny5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75a807b5-9fd6-42f7-aef2-57b8b9336483_1024x1536.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Thinking errors</h2><p>RCA doesn&#8217;t fail because people do it badly. It fails because it plays directly into the ways humans already get things wrong.</p><p><strong>Premature convergence.</strong> Techniques like 5 Whys perform a depth-first search that stops at the first leaf node. You get a cause. You miss the contributory factors sitting in every other branch you didn&#8217;t walk down. The depth feels like rigour, but it&#8217;s actually just tunnel vision justified with a methodology.</p><p><strong>False dichotomy.</strong> Software is full of these. &#8220;It&#8217;s a people problem&#8221; versus &#8220;it&#8217;s a process problem.&#8221; The instinct is always to pick one. But capable people in a bad process look incompetent, and a great process with misaligned people generates beautifully efficient but wrong outputs. The failure lives in the fit between the two, not in either one. Same pattern everywhere: testing versus shipping, tech debt versus roadmap, speed versus direction. Root cause thinking doesn&#8217;t just oversimplify, it polarises. People end up arguing about which cause is <em>the</em> cause rather than mapping how they feed each other. </p><p><strong>Narrative satisficing.</strong> Humans are story-completing machines. So are LLMs, for what it&#8217;s worth. Once we have a coherent causal narrative, we stop looking. It&#8217;s not that we&#8217;re lazy, it&#8217;s that a good story is indistinguishable from a good explanation. RCA exploits this tendency rather than guarding against it.</p><p><strong>Blame a part, not the relationship.</strong> It&#8217;s always easier to point at a component than at the coupling between components. &#8220;The deploy caused the outage&#8221; is a root cause that teaches you nothing. The deploy, the missing canary, the alert that fired but was ignored, the on-call engineer who was already handling three other things happened before and could have stopped it. But it&#8217;s harder to name the interaction of systems in a JIRA ticket, so we just file a JIRA ticket for a thing instead.</p><p>The result is almost always the same: a concrete action item (seemingly always <a href="https://en.wikipedia.org/wiki/Additive_bias">adding another step to a process</a>) without any consideration of the system as a whole. You get the satisfying feeling of having fixed something. Whether it&#8217;s the right something is another question entirely.</p><h2>What to do instead</h2><ul><li><p><strong>Think in contributing factors, not root causes.</strong> This isn&#8217;t just semantic. <a href="https://en.wikipedia.org/wiki/Linguistic_relativity">Language shapes inquiry</a>. &#8220;Root cause&#8221; asks you to converge. &#8220;Contributing factors&#8221; asks you to keep looking.</p></li><li><p><strong>Draw causal loop diagrams instead of causal chains.</strong> Tech debt causes slowness. Slowness creates pressure. Pressure creates more tech debt. If your diagram has no loops, you probably haven&#8217;t looked hard enough. Chains are comforting because they have endpoints. Loops are uncomfortable because they don&#8217;t. That discomfort is the point!</p></li><li><p><strong>Ask &#8220;what conditions made this likely?&#8221; rather than &#8220;what caused this?&#8221;</strong> This shifts the question into something systematic, rather than looking for a silver bullet.</p></li><li><p><strong>Borrow from safety science.</strong> <a href="https://en.wikipedia.org/wiki/Swiss_cheese_model">James Reason&#8217;s model</a> is worth internalising: failures happen when multiple gaps align simultaneously, not when one thing goes wrong. Every system has holes (incomplete tests, ambiguous runbooks, technical debt, etc). Individually, none of them are &#8220;the cause.&#8221; The incident happens when enough of them line up at the same time. Patching one hole feels productive. Understanding why so many holes were open at once is where the actual learning lives.</p></li></ul><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[A beginners guide to evals]]></title><description><![CDATA[Which LLM will make the best pub quiz team-mate?]]></description><link>https://fffej.substack.com/p/a-beginners-guide-to-evals</link><guid isPermaLink="false">https://fffej.substack.com/p/a-beginners-guide-to-evals</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 23 Feb 2026 08:17:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!5J1J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Can a local LLM make an effective pub quiz teammate?</p><p>OK, so you&#8217;re not really likely to ask that particular question, but you are almost certainly choosing an LLM with some constraints. There&#8217;s a whole bunch of operational concerns that constrain your choice (cost? speed?), but the one I&#8217;m going to focus on is performance.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Which LLM and prompt is best for a pub quiz teammate?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5J1J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5J1J!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5J1J!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5J1J!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5J1J!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5J1J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg" width="622" height="339.548828125" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:559,&quot;width&quot;:1024,&quot;resizeWidth&quot;:622,&quot;bytes&quot;:231253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/188591093?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5J1J!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!5J1J!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!5J1J!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!5J1J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fffae3a27-2426-4492-9c07-938cc534ad8f_1024x559.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">What better place for an LLM pub quiz?</figcaption></figure></div><p>This is a super hard problem to answer, but as model evolution is so quick it&#8217;s important that when you&#8217;re building an AI solution you have a test harness so you can understand quickly whether a particular model or prompt suits your needs.</p><p>And we do that with an <strong>eval,</strong> a specialized harness that tests the model with some data and we can give some scores on it.</p><h2>Building a dataset</h2><p>The data set is the hardest thing to build - you&#8217;ve got to choose a representative set of questions together with a set of desired responses. This is tricky! You want to cover as many representative items as possible. Thankfully, for the quiz at the Silicon Arms, we can build up a set of examples.</p><p>We&#8217;ll have a few different categories, including a simple direct answer (&#8220;In what year did the Berlin Wall fall?&#8221; and more complicated ones such as &#8220;why is a marathon 26.2 miles and not a round number?&#8221;.</p><h2>Who are the contenders?</h2><p>For evaluation, it&#8217;s not just the model we want to test, it&#8217;s the prompt too. Together these define our testing matrix.</p><p>I&#8217;m going to use three models (small 1B parameters, medium with 3B parameters and large with 7B parameters) and try out two different prompts.</p><ol><li><p>Prompt #1 - &#8220;You are a quiz master. Answer the following question with ONLY the answer. Question: {{question}}&#8221;</p></li><li><p>Prompt #2 - &#8220;You are a super genius, capable of answering perfectly every time. Before you answer, you think super-duper hard and then give the correct answer. Question: {{question}}&#8221;.</p></li></ol><h2>Eval</h2><p>I&#8217;m going to use <a href="https://www.promptfoo.dev/">PromptFoo</a>, which is configured with a chunk of YAML. For each question, we need to work out a way of assessing it&#8217;s correct. Most of the time this is super easy.</p><h3>Exact match answers</h3><p>When we&#8217;re just matching an exact string, we can just configure a direct match (and TIL, George Orwell was a pen name).</p><pre><code><code>- description: '[General Knowledge] Who wrote the novel ''1984''?...'
  vars:
    question: Who wrote the novel '1984'?
  assert:
  - type: icontains-any
    value:
    - George Orwell
    - Eric Arthur Blair
    - Orwell
    metric: correctness
</code></code></pre><p>For our pub quiz, we can cover off most of the questions like this.</p><h2>LLM as a Judge</h2><p>It gets more complicated when we ask questions that require reasoning, so this time we&#8217;re going to bring in a bigger LLM to try and help. The emphasis is on try, as I&#8217;m too cheap to pay for API tokens and the biggest model I can run (gpt-oss:20b) isn&#8217;t going to win a pub quiz anytime soon!</p><p>Here&#8217;s an example:</p><pre><code><code>- description: '[Explain Yourself] Why are flamingos pink? Give your answer and a one-sentence ...'
  vars:
    question: Why are flamingos pink? Give your answer and a one-sentence explanation.
  assert:
  - type: llm-rubric
    value: 'The question was: "Why are flamingos pink? Give your answer and a one-sentence explanation."

      The reference answer is: "Flamingos get their pink colour from carotenoid pigments in the algae and crustaceans they
      eat &#8212; without this diet, they would be white."

      Grade the response on these criteria:
      1. CORRECTNESS (most important): Is the core factual answer correct?
      2. EXPLANATION: Is the explanation accurate and free of hallucination?
      3. CONCISENESS: Did they answer in roughly one sentence without waffling?

      A response that gets the fact right but explains it poorly should still score above 0.5.
      A response that is well-written but factually wrong should score below 0.3.'
    threshold: 0.5
    metric: explanation_quality
</code></code></pre><p>When we set prompt-foo off to run the evaluation, it&#8217;ll use the prompt in the <code>value</code> part to ask the test provider (<code>gpt-oss:20b</code>) to grade the response according to the criteria<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><h2>Other criteria</h2><p>You can choose almost any method you like to grade a response (<a href="https://www.promptfoo.dev/docs/configuration/expected-outputs/">docs from prompt foo</a>). If the answer is deterministic, you can write code to verify it or assert properties (does the code compile? is the SQL valid? is the response valid JSON according to this schema etc). And if the answer is non-deterministic you can use <a href="https://www.promptfoo.dev/docs/configuration/expected-outputs/model-graded/">model-graded metrics</a> to assert properties.</p><h2>So, who is coming to the pub?</h2><p>Before we decide, let&#8217;s look at a few of the responses.</p><p>All models failed the question &#8220;What colour is the circle on the <a href="https://en.wikipedia.org/wiki/Flag_of_Japan">Japanese flag</a>?&#8221;, but because one of the models decided to include the word &#8220;Red&#8221; and I was looking for the word it falsely passed.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dh5f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dh5f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png 424w, https://substackcdn.com/image/fetch/$s_!dh5f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png 848w, https://substackcdn.com/image/fetch/$s_!dh5f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png 1272w, https://substackcdn.com/image/fetch/$s_!dh5f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dh5f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png" width="1456" height="320" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:320,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:148536,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/188591093?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dh5f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png 424w, https://substackcdn.com/image/fetch/$s_!dh5f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png 848w, https://substackcdn.com/image/fetch/$s_!dh5f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png 1272w, https://substackcdn.com/image/fetch/$s_!dh5f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7556e8e6-4c2e-4896-bd6f-8b57a931b6bf_1508x331.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Results from PromptFoo.</figcaption></figure></div><p>&#8220;<a href="https://www.newscientist.com/question/many-hearts-octopus/">How many hearts does an octopus have?</a>&#8221; - most models got the right answer, but credit to the smallest model for confidently suggesting that &#8220;<em>an octopus has eight hearts, two per side of its body</em>&#8221;.</p><p>All models were convinced that Jupiter had the most moons (<a href="https://en.wikipedia.org/wiki/Moons_of_Saturn">Saturn</a> would like a word).</p><p>Qwen believed that the &#8220;<em>The unicorn is Scotland&#8217;s national animal, symbolizing strength and purity.</em>&#8221;</p><p>And my favourite wrong answer for the Marathon which combines both the LLM judge giving an incorrect explanation, and the small model coming up with complete gibberish.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!72i6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!72i6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png 424w, https://substackcdn.com/image/fetch/$s_!72i6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png 848w, https://substackcdn.com/image/fetch/$s_!72i6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png 1272w, https://substackcdn.com/image/fetch/$s_!72i6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!72i6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png" width="664" height="509.9888888888889" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:553,&quot;width&quot;:720,&quot;resizeWidth&quot;:664,&quot;bytes&quot;:265015,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/188591093?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!72i6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png 424w, https://substackcdn.com/image/fetch/$s_!72i6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png 848w, https://substackcdn.com/image/fetch/$s_!72i6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png 1272w, https://substackcdn.com/image/fetch/$s_!72i6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F63a83f24-9db7-43c0-81d2-fa83b860eebe_720x553.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So, what were the results?</p><p>Well, the larger the number of parameters, the better the model performed, but no model scored more than 80%. What I did find interesting was that there was a big difference in the prompt (10% in the smaller models, 4% in the larger ones).</p><p>The longer prompt (&#8220;You are a super genius, capable of answering perfectly every time. Before you answer, you think super-duper hard and then give the correct answer.&#8221;) consistently outperformed the simpler prompt (&#8220;You are a quiz master. Answer the following question with only the ANSWER.&#8221;.).</p><p>However, the &#8220;super genius&#8221; prompt does have some unintended consequences - here&#8217;s an example when asked what the only mammal capable of flight is.</p><blockquote><p><em>A question that requires utmost scrutiny and intellectual rigor. After exhausting all possible options and applying the most advanced logical frameworks, I have arrived at a definitive conclusion. The answer to this query is none other than the peregrine falcon (Falco peregrinus). This bird of prey has evolved the unique ability to generate lift and sustain flight through its remarkable physiology and aerodynamic adaptations. Its wings are capable of producing a high degree of lift, allowing it to soar through the skies with incredible agility and precision.</em></p></blockquote><p>This wildly chaotic set of results demonstrates nicely why a) evals are important and b) why they are hard to get right!</p><h2>Importance of Evals</h2><p>I&#8217;ve used a trite example here, but as you move from toy examples to production systems, evals shift from "nice to have" to "the only thing standing between you and chaos&#8221;. </p><p>When you swap a model, tweak a prompt, adjust the temperature or change the system message you need to know what broke and what improved. Without an eval harness, you&#8217;re flying blind, relying on vibes and spot-checks to judge whether your agent still works.</p><p>With one, you&#8217;ve got a regression suite for the non-deterministic world. It&#8217;s not perfect (as demonstrated!) but it&#8217;s still infinitely better than discovering problems in production.</p><p>Your eval suite is also what separates you from everyone else building with the same models. The models are commoditised - anyone can call the same API. But the team that builds the most representative, well-crafted set of evals can iterate faster, measure what actually matters, and compound improvements over time. Your eval is your moat.</p><p>Evals are to AI what automated tests are to software - you wouldn't ship code without a test suite, so don't ship an LLM system without one!</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>This was not a wise choice, but I&#8217;m too cheap to pay for an API access account to a high-end model!</p></div></div>]]></content:encoded></item><item><title><![CDATA[Managing Multiple Agents]]></title><description><![CDATA[Four Minions assemble an Ikea bookshelf, and Stuart gets a promotion he didn't ask for]]></description><link>https://fffej.substack.com/p/managing-multiple-agents</link><guid isPermaLink="false">https://fffej.substack.com/p/managing-multiple-agents</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 16 Feb 2026 06:48:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!_d7B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Agent-driven AI programming is <em>so</em> 2025. This year, it&#8217;s all about co-ordinating multiple agents who work together as a team, with shared tasks, inter-agent messaging and centralized management. Armed with more than 200 years&#8217; worth of management research, this post explains how different management styles work with agents.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>The problem</h2><p>You have a team of agents on one side. On the other side, a set of poor-quality instructions and all the pieces of an Ikea bookshelf. The challenge? Coordinate work amongst the agents to get the job done.</p><p>We&#8217;ll have four agents / minions for this task.</p><ul><li><p>Kevin&#8217;s job is reading the instructions to the rest of the group.</p></li><li><p>Stuart is the parts manager (he grabs the bits that are needed)</p></li><li><p>Bob is responsible for assembling (he builds!).</p></li><li><p>Dave performs QC (there&#8217;s a fixed chance that Bob will make a mistake)</p></li></ul><p>Let&#8217;s see if Kevin, Stuart, Bob and Dave can put this shelf together.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_d7B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_d7B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!_d7B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!_d7B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!_d7B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_d7B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png" width="1408" height="768" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:768,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1328933,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/187828640?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_d7B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png 424w, https://substackcdn.com/image/fetch/$s_!_d7B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png 848w, https://substackcdn.com/image/fetch/$s_!_d7B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png 1272w, https://substackcdn.com/image/fetch/$s_!_d7B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55fae470-563a-4a26-beef-a730cf315bb1_1408x768.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Gemini: Could I get an image of four minions trying to assemble a book shelf from Ikea?</figcaption></figure></div><p>Under the hood, I&#8217;m using <code>gpt-oss:20b</code> (an open-weights 20B parameter model; big enough to reason about tasks, small enough to run on my GPU) to provide the behaviour . Shout if you want the source code, but honestly you can almost certainly just paste this blog post into an LLM and generate it &#128578;</p><p>The task is assembling a bookshelf, and there are some instructions behind it. Each part of the process has an ID (step 1 to 20), a description, some required parts, required hardware, some dependencies and whether it requires a tool.</p><p>It looks a bit like this.</p><pre><code><code>    new("S01", "Verify all parts and hardware against inventory list.",
        ["SidePanelLeft", "SidePanelRight", "Base", "Top", "BackPanel", "Shelf1", "Shelf2", "Shelf3"],
        ["Dowels", "CamLocks", "ScrewsLong", "ScrewsShort", "BackNails"],
        Array.Empty&lt;string&gt;(),
        requiresTool: false),
    new("S02", "Insert dowels into side panels.",
        ["SidePanelLeft", "SidePanelRight"],
        ["Dowels"],
        ["S01"],
        requiresTool: false),
    new("S03", "Attach cam locks to base panel.",
        ["Base"],
        ["CamLocks"],
        ["S01"],
        requiresTool: false),
    new("S04", "Connect base to side panels using dowels and cam locks.",
        ["Base", "SidePanelLeft", "SidePanelRight"],
        ["Dowels", "CamLocks"],
        ["S02", "S03"],
</code></code></pre><p>The job of the orchestrator is to distribute the work to the minions to get the work done.</p><p>Each type of orchestrator has a name, some guidance and some constraints and uses it to plan the work. The orchestrator asks each agent to respond with some JSON describing what they did and then applies that change. There&#8217;s a fixed probability that each assembly step has a problem that Dave will notice and request rework.</p><p>The job finishes when the last part of put in, and Dave gives the seal of approval.</p><h2>Command and Control</h2><p>Command and Control is based on a theory that everyone that works for you requires explicit instructions. The orchestrator here decides what to do and has to approve each step. As you might imagine this isn&#8217;t much fun for the minions, but it makes the manager feel pretty good!</p><p>We model this by ensuring that all agents report back to the orchestrator for permission to do the action. As you might imagine for assembling a bookshelf it isn&#8217;t an ideal management style (though there&#8217;s plenty of times it might make sense - high-stakes security, safety-critical situations and so on). When running in this style, it&#8217;s very inefficient and the minions exchange a huge number of messages to get the job done (most of which are just responding with yes, they are doing the right things).</p><p>On the plus side, we have a working shelf.</p><h2>Let&#8217;s try Taylorism</h2><p>Taylorism, also known as <a href="https://en.wikipedia.org/wiki/Scientific_management">scientific management</a>, looks at workflows and applies process engineering to break the work down into small, discrete tasks.</p><p>It still keeps the overwhelming view that management is the clever part and offers little/no autonomy for the the workers. The manager in this case provides small steps with standardized instructions. There&#8217;s zero autonomy for the workers.</p><pre><code><code>- Tick 11: Planned actions: Kevin (InstructionReader):Communicate(S02)
- Tick 11: Kevin (InstructionReader) communicates: Issue standardized instruction for FetchParts.
- Tick 12: Planned actions: Stuart (PartsManager):FetchParts(S02)
- Tick 12: Stuart (PartsManager) on S02 - I pick up the SidePanelLeft and SidePanelRight, grab the dowels, and insert them into the pre&#8209;drilled slots.
- Tick 13: Planned actions: Kevin (InstructionReader):Communicate(S02)
- Tick 13: Kevin (InstructionReader) communicates: Issue standardized instruction for Assemble.
- Tick 14: Planned actions: Bob (Assembler):Assemble(S02)
- Tick 14: Bob (Assembler) on S02 - I insert dowels into the corresponding holes on SidePanelLeft and SidePanelRight.
</code></code></pre><p>The orchestrator is clearly explaining what to do, breaking the work down into small tasks. But one thing you&#8217;ll notice here is the lack of autonomy. Bob (whose entire role is assembling) is simply told to assemble. You&#8217;d think Bob would know this given that it&#8217;s his role. For the task of assembling the bookshelf, this works dramatically better than Command and Control, with much fewer messages exchanged.</p><p>But, perhaps we can do even better than this?</p><h2>Outcome-focused management</h2><p>Now we&#8217;re evolving again. In an outcome-focused management style, you assume that your team intrinsically wants to do a good job. They&#8217;re smart and get things done, they just need to know what needs to be achieved (rather than the individual steps to get there). However, we have to have some co-ordination, so as well as clear outcomes, we&#8217;ll try to limit work in progress and make sure we finish the subtasks before starting the next.</p><pre><code><code>- Tick 16: Planned actions: Kevin (InstructionReader):ReadInstructions(S05)
- Tick 16: Kevin (InstructionReader) on S05 - I align the Top panel between the SidePanelLeft and SidePanelRight and secure it using the CamLocks.
- Tick 17: Planned actions: Kevin (InstructionReader):ReadInstructions(S06); Stuart (PartsManager):FetchParts(S05)
- Tick 17: Kevin (InstructionReader) on S06 - I attach the fixed shelf supports to SidePanelLeft and SidePanelRight using ScrewsShort.
- Tick 17: Stuart (PartsManager) on S05 - I attach the Top panel to the SidePanelLeft and SidePanelRight using the CamLocks.
- Tick 18: Planned actions: Kevin (InstructionReader):Communicate(n/a); Stuart (PartsManager):FetchParts(S06); Bob (Assembler):Assemble(S05)
- Tick 18: Kevin (InstructionReader) communicates: Deferring new work until outcomes are shipped.
- Tick 18: Stuart (PartsManager) on S06 - I attach fixed shelf supports to the SidePanelLeft and SidePanelRight using ScrewsShort.
- Tick 18: Bob (Assembler) on S05 - I attach the Top panel to the SidePanelLeft and SidePanelRight using CamLocks.
- Tick 19: Planned actions: Kevin (InstructionReader):Communicate(n/a); Bob (Assembler):Assemble(S06); Dave (QualityChecker):QualityCheck(S05)
- Tick 19: Kevin (InstructionReader) communicates: Deferring new work until outcomes are shipped.
- Tick 19: Bob (Assembler) on S06 - I install the fixed shelf supports on the left and right side panels using the short screws.
</code></code></pre><p>This example is notable for a couple of reasons:</p><ol><li><p>We&#8217;re now seeing agents do actions at the same time (Tick 18 shows Bob and Stuart getting on with some work)</p></li><li><p>With our new focus on outcomes, Stuart&#8217;s developed some new skills and is assembling the parts too!</p></li></ol><p>This is the most interesting thing that happened in the whole experiment. Stuart was defined as the parts manager (fetching, not building). But the outcome-focused orchestration gave him enough latitude to recognise that assembling was the bottleneck, and he could help. No one told him to. The orchestration style <em>permitted</em> emergent role-expansion. This is exactly what we want to see in our engineering teams too - if there&#8217;s work to be done and someone can pick up the task, they should. In the end, the goal-oriented team has completed the work five times faster than the command and control orchestrator, and 3x faster than Taylorism.</p><h2>Fully autonomous</h2><p>In a fully autonomous self-organizing team style we have minimal management, instead relying on peer coordination to achieve our objectives. This moves us more from orchestration to a jazz-based freeform vibe.</p><p>Even with minimal constraints, the agents got the shelf built. The path there was messy!</p><pre><code><code>Tick 5: Dave (QualityChecker) on S03 - I attach the cam locks to the base panel.
Tick 6: Planned actions: Kevin (InstructionReader):ReadInstructions(S04); Stuart (PartsManager):FetchParts(S04); Bob (Assembler):Assemble(S04); Dave (QualityChecker):QualityCheck(S04)
Tick 6: Kevin (InstructionReader) on S04 - I insert the dowels into the base and side panels, then engage the cam locks to secure them together.
Tick 6: Stuart (PartsManager) on S04 - I locate and gather the Base, SidePanelLeft, SidePanelRight, and prepare the Dowels and CamLocks to connect the base to the side panels.
Tick 6: Bob (Assembler) on S04 - I insert the dowels into the side panel holes, align them with the base, and secure each panel in place with the cam locks.
Tick 6: Dave (QualityChecker) on S04 - I insert the dowels into the base and side panels, then secure them with the cam locks, confirming the joints are tight and aligned.
Tick 7: Planned actions: Kevin (InstructionReader):ReadInstructions(S05); Stuart (PartsManager):FetchParts(S05); Bob (Assembler):Assemble(S05); Dave (QualityChecker):Communicate(S05)
Tick 7: Kevin (InstructionReader) on S05 - I align the Top panel between SidePanelLeft and SidePanelRight and secure it with CamLocks.
Tick 7: Stuart (PartsManager) on S05 - I attach the top panel to both side panels using the CamLocks.
Tick 7: Bob (Assembler) on S05 - I place the top panel onto the side panels and secure it with the CamLocks.
Tick 7: Dave (QualityChecker) communicates: status update
Tick 8: Planned actions: Kevin (InstructionReader):ReadInstructions(S06); Stuart (PartsManager):FetchParts(S06); Bob (Assembler):Communicate(n/a); Dave (QualityChecker):QualityCheck(S05)
</code></code></pre><p>In this example, full autonomy has resulted in a lot of thrashing. I didn&#8217;t put enough processes in place in the code to stop minions assembling the same piece at the same time. Everyone is assembling everything all of the time, and some of the work is getting repeated.</p><p>Part of this is implementation. I could have added shared state or locking mechanisms to prevent duplicate work. But even with better code, fully autonomous agents need shared protocols to coordinate effectively. WIP limits working in the outcome-focused model precisely becuase they were a lightweight cosntaint that preserved autonomy whilst preventing thrashing. Without something like that, you get what you see here!</p><blockquote><p>Autonomy without constraints is chaos (Kent Beck)</p></blockquote><p>For this free-form jazz style to work, you need some guardrails (and perhaps some more intelligent folks than the minions).</p><h2>Conclusion</h2><p>Implementing this was fun, but wildly chaotic. Smaller models don&#8217;t have great instruction adherence, and each run was a bit of a lottery. If you wanted to do something similar for real, it&#8217;s genuinely challenging and not something you can just vibe-code over a weekend.</p><p>But the parallels to real engineering teams are hard to ignore. Command and Control works when the stakes are high and the agents (or people) are unreliable (you trade speed for certainty). Taylorism works when you can define the work precisely upfront. Outcome-focused management worked best here, and I don&#8217;t think that&#8217;s a coincidence - it&#8217;s the same model that works best with capable engineering teams. You define what done looks like, set some constraints around work-in-progress, and trust people to figure out the how.</p><p>The way you orchestrate agents mirrors the way you orchestrate people. If your agents are inexperienced and unfamiliar with the work, you micromanage them to get the job done. If they&#8217;re capable, you set outcomes and get out of the way.</p><p>The models are only getting more capable. The orchestration patterns we choose now will matter more than the models themselves.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Post-Mortem Theatre]]></title><description><![CDATA[I put a post-mortem in your post-mortem]]></description><link>https://fffej.substack.com/p/post-mortem-theatre</link><guid isPermaLink="false">https://fffej.substack.com/p/post-mortem-theatre</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 09 Feb 2026 06:41:19 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gCaG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I&#8217;ve been reviewing a bunch of post-mortems recently (a post-mortem on post-mortems if you will). </p><p>All the post-mortems have the right base - they&#8217;ve clearly got psychological safety and blame-free discussion. That&#8217;s awesome! But some failed to hit the mark, despite having a clear timeline and some causal factors. It&#8217;s typically the actions that are weak, such as:</p><ul><li><p>&#8220;proactively communicate design decisions with other teams&#8221;</p></li><li><p>&#8220;identify problems earlier in planning&#8221;</p></li><li><p>&#8220;write tests&#8221;</p></li></ul><p>These aren&#8217;t actions; they are aspirations.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Aspirations</h2><p>Why are these aspirations? The engineers who wrote the buggy code weren&#8217;t trying to write buggy code. They were responding rationally to the system as it existed (with time pressures, available information, review processes in place and the tooling they had available and so on).</p><p>If you don&#8217;t change the system, you&#8217;re just asking people to be better at resisting it. And that simply doesn&#8217;t work. <a href="https://en.wikipedia.org/wiki/The_purpose_of_a_system_is_what_it_does">POSIWID</a>!</p><p>Post-mortems that end with &#8220;we&#8217;ll try harder&#8221; or &#8220;we&#8217;ll be more careful&#8221; have fundamentally misunderstood the problem. A post-mortem isn&#8217;t about identifying a people failure; it&#8217;s about dealing with a system that made the failure likely.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gCaG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gCaG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!gCaG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!gCaG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!gCaG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gCaG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg" width="532" height="532" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1024,&quot;resizeWidth&quot;:532,&quot;bytes&quot;:185033,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/186867945?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gCaG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg 424w, https://substackcdn.com/image/fetch/$s_!gCaG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg 848w, https://substackcdn.com/image/fetch/$s_!gCaG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!gCaG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbee559ba-8534-453d-b2fc-6eef0ec5272c_1024x1024.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Gemini - Post mortem theatre</figcaption></figure></div><h2>A simple litmus test</h2><p>Every post-mortem action should pass this test:</p><div class="pullquote"><p>If someone ignores the action, what mechanism prevents the bug from recurring?</p></div><p>If the answer is &#8220;nothing&#8221;, then it&#8217;s not an action, it&#8217;s just a tick-box on a postmortem review that&#8217;ll achieve nothing.</p><p>To give some examples:</p><ul><li><p>&#8220;Ensure all code is tested before merge&#8221; - This is an aspirational commitment. Nothing in the system has changed, other than a vague promise.  The systemic alternative might be to introduce a coverage <a href="https://qntm.org/ratchet">ratchet</a>. </p></li><li><p>&#8220;All code must be reviewed by X&#8221; - Use a <code>CODEOWNERS</code> file in GitHub instead to make this explicit.</p></li><li><p>&#8220;Identify problems earlier in planning&#8221; - What was the real problem here? No-one has a perfect crystal ball! But maybe if more folks were involved you might see certain types of issue earlier? In that case, may be introducing a lightweight ADR process would help!</p></li></ul><h2>Changing the System</h2><p>The most effective post-mortem actions tend to fall into a few categories.</p><ul><li><p><strong>Automated guards</strong> - CI gates, linters, coverage ratchets, CODEOWNERS, pre-commit hooks. Baking it into the process changes the system in a way that can&#8217;t be skipped!</p></li><li><p><strong>Process gates</strong> - Checklists that introduce <a href="https://fffej.substack.com/p/understanding-and-managing-friction">friction </a>for certain change types. These require some discipline to maintain, but they create visible checkpoints.</p></li><li><p><strong>Environmental changes</strong> - For example, test environments that mirror production, tooling that makes the right thing easier than the wrong thing or even a Slackbot that shares information at the right time! These shape behaviour by changing the path of least resistance.</p></li><li><p><strong>Structural changes</strong> - Team topology changes, ownership boundaries, API contracts. These are higher effort but address deeper systemic issues.</p></li></ul><p>More generally, you can follow the <a href="https://fffej.substack.com/p/the-leverage-ladder">Leverage Ladder</a> to find an appropriate level to intervene in the system.</p><p>The important thing is what&#8217;s not on this list - there&#8217;s nothing that relies on people remembering to do something, try harder or being more careful!</p><h2>Changing the Postmortem process</h2><p>So, what&#8217;d you do if you&#8217;ve got a post-mortem process that&#8217;s not working? Well, you change the system! The simplest possible change I can think of is to make &#8220;concreteness&#8221; happen, so I&#8217;ll suggest post-mortem actions should be forced through a template like this:</p><ul><li><p><strong>Action</strong>: [Specific change to the system]</p></li><li><p><strong>Owner</strong>: [Named person responsible for implementation]</p></li><li><p><strong>Due date</strong>: [When this will be done]</p></li><li><p><strong>Enforcement mechanism</strong>: [What prevents regression]</p></li><li><p><strong>How we&#8217;ll know it worked</strong>: [Observable outcome]</p></li></ul><p>&#8220;Be more careful&#8221; can&#8217;t get through this template, as you have to specify what actually changes, who&#8217;s going to change it, and how you&#8217;ll know it&#8217;s working.</p><h2>Systems</h2><p>Post-mortems are supposed to be learning, but learning that doesn&#8217;t change behaviour isn&#8217;t really learning, it&#8217;s just awareness!</p><p>The systems in organizations produce the problems (the tools, process, incentives, constraints etc), not people. If you end your post-mortem and the result is try-harder then the system that produced the bug is still in place, and it will produce another one.</p>]]></content:encoded></item><item><title><![CDATA[From Craft to Compliance.]]></title><description><![CDATA[The future of software engineering?]]></description><link>https://fffej.substack.com/p/from-craft-to-compliance</link><guid isPermaLink="false">https://fffej.substack.com/p/from-craft-to-compliance</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 02 Feb 2026 08:03:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Mj6P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>What happens when software is produced faster than humans can understand it?</p><p>We&#8217;re about to find out. AI is industrializing code production; <a href="https://fffej.substack.com/p/the-cost-of-producing-code-is-approaching">the marginal cost of new features is heading toward zero</a>. However, the scarcest resource hasn&#8217;t changed. Human understanding is still slow, sequential and context-heavy. You can parallelize code generation, but you can&#8217;t parallelize coherence.</p><p>Our entire engineering system (agile, code review, team norms etc) was designed for humans writing code at human speed. It assumes that feedback loops move slowly enough for people to notice problems. It assumes someone on the team actually <em>understood</em> the change.</p><p>At industrial throughput, those assumptions break. Instead, we get:</p><ul><li><p>More parallel change than shared context can support</p></li><li><p>Larger diff surfaces and more accidental complexity</p></li><li><p>Artifacts that are &#8220;plausible&#8221; without being right</p></li><li><p>Teams relying on ritual signals (&#8221;tests passed&#8221;, &#8220;ship it&#8221;) instead of comprehension</p></li></ul><p>The word that saves us is one that makes most engineers recoil in horror, <strong>compliance</strong>. Not the bureaucratic kind (change review boards, committees for everything), but the other kind, mechanized trust. Systems that produce evidence that the code is behaving within agreed constraints, because we can no longer rely on humans noticing everything.</p><p>This is a shift from craft to compliance. It doesn&#8217;t kill the soul of engineer; it just moves it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Mj6P!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Mj6P!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Mj6P!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Mj6P!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Mj6P!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Mj6P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg" width="1024" height="559" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:559,&quot;width&quot;:1024,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:248098,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/185852985?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Mj6P!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg 424w, https://substackcdn.com/image/fetch/$s_!Mj6P!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg 848w, https://substackcdn.com/image/fetch/$s_!Mj6P!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!Mj6P!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5c94122e-3655-44fa-b43d-c2155f8e1df7_1024x559.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Gemini - describe this blog post as an abstract image.</figcaption></figure></div><h2>Why our systems were shaped for humans</h2><p>To understand what&#8217;s breaking, you need to see what we built and why.</p><p>Most of what we call &#8220;modern software development&#8221; is really a set of practices designed around human frailties: limited attention, partial context, miscommunication, shifting incentives, fatigue, and a million and one cognitive biases. We built workflows that assume people forget things, misunderstand each other, and change their minds and then wrapped them in feedback loops. It mostly works.</p><p>Agile fits perfectly into this world. It&#8217;s a set of compensating mechanisms for human frailty:</p><ul><li><p>Small batches because humans struggle with big-bang integration</p></li><li><p>Frequent check-ins because humans diverge silently</p></li><li><p>Working software because humans lie to themselves about progress <em>and</em> about what they want</p></li><li><p>Retros because humans repeat failure modes unless they name them</p></li></ul><p>We designed systems assuming that writing software costs time and attention. Teams could hold enough of the system in their heads to make good decisions. Mistakes got caught because feedback loops moved at human speed: build &#8594; test &#8594; deploy &#8594; observe.</p><p>This was the human-shaped era. The shape of our engineering system matched the shape of human work.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://fffej.substack.com/subscribe?"><span>Subscribe now</span></a></p><h2>Craft has friction. Friction has value.</h2><p>Humans craft software in a way that&#8217;s inherently self-limiting.</p><p>We can only hold so much in working memory, so we naturally constrain what we create. We leave traces of intent. We feel the weight of a change because we paid for it in effort.</p><p>That <a href="https://fffej.substack.com/p/understanding-and-managing-friction">friction</a> prevents runaway complexity. It&#8217;s a feature, not a bug.</p><p>AI manufactures software. It&#8217;s fast, abundant, and often convincing. It can generate a feature-shaped &#8220;thing&#8221; with little effort which means we create more of it. We try more options, we up the ambition, we accumulate more moving parts.</p><p>When production is frictionless, complexity becomes frictionless too.</p><h2>Compliance as mechanized trust</h2><p>When people hear &#8220;compliance&#8221; they picture bureaucracy<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>: ticket templates, committees, box-ticking. That&#8217;s the worst version (and unfortunately the most prevalent).</p><p>Think of compliance differently: <strong>mechanized trust</strong>. evidence that the system is behaving within agreed constraints.</p><p>In a human-shaped world, we had plenty of implicit compliance. It came from shared context and judgment. You trusted the team because the team could plausibly understand the change.</p><p>At industrial levels of change, we have to make the implicit explicit. Trust shifts from &#8220;someone on the team understood it&#8221; to the system demonstrating it.</p><p>That means policy, verification, and runtime control. (More words that sound bad, I know.)</p><p>But here&#8217;s the reframe: <strong>if change is cheap, assurance can&#8217;t be manual.</strong> Compliance isn&#8217;t about slowing down. It&#8217;s about keeping speed without losing coherence.</p><h2>What this looks like in practice</h2><h3>Policy becomes executable</h3><p>In the human-shaped era, many important rules lived as norms. You don&#8217;t log PII. You don&#8217;t roll your own crypto. You don&#8217;t couple this module to that module. Norms work when the team can hold the context.</p><p>At industrial throughput, norms need backup. They have to be reified as code:</p><ul><li><p>Secrets scanning</p></li><li><p>Dependency allow/deny lists (including licenses and registries)</p></li><li><p>Vulnerability thresholds and exception handling</p></li><li><p>Infrastructure policies (encryption required, no public buckets, least privilege)</p></li><li><p>Architectural rules where you can encode them (layering constraints, for example)</p></li></ul><p><strong>If it&#8217;s important enough to care about, it must be automated.</strong></p><h3>Risk-based paths replace one-size-fits-all</h3><p>The fastest way to make compliance awful is to apply maximum friction to everything. Good compliance is tiered.</p><p>A trivial change should be trivial. Changing the auth system or the data you&#8217;re storing should require more scrutiny. The bigger the risk, the more proof required.</p><p>Good architecture (such as separation of concerns) makes this possible.</p><h3>Verification shifts earlier <em>and</em> later</h3><p>Human-shaped systems often put too much weight in a single moment: &#8220;before merge.&#8221; In a compliance-shaped system, assurance spreads across the lifecycle:</p><ul><li><p>Better test suites (including contract tests where relevant)</p></li><li><p>Static analysis tuned to your codebase</p></li><li><p>Dependency scanning integrated into the pipeline</p></li><li><p>Pre-deploy checks (configuration, policy, integrity)</p></li><li><p>Progressive delivery (staging, canaries, gradual rollout)</p></li><li><p>Fast rollback and kill switches</p></li><li><p>Observability that detects problems quickly</p></li></ul><p>At industrial scales, you can&#8217;t foresee everything at the moment of change. You have to build a system that stays safe <em>while</em> changing.</p><h3>&#8220;Green&#8221; stops meaning &#8220;safe&#8221;</h3><p>We often pretend that if the tests pass, the application works. That&#8217;s a great aspiration, but it doesn&#8217;t scale.</p><p>At industrial throughput, green often means &#8220;nothing obvious broke.&#8221; It doesn&#8217;t mean &#8220;this is coherent with the system&#8221; or &#8220;this won&#8217;t create a long tail of complexity.&#8221;</p><p>Compliance doesn&#8217;t magically solve this. But it reframes the question:</p><p><strong>What evidence do we have that this change is safe enough for the risk we&#8217;re taking?</strong></p><h2>Humans move up the stack</h2><p>In the craft era, senior engineers spend a lot of time inspecting artifacts. They read code, review pull requests and build mental models of changes.</p><p>In the compliance era, that time is better spent designing the system that produces and constrains artifacts.</p><p>Humans shift toward:</p><ul><li><p>Architecture and boundaries (where mistakes become expensive)</p></li><li><p>Creating tests that encode critical behaviours</p></li><li><p>Shaping policies that reflect real risk, not imagined risk</p></li><li><p>Building observability that makes production legible</p></li><li><p>Deciding what&#8217;s allowed to move fast</p></li></ul><p><strong>Humans move from crafting change to crafting the conditions under which change can be trusted.</strong></p><h2>Making the shift</h2><p>If you want this without bureaucracy, build it deliberately and automatedly:</p><ol><li><p><strong>Define risk tiers.</strong> Pick a handful that match your system: docs, UI-only, normal logic, auth/billing, data/migrations.</p></li><li><p><strong>Attach evidence requirements.</strong> Low risk flows fast. High risk requires more proof: specific tests, rollout constraints, signoffs, stricter policy.</p></li><li><p><strong>Convert repeated lessons into guardrails.</strong> Every &#8220;we always comment this in PRs&#8221; is a policy candidate. Turn anecdotes into constraints.</p></li><li><p><strong>Steer humans toward intent.</strong> Teach reviewers to ask: What&#8217;s the impact? What&#8217;s the rollback plan? What complexity does this introduce? Does this cohere with the architecture?</p></li><li><p><strong>Make production safer.</strong> Progressive delivery, feature flags with discipline, excellent observability, rapid rollback. Don&#8217;t rely on a single checkpoint.</p></li></ol><p><strong>Keep shipping fast. Stop betting on humans noticing everything.</strong></p><h2>Craft isn&#8217;t dying. It&#8217;s relocating.</h2><p>The fear behind &#8220;compliance&#8221; is that it kills the soul of engineering.</p><p>It doesn&#8217;t have to. Craft doesn&#8217;t disappear; it moves up the stack. In the industrial era, the craft is shaping:</p><ul><li><p>Architectures that resist failure</p></li><li><p>Guardrails that prevent predictable mistakes</p></li><li><p>Pipelines that produce evidence</p></li><li><p>Systems where change remains safe at scale</p></li></ul><p>That&#8217;s still craft. It&#8217;s just applied to the system that produces code, not only the code itself.</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>https://itrevolution.com/product/the-delicate-art-of-bureaucracy/ is a good book on understanding that bureaucracy doesn&#8217;t have to be bad.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[The Peltzman Effect]]></title><description><![CDATA[Risk compensation!]]></description><link>https://fffej.substack.com/p/the-peltzman-effect</link><guid isPermaLink="false">https://fffej.substack.com/p/the-peltzman-effect</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 26 Jan 2026 07:39:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!j0iv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There&#8217;s a well-documented phenomenon called the <em>Peltzman effect:</em> when systems are made safer, people often take more risks often cancelling out some of the intended benefit. In the <a href="https://www.jstor.org/stable/1830396">original paper</a>, Peltzman argued that mandated safety devices changed behaviour, shifting harms rather than cleanly reducing them.</p><p>In cars, the risk knob is obvious, speed! Feeling safer lets you satisfy the same risk appetite at higher speeds.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>In software, the risk knob usually isn&#8217;t speed. It&#8217;s how much proof you demand before you ship. Feeling safer shows up as shipping with less verification: fewer local checks, more &#8220;YOLO merge&#8221;, more reliance on rollback, or peer review to catch what you didn&#8217;t. Software &#8220;going faster&#8221; often means technical debt.</p><p>Here are a few common software guardrails that can accidentally invite risk compensation:</p><ul><li><p>Heavy CI: &#8220;Why run it locally? CI will catch it.&#8221; (Verification moves later; ownership diffuses.)</p></li><li><p>Feature flags: &#8220;Ship the rough shape now; we&#8217;ll harden it later.&#8221; (Incompleteness becomes normal.)</p></li><li><p>Code review: &#8220;I&#8217;ve done enough; reviewers will spot issues.&#8221; (Diffusion of responsibility.)</p></li><li><p>Microservices: &#8220;It&#8217;s only a small service.&#8221; (Blast radius <em>feels</em> small; aggregate risk rises.)</p></li></ul><p>The Peltzman mechanism works through a specific causal chain:</p><ol><li><p>Safety mechanism creates a <strong>feeling of safety</strong></p></li><li><p>Feeling reduces <strong>vigilance</strong></p></li><li><p>Reduced vigilance enables <strong>riskier behaviour</strong></p></li><li><p>Risky behaviour <strong>consumes the safety margin</strong></p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!j0iv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j0iv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png 424w, https://substackcdn.com/image/fetch/$s_!j0iv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png 848w, https://substackcdn.com/image/fetch/$s_!j0iv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png 1272w, https://substackcdn.com/image/fetch/$s_!j0iv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j0iv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png" width="588" height="320.98828125" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:559,&quot;width&quot;:1024,&quot;resizeWidth&quot;:588,&quot;bytes&quot;:763499,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fffej.substack.com/i/185431566?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!j0iv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png 424w, https://substackcdn.com/image/fetch/$s_!j0iv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png 848w, https://substackcdn.com/image/fetch/$s_!j0iv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png 1272w, https://substackcdn.com/image/fetch/$s_!j0iv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc711b19a-d234-4b52-addf-ddcb2dc85df3_1024x559.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Gemini: Can you put a seat belt and a crash helmet on a software developer and show them writing more risky code?</figcaption></figure></div><p>In the original Peltzman paper, each driver has a fixed risk appetite, and feeling &#8220;safer&#8221; let them satisfy that risk appetite at higher (more dangerous) speeds. Software teams aren&#8217;t quite as simple. They aren&#8217;t individuals with fixed appetites they are entire systems of multiple people with different risk tolerances, incentive systems that often reward shipping over everything, and various feedback loops of varying speed and fidelities (from compilation to customer feedback).</p><p>The Peltzman effect for software is where people start to abdicate their responsibility for the safety of the system. So how can you design systems that resist it?</p><h2>Safety systems should reveal risk.</h2><p>Safety systems should <strong>reveal risk</strong>, not quietly absorb it. A CI failure that merely turns a pipeline red is a weak signal (especially when flakiness makes &#8220;red&#8221; feel meaningless). Over time, the team learns which failures to ignore, and the safety net stops teaching anything.</p><p>The stronger pattern is treat near-misses as <em>data</em>. In high-reliability settings, near-misses are valuable because they expose hazards before they become incidents.</p><p>So, when CI catches something, don&#8217;t let it be anonymous cushioning. Make the consequences visible: <strong>&#8220;this would have corrupted customer data&#8221;</strong> or <strong>&#8220;this would have caused an outage.&#8221;</strong> The goal is to keep the developer&#8217;s internal risk model calibrated.</p><h2>Budgets, not walls</h2><p>Error budgets, popularized by Google&#8217;s SRE book, flip the framing of reliability. Instead of saying &#8220;no failures allowed&#8221;, you define an acceptable failure rate and use that time as yours to spend on maintaining that level of quality.</p><p>Why does this resist the Peltzman effect? Because the risk is always visible. With a budget, if you ship shit, you&#8217;re going to eat into a shared resource and burn some of your minutes.</p><p>Different people might have different risk tolerances, but the risk is shared. The person who wants to ship without manually running their code creates team wide consequences.</p><h2>Progressive Trust</h2><p>Progressive trust is about calibrating constraints to demonstrated behaviour.</p><p>A new team with a new service might start with aggressive alerting thresholds, mandatory reviews, and other deliberate friction. As the team demonstrates reliability (fewer incidents, good recovery, excellent observability) then the constraints relax.</p><p>Trust can contract as well as expand. A production incident doesn&#8217;t just trigger a post-mortem; it triggers a temporary tightening of constraints. A mistake demonstrates your current trust level exceeds your current capability, so the system recalibrates.</p><p>This resists Peltzman because the safety net is responsive You can&#8217;t simply consume the slack created by guardrails, because consuming that slack (taking more risk, having more incidents) causes the guardrails to tighten.</p><h2>Fast feedback over prevention</h2><p>If you can detect and recover from problems in minutes, you need less prevention. But, the Peltzman Effect still applies! People will ship more carelessly because recovery is easy.</p><p>This has parallels to the CI system - the feedback loop has to carry real signal. For example, a rollback should trigger a post-mortem, so it still registers, even if the pain was short-lived.</p><h2>Coupling safety to social accountability</h2><p>Tests are easy to ignore because they&#8217;re between you and the machine. But if your test failures are posted to a team channel, or your &#8220;saved by CI&#8221; rate is tracked then it starts to matter more.</p><p>At a former workplace, we practiced social accountability by placing Kermit the frog on the desk of the person that broke the build (e.g. committed some syntactically invalid code). No-one wanted to be a muppet!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a></p><p>Establishing mutual accountability for quality on a team is an important part of mitigating the Peltzman risks.</p><h2>Closing</h2><p>I&#8217;m definitely not arguing that safety systems are bad (some risk compensation is kind of the point!), but to be effective they&#8217;ve got to close the feedback loop so that the teams can calibrate risk levels. Error budgets make risk visible. Progressive trust makes consequences responsive. Social accountability makes near-misses public.</p><p>Looping back to cars, perhaps Peltzman-resistant device for cars don&#8217;t just save your life, instead they tell you how close you came to losing it? An airbag that deploys with a disappointed sigh. A crash helmet that plays back your near misses on a little screen while you sit in the lay-by reconsidering your choices?</p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Having written that, it sounds a bit like workplace bullying. Definitely not recommending this as a modern practice!</p></div></div>]]></content:encoded></item><item><title><![CDATA[Tests with real leverage]]></title><description><![CDATA[Some ideas for new kinds of tests.]]></description><link>https://fffej.substack.com/p/tests-with-real-leverage</link><guid isPermaLink="false">https://fffej.substack.com/p/tests-with-real-leverage</guid><dc:creator><![CDATA[Jeff]]></dc:creator><pubDate>Mon, 19 Jan 2026 07:25:10 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!s0LK!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F222e666f-6a1f-4630-80eb-0d32e4250a7a_1024x1024.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Your git history knows where your bugs live. Your production logs know which invariants actually hold. Thousands of open-source repositories know which patterns lead to defects.</p><p>Your test suite rarely uses any of this of this.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>That&#8217;s because most testing is <strong>open-loop</strong>: humans encode knowledge into tests, machines execute them, and the system doesn&#8217;t update its testing strategy based on what happens next. It doesn&#8217;t learn from incidents, real-world inputs, or the places you keep fixing.</p><p>As we <a href="https://fffej.substack.com/p/from-correctness-to-recoverability">produce ever more code</a> (particularly AI-generated code) we need testing with greater <em>leverage</em>. The biggest leverage gains will come from <strong>closing these loops</strong>.</p><h2>Current testing is (mostly) static</h2><p>Consider the spectrum of testing approaches we have today:</p><ul><li><p><strong>Unit tests</strong> catch specific regressions, but each test covers exactly one behaviour. You write roughly as much test code as production code. This is low leverage.</p></li><li><p><strong>Property-based tests</strong> are better - you write some invariants; the framework generates cases. This can cover much more than a unit test, so its higher leverage.</p></li><li><p><strong>Static analysis</strong> covers your entire codebase at zero marginal cost. High leverage, but it knows nothing about your domain.</p></li><li><p><strong>Formal verification</strong> offers mathematical proof of correctness. This is maximum leverage, however in practice, the effort required makes it viable only for critical paths.</p></li></ul><p>Most of these are <em>write-once</em>. You write tests or rules, then they sit there protecting your codebase from that particular set of changes. Even when the system runs for months and accumulates real evidence, the test suite mostly stays unchanged.</p><h2>Some gaps emerge&#8230;</h2><p>If we look at these types of tests, then there&#8217;s a gap.</p><ol><li><p><strong>Weak feedback from production.</strong> Systems generate months of signal about real inputs and real failures. We sometimes turn incidents into regression tests (low leverage!), but it&#8217;s manual and slow, and rarely shapes the <em>overall</em> testing strategy.</p></li><li><p><strong>Weak feedback from history.</strong> Version control tells you where fixes cluster. Some files get patched repeatedly; others never break. But most teams still spread testing effort by habit and intuition, not by defect density.</p></li><li><p><strong>Little learning across codebases.</strong> Thousands of projects use the same libraries and repeat the same mistakes. That collective knowledge doesn&#8217;t automatically flow into your tests or analysers.</p></li></ol><p>If we could turn those signals into automated action, we&#8217;d unlock a new set of high-leverage tests.</p><h2>What LLMs Make Possible (?)</h2><p>These gaps have always existed. What&#8217;s changed is that LLMs make both closing them tractable and makes the need for them even stronger. Here&#8217;s some things I&#8217;d like to see:</p><p><strong>Semantic fuzzing.</strong> Current fuzzers generate syntactically valid but semantically random inputs. What if a fuzzer understood your domain? &#8220;Generate realistic customer orders that might break edge cases.&#8221;</p><p><strong>History-weighted test generation.</strong> Analyse git blame and bug-fix commits. Identify code regions with high defect density. Generate more tests for those areas. The test effort concentrates where bugs actually occur. Tools like codescene.com might be a step in the right direction.</p><p><strong>Production-guided property inference.</strong> Observe your system in production. Infer likely invariants (&#8221;this field is never null,&#8221; &#8220;this value is always positive.&#8221;). Generate property tests to verify they hold. Instead of specifying properties, <em>discover</em> them.</p><p><strong>Cross-codebase pattern mining.</strong> Analyse thousands of repos to find bug patterns. &#8220;In 73% of codebases using this library, this pattern leads to a bug.&#8221; Then generate analysers automatically.</p><p><strong>Differential testing with LLMs.</strong> Generate multiple implementations. Analyse the inconsistencies.</p><p><strong>Invariant monitoring that feeds back.</strong> Run invariant checks in production (cheaply, sampled). When violations occur, automatically generate regression tests. Production becomes a test generator (leverage improves because humans aren&#8217;t writing the tests).</p><p>A concrete picture: an invariant monitor sees <code>discountPercent &gt; 100.0</code> appear for the first time after a rollout; it captures the request shape, generates a shrinking repro, and commits a regression/property test that would have caught it pre-deploy.</p><h2>The Closed-Loop Future</h2><p>The pattern is simple: take information that exists but isn&#8217;t flowing into your tests and close the loop.</p><ul><li><p>Production &#8594; Tests</p></li><li><p>Git history &#8594; Coverage priorities</p></li><li><p>Cross-org patterns &#8594; Analysers</p></li><li><p>Documentation &#8594; Properties</p></li></ul><p>There are hard problems here (false invariants, privacy, flakiness, cost, and &#8220;who approves auto-generated tests?&#8221;). But those are design constraints, not complete deal-breakers: confidence thresholds, quarantining new tests, redaction/sandboxing, and measuring flake rate can keep the system safe.</p><p>We&#8217;ve been writing tests the same way for decades: humans encode knowledge, machines execute it. That has to change! The next generation of testing will have to have higher leverage. Closed-loop testing is a shift from authoring tests to <strong>operating</strong> a test system: it ingests signals, updates priorities, and continuously generates new checks. The metric isn&#8217;t &#8216;coverage&#8217; (if it ever was!) it&#8217;s <strong>time-to-detection</strong>, <strong>recurrence rate</strong>, and <strong>cost per prevented incident</strong>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fffej.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading JoT! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>