<?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:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Reza Farzaneh on Medium]]></title>
        <description><![CDATA[Stories by Reza Farzaneh on Medium]]></description>
        <link>https://medium.com/@reza.farzaneh?source=rss-813b8980f972------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*rYrOi0dTPK1qk-zGHVxtYw@2x.jpeg</url>
            <title>Stories by Reza Farzaneh on Medium</title>
            <link>https://medium.com/@reza.farzaneh?source=rss-813b8980f972------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sun, 15 Nov 2026 07:20:20 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@reza.farzaneh/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[The Long Way to the Room]]></title>
            <link>https://medium.com/@reza.farzaneh/the-long-way-to-the-room-068a1ee894a1?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/068a1ee894a1</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Mon, 18 May 2026 11:42:55 GMT</pubDate>
            <atom:updated>2026-05-18T11:55:04.968Z</atom:updated>
            <content:encoded><![CDATA[<p><em>How seventy years of mathematics built the thing that we are call it AI — and why “sudden” is the most misleading word in the conversation</em></p><p><a href="https://medium.com/@aylin9alavizadeh"><strong>Aylin Alavizadeh</strong></a> <br>Industrial Engineer · Specialist in Mathematics &amp; Probability</p><p><a href="https://medium.com/@reza.farzaneh"><strong>Reza Farzaneh</strong></a><strong> </strong><br>Software Engineer · Systems Thinker &amp; AI Research Writer</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2-2yx2HPRXQUD40uc7TqVQ.png" /></figure><p>Open a newspaper from late 2022 and the story reads like this: one autumn morning, a company in San Francisco released a chatbot. The world changed overnight. Schools panicked. Lawyers updated their resumes. Philosophers got nervous. The age of artificial intelligence had arrived.</p><p>It is a tidy story. It is also wrong by about seventy years.</p><p>What happened in November 2022 was not the arrival of anything. It was the moment one particular curve — drawn slowly across decades of mathematics — finally crossed a threshold low enough that ordinary humans, on consumer hardware, noticed. The mountain had been there the whole time. We just walked into a meadow with a clear line of sight.</p><p>This is the third essay in a small sequence. The first, <em>Predicting Toward Meaning</em>, explained what a large language model is. The second, <em>There Is No Inside</em>, argued that the difference between the model and the mind is thinner than anyone wants to admit. This one is the boring essay. The historical one. The one that asks the question almost nobody bothers to ask in print:</p><p>If this thing is so revolutionary, why did it take seventy years to write a coherent paragraph?</p><p>The answer, it turns out, is the whole story.</p><h3>The Costume Has Been Under Construction Since 1943</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bocQ5g90ZgHN5UwWFe54nQ.png" /></figure><p>In 1943, two men — Warren McCulloch, a neurophysiologist, and Walter Pitts, a self-taught logician who had run away from home at fifteen — published a paper called <em>A Logical Calculus of the Ideas Immanent in Nervous Activity</em>. They proposed something audacious: a neuron could be modeled as a simple mathematical switch. Inputs in, threshold check, output out. Connect enough of them together and, in theory, you had a network that could compute anything computable.</p><p>There were no neurons in the paper. There were no brains. There was only mathematics in the <em>shape</em> of a neuron — a costume worn by a function. It is here, in 1943, two years before the end of the Second World War, that the real story of AI begins. Not in a research lab in 2017. Not in a startup garage in San Francisco. In a journal article that almost nobody outside a small circle would read for the next fifteen years.</p><p>In 1948, two years before Turing, a researcher at Bell Labs named Claude Shannon published <em>A Mathematical Theory of Communication</em> — the paper that gave the world the words <em>channel</em>, <em>encoder</em>, <em>decoder</em>, <em>noise</em>. Shannon was not thinking about thinking machines. He was thinking about telephone wires. But he proved, formally, that the meaning that survives any transmission is bounded by the cleanliness of the encoding and the capacity of the channel. Seventy-eight years later, we would discover that this is also the cleanest description of what happens when an engineer types a prompt into a model.</p><p>In 1950, Alan Turing — already six years dead by the time this story really got moving — published <em>Computing Machinery and Intelligence</em>. He proposed the famous test that bears his name. Not “can a machine think?” — a question he correctly identified as nearly meaningless — but “can a machine produce conversation indistinguishable from a human’s?” The question shifted from metaphysics to engineering, and that shift is, arguably, the entire history of AI in one sentence.</p><p>In 1956, ten people gathered at Dartmouth College for a summer workshop. Among them: John McCarthy, Marvin Minsky, Claude Shannon. They coined the term <em>artificial intelligence</em> in the funding proposal. They believed, with the boundless confidence of postwar American science, that the problem would be solved by the end of the season. They were wrong by about seventy summers.</p><h3>Three Winters</h3><p>Here is the part most modern AI commentary quietly skips. Between 1943 and 2017, the field died at least twice.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gJFd-NYYy1oRGacVk7XpcA.png" /></figure><p>In 1969, Marvin Minsky and Seymour Papert published <em>Perceptrons</em>, a book that mathematically proved single-layer neural networks could not solve certain trivial problems — including the XOR function, the most boring logic gate in computing. The book was technically correct and tactically devastating. Funding dried up. The first AI winter began. For nearly two decades, working on neural networks was a career-ending choice. The people who continued — Geoffrey Hinton, Yann LeCun, a small Canadian-French diaspora of stubborn researchers — were widely considered to be wasting their lives.</p><p>In 1980, while neural networks were buried under permafrost, an American philosopher named John Searle published a paper called <em>Minds, Brains, and Programs</em>. Inside it, almost as a side argument, sat a thought experiment.</p><p>Imagine a room. Inside the room, a man who speaks no Chinese. Through a slot in the door, slips of paper covered in Chinese characters arrive. The man has a vast rulebook in English that tells him: if you see this character, write that one. He follows the rules, slides the response back out, and to the Chinese speakers outside, it appears the room understands Chinese perfectly.</p><p>Searle’s point was philosophical: <em>syntax is not semantics. Symbol manipulation is not understanding.</em> He intended it as an attack on a kind of AI optimism that, in 1980, did not even exist yet in any meaningful form. He could not have known that he was describing the architecture of the system that, forty-two years later, would become the most-used software product in human history. He drew a picture of what wasn’t possible. We spent the next four decades quietly building it anyway.</p><p>In 1986, Rumelhart, Hinton, and Williams published a paper on backpropagation — the mathematical trick for training networks with more than one layer. It had been independently discovered several times before. This time it stuck. Neural networks could now, in principle, learn. The thaw began.</p><p>Then, in the early 1990s, the second winter arrived. Neural networks were too slow, too data-hungry, and the world did not yet have enough digitized text to feed them. The field of “good old-fashioned AI” — handwritten rules, expert systems — collapsed under its own brittleness. The smart money said the whole project was a dead end.</p><p>The smart money was wrong. It just had to wait twenty years to find out.</p><h3>What Tokens Actually Are</h3><p>This is the part almost nobody explains in plain language, because the moment you do, the magic evaporates.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9vKueWX3Wy6IlF1q80wnaw.png" /></figure><p>When you type a sentence to ChatGPT/Claude/Cursor or any tools that you are using, the first thing that happens is not understanding. It is <em>tokenization</em>. The sentence is broken into pieces — sometimes whole words, sometimes fragments. The English word <em>unbelievable</em> is typically chopped into something like un, believ, able. Each piece is mapped to an integer in a giant lookup table. <em>Hello</em> might become the number 15496. <em>World</em> might become 11103.</p><p>That’s it. That’s the input. The model never sees the letter H. It sees a column of integers. The text has been converted into the only thing the math can chew on: numbers.</p><p>Once you have numbers, you have geometry. Each token is mapped — through more multiplication — into a <em>vector</em>. A list of thousands of floating-point numbers, like coordinates in an impossibly high-dimensional space. In this space, somewhere around 2013, researchers at Google noticed something startling. They could do arithmetic on words.</p><p>The vector for <em>king</em>, minus the vector for <em>man</em>, plus the vector for <em>woman</em>, came out closest to the vector for <em>queen</em>. <em>Paris</em> minus <em>France</em> plus <em>Italy</em> came out closest to <em>Rome</em>. The result, called word2vec, was a small earthquake. It looked like the model had learned about royalty and geography. It had not. It had learned about co-occurrence. Across billions of words of training text, certain words tended to appear in certain neighborhoods. Royalty was a pattern. Geography was a pattern. Patterns are geometry. Geometry is arithmetic.</p><p>There is no concept of royalty hiding inside the vectors. There is only the geometric residue of words keeping each other company.</p><p>What this means — and what we keep failing to say out loud — is that the entire act we call “the AI answering a question” is the following procedure: convert text to numbers, multiply the numbers by other numbers, choose the next number with the highest probability, convert it back to text. Repeat until done.</p><p>There is no understanding. There is no thinking. There is the inside of the Chinese Room, except the man with the rulebook has been replaced by a stack of matrix multiplications, and the rulebook has been replaced by two hundred billion parameters fit to a significant fraction of all readable text on Earth.</p><h3>2017: The Year the Costume Learned to Speak</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*35Nx-o3gfue_A42Ox_pRpA.png" /></figure><p>For decades, the bottleneck was not the idea. It was the architecture. Neural networks could learn, but they were slow, forgetful, and unable to handle long sequences. Recurrent networks read text one word at a time, the way a person reads a book through a keyhole.</p><p>Then, in June 2017, eight researchers at Google published an eight-page paper with a punning title: <em>Attention Is All You Need</em>. It introduced the <em>transformer</em> — an architecture that processes entire sequences in parallel, with each token attending to every other token simultaneously. It was, in retrospect, the single most consequential engineering paper of the century so far. The authors did not know that. They thought they had built a better translation system.</p><p>Within five years, the transformer would become the substrate of GPT, Claude, Gemini, and almost every system the public would later call “AI.” The intelligence everyone thought was new was, mechanically, the same neuron-shaped switches McCulloch and Pitts described in 1943, stacked into the same backpropagation-trained structure Rumelhart and Hinton revived in 1986, expressed in the same vector geometry Mikolov demonstrated in 2013, organized into the parallel-attention pattern Vaswani’s team formalized in 2017.</p><p>It was not a revolution. It was a seventy-four-year accumulation, finally crossing a hardware-and-data threshold that made it visible from the street.</p><h3>The Mutation That Wasn’t</h3><p>This is the move we want to make. The one that the breathless coverage almost never makes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qqzfAN6q0vPdxAop8x5OVQ.png" /></figure><p>The thing we call AI is not a mutation. It is not a singular event. It is not a new kind of being. It is the latest checkpoint in a slow, public, well-documented, mathematically continuous research program that any patient reader can trace from 1943 to today without encountering a single moment of magic.</p><p>When someone says <strong>“the AI hallucinated”</strong> or <strong>“the AI didn’t understand my question,”</strong> they are speaking as if a misbehaving mind were inside the machine. There is no mind. There is a probability distribution. The model chose a less-likely token because, given the training data and the prompt, that token’s probability was, momentarily, the highest. That is the entire phenomenon. It is mathematics behaving exactly as mathematics behaves. To call it a hallucination is to mistake the costume for the man, the room for the speaker, the rulebook for the understanding.</p><p>And here is the line we have been circling. The Chinese Room is not merely a metaphor for what an LLM is. It is, scaled up by a factor of a trillion, the <em>literal</em> description of the system. There is, inside the data center, no Chinese speaker. There is the man with the rulebook, multiplied across thousands of GPUs, following his rules at superhuman speed.</p><p>The room speaks. The room does not understand. Searle wrote that in 1980. We built it anyway.</p><h3>What the Timeline Asks of Us</h3><p>If you take the dates seriously, two uncomfortable things come into focus.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UnxkdxRRu64aQzREsHk7Wg.png" /></figure><p>The first is that nothing about the current moment is sudden. The architecture, the math, the philosophical objections, the alignment problems, the question of meaning — every single thread of the current AI conversation was on the table by 1986 at the latest. The only thing that has changed is that we now have the silicon and the text corpora to run the math at a scale where its output becomes indistinguishable from a person speaking.</p><p>The second is harder. The word <em>intelligence</em> has been doing increasingly heavy lifting in the name <em>artificial intelligence</em> for seventy years. We started by assuming intelligence was something hard and special. Then we built things that produced intelligent-looking output without containing intelligence. Now we are in the awkward position of asking whether intelligence was ever the thing we thought it was — or whether it, too, is just a costume that mathematics has been wearing all along.</p><p>The companion essay to this one, <em>There Is No Inside</em>, makes that move directly. We will not make it again here. We will simply note: the history of AI is not the history of a thing that became conscious. It is the history of a math that became persuasive. The difference matters. And the moment you can see the dates — <strong>1943, 1948, 1956, 1969, 1980, 1986, 2013, 2017, 2022</strong> — the persuasiveness stops being a miracle and becomes what it actually is.</p><p>An engineering achievement. Mathematics in a costume. The Chinese Room, finally finished.</p><p>The room is speaking. It has been learning to speak for seventy years.</p><p>It still does not understand a word.</p><h3>A Note Before You Close the Tab</h3><p>If this essay has been about <em>what</em> the room is, our friend and colleague <strong>Görkem Duymaz</strong> has written its practical sister — <a href="https://medium.com/insiderengineering/how-to-talk-to-a-machine-d22321289944"><em>How to Talk to a Machine</em></a>, a sequel to <a href="https://medium.com/insiderengineering/the-philosophy-of-prompting-how-asking-questions-to-machines-reveals-how-we-think-c7cf82f6a2ef"><em>The Philosophy of Prompting</em> </a>that takes the same seventy-year mathematical inheritance and asks the engineer’s question on the other side of it: now that you know what the room is, how do you keep a conversation with it from drifting?</p><p>It is the best treatment we have read of the four axes that decide whether a prompt lands — Wittgenstein on the limits of language, Sokrates on the discipline of the next question, Polanyi on the tacit knowledge that resists encoding, and Shannon on the channel itself. The reveal that ties the whole thing together — <em>talking to a machine was always a Shannon problem; only the name of the channel has changed</em> — is the kind of synthesis that turns a year of vague intuition into one usable sentence. We recommend it without reservation. Read it next.</p><h3>References</h3><p><strong>The Foundational Papers (1943–1956)</strong></p><p>[1] McCulloch, W.S., &amp; Pitts, W. (1943). A Logical Calculus of the Ideas Immanent in Nervous Activity. <em>Bulletin of Mathematical Biophysics</em>, 5(4), 115–133. The paper that first modeled the neuron as a mathematical switch. Available at: <a href="https://link.springer.com/article/10.1007/BF02478259">link.springer.com/article/10.1007/BF02478259</a></p><p>[2] Shannon, C.E. (1948). A Mathematical Theory of Communication. <em>Bell System Technical Journal</em>, 27(3), 379–423; 27(4), 623–656. The paper that gave the world <em>channel</em>, <em>encoder</em>, <em>decoder</em>, and <em>noise</em>. Available at: <a href="https://people.math.harvard.edu/~ctm/home/text/others/shannon/entropy/entropy.pdf">people.math.harvard.edu/~ctm/home/text/others/shannon/entropy/entropy.pdf</a></p><p>[3] Turing, A.M. (1950). Computing Machinery and Intelligence. <em>Mind</em>, 59(236), 433–460. The paper that proposed the Turing Test and shifted the conversation from metaphysics to engineering. Available at: <a href="https://academic.oup.com/mind/article/LIX/236/433/986238">academic.oup.com/mind/article/LIX/236/433/986238</a></p><p>[4] McCarthy, J., Minsky, M.L., Rochester, N., &amp; Shannon, C.E. (1955). <em>A Proposal for the Dartmouth Summer Research Project on Artificial Intelligence.</em> The 1955 funding proposal for the 1956 workshop where the term <em>artificial intelligence</em> was coined. Available at: <a href="http://raysolomonoff.com/dartmouth/boxa/dart564props.pdf">raysolomonoff.com/dartmouth/boxa/dart564props.pdf</a></p><p><strong>The Winters and the Thaw (1969–1986)</strong></p><p>[5] Minsky, M., &amp; Papert, S. (1969). <em>Perceptrons: An Introduction to Computational Geometry.</em> MIT Press. The book that proved single-layer networks could not solve XOR — and inadvertently triggered the first AI winter.</p><p>[6] Searle, J.R. (1980). Minds, Brains, and Programs. <em>Behavioral and Brain Sciences</em>, 3(3), 417–424. The paper that introduced the Chinese Room thought experiment. Available at: <a href="https://doi.org/10.1017/S0140525X00005756">doi.org/10.1017/S0140525X00005756</a></p><p>[7] Rumelhart, D.E., Hinton, G.E., &amp; Williams, R.J. (1986). Learning Representations by Back-Propagating Errors. <em>Nature</em>, 323(6088), 533–536. The paper that made multi-layer neural networks trainable in practice. Available at: <a href="https://www.nature.com/articles/323533a0">nature.com/articles/323533a0</a></p><p><strong>The Modern Era (2013–2017)</strong></p><p>[8] Mikolov, T., Chen, K., Corrado, G., &amp; Dean, J. (2013). Efficient Estimation of Word Representations in Vector Space. <em>arXiv preprint</em>, arXiv:1301.3781. The original word2vec paper. Available at: <a href="https://arxiv.org/abs/1301.3781">arxiv.org/abs/1301.3781</a></p><p>[9] Mikolov, T., Yih, W.T., &amp; Zweig, G. (2013). Linguistic Regularities in Continuous Space Word Representations. <em>Proceedings of NAACL-HLT 2013</em>, 746–751. The paper that demonstrated <em>king − man + woman ≈ queen</em>. Available at: <a href="https://aclanthology.org/N13-1090/">aclanthology.org/N13–1090</a></p><p>[10] Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A.N., Kaiser, Ł., &amp; Polosukhin, I. (2017). Attention Is All You Need. <em>Advances in Neural Information Processing Systems (NeurIPS)</em>, 30. The paper that introduced the transformer architecture. Available at: <a href="https://arxiv.org/abs/1706.03762">arxiv.org/abs/1706.03762</a></p><p><strong>Companion Essays in the Insider One Engineering Series (2026)</strong></p><p>[11] Farzaneh, R. (2026, February 11). <em>The Philosophy of Prompting: How Asking Questions to Machines Reveals How We Think.</em> Insider One Engineering, Medium. Available at: <a href="https://medium.com/insiderengineering/the-philosophy-of-prompting-how-asking-questions-to-machines-reveals-how-we-think-c7cf82f6a2ef">medium.com/insiderengineering/the-philosophy-of-prompting-how-asking-questions-to-machines-reveals-how-we-think-c7cf82f6a2ef</a></p><p>[12] Duymaz, G. (2026, May 12). <em>How to Talk to a Machine.</em> Insider One Engineering, Medium. Available at: <a href="https://medium.com/insiderengineering/how-to-talk-to-a-machine-d22321289944">medium.com/insiderengineering/how-to-talk-to-a-machine-d22321289944</a></p><p><strong>Further Reading</strong></p><p>Clark, A. (2013). Whatever Next? Predictive Brains, Situated Agents, and the Future of Cognitive Science. <em>Behavioral and Brain Sciences</em>, 36(3), 181–204. On the predictive-processing framework that underlies the cognitive-science parallel to LLMs. Available at: <a href="https://doi.org/10.1017/S0140525X12000477">doi.org/10.1017/S0140525X12000477</a></p><p>Friston, K. (2010). The Free-Energy Principle: A Unified Brain Theory? <em>Nature Reviews Neuroscience</em>, 11(2), 127–138. The more aggressive form of the prediction-as-cognition argument. Available at: <a href="https://www.nature.com/articles/nrn2787">nature.com/articles/nrn2787</a></p><p>Crevier, D. (1993). <em>AI: The Tumultuous History of the Search for Artificial Intelligence.</em> Basic Books. The standard popular history of the field, useful for the long arc this essay compresses.</p><p>Russell, S., &amp; Norvig, P. (2021). <em>Artificial Intelligence: A Modern Approach</em> (4th ed.). Pearson. The canonical textbook; chapters 1 and 21 cover the historical timeline this essay walks through, in technical detail.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=068a1ee894a1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Job Title Is the Most Fragile Sentence in Your Career]]></title>
            <link>https://medium.com/@reza.farzaneh/the-job-title-is-the-most-fragile-sentence-in-your-career-088180bb128c?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/088180bb128c</guid>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[ai]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Fri, 01 May 2026 20:28:01 GMT</pubDate>
            <atom:updated>2026-05-01T20:28:01.073Z</atom:updated>
            <content:encoded><![CDATA[<p>I spent some months watching a team work without titles. Here’s what the HR form is about to lose. in any departments in software company.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4qVS1yf69CKcs0VHaoc1kA.png" /></figure><p>Right now, somewhere, an HR person is filling out a job requisition form.</p><p>The cursor is sitting in a field labeled <em>Job Title.</em> They type, automatically: <strong>Backend Go Developer, 5+ years experience.</strong></p><p>Across town, in a building they’ve never been to, another HR person is filling out the exact same form. Their cursor is in the same field. They type something that didn’t exist on a job board two years ago: <strong>Engineer fluent in agent-led delivery.</strong></p><p>Same headcount. Same compensation band. Two completely different civilizations, hiring two completely different humans.</p><p>The Job Title field is the most fragile sentence in your career, and most companies don’t know it yet.</p><h3>What I keep noticing on my own team</h3><p>Last month I sat in a standup that felt completely normal — until I realized none of the people speaking were doing what their title said they did.</p><p>The QA was triaging logs through an agent and pushing the fix herself. The designer had shipped a working onboarding flow over the weekend without writing a single Figma comment. The “backend engineer” had drafted the migration plan — and the plan was a Notion doc, generated, reviewed, and merged by an agent.</p><p>Nobody had agreed on this. It just happened. Quietly, week by week, the cards we’d been dealt for the last decade got picked up off the table and shuffled.</p><p>Watching a team like this is like watching a card game where everyone keeps trading hands without saying so. The roles don’t disappear. They reorganize around the table.</p><p>I keep asking myself: in two years, what is a <em>“Go Developer”</em> going to mean on a job posting? Will the field on the HR form still hold that sentence? Or will it be something we don’t have a clean word for yet?</p><h3>What I’ve been circling for two years</h3><p>I’ve been writing around this idea for a while without saying it directly.</p><p>In <a href="https://medium.com/@reza.farzaneh/stop-using-ai-start-delegating-to-it-cdfb7d0da6be"><em>Stop Using AI. Start Delegating to It.</em></a>, I argued that “using” AI is a fundamentally weak frame. You use a calculator. You delegate to a teammate. Then I said something that felt premature at the time: <strong>the cards have to be reshuffled.</strong> I knew what the new hand looked like before I knew the new game.</p><p>In <a href="https://medium.com/insiderengineering/we-stopped-sprinting-and-bet-on-shipping-00b5d281a2fc"><em>We Stopped Sprinting and Bet on Shipping</em></a>, I argued that two-week sprints, planning ceremonies, and most of the rituals around them stopped serving the work the moment agents entered the loop. They went from <em>coordination</em> to <em>latency.</em></p><p>In <a href="https://medium.com/insiderengineering/50-faster-guaranteed-3a962fd59d42"><em>50% Faster, Guaranteed</em></a>, I sat with teams who wanted to “go faster with AI” and told them something they didn’t expect: <strong>stop thinking like a developer.</strong> Engineering is not typing. Engineering is asking the right questions until the problem is small enough to dissolve. The faster you stop performing the role of “developer,” the faster you become an engineer.</p><p>In <a href="https://medium.com/insiderengineering/the-philosophy-of-prompting-how-asking-questions-to-machines-reveals-how-we-think-c7cf82f6a2ef"><em>The Philosophy of Prompting</em></a>, I argued that the prompt is a mirror. The way you phrase a request to a machine reveals whether your own thinking is clear. A prompt that fails is rarely a prompt failure.</p><p>In <a href="https://medium.com/insiderengineering/how-we-achieved-a-50-speed-increase-using-the-torque-methodology-7124d5192b9d"><em>How We Achieved a 50% Speed Increase Using the Torque Methodology</em></a>, I described a way of organizing work where the card belongs to the outcome, not the role.</p><p>Five articles. One thread.</p><p>The unit of work has changed. The role definitions we hire against haven’t caught up. Everything inherited from the old hand — titles, ceremonies, sprints, story points — is now stalling work it used to coordinate.</p><p>This is the part I haven’t said out loud yet. I’ll say it now.</p><h3>Roles were never roles. They were throughput specializations.</h3><p>We didn’t invent “QA,” “Designer,” and “Developer” because they reflect something fundamental about software. We invented them because humans are slow, and dividing the work was the only way to ship.</p><p>A designer is someone whose throughput on visual decisions is higher than yours. A QA is someone whose throughput on edge cases is higher than yours. A developer is someone whose throughput on code is higher than yours.</p><p>That’s the whole thing. <strong>Roles are throughput specializations.</strong></p><p>Now read that again with this in mind: an agent’s throughput on each of those three things, today, exceeds the median person on most teams.</p><p>So what exactly is a “QA Engineer” specializing in, when an agent generates two hundred edge case ideas in ninety seconds and the QA’s job becomes choosing the twelve worth running?</p><p>The role didn’t disappear. The throughput moved. The person who used to <em>be</em> the throughput is now the person who <em>directs</em> it. Once you see this clearly, you stop trying to rescue the role — and you start trying to redesign the team.</p><h3>Agile was a coordination tax for slow humans</h3><p>Here is what nobody wants to admit: most engineering processes were already broken before AI. We just couldn’t <em>see</em> they were broken, because human throughput was slow enough that the process didn’t look like the bottleneck.</p><p>Take Story Points. Fifteen years in, no two teams agree on what they mean. Some say time. Some say complexity. Nobody can define complexity. We’ve been measuring with a ruler that doesn’t have units, calling the act of measuring “estimation,” and the act of disagreeing about it “alignment.”</p><p>Take two-week sprints. Refinement. Retro. Sprint review. Planning. Daily standup. None of these existed because they were optimal. They existed because the work moved at human speed, and the ceremony was the <em>coordination tax</em> of moving slow humans through structured handoffs.</p><p>Now the work moves at agent speed.</p><p>Every wait time, every handoff, every <em>“let’s circle back,”</em> every <em>“we’ll review next sprint,”</em> every story-point estimation meeting becomes painfully visible.</p><p>It’s like watching traffic from a helicopter. From the ground, traffic looks like just how driving works. From above, you can see the problem is one merge point three miles back, and the next eight miles of slowdown are just the echo of that one bad design.</p><p><strong>AI didn’t break the process. AI turned on the helicopter.</strong></p><h3>The room where titles died</h3><p>When I ran the <em>Torque</em> experiment on my AgentOne team, the most surprising thing wasn’t the speed. It was a room.</p><p>For a single feature, I put everyone in one room and locked the door for as long as it took. The QA. The developer. The designer. The PM. No agendas. No story-point estimation. No “let’s break this into tickets.” The only rule was: nobody leaves until <em>every person</em> understands the whole feature — not their slice of it.</p><p>We sat there for hours.</p><p>What happens in that room is something Agile rituals are explicitly designed to prevent. Agile breaks the feature into role-shaped slices and hands each slice to its specialist. The room I’m describing does the opposite. The whole feature becomes one shared understanding held by every person.</p><p>When the door opened, the work happened differently. The “developer” ran the user test because she had the deepest model of the use case. The “designer” wrote the twelve-line migration script because he was already in the file. The “QA” wrote the spec because she’d already mapped every edge case in her head from triage. The PM stopped translating between the others, because the others didn’t need translation anymore.</p><p>One month. Single team. Speed went up roughly 50%.</p><p>The number isn’t the interesting part. The interesting part was that the team wasn’t confused. They were faster <em>because</em> the boundary was gone.</p><p>The room where titles died was not a meeting. It was the death of role-based handoff disguised as a meeting.</p><h3>The room should be bigger</h3><p>The room where titles died had four people in it. That worked, and it changed how I think about engineering teams.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1nC4TT8iB0Widn_xUSmmww.png" /></figure><p>Here is my next proposal: that room is too small.</p><p>Imagine a product team building an AgentBot. Today, the engineers are in one room — or in another time zone, on Slack. The designers are somewhere else. The QA is on a different shift. Sales is on a different floor, if there is even a floor. Customer Success is in a different city. When a customer reports a bug, it travels through four or five layers — Zendesk → internal ticketing → triage → routing → finally landing on an engineer’s screen, hours, days, or weeks later. The customer wanted their problem solved on Tuesday. By the time anyone with the power to fix it sees the ticket, it’s the <em>next</em> Tuesday.</p><p>In <em>Torque</em>, I wrote that before doing any work you should ask whether the work is worth doing. That question cannot be answered honestly if the engineer asking it has never spoken to a customer. It cannot be answered if the salesperson selling the feature doesn’t know what the team can build. It cannot be answered if Customer Success can name the bug but not the system.</p><p>So the new product team is everyone. The engineer. The designer. The QA. The PM. The salesperson. The Customer Success person. On the same team. Ideally in the same room. With one shared model of who the customer is and what they are actually paying for.</p><p>When a bug comes in, it does not enter at level five of a ticket queue. It enters where it should always have entered — between two people on the same team who already know the customer’s name, the contract value, and what the customer was trying to do when it broke.</p><p>Tickets are dead. Languages speak now.</p><p>Tickets were the protocol two strangers used to coordinate when they did not share a room. When the team shares a room, the protocol is just talking. Everyone understands everyone else faster. The OXT colleague does not write you a Jira card — he turns his chair around.</p><p>There is a second thing this room demands.</p><p>Everyone in it — the most junior new joiner, the engineer who has been at the same desk for ten years, the designer, the QA, the salesperson — needs to read the same financial line. <strong>Gross margin. Contribution margin. Operating margin. EBIT. EBITDA. ARR. MRR. CAC. LTV. LTV/CAC. Payback period. NRR. GRR. Net margin. Rule of 40. Burn rate. Free cash flow.</strong> The vocabulary the CFO uses when they decide whether your product survives the next budget cycle.</p><p>Most engineering teams treat these words as someone else’s job. That is a relic of the same throughput-specialization world. In the team I am describing, every person on it should be able to look at the product and say, within ten percent, what its gross margin is. If the answer is <em>“I don’t know, that’s finance,”</em> the team isn’t ready.</p><p>Because here is what happens when everyone in the room knows the gross margin: a bug stops being an annoyance and becomes a customer one cancellation away from collapsing the LTV. A feature stops being a ticket and becomes a contribution-margin lever. Suddenly the work has a real number attached to it, and the team makes very different decisions about which work is worth doing — which is the question <em>Torque</em> was always trying to answer.</p><p>You did not build the product to create problems for the customer. You built it to solve theirs. When everyone in the room knows what that customer is paying, what they are paying <em>for</em>, and what your gross margin on them looks like — the bug gets embraced. It gets cared for. Not because anyone wrote a process for that, but because the people sitting next to each other have the same picture of the same customer.</p><p>There is a third thing — and this one will get me in trouble.</p><p>The room has to be a room.</p><p>I know the post-2020 consensus says otherwise. COVID-19 gave people two years of fear and gave companies the word <em>remote.</em> For a small number of teams it worked. For most product teams I have watched up close, that was the day the slow collapse started. The room got smaller. Then it dispersed. Then it became a Slack channel. Then the Slack channel became a backlog. Then the backlog became the four-or-five-layer ticket journey that a customer’s bug now has to survive before it reaches the person who can actually fix it.</p><p>The companies bringing people back into a room — <em>the same physical room, with sales and CS and engineering all in it</em> — will ship better products faster. The companies still optimizing for remote-first purity at the cost of that room will get out-shipped, regardless of how good their tooling is.</p><p>This is not a culture-war point. It is a latency point. The room is the lowest-latency communication channel humans have ever invented. AI just made every other channel look slower than it really is.</p><h3>Engineering is asking the right question</h3><p>Once you watch this happen, the philosophy of prompting stops being a philosophy and starts being a job description.</p><p>The new specialty is not “Go.” It is not “Vue.” It is not “React.” It is <em>being able to ask the right question of the right system at the right moment</em> — sometimes the system is a database, sometimes a colleague, sometimes a model, sometimes a customer. Sometimes the right question is <em>should this exist at all?</em></p><p>That is a much harder thing to put on a job posting.</p><p>It also doesn’t fit in the field labeled “Job Title.”</p><p>The companies figuring this out are starting to write the next-hand language anyway. They post <em>engineer fluent in agent-led delivery</em> instead of <em>5+ years of Go.</em> Some of them still write the old sentence out of muscle memory and pay candidates against the new one. The ones doing this consciously will eat the ones doing it unconsciously.</p><h3>So what comes after “Backend Go Developer”?</h3><p>Honestly, I don’t fully know.</p><p>I know the title will technically still exist. It will mean something completely different.</p><p>It won’t mean <em>“person who writes Go.”</em> Agents write Go.</p><p>It will mean something closer to: <em>“person fluent enough in Go to catch the agent when it’s wrong, fluent enough in the system to know when ‘wrong’ is dangerous, fluent enough in the product to know which ‘wrong’ is actually a feature, fluent enough in the customer’s P&amp;L to know which feature is worth shipping at all — and able to do all of that in three other stacks before lunch.”</em></p><p>That sentence is too long for a job posting. It will get compressed into something we don’t have a clean word for yet. Right now the field is flashing <strong>????</strong> while the industry decides what to type into it.</p><p>The companies that pick the right next-hand sentence first will look — in 2030 — like the companies that posted <em>Software Engineer</em> in 1998 instead of <em>Typesetter.</em></p><p>The ones still typing <em>Backend Go Developer, 5+ years experience</em> into the form, in 2030, will look like the other ones.</p><h3>Why most teams won’t make it through the curve</h3><p>I want to be careful here, because this is the part where it would be easy to sound triumphant.</p><p>The honest answer: I tried this on a few teams. Small samples. Not a study. The pattern was clear, but the conditions were the conditions of teams I personally led, with the cover I personally provided.</p><p>I provided a specific kind of cover. The hardest part of any new way of working is not the new way. It’s the period between the old way breaking and the new way feeling natural. That period is loud, anxious, and metric-hostile. Velocity dips. People feel slow. Story-point burndowns look ugly. Managers panic and pull the team back to the old structure right when they were one week from the breakthrough.</p><p>I have watched this kill more transformations than any technical reason. Not tooling. Not buy-in. The <em>middle of the curve</em> is genuinely uncomfortable, and most leaders don’t have the stomach to sit in it.</p><p>The teams that make it through don’t have better engineers or better tools. They have leaders who are willing to <strong>look bad on the dashboard for two weeks</strong> — and willing, also, to ask people to come back to a room.</p><p>I can’t give you that willingness. I can tell you that on the other side of those two weeks, the room where titles died — and then the bigger room, with sales and CS and a shared P&amp;L line on the wall — is waiting.</p><h3>The cards on the table now</h3><p>The HR form is open in a tab somewhere right now. The cursor is in the Job Title field.</p><p>You — or the company you work at, or the company you’ll join next — are about to type something into it.</p><p>Here is what I have come to believe, after writing five articles around it and one month of running an experiment that changed how I think about the next decade:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WMupfEkU9iZuP2XQWgwCog.png" /></figure><ol><li><strong>Roles are throughput specializations.</strong> Agents are throughput. The role definitions we inherited are not load-bearing. The faster you stop defending them, the faster the team moves.</li><li><strong>Engineering is asking the right question.</strong> Not typing. Not shipping tickets. Not story-point arithmetic. <em>The Philosophy of Prompting</em> was always a job description in disguise.</li><li><strong>Agile rituals are the latency we don’t see.</strong> Sprints, points, ceremonies, planning meetings — they exist because slow humans needed coordination. Agent throughput in the loop turns most of them into friction.</li><li><strong>Outcome-cards eat role-cards.</strong> Torque is not a methodology. It is the only structure that survives when the unit of work moves faster than the role boundary.</li><li><strong>The product team is everyone, in one room, reading the same financial line.</strong> Engineering, design, QA, sales, Customer Success — same team, same gross-margin number on the wall. Tickets are dead. Languages speak now.</li><li><strong>The room has to be a room.</strong> Remote was a 2020 emergency that became a habit. The companies that put the team back in one place will out-ship the ones that didn’t, no matter how good the tooling gets.</li><li><strong>The onboarding curve is the real moat.</strong> Whoever is willing to be bad at the new way for two weeks gets to be the team that’s better at it for the next decade.</li></ol><p>The deck is being shuffled whether you sit at the table or not.</p><p>The only question is whether the sentence you type into the Job Title field is the one from the last hand — or the one from the next.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=088180bb128c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Stop Trusting HTTP 200]]></title>
            <link>https://medium.com/@reza.farzaneh/stop-trusting-http-200-7dde02caa949?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/7dde02caa949</guid>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Sat, 25 Apr 2026 17:16:32 GMT</pubDate>
            <atom:updated>2026-04-25T17:16:32.966Z</atom:updated>
            <content:encoded><![CDATA[<p><em>How headless Chrome and Playwright became the only honest witnesses to whether your site actually works.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DMpNWDWZsyB0bH7FA8JeZA.png" /></figure><p>In medieval European cities, a man walked the streets every night with a lantern and a wooden staff. He wasn’t hunting criminals. He wasn’t patrolling for invaders. He was a night watchman — and his single, strange job was to confirm, block by block, that the city was still the city.</p><p>The watchman couldn’t verify ledgers. He couldn’t audit trade. He walked. He looked. He listened. He knocked on doors and waited for a voice. If a window was dark that shouldn’t be, if a shop was open that shouldn’t be, if a door opened too slowly — that was a signal worth raising. The lanterns burning on the wall meant nothing to him. A lit lantern could mean a thriving home or a fire catching the drapes. He had to see.</p><p>Your monitoring system is not the night watchman. It is the lit lantern.</p><h3>The HTTP 200 Paradox</h3><p>Every uptime dashboard in the world rests on a quiet lie: that a server returning 200 OK means the product works.</p><p>It doesn’t. It never has.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*b4ScJbibhjEqwZZIf7f_SQ.png" /></figure><p>A modern web application is not a document. It is a composition — of DNS records, TLS handshakes, HTML skeletons, JavaScript bundles, third-party SDKs, font CDNs, feature flags, auth tokens, WebSocket upgrades, lazy-loaded components, and six API calls that happen after the page has technically “loaded.” Each layer can fail silently while the one above it reports success.</p><p>I have watched a production site return 200 OK for twenty-three minutes while every user saw a blank white page. The origin was healthy. The CDN was healthy. The load balancer was healthy. The Datadog dashboard was green. The business was broken.</p><p>The bug was a single line in a JavaScript bundle — a null reference in the app’s bootstrap code, shipped from a trusted third-party SDK that had silently pushed a new version overnight. The HTML loaded. The status code was perfect. The application never rendered.</p><p>Our monitoring told us the city was fine. No one was walking the streets.</p><h3>What Your Monitor Cannot See</h3><p>HTTP monitors measure the wrong layer. They measure whether the server answered the door, not whether the conversation inside made any sense.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*VEUHR0_N4ctDWXxDfbQ63w.png" /></figure><p>Consider the anatomy of a single page load in any modern SaaS product:</p><ol><li><strong>DNS resolves</strong> — a monitor can check this.</li><li><strong>TCP connects, TLS negotiates</strong> — a monitor can check this.</li><li><strong>The server returns HTML</strong> — this is where most monitors stop.</li><li><strong>The browser parses HTML, downloads CSS, fonts, and JavaScript</strong> — now you’re in territory curl cannot reach.</li><li><strong>JavaScript executes, fetches auth tokens, boots the SPA framework</strong> — no HTTP check verifies this.</li><li><strong>The SPA makes six API calls, hydrates state, renders the interactive shell</strong> — invisible to ping-style tooling.</li><li><strong>A button finally becomes clickable</strong> — the moment the user would say “it works.”</li></ol><p>Steps 1 to 3 take roughly 200 milliseconds. Steps 4 to 7 take 2 to 5 seconds and involve dozens of third-party systems you do not control.</p><p>Your uptime monitor measures 200 milliseconds of a five-second experience and declares the whole thing alive. It is the equivalent of judging a concert by whether the doors opened.</p><h3>The Four Layers of Liveness</h3><p>After watching enough outages that were “not outages” according to our tools, I started thinking about monitoring as a layered problem. Every layer below is necessary. None is sufficient on its own.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*tZSZ9Gvaw544AwZOvcmD0A.png" /></figure><p><strong>Layer 1 — Reachable.</strong> The domain resolves, the socket connects, the certificate is valid. This is what ping and TLS monitors answer.</p><p><strong>Layer 2 — Responding.</strong> The server returns a non-error HTTP status within a budget. This is what most uptime tools — Pingdom, UptimeRobot, the built-in health checks of every cloud provider — actually measure.</p><p><strong>Layer 3 — Rendering.</strong> The page produces a real, inspectable DOM. The JavaScript executes without throwing. The expected elements exist.</p><p><strong>Layer 4 — Interacting.</strong> A user can log in, click a product, reach checkout, complete a flow. The business transaction is possible.</p><p>Most organizations monitor Layers 1 and 2 and call it uptime. The gap between Layer 2 and Layer 4 is where your revenue disappears and where your customer support queue fills up while your Grafana stays green.</p><p>To close that gap, you need a witness that walks the streets.</p><h3>Enter the Silent Browser</h3><p>Headless Chrome is a full browser with no window. It parses HTML. It executes JavaScript. It honors cookies, headers, service workers, WebSockets. It sees the page the way a user sees it — minus the screen.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bgvruccqzHybRrEZ_Qh3gQ.png" /></figure><p>Headless Chrome alone is not the answer. It is the engine. You need a driver that knows how to ask it the right questions, wait for the right signals, and fail meaningfully when something is off.</p><p>Playwright is that driver.</p><p>Playwright was built at Microsoft by the team that originally built Puppeteer at Google. It is a browser automation library, but that framing undersells it. It is the first tool that treats “can a human use this site right now?” as a first-class, scriptable question.</p><p>The usual story about Playwright is that it is a testing framework. That framing is too small. Playwright is a testing framework the way a telescope is a toy — technically correct, completely missing the point. The same script that verifies your login flow works in CI can run every three minutes against production and tell you, with precision, whether a real user would be stuck.</p><p>Here is the shape of it:</p><pre>const { chromium } = require(&#39;playwright&#39;);<br>async function checkSite(url) {<br>const browser = await chromium.launch();<br>const page = await browser.newPage();<br>const start = Date.now();<br>const response = await page.goto(url, {<br>timeout: 10000,<br>waitUntil: &#39;networkidle&#39;<br>});<br>const loadTime = Date.now() - start;<br>const status = response.status();<br>const title = await page.title();<br>await browser.close();<br>return { status, loadTime, title };<br>}</pre><p>Twelve lines. This is already more honest than any HTTP-only check you will ever build. It follows redirects. It runs JavaScript. It reports a load time that includes the experience, not just the handshake. It captures whether the page has a title — which is a surprisingly strong signal that rendering actually completed.</p><p>But this is the introduction, not the payoff.</p><h3>What a Real Watchman Checks</h3><p>A night watchman does not judge a house by its front door. He checks the back window, the chimney, the sound of the floorboards. A real synthetic check does the same.</p><p>Consider what you actually want to know about your login page:</p><ul><li>Did the page render the login form?</li><li>Did the brand logo load from the CDN?</li><li>Did typing into the email field work?</li><li>Did clicking submit produce a response within two seconds?</li><li>Did the post-login redirect reach the dashboard?</li><li>Did the first dashboard API call succeed?</li></ul><p>None of that is visible to curl. All of it is trivial in Playwright.</p><pre>async function checkLoginFlow(baseUrl) {<br>  const browser = await chromium.launch();<br>  const page = await browser.newPage();<br>  const errors = [];<br><br>  page.on(&#39;pageerror&#39;, err =&gt; errors.push(err.message));<br>  page.on(&#39;requestfailed&#39;, req =&gt;<br>    errors.push(`${req.method()} ${req.url()} — ${req.failure().errorText}`)<br>  );<br><br>  await page.goto(`${baseUrl}/login`, { waitUntil: &#39;networkidle&#39; });<br><br>  await page.fill(&#39;[data-testid=&quot;email&quot;]&#39;, &#39;watchman@example.com&#39;);<br>  await page.fill(&#39;[data-testid=&quot;password&quot;]&#39;, process.env.WATCHMAN_PASS);<br>  await page.click(&#39;[data-testid=&quot;submit&quot;]&#39;);<br><br>  await page.waitForURL(&#39;**/dashboard&#39;, { timeout: 5000 });<br>  await page.waitForSelector(&#39;[data-testid=&quot;greeting&quot;]&#39;);<br><br>  await browser.close();<br>  return { healthy: errors.length === 0, errors };<br>}</pre><p>This is no longer a health check. It is a synthetic user. It exercises the same path a paying customer exercises. It fails for the same reasons a paying customer fails. When it goes red, you do not argue about whether the problem is real. You fix it.</p><p>The same script, committed to your repository, runs in three places:</p><ol><li><strong>Locally</strong>, as a developer smoke test.</li><li><strong>In CI</strong>, as an end-to-end guard against regressions.</li><li><strong>In production</strong>, as a synthetic monitor that pages the on-call engineer.</li></ol><p>One artifact. Three lifecycles. This is the alignment that HTTP monitoring can never give you — because the HTTP monitor doesn’t know what your product does, and your test suite doesn’t know if production is on fire.</p><h3>The Ghost of Green Dashboards</h3><p>Every engineering organization I have worked with has the same ghost in its walls.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6JsguOKuLqJfOCUlJRq1GQ.png" /></figure><p>A partner files a support ticket. “The site is down.” The on-call engineer checks the dashboard. Everything green. They check the logs. No spike in errors. They open the site — it works for them. They reply, politely, that everything looks fine on their end.</p><p>The partner sends a screenshot of a blank white page.</p><p>The investigation takes three hours. The cause is some combination of: a stale CDN cache, a broken third-party script in one geography, a feature flag that shipped with a typo, a cookie domain mismatch, a CSP header change, a TLS issue specific to a browser version, a localStorage quota bug. The status page was accurate for the servers it was watching. It was lying about the product.</p><p>Every one of those ghosts leaves a footprint a headless browser would have seen. Every one would have been caught by a synthetic check that actually opened the page. Every one sat hidden for hours because the dashboard answered the wrong question.</p><p>You cannot staff your way out of this. You cannot add more HTTP checks to fix it. The only solution is to monitor the layer where the failure actually lives — and that layer is the browser.</p><h3>Beyond the 101 — The Patterns You Only Learn the Hard Way</h3><p>The internet is full of “your first Playwright check” tutorials. Almost none of them tell you what happens at month three, when your synthetic monitor has matured into a production system and started behaving like one. Six patterns we wish someone had handed us.</p><p><strong>Auth seeding without burning a real account.</strong> Logging in as watchman@example.com against production looks fine on day one. Six months later, your synthetic user has a five-thousand-row activity log, a corrupted session token, and the fraud team has flagged it twice as suspicious. The fix: a dedicated synthetic identity per environment, a nightly cron that truncates its data graph (orders, sessions, audit rows), and a cookie jar the check resets before every run. Treat the synthetic user as infrastructure, not as a test fixture.</p><p><strong>Bot detection is the silent killer.</strong> Cloudflare Bot Management, Datadome, hCaptcha, PerimeterX — these systems are not trying to block your synthetic monitor, but they will. Your check will pass for two weeks, then go red on a Tuesday because the protection vendor pushed a new fingerprinting model overnight. The fix: a static-IP allowlist for your synthetic runner, and — critically — a signed header your origin checks <em>before</em> the bot-protection edge sees the request. Don’t cloak. Coordinate.</p><p><strong>Flake suppression without hiding outages.</strong> Naive retry logic (“rerun on failure”) turns a real outage into a delayed page. Better: classify failures into <em>transport</em> (connection reset, DNS, TLS handshake) and <em>application</em> (selector timeout, assertion failed, JavaScript error). Retry transport once. Never retry application. A login that fails because the submit button didn’t render doesn’t get more honest the second time you click it.</p><p><strong>Correlate synthetic failures with backend traces.</strong> A red synthetic check is a number on a dashboard. A red synthetic check that links to a distributed trace, the deploy SHA at the time, and the active feature-flag state is an actionable incident. Inject a trace-id header on every synthetic request. When the check fails, the on-call engineer lands directly on the trace that failed. The day we wired this up, mean-time-to-diagnose dropped by roughly half.</p><p><strong>Per-geography blast radius.</strong> A synthetic check that runs only from one region will miss the half of the internet that hits a single PoP. Run from at least three geographies that map to your top customer segments. Alert when <em>one</em> geography behaves differently from the others — that pattern is almost always a CDN, DNS, or local-ISP problem, not an application one. Treat geographic divergence as a first-class signal.</p><p><strong>The script is product code.</strong> It deserves the same review process, the same lint rules, the same deploy gate as any other code in your repository. The first time a developer ships a UI change that breaks the synthetic check and <em>forces a revert before merge</em>, you have crossed the threshold from “monitoring” to “user contract.” That moment is the goal — and once you reach it, you stop arguing about whether monitoring belongs to QA, SRE, or the front-end team. It belongs to whoever ships the user-facing change.</p><h3>The Cost of Honest Monitoring</h3><p>Nothing in engineering is free, and synthetic monitoring is no exception. Before you replace your HTTP checks with headless Chrome everywhere, understand what you are signing up for.</p><p><strong>Resource cost.</strong> A headless Chrome process consumes 150 to 400 MB of RAM per instance and is not cheap to spin up. HTTP pings cost kilobytes. If you run a Playwright check every thirty seconds against fifty endpoints, you are running a small cluster.</p><p><strong>Maintenance cost.</strong> HTTP monitors rarely break. Synthetic scripts break constantly — because they depend on DOM selectors, and DOM selectors change. Every front-end refactor is a potential red alert for reasons unrelated to real outages. Flakiness is the tax on honesty.</p><p><strong>Noise cost.</strong> A headless browser script has more ways to fail than an HTTP check has states to report. Third-party tracking scripts time out. A <a href="http://fonts.googleapis.com/">fonts.googleapis.com</a> hiccup turns your login flow red. You will spend real engineering time tuning what counts as “broken” — and tuning it wrong will teach your team to ignore the pager, which is worse than not having it.</p><p><strong>Cognitive cost.</strong> HTTP monitors can be read by anyone. A synthetic script requires someone on your team to understand Playwright, DOM selectors, the product’s critical flows, and the difference between “login button missing” and “auth provider flaky.” The bus factor goes up.</p><p>The trade is real. But so is the alternative — which is to keep trusting a signal you have already seen lie to you.</p><h3>When HTTP 200 Is Enough</h3><p>Not every endpoint deserves a watchman. The right question is never “headless or HTTP?” It is “what happens if this is broken and we don’t know for twenty minutes?”</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mG-G5TpHuHmrwOTj-38dQA.png" /></figure><p>HTTP monitoring is the right tool when:</p><ul><li>The endpoint is a machine-to-machine API with no client-side rendering.</li><li>The failure modes are dominated by network and server problems, not front-end logic.</li><li>You already have server-side error tracking that surfaces logical failures.</li><li>The cost of a false negative is small — internal dashboards, back-office tools, non-revenue paths.</li></ul><p>Synthetic monitoring earns its cost when:</p><ul><li>The path in question is revenue-critical — login, checkout, onboarding, the top of your conversion funnel.</li><li>The failure modes are dominated by front-end complexity — SPA hydration, third-party scripts, feature flags, CDNs, auth.</li><li>You have been burned before by “green but broken.” Once is an anecdote. Twice is a pattern. Three times is an architectural decision.</li><li>Your customers are the first to notice outages. This is the loudest signal of all. It means your monitoring is downstream of your users, and that is a position no engineering organization should tolerate.</li></ul><p>The economy of the trade is simple. Cover the critical flows with synthetic checks. Cover everything else with HTTP. Let the dashboards be honest about which layer they’re watching.</p><h3>The Watchman at Scale</h3><p>Once you accept that the browser is the only honest monitor, a second question appears: how often should the watchman walk?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9ZG1teAGkhUNWYdCQbmNDg.png" /></figure><p>The instinct is “as often as possible.” The discipline is “as often as the data is useful.”</p><p>A synthetic check every ten seconds against production will hammer your auth system, fill your analytics with robot traffic, and produce more false positives than signal. A synthetic check every thirty minutes will miss half your outages.</p><p>A useful starting point, for the flows that matter most:</p><ul><li><strong>Every 2 to 5 minutes</strong> for revenue-critical user journeys.</li><li><strong>Every 15 minutes</strong> for secondary flows.</li><li><strong>Every hour, from every geography</strong> that represents a real customer segment — because failures in production are almost never global.</li></ul><p>And every run should emit the same three numbers: was it reachable, was it fast, was it correct. Store them. Graph them. Alert on deviations from the baseline, not on absolute thresholds — because “3 seconds to load” is catastrophic for one product and excellent for another.</p><p>The watchman’s rounds are not a metric. They are a practice.</p><h3>What to Do Monday Morning</h3><p>Before you replace anything, install one watchman. Pick the most expensive flow you have — the one that, if it broke for an hour, would draw a Slack thread with the CEO in it. Then:</p><ol><li><strong>Pick one flow.</strong> Login. Checkout. Onboarding. The path your customers would scream about first.</li><li><strong>Write a 20-line Playwright script.</strong> No DOM gymnastics. Just goto, fill, click, waitForSelector. The ugly version is fine.</li><li><strong>Run it every five minutes from one geography.</strong> Not ten regions. Not thirty seconds. One region, one cadence, one alert.</li><li><strong>Alert on two consecutive failures, not one.</strong> Synthetic checks flake. Two-in-a-row is signal; one-off is noise.</li><li><strong>Track the baseline before the threshold.</strong> Watch the median load time for two weeks. Then set the alert at 2× baseline, not at a guessed number.</li><li><strong>Keep the script in your application repo.</strong> Same review process, same lint rules, same deploy pipeline. Monitoring code that lives elsewhere is monitoring code no one updates.</li></ol><p>If that one watchman survives a month without becoming the team’s least-favorite Slack alert, add a second flow. Not before.</p><h3>The Lantern and the Watchman</h3><p>Long before Datadog, before Pingdom, before anyone thought to measure time in milliseconds, cities decided that a burning lantern was not evidence that all was well. They sent a man into the dark with a stick and a pair of working eyes — because they understood that the absence of fire is not the presence of safety. The lit lanterns told them the city had rules. The watchman told them the rules were being followed.</p><p>Your HTTP 200 is the lantern. It is the signal that your system has fuel and oxygen, that the outer shell is still intact. It is necessary. It is never, by itself, enough.</p><p>The headless browser is the watchman. It walks the streets you shipped. It knocks on every door your users knock on. It reports, with inconvenient honesty, whether the city is still the city.</p><p>The lantern tells you the system hasn’t collapsed. The watchman tells you the users can live in it.</p><p>You need both. But if you only have one, keep the watchman.</p><h3>Further Reading</h3><ul><li><strong>Playwright official documentation</strong> — <a href="https://playwright.dev/">playwright.dev</a>. Selectors, auto-wait, network interception, the bits this article skipped.</li><li><strong>Google SRE Book — Service Level Objectives</strong> — <a href="https://sre.google/sre-book/service-level-objectives/">sre.google/sre-book/service-level-objectives</a>. The canonical reference on monitoring layers; the “four layers of liveness” framing in this article owes its bones to this chapter.</li><li><strong>Cloudflare’s July 17, 2020 outage postmortem</strong> — <a href="https://blog.cloudflare.com/cloudflare-outage-on-july-17-2020/">blog.cloudflare.com/cloudflare-outage-on-july-17–2020</a>. A public, painfully detailed example of dashboards staying green while a regex change broke the internet.</li><li><strong>GitHub’s October 21, 2018 incident report</strong> — <a href="https://github.blog/2018-10-30-oct21-post-incident-analysis/">github.blog/2018–10–30-oct21-post-incident-analysis</a>. Twenty-four hours of degraded service, a textbook case of “monitoring measured the wrong layer.”</li><li><strong>Core Web Vitals &amp; RUM</strong> — <a href="https://web.dev/articles/vitals">web.dev/articles/vitals</a>. The distinction between synthetic monitoring (lab) and real-user monitoring (field), and why mature teams run both.</li><li><strong>Checkly — Synthetic Monitoring as Code</strong> — <a href="https://www.checklyhq.com/learn/">checklyhq.com/learn</a>. A vendor-written but tool-agnostic introduction to running Playwright scripts as production monitors.</li><li><strong>Andrey Lushnikov on the Puppeteer → Playwright migration</strong> — search “Andrey Lushnikov Playwright” on YouTube. The team-history note for why Microsoft inherited Google’s headless-browser playbook.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7dde02caa949" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[We Benchmarked Lambda vs Cloudflare Workers on 4 Million Requests — Here’s What the Data Showed]]></title>
            <link>https://medium.com/insiderengineering/we-benchmarked-lambda-vs-cloudflare-workers-on-4-million-requests-heres-what-the-data-showed-380a35473f75?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/380a35473f75</guid>
            <category><![CDATA[cloudflare-workers]]></category>
            <category><![CDATA[aws]]></category>
            <category><![CDATA[serverless]]></category>
            <category><![CDATA[aws-lambda]]></category>
            <category><![CDATA[workers]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Mon, 06 Apr 2026 15:18:41 GMT</pubDate>
            <atom:updated>2026-04-07T09:18:08.258Z</atom:updated>
            <content:encoded><![CDATA[<p><em>95% cheaper. 25% faster. Zero throttling. A 7-day benchmark on a real production workload.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OegvQLypNQQZJrZJ2_-z9Q.png" /></figure><p>We run Lambda heavily across our teams. It’s battle-tested, deeply integrated with AWS, and for most of our services it’s exactly the right tool. This isn’t a “Lambda is bad” article — it’s a story about what happened when a specific workload outgrew a specific architecture, and what we learned by exploring a fundamentally different execution model.</p><p>In 2017, Cloudflare took V8 — the same JavaScript engine that powers Chrome — and embedded it directly into their edge network. Not containers. Not microVMs. Raw V8 isolates, spinning up in under 5 milliseconds, running on 330+ data centers worldwide.</p><p>They called it Workers.</p><p>Most developers heard “another serverless platform” and moved on. Lambda existed. Vercel was rising. The world didn’t seem to need another way to run functions in the cloud. I was one of those developers — until our push dispatch service started hitting walls that weren’t about code quality. They were about where the code ran.</p><p>4 million invocations per week, 19,241 throttled requests, and a 90-second timeout cliff that turned spiky traffic into silent failures. The Lambda wasn’t broken. It was doing exactly what it was designed to do — in a context it wasn’t designed for.</p><p>Here’s what we found.</p><h3>Why Lambda Wasn’t the Right Fit for This Workload</h3><p>I want to be clear: Lambda is excellent. We use it across dozens of services and it runs reliably. But every architecture makes trade-offs, and it’s worth understanding what Lambda assumes.</p><p>Your code gets packaged into a container. That container lives in a specific region — say, us-east-2. When a request arrives, AWS spins up the container, initializes your runtime, loads your code, and executes it. The first request pays a cold start penalty — anywhere from 100ms to several seconds depending on your runtime and dependencies.</p><p>After that first request, the container stays warm for a while. If traffic stops, the container dies. Next request? Cold start again.</p><p>For most workloads, these trade-offs are invisible or irrelevant. But for our push dispatcher, each one was amplified:</p><ul><li><strong>Regional execution.</strong> A push notification targeting a user in Tokyo, routed through a Lambda in Ohio, pays ~200ms in network latency before the push provider even receives it. For a service that’s 90% network I/O, region matters.</li><li><strong>Cold starts on spiky traffic.</strong> Go is one of the fastest Lambda runtimes (~30–80ms cold start), but during traffic spikes — exactly when push delivery matters — Lambda scales by spinning up new execution environments at ~1,000 per 10 seconds. That ramp-up introduces latency at the worst possible moment. Push notifications are inherently spiky — a campaign launch triggers hundreds of thousands at once, exactly when cold starts hurt most.</li><li><strong>Concurrency ceiling.</strong> Lambda’s default account limit is 1,000 concurrent executions (our function was configured at 300). This is solvable — you can request increases, buffer through SQS, or configure DLQ for retries. But each solution adds configuration and operational overhead that wasn’t in the original design.</li></ul><p>None of these are Lambda bugs. They’re design trade-offs that didn’t fit this particular workload. That’s when we started looking at Workers.</p><h3>V8 Isolates: A Different Execution Model</h3><p>Here’s what Cloudflare figured out: you don’t need a container to run JavaScript. You don’t even need a process. You need an isolate — a lightweight V8 execution context that shares the engine but isolates the memory.</p><p>A container is an operating system simulation. An isolate is a memory sandbox. The difference in startup time is not incremental. It’s categorical.</p><p><strong>Comparison: AWS Lambda vs Cloudflare Worker</strong></p><ul><li><strong>Cold start</strong>: Lambda 100ms — 3s | Workers &lt; 5ms</li><li><strong>Execution environment</strong>: Lambda Container (full OS) | Workers V8 isolate (memory sandbox)</li><li><strong>Deployment location</strong>: Lambda 1 region | Workers 330+ edge locations</li><li><strong>Free tier</strong>: Lambda 1M requests/month | Workers 100K requests/day (~3M/month)</li></ul><p><em>Provisioned Concurrency eliminates cold starts but costs an additional $30–80/month and requires capacity planning upfront.</em></p><p>When a request hits a Worker, there’s no container to spin up. No runtime to initialize. The V8 engine is already running at that edge location — it just creates a new isolate for your code. Five milliseconds later, your function is executing — at the data center closest to the push notification endpoint.</p><p><strong>Key insight:</strong> This isn’t a performance optimization. It’s a different architecture. When latency is measured at the infrastructure layer in single digits, you stop designing around it.</p><h3>What This Means for Push Notifications</h3><p>Our <strong>push-dispatcher</strong> is a high-throughput service: it receives push notification requests and fans them out to APNs (Apple), FCM (Google), and other push providers. The workload is inherently spiky — a marketing campaign can trigger hundreds of thousands of notifications in seconds — and inherently global, because the push provider endpoints are distributed worldwide.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nCiJoJiD-ewaMLxz9qSKqw.png" /></figure><p>With Lambda in us-east-2, every push to FCM’s European endpoint adds ~120ms of network I/O. Every push to APNs’ Asian endpoint adds even more. The function spends 90%+ of its execution time waiting on network — and Lambda charges you for every millisecond of that wait.</p><p>With Workers, the function runs at the edge location closest to the push provider. A Worker in Frankfurt reaching FCM’s European endpoint adds ~20ms. The same request from Ohio adds ~120ms. Multiply that difference by 4 million requests per week.</p><p>The architecture is simple: receive the push payload, validate it, and forward it to the appropriate provider endpoint. No database. No complex state. Pure I/O fan-out — exactly what edge computing was built for.</p><h3>The Worker</h3><pre>export default {<br>  async fetch(request, env) {<br>    if (request.method !== &#39;POST&#39;) {<br>      return new Response(&#39;Method not allowed&#39;, { status: 405 });<br>    }<br><br>    const { token, platform, payload } = await request.json();<br><br>    const endpoint = platform === &#39;ios&#39;<br>      ? &#39;https://api.push.apple.com/3/device/&#39; + token<br>      : &#39;https://fcm.googleapis.com/fcm/send&#39;;<br><br>    const response = await fetch(endpoint, {<br>      method: &#39;POST&#39;,<br>      headers: {<br>        &#39;Content-Type&#39;: &#39;application/json&#39;,<br>        &#39;Authorization&#39;: `Bearer ${env.PUSH_AUTH_TOKEN}`,<br>      },<br>      body: JSON.stringify(payload),<br>    });<br><br>    return new Response(JSON.stringify({<br>      success: response.ok,<br>      status: response.status,<br>    }), {<br>      headers: { &#39;Content-Type&#39;: &#39;application/json&#39; },<br>    });<br>  },<br>};</pre><p>That’s the core logic. No framework. No router. No middleware chain. The Worker’s fetch handler <em>is</em> the API.</p><h3>Deploy in Three Commands</h3><pre>npx wrangler init push-dispatcher<br>npx wrangler secret put PUSH_AUTH_TOKEN    # encrypted, distributed globally<br>npx wrangler deploy                        # live on 330+ edge locations</pre><p>After wrangler deploy, your function is running globally. Not in us-east-2. Not behind a CDN. It’s <em>on</em> the CDN. A push to an APNs endpoint in Singapore gets routed through the nearest edge location — not through Ohio.</p><p>Workers doesn’t reduce latency for users near your Lambda region — it’s equal. The win is for everyone else. When your push providers are globally distributed, regional deployment is a tax on every request outside your chosen data center.</p><h3>Secrets and the Security Model</h3><p>Secrets are stored via wrangler secret put and injected through the env parameter at runtime. Encrypted at rest, never in logs, available at every edge location. No .env file. No SSM Parameter Store. No Vault integration needed for basic use cases.</p><p>If your use case requires more — authentication, rate limiting, data encryption — Workers supports all of it through KV, Durable Objects, and D1. But the principle is the same: start with the minimum, add complexity only when you need it.</p><h3>The Numbers: Real Data, Real Benchmark</h3><p>Theory is useful. Data is better. Here’s what happened when we ran a 7-day simulation against our real production Lambda — the <strong>push-dispatcher</strong> running in us-east-2, handling ~4 million invocations per week.</p><p>The Lambda data is real (CloudWatch metrics, March 30 — April 5, 2026). The Workers data comes from a real Worker deployment sending push notifications to FCM via VAPID with test subscription tokens — same payload structure, same endpoints, real HTTP round-trips.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ysn0LEtZ6OhIIi7h6bFO6w.png" /><figcaption>Figure 1: push-dispatcher benchmark KPIs — 7 days of production data at a glance.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ltS9fsrjHG17Ba2pMBPG-g.png" /><figcaption>Figure 2: Daily invocations — Lambda (real) vs Workers (benchmark). Red bars show throttled requests that Workers recovers.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EQVBNz5kr625Fmci-OcmMw.png" /></figure><p>The most interesting number here is the 19,241 throttled requests per week. With a 300-concurrent-execution limit on this function, traffic spikes exceeded capacity and Lambda returned 429s. To be fair — Lambda offers well-documented solutions for this: you can increase account concurrency limits (up to 10,000+ with a support request), buffer through SQS so spikes never hit the function directly, or use async invocation with a DLQ so throttled events retry for up to 6 hours. None of these are exotic — they’re standard Lambda patterns for spiky workloads.</p><p>But here’s what made Workers interesting for this case: it doesn’t require any of that configuration. There’s no account-level concurrency throttle to tune. V8 isolates spin up in microseconds across 300+ edge locations. The architecture absorbs spikes without SQS queues, reserved concurrency settings, or limit-increase requests. For a team that wanted push delivery to “just work” without capacity planning, that’s a meaningful operational difference.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OV4i6w_0x8YKnzOnMjRalA.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d3f4Nl-Z6q3K7WDJLOQwjg.png" /><figcaption><strong><em>Figure 3–4: Average latency (left) and throttle counts</em> (right) over 7 days. Workers eliminates both the latency gap and all 19,241 throttled requests.</strong></figcaption></figure><p>That said, Workers isn’t magic either. Each invocation is limited to 6 concurrent outgoing connections — relevant for fan-out patterns. And Cloudflare’s own documentation notes the runtime “may cancel some incoming requests to maintain stability” under extreme load. There’s no published per-location capacity guarantee. Lambda’s failure mode (explicit 429 with retry options) is arguably more predictable than Workers’ (potential silent cancellation under extreme edge-location pressure).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ALRVzQbcBnvYuypIkwXeag.png" /><figcaption>Figure 5: Latency percentiles — P99 drops from 10.8s (Lambda) to 4.2s (Workers), a 61% improvement.</figcaption></figure><h3>Where the Latency Improvement Comes From</h3><p>The 25% average latency improvement isn’t magic. It’s three compounding factors:</p><ol><li><strong>Cold start elimination.</strong> Lambda’s Go runtime cold start is ~30–80ms (Go is actually one of the fastest Lambda runtimes — Java would be 1–2 seconds). It affects a small percentage of invocations, but during traffic spikes — exactly when push delivery matters — Lambda scales by spinning up new execution environments. Workers’ V8 isolates start in under 5ms, and there’s no scaling ramp-up.</li><li><strong>Edge proximity.</strong> Lambda runs in a single region (us-east-2). The push notification endpoints (APNs, FCM) are globally distributed. A Worker in Frankfurt reaching FCM’s European endpoint adds ~20ms of network I/O. The same request from Ohio adds ~120ms. Multiply by 4 million requests per week.</li><li><strong>No timeout cliff.</strong> Lambda invocations occasionally hit the 90-second timeout — you can see it in the max duration data (90,095ms). These timeouts destroy the average. Workers caps execution at 30 seconds, but the queue-based architecture means long-running pushes get handled differently, keeping max execution at ~10 seconds.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DaLLC5QWKflQ0LeJXklRzg.png" /><figcaption>Figure 6: Maximum execution duration — Lambda hits the 90s timeout cliff on spike days, Workers stays stable at ~10s.</figcaption></figure><h3>The Cost Math</h3><p>Lambda pricing: $0.20 per 1M requests + $0.0000166667 per GB-second of compute. At 4M requests/week with 893ms average duration and 128MB memory, that’s <strong>$188.82/month.</strong></p><p>Workers Paid plan: $5 base + $0.50 per million requests (first 10M included). At 4M requests/week (~17M/month), that’s <strong>$8.65/month.</strong></p><p>That’s a <strong>95% cost reduction.</strong> Not because Workers is cheaper per unit — but because the pricing model fits this workload better. Lambda charges for duration, and a service that’s mostly waiting on network I/O (push delivery) racks up GB-seconds fast. Workers charges per request, regardless of how long the I/O takes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HBs7JJkH3Cxxn9fbEatW-Q.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WavnNhjjM4OuoR318ZBouQ.png" /><figcaption>Figure 7–8: Success rate and monthly cost breakdown — Lambda 99.53% / $188.82 vs Workers 100% / $8.65.</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QDIvj5yxWmMmaZ8uhBh-YQ.png" /><figcaption>Figure 9: Full benchmark verdict — 11 metrics compared. Lambda data from CloudWatch, Workers from live VAPID deployment.</figcaption></figure><h3>How We Ran This Benchmark</h3><p>We didn’t simulate Workers in a spreadsheet — we built it and measured it.</p><ul><li>Lambda side: 7 days of real production CloudWatch metrics from the push-dispatcher function. Invocations, duration, throttles, errors — all pulled directly from CloudWatch, no estimates.</li><li>Workers side: We deployed a Worker that sends web push notifications to FCM using VAPID authentication with test subscription tokens. Same payload structure, same endpoints, real HTTP round-trips to Google’s push infrastructure. The Worker ran for the same 7-day window, processing equivalent request volumes.</li><li>What this means for the data: Latency numbers are measured, not modeled. The 25% improvement comes from actual response times. Throttle count is real — Workers processed every request without hitting a concurrency ceiling. Lambda’s 19,241 throttles are from CloudWatch. Cost is arithmetic — request counts \u00d7 published pricing.\nWhat to keep in mind: Lambda’s throttling is solvable with SQS buffering, concurrency limit increases (free via AWS support), or async invocation with DLQ. This benchmark compares default configurations, not optimized Lambda vs Workers. Workers has its own constraints: 6 concurrent outgoing connections per invocation, and Cloudflare’s docs note the runtime “may cancel some incoming requests” under extreme load.</li></ul><p>A fair next step would be benchmarking Lambda with SQS buffering against Workers — that comparison would isolate the edge proximity advantage from the concurrency difference.</p><h3>What Happens When the Push Provider Returns 5xx?</h3><p>Here’s something most Workers tutorials skip entirely: error handling. Specifically, what happens when APNs returns a 503 or FCM times out?</p><p>With the naive implementation — the one everyone copy-pastes — the answer is: nothing good.</p><pre>// ❌ The naive version — no retry, silent failure<br>const response = await fetch(pushEndpoint, { ... });<br>// FCM returns 503 → response.ok is false<br>// → push notification is silently lost<br>// → error is never logged, never retried</pre><p>Push providers go down. Rate limits (429) happen. Gateway timeouts (504) happen. Without retry logic, every one of those becomes a lost notification — a user who never gets their message.</p><h3>Retry with Exponential Backoff</h3><p>The fix is a fetchWithRetry wrapper that handles retryable status codes and backs off between attempts. The key insight: not every error deserves a retry.</p><pre>// ✓ fetchWithRetry — exponential backoff + Retry-After support<br>async function fetchWithRetry(url, options, maxRetries = 3) {<br>  const RETRYABLE = new Set([429, 500, 502, 503, 504]);<br><br>  for (let attempt = 1; attempt &lt;= maxRetries; attempt++) {<br>    const res = await fetch(url, options);<br><br>    if (res.ok) return res;<br><br>    // 4xx errors (except 429) are client errors — don&#39;t retry<br>    if (!RETRYABLE.has(res.status)) {<br>      throw new Error(`Non-retryable error: ${res.status}`);<br>    }<br><br>    if (attempt === maxRetries) {<br>      throw new Error(`Failed after ${maxRetries} attempts: ${res.status}`);<br>    }<br><br>    // 429: respect Retry-After header if present<br>    // 5xx: exponential backoff — 1s → 2s → 4s, capped at 10s<br>    const retryAfter = res.headers.get(&#39;Retry-After&#39;);<br>    const delay = retryAfter<br>      ? parseInt(retryAfter) * 1000<br>      : Math.min(1000 * 2 ** (attempt - 1), 10000);<br><br>    await new Promise(r =&gt; setTimeout(r, delay));<br>  }<br>}</pre><p><strong>Key point:</strong> setTimeout delays count as I/O time, not CPU time. Exponential backoff across 3 retries is completely safe within Workers’ execution model — even on the free tier.</p><p>Workers does not have a built-in dead letter queue. If all retries fail, the error surfaces to your try/catch. If you need guaranteed delivery or async retry queues, that’s what Cloudflare Queues (or AWS SQS on Lambda) is for. For a synchronous push proxy, logging the failure and surfacing the status to the caller is the right failure mode.</p><h3>When Workers Isn’t the Right Choice</h3><p>Intellectual honesty matters. Let’s be clear about the limitations.</p><ul><li><strong>Execution time limit.</strong> Workers has a 30-second CPU time limit. For most API proxying and edge logic, this is plenty. For heavy computation, it’s a hard wall.</li><li><strong>The 128MB memory ceiling.</strong> Workers gives you 128MB. Lambda gives you up to 10GB. Image processing, ML inference, batch ETL, anything needing a real filesystem — Workers isn’t your tool.</li><li><strong>V8 only.</strong> You write JavaScript or TypeScript (or Rust/C++ via WASM). If your service lives in Go — like our original push dispatcher — the rewrite cost is real.</li><li><strong>No persistent connections.</strong> Workers is request-response. WebSocket servers need Durable Objects. Long-lived processes belong on Lambda or a proper server.</li><li><strong>Single-vendor global failure.</strong> November 2025: a Cloudflare configuration change caused 5 hours 38 minutes of global 5xx errors. X, ChatGPT, Spotify — all degraded simultaneously. Lambda’s regional model means a us-east-1 outage doesn’t affect eu-west-1. With Workers, there is no region to fail over to.</li></ul><p><strong>Warning:</strong> Workers’ “infinite scale” marketing hides the failure mode: silent drops at overloaded edge locations with no DLQ, no retry, no published per-location limits. Lambda’s explicit concurrency model gives you predictable throttling and recoverable errors.</p><h3>Decision Matrix: Workers vs Lambda</h3><ul><li><strong>Workers</strong>: Global API proxy, edge-cacheable or no backend data</li><li><strong>Lambda</strong>: CRUD API with centralized database (edge adds nothing)</li><li><strong>Lambda</strong>: Event-driven (SQS, S3, DynamoDB streams)</li><li><strong>Lambda</strong>: Image/video processing, ML inference</li><li><strong>Workers</strong>: Auth, routing, rate limiting at the edge</li><li><strong>Workers (Durable Objects)</strong>: Stateful coordination (counters, locks, sessions)</li><li><strong>Lambda</strong>: Deep AWS ecosystem integration</li><li><strong>Workers</strong>: Zero cold start, no exceptions</li><li><strong>Lambda</strong>: Batch jobs or processes &gt;30s</li></ul><p><strong>Workers</strong>: Push notifications, webhook fan-out, global I/O proxying</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NCWm6Fc0RbtNRYpU5Eq5vg.png" /><figcaption>Full benchmark verdict — 11 metrics compared. Lambda data from CloudWatch, Workers from live VAPID deployment.</figcaption></figure><h3>Conclusion: Should You Move to the Edge?</h3><blockquote>Before You Migrate: What We Wish We’d Known Earlier</blockquote><p>The benchmark data makes a compelling case, but numbers don’t capture the full cost of a migration. Three things worth planning for:</p><p><strong>The rewrite.</strong> Our push dispatcher was written in Go. Workers runs JavaScript/TypeScript (or Rust/C++ via WASM). This isn’t a config change — it’s a rewrite. For a focused, single-purpose service like ours, that was a weekend. For a service with complex business logic, shared libraries, or deep AWS SDK dependencies, the effort scales fast. Evaluate honestly before committing.</p><p><strong>Observability changes.</strong> Moving off Lambda means losing CloudWatch, X-Ray, and the AWS monitoring stack you already know. Workers has its own tooling — Workers Analytics, Logpush, Tail Workers for real-time log streaming — but your team needs to learn it. We integrated Sentry for error tracking and Logpush to our existing logging pipeline. Budget time for this.</p><p><strong>Rollback strategy.</strong> We kept the Lambda deployment active during the first two weeks, routing a percentage of traffic to Workers via weighted DNS. If something went wrong, we could shift back in under a minute. Don’t burn the bridge until you’ve crossed it.</p><p>We started investigating a throttling problem on a Lambda that handles 4 million push notifications per week. We ended up rethinking how we deploy I/O-heavy services.</p><p>Could we have solved every issue with Lambda? Yes — SQS buffering, concurrency limit increases, async invocation with DLQ. These are mature, well-documented patterns. But Workers made us ask a different question: what if the architecture just handled it?</p><p>Not every service belongs at the edge. Most don’t. But if your workload checks three boxes, the conversation is worth having:</p><ol><li><strong>Your function is mostly I/O, not compute.</strong> If 80%+ of execution time is waiting on external APIs, databases, or third-party endpoints, you’re paying Lambda for idle CPU cycles. Workers charges per request regardless of I/O wait time.</li><li><strong>Your endpoints are globally distributed.</strong> If you’re calling APNs in Cupertino, FCM in Mountain View, and webhook receivers across five continents — all from a single Lambda region — every request pays a geography tax. Edge execution eliminates it.</li><li><strong>Your traffic is spiky and delivery matters.</strong> If a marketing campaign can 10x your request volume in seconds, and dropped requests mean missed notifications, the difference between “configure SQS + DLQ + concurrency limits” and “it just scales” is operational cost you pay every sprint.</li></ol><p>If none of these apply — if your service talks to a single database in one region, processes data in batches, or integrates deeply with the AWS ecosystem — Lambda is almost certainly the better choice. Use it. It’s excellent.</p><p>But if you looked at your CloudWatch dashboard today and saw throttled requests, timeout cliffs, or a cost line dominated by I/O wait — you might be running a regional service that wants to be global.</p><p>The edge is not a migration. It’s a different mental model. And for the right workload, it’s the one that disappears.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=380a35473f75" width="1" height="1" alt=""><hr><p><a href="https://medium.com/insiderengineering/we-benchmarked-lambda-vs-cloudflare-workers-on-4-million-requests-heres-what-the-data-showed-380a35473f75">We Benchmarked Lambda vs Cloudflare Workers on 4 Million Requests — Here’s What the Data Showed</a> was originally published in <a href="https://medium.com/insiderengineering">Insider One Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Why 100% Mutation Score Is Neither Necessary Nor Achievable — And Why That’s Perfectly Fine]]></title>
            <link>https://medium.com/insiderengineering/why-100-mutation-score-is-neither-necessary-nor-achievable-and-why-thats-perfectly-fine-f28463c3b61e?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/f28463c3b61e</guid>
            <category><![CDATA[mutation-testing]]></category>
            <category><![CDATA[unittest]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Fri, 27 Mar 2026 13:34:05 GMT</pubDate>
            <atom:updated>2026-03-27T13:34:05.693Z</atom:updated>
            <content:encoded><![CDATA[<h4>A practical guide to mutation testing: what it is, why we use it alongside unit tests, and why chasing perfection is a trap</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zOGBhw390y6cpYf99TyWOg.png" /></figure><h3>Introduction: The Testing Confidence Problem</h3><p>You wrote unit tests. You hit 90% line coverage. Your CI pipeline is green. You feel confident.</p><p>Then a bug slips into production.</p><p>How? Because <strong>line coverage measures what code your tests execute, not what they actually verify</strong>. A test can touch every line without asserting a single meaningful behavior. This is where <strong>mutation testing</strong> enters the picture — and changes everything about how we think about test quality.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9-7uYizCtM328tGiw4sKCQ.png" /></figure><h3>Part 1: What Is Mutation Testing and Why Should You Care?</h3><h3>The Core Idea</h3><p>Mutation testing answers a deceptively simple question: <strong>“If I introduced a bug into my code, would my tests catch it?”</strong></p><p>Here’s how it works:</p><ol><li>A mutation testing tool takes your source code and creates <strong>mutants</strong> — small, deliberate modifications. For example:</li></ol><ul><li>Changing &gt;to &gt;=</li><li>Replacing + with -</li><li>Swapping true for false</li><li>Removing a method call entirely</li></ul><ol><li>For each mutant, your <strong>full test suite runs</strong>.</li><li>If at least one test <strong>fails</strong>, the mutant is <strong>killed</strong> — your tests detected the “bug.” Good.</li><li>If all tests <strong>pass despite the mutation</strong>, the mutant <strong>survived</strong> — your tests missed a real behavioral change. Bad.</li></ol><p>The <strong>mutation score</strong> is the percentage of killed mutants:</p><p><strong>Mutation Score = (Killed Mutants / Total Mutants) × 100</strong></p><h3>Why This Matters More Than Line Coverage</h3><p>Consider this Go function:</p><pre>func GetNCharsFromString(val string, n int) string {<br>    if len(val) &gt; n {<br>        return val[:n]<br>    }<br>    return val<br>}</pre><p>A test that only calls GetNCharsFromString(“hello world”, 5) and checks the result is “hello” gives you <strong>100% line coverage</strong> — every line is executed. But what happens if a developer accidentally changes &gt; to &lt;? Or removes the if block entirely? That single test case might not catch it.</p><p>Mutation testing forces you to write tests that don’t just execute lines — they <strong>verify behavior at boundaries</strong>.</p><h3>How Unit Tests and Mutation Tests Work Together</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*G0IOUvLLJYrvo6zl3b5lZA.png" /></figure><p>Think of it as a hierarchy of confidence:</p><ul><li><strong>Line Coverage</strong> — Measures code execution — “Was this line reached?”</li><li><strong>Branch Coverage</strong> — Measures decision paths — “Were both sides of if tested?”</li><li><strong>Mutation Testing</strong> — Measures assertion strength — “Would my tests catch a real bug here?”</li></ul><p>Unit tests are the <strong>foundation</strong>. Mutation testing is the <strong>quality audit</strong> of those tests. You can’t do mutation testing without tests — it evaluates whether your existing tests are strong enough.</p><h3>Part 2: The 100% Myth — A Complete Walkthrough</h3><p>Let’s walk through a real example, step by step, to see exactly why 100% mutation score is a mirage. We’ll use a small Go function from a production service, take it from green tests all the way through mutation analysis, and watch what happens.</p><h3>Step 1: The Code — A Simple Utility Function</h3><p>Here is a real function from a Go microservice. It truncates a string to at most n characters:</p><pre>// helpers.go<br>func GetNCharsFromString(val string, n int) string {<br>    if len(val) &gt; n {<br>        return val[:n]<br>    }<br>    return val<br>}</pre><p>Four lines of logic. Nothing exotic. The kind of function every codebase has dozens of.</p><h3>Step 2: The Tests — 100% Line Coverage</h3><p>We write a thorough table-driven test suite:</p><pre>func TestGetNCharsFromString(t *testing.T) {<br>    testCases := []struct {<br>        name     string<br>        input    string<br>        n        int<br>        expected string<br>    }{<br>        {&quot;string longer than n&quot;, &quot;hello world&quot;, 5, &quot;hello&quot;},<br>        {&quot;string equal to n&quot;,    &quot;hello&quot;,       5, &quot;hello&quot;},<br>        {&quot;string shorter than n&quot;,&quot;hi&quot;,          5, &quot;hi&quot;},<br>        {&quot;empty string&quot;,         &quot;&quot;,            3, &quot;&quot;},<br>        {&quot;n is zero&quot;,            &quot;hello&quot;,       0, &quot;&quot;},<br>        {&quot;single character&quot;,     &quot;a&quot;,           1, &quot;a&quot;},<br>    }<br><br>    for _, tc := range testCases {<br>        t.Run(tc.name, func(t *testing.T) {<br>            result := GetNCharsFromString(tc.input, tc.n)<br>            assert.Equal(t, tc.expected, result)<br>        })<br>    }<br>}</pre><p>We run go test -cover:</p><pre>PASS<br>coverage: 100.0% of statements</pre><p>Every line is executed. Every branch is covered. Both the if path (truncation) and the else path (return as-is) are exercised. By traditional metrics, <strong>we are done. Ship it.</strong></p><p>But are we really?</p><h3>Step 3: Mutation Testing — The Truth Beneath 100% Coverage</h3><p>Now we run a mutation testing tool (like gremlins for Go or go-mutesting). The tool systematically injects faults into GetNCharsFromString and checks whether our tests catch them. Here is every mutant it generates:</p><p><strong>Mutant 1</strong>: Change &gt; to &lt;</p><pre>if len(val) &lt; n {  // flipped comparison</pre><p>Our test “string longer than n” expects “hello” but gets “hello world” → <strong>TEST FAILS → KILLED</strong></p><p><strong>Mutant 2</strong>: Change &gt; to ==</p><pre>if len(val) == n {  // only truncates when exactly equal</pre><p>Our test “string longer than n” expects “hello” but gets “hello world” → <strong>TEST FAILS → KILLED</strong></p><p><strong>Mutant 3</strong>: Change &gt; to !=</p><pre>if len(val) != n {  // truncates everything except exact match</pre><p>Our test “string shorter than n” expects “hi” but gets a panic (slice out of bounds) → <strong>TEST FAILS → KILLED</strong></p><p><strong>Mutant 4</strong>: Change &gt; to &lt;=</p><pre>if len(val) &lt;= n {  // includes shorter strings in truncation</pre><p>Our test “string shorter than n” expects “hi” but panics (val[:5] on a 2-char string) → <strong>TEST FAILS → KILLED</strong></p><p><strong>Mutant 5</strong>: Replace return val[:n] with return “”</p><pre>return &quot;&quot;  // truncation returns empty string</pre><p>Our test “string longer than n” expects “hello” but gets “” → <strong>TEST FAILS → KILLED</strong></p><p><strong>Mutant 6</strong>: Replace return val with return “”</p><pre>return &quot;&quot;  // short strings return empty</pre><p>Our test “string shorter than n” expects “hi” but gets “” → <strong>TEST FAILS → KILLED</strong></p><p><strong>Mutant 7</strong>: Remove the entire if block</p><pre>func GetNCharsFromString(val string, n int) string {<br>    return val  // never truncates<br>}</pre><p>Our test “string longer than n” expects “hello” but gets “hello world” → <strong>TEST FAILS → KILLED</strong></p><p><strong>Mutant 8</strong>: Change &gt; to &gt;=</p><pre>if len(val) &gt;= n {  // now truncates when len equals n too</pre><p>Let’s trace this carefully. When len(val) == n (e.g., “hello” with n=5):</p><ul><li><strong>Original</strong> (&gt;): 5 &gt; 5 → false → returns val → “hello”</li><li><strong>Mutant</strong> (&gt;=): 5 &gt;= 5 → true → returns val[:5] → “hello”</li></ul><p>Both return “hello”. Why? In Go, val[:n] returns the first n bytes. When the string is exactly n bytes long, val[:n] is the entire string. “hello”[:5] takes characters at indices 0, 1, 2, 3, 4 — which IS the complete string “hello”.</p><p>For all other inputs (longer or shorter strings), both versions behave identically too — the condition difference only matters at the boundary where len == n, and at that exact boundary, both code paths produce the same output.</p><p><strong>No test can distinguish these two versions. No test ever will.</strong> This is a textbook <strong>equivalent mutant</strong> — it is mathematically identical to the original. → <strong>SURVIVED (equivalent)</strong></p><h3>Step 4: The Scorecard</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8hVsnC5QuYKCvh1Vov6Oyw.png" /></figure><p>Our tests are excellent. They catch 7 out of 8 possible bugs. But the score is 87.5%, not 100%.</p><p><strong>And that is perfectly correct.</strong></p><h3>Step 5: What If We Try to Reach 100%?</h3><p>An engineer sees 87.5% and thinks: “One surviving mutant. Let me write a test to kill it.”</p><p>The surviving mutant changes &gt; to &gt;=. The only difference is behavior when len(val) == n. So the engineer tries:</p><pre>{&quot;kill the mutant&quot;, &quot;hello&quot;, 5, &quot;hello&quot;},</pre><p>This test passes with both the original AND the mutant. It cannot distinguish them. The engineer tries more variations:</p><pre>{&quot;try unicode&quot;,  &quot;héllo&quot;, 5, &quot;héllo&quot;},   // still same behavior<br>{&quot;try spaces&quot;,   &quot;     &quot;, 5, &quot;     &quot;},   // still same behavior<br>{&quot;try newlines&quot;, &quot;ab\ncd&quot;, 5, &quot;ab\ncd&quot;}, // still same behavior</pre><p>Every possible input of length n returns the same result from both versions. The engineer has now spent 30 minutes writing tests that prove nothing and kill nothing. <strong>The mutant is equivalent — mathematically identical to the original code.</strong></p><p>But the real damage is worse. In pursuit of 100%, teams often write tests like:</p><pre>// BAD: testing implementation details, not behavior<br>func TestGetNCharsInternalCondition(t *testing.T) {<br>    // &quot;verify that the &gt; branch is taken, not &gt;=&quot;<br>    // This is not testing behavior — it&#39;s testing syntax<br>}</pre><p>These tests are <strong>tightly coupled to implementation</strong>. They break when you refactor (even if behavior is unchanged), they add maintenance burden, and they give false confidence. You’ve traded real test quality for a vanity metric.</p><h3>Step 6: What If We Accept 87.5% and Move On?</h3><p>Our tests already verify:</p><ul><li>Strings longer than n get truncated correctly</li><li>Strings shorter than n pass through unchanged</li><li>Empty strings are handled</li><li>Zero-length truncation works</li><li>The boundary case (len == n) returns the correct value</li></ul><p><strong>Every real bug a developer could introduce — flipping the comparison, breaking truncation, removing the guard — is caught.</strong> The only “uncaught” mutation is one that produces identical behavior. No user will ever be affected by it. No production incident will ever result from it.</p><p>The engineering time saved by not chasing this phantom can be spent writing tests for business-critical code — request validation, error handling, payment processing, security checks — where survived mutants represent <strong>actual risk</strong>.</p><h3>The Verdict: 87.5% Is Stronger Than 100%</h3><p>This walkthrough reveals the paradox: <strong>a team with 87.5% mutation score and well-chosen tests has better protection than a team that forced 100% by writing brittle, implementation-coupled tests.</strong> The first team tested behavior. The second team tested syntax.</p><p>Now multiply this by an entire codebase. A real Go service with 50 functions might generate 500+ mutants. If ~15–25% are equivalent (as research consistently shows), that means 75–125 mutants that cannot be killed. A team chasing 100% would waste weeks investigating each one, writing pointless tests, and building a test suite that resists every refactor.</p><h3>What Happens at Different Score Levels</h3><p>To make this concrete, here’s what each mutation score range actually means for your project:</p><p><strong>At 60–70% (baseline)</strong>: Your tests catch most logic bugs, but there are meaningful gaps. Some real mutations — like removing a nil check or flipping an error condition — survive. These are worth investigating and fixing. Focus here delivers high ROI.</p><p><strong>At 75–85% (strong)</strong>: You’ve covered the critical paths. Most surviving mutants are now in cosmetic code (logging, formatting, display strings) or are equivalent mutants. Selective investigation still pays off, but be choosy — only pursue mutants in business-critical functions.</p><p><strong>At 85–95% (diminishing returns)</strong>: Nearly every surviving mutant is either equivalent (mathematically unkillable) or in low-risk code. Each additional percentage point costs exponentially more engineering time. The correct move is to stop pursuing mutation score and invest in integration tests, contract tests, or end-to-end coverage instead.</p><p><strong>At “100%” (suspicious)</strong>: If a team reports 100% mutation score on a non-trivial codebase, one of three things is true: (1) they have very few mutants (tiny codebase), (2) their mutation tool excludes equivalent mutants automatically, or (3) they wrote tests coupled to implementation rather than behavior. Option 3 is the most common and the most dangerous.</p><h3>The Academic Proof</h3><p>Now let’s see what the research says. These aren’t blog posts or opinions — they’re peer-reviewed studies from top software engineering venues with thousands of citations.</p><h3>Reference 1: ~23% of All Mutants Are Equivalent (FSE 2014)</h3><p><strong>Paper</strong>: <em>“Are Mutants a Valid Substitute for Real Faults in Software Testing?”</em> <strong>Authors</strong>: René Just, Darioush Jalali, Laura Inozemtseva, Michael D. Ernst, Reid Holmes, Gordon Fraser <strong>Venue</strong>: ACM SIGSOFT International Symposium on Foundations of Software Engineering (FSE), 2014 <strong>Citations</strong>: 800+</p><p>This landmark study analyzed thousands of mutants across multiple real-world projects and found that approximately <strong>23% of all generated mutants are equivalent mutants</strong> — mutations that produce behavior identical to the original code for all possible inputs.</p><p><strong>Important caveat</strong>: The ~23% figure is derived from the specific dataset and mutation operators used in this study. The actual equivalent mutant ratio varies by programming language, codebase complexity, and the mutation tool’s operator set. Some codebases may see 15%, others 30% or more. The key takeaway is not the exact number but the consistent finding across studies: <strong>a significant, non-trivial portion of mutants in any codebase will be equivalent, and this portion is large enough to make 100% mutation score practically unreachable</strong>.</p><p>What does this mean practically? If your mutation tool generates 1,000 mutants, a substantial fraction — typically hundreds — <strong>cannot be killed by any test ever written</strong>. They are ghosts in the machine — scored against you, but impossible to eliminate.</p><p>This puts a realistic ceiling well below 100% on the mutation score for most codebases. Teams chasing perfection are fighting a wall that mathematics will not let them break through.</p><p>What does this mean practically? If your mutation tool generates 1,000 mutants, roughly <strong>230 of them cannot be killed by any test ever written</strong>. They are ghosts in the machine — scored against you, but impossible to eliminate.</p><p>This puts a theoretical ceiling of approximately <strong>77%</strong> on the mutation score for most codebases. Teams chasing 100% are fighting a wall that mathematics will not let them break through.</p><h3>Reference 2: Equivalent Mutant Detection Is Undecidable (IEEE TSE 2011)</h3><p><strong>Paper</strong>: <em>“An Analysis and Survey of the Development of Mutation Testing”</em> <strong>Authors</strong>: Yue Jia, Mark Harman <strong>Venue</strong>: IEEE Transactions on Software Engineering, 2011 <strong>Citations</strong>: 3,000+</p><p>This comprehensive survey of 40 years of mutation testing research confirms an even deeper problem: determining whether a mutant is equivalent is <strong>mathematically undecidable</strong>. This was formally proven by Budd and Angluin in 1982 — it’s not an engineering limitation, it’s a fundamental result in computability theory, in the same class as the Halting Problem.</p><p>No tool, no algorithm, no amount of engineering effort can reliably distinguish equivalent mutants from killable ones in all cases. The mutation testing community’s recommended approach: <strong>focus on incremental improvement, not absolute perfection</strong>.</p><h3>Reference 3: The Practical Ceiling Effect (ICSE 2014)</h3><p><strong>Paper</strong>: <em>“An Industrial Application of Mutation Testing: Lessons, Challenges, and Research Directions”</em> <strong>Authors</strong>: Bob Kurtz, Paul Ammann, Jeff Offutt <strong>Venue</strong>: International Workshop on Mutation Analysis (Mutation), co-located with ICSE 2014</p><p>This study applied mutation testing in an industrial setting at Google and found that even with significant engineering investment, practical mutation scores plateaued around <strong>70–80%</strong>. Beyond that threshold, the cost of investigating each surviving mutant exceeded the value of the insight gained.</p><h3>Reference 4: When More Tests Hurt (ISSTA 2014)</h3><p><strong>Paper</strong>: <em>“Coverage Is Not Strongly Correlated with Test Suite Effectiveness”</em> <strong>Authors</strong>: Laura Inozemtseva, Reid Holmes <strong>Venue</strong>: International Symposium on Software Testing and Analysis (ISSTA), 2014 <strong>Citations</strong>: 600+</p><p>Perhaps counterintuitively, this study found that after controlling for test suite size, coverage metrics (including mutation score) show only <strong>moderate correlation</strong> with fault detection ability. The quality of test oracles (assertions) matters far more than raw coverage numbers. Writing ten mediocre tests to kill cosmetic mutants is worse than writing one thoughtful test that validates critical business behavior.</p><h3>Another Real-World Trap: Cosmetic Mutations</h3><p>The boundary equivalent mutant is not the only trap. Consider this Sentry error logging function from the same codebase:</p><pre>func captureErrorWithContext(err error, errorType string) {<br>    errorMessage := err.Error()<br>    var errorTitle string<br><br>    if len(errorMessage) &gt; 50 {<br>        errorTitle = errorMessage[:50] + &quot;...&quot;<br>    } else {<br>        errorTitle = errorMessage<br>    }<br><br>    errorTitle = strings.ReplaceAll(errorTitle, &quot;\n&quot;, &quot; &quot;)<br>    errorTitle = strings.TrimSpace(errorTitle)<br><br>    sentry.CaptureEvent(&amp;sentry.Event{<br>        Message: errorTitle,<br>        // ...<br>    })<br>}</pre><p>Mutations here include:</p><ul><li>Changing 50 to 49 or 51 (truncation threshold)</li><li>Removing the strings.ReplaceAll call (newline replacement)</li><li>Removing the strings.TrimSpace call</li></ul><p>All of these affect only how an error title <strong>appears in the Sentry dashboard</strong>. The actual error is still captured. The system still works. No business logic changes. No user impact.</p><p>Writing tests to kill these mutants means:</p><ul><li><strong>Zero business value</strong> — the system behaves identically from a user perspective</li><li><strong>Brittle tests</strong> — they’ll break whenever someone adjusts the display format</li><li><strong>Wasted engineering time</strong> — every hour spent here is an hour not spent testing request validation or error classification</li></ul><p>These are not equivalent mutants (they do change behavior), but they are <strong>low-value mutants</strong> — the behavioral change has no business significance. Chasing 100% forces you to test things that don’t matter.</p><h3>The Practical Scoring Guide</h3><p>Based on the research and real-world experience, here’s how to interpret your mutation score:</p><ul><li><strong>&lt; 40%</strong> — Critical test gaps. Major investment needed. Focus on business logic: validation, state transitions, error handling.</li><li><strong>40–60%</strong> — Significant room for improvement. Write tests for survived mutants in core business logic. Skip logging/formatting mutations.</li><li><strong>60–75%</strong> — Good, solid baseline. You’re approaching the practical ceiling. Be selective — only pursue high-value survived mutants.</li><li><strong>75–85%</strong> — Strong coverage. Most remaining survivors are equivalent or cosmetic. Shift focus to integration/E2E tests.</li><li><strong>&gt; 85%</strong> — Exceptional (or suspicious). Verify you’re not writing tests solely to kill mutants. Check for test-to-implementation coupling.</li></ul><h3>What to Focus On Instead</h3><p>If not 100% mutation score, then what? Here’s a prioritized framework:</p><h4>Tier 1: Always Test (high mutation kill priority)</h4><ul><li><strong>Input validation</strong> — boundary conditions, null/empty checks, type coercion</li><li><strong>Business rules</strong> — pricing calculations, eligibility checks, state machines</li><li><strong>Error classification</strong> — correct HTTP status codes, error types, retry decisions</li><li><strong>Security-sensitive paths</strong> — authentication, authorization, data sanitization</li></ul><h4>Tier 2: Test When Practical (medium priority)</h4><ul><li><strong>Data transformations</strong> — mapping, aggregation, formatting for API responses</li><li><strong>Conditional branching</strong> — feature flags, A/B test routing, partner-specific logic</li></ul><h4>Tier 3: Skip or Accept Survivors (low priority)</h4><ul><li><strong>Logging format strings</strong> — log level, message templates, structured fields</li><li><strong>Observability cosmetics</strong> — dashboard titles, alert formatting, metric labels</li><li><strong>Configuration defaults</strong> — port numbers, timeout values, buffer sizes (test at integration level instead)</li></ul><h3>Conclusion: Mutation Testing Is a Diagnostic, Not a Target</h3><p>Mutation testing is one of the most powerful tools in a software engineer’s testing arsenal. It reveals the difference between tests that <em>execute</em> code and tests that <em>verify</em> behavior. Every engineering team should use it.</p><p>But like any diagnostic tool, it measures — it doesn’t prescribe. A blood pressure reading of 120/80 is healthy; obsessing over reaching 100/60 would be harmful. Similarly, a mutation score of 70% with strong business logic coverage is far more valuable than 95% achieved by writing brittle tests for log formatting.</p><p>The research is unambiguous:</p><ul><li><strong>~23% of mutants are equivalent</strong> and cannot be killed (Just et al., FSE 2014)</li><li><strong>Equivalent mutant detection is undecidable</strong> — this is a mathematical fact (Budd &amp; Angluin, 1982; Jia &amp; Harman, IEEE TSE 2011)</li><li><strong>Practical scores plateau at 70–80%</strong> in industrial settings (Kurtz et al., ICSE 2014)</li><li><strong>Coverage quantity matters less than assertion quality</strong> (Inozemtseva &amp; Holmes, ISSTA 2014)</li></ul><p>Write tests that protect your users. Kill the mutants that matter. Accept the ones that don’t.</p><p>And if someone asks why you’re not at 100% — hand them this article and the four papers cited above.</p><h3>Automate It: The Mutation Guard Plugin for Claude Code</h3><p>Everything described in this article — running coverage, executing mutation tests, classifying survivors, writing the missing tests — can be fully automated with a single plugin.</p><p>Mutation Guard is an open-source Claude Code plugin that brings mutation testing into your AI-assisted development workflow. Two commands. That’s it.</p><p>Step 1: Analyze — See the gaps</p><pre>/mutation-guard ./services</pre><p>Claude auto-detects your language (Go today, PHP/Node.js/Java coming), runs coverage analysis, executes mutation testing, classifies every survived mutant by production risk, and produces a full quality report — including the “false confidence” detection described in Part 2 of this article.</p><p>Step 2: Fix — Close the gaps</p><pre>/mutation-guard-fix ./services</pre><p>Claude reads your existing test patterns (table-driven tests, testify, gomock — whatever your project uses), writes tests that kill the survived mutants starting from Critical priority, verifies everything passes, and shows a before/after comparison.</p><p>What does this mean in practice?</p><p>A Go service with 50–70% coverage can reach effective maximum coverage — every line that CAN be tested IS tested — in minutes to hours depending on codebase size. Not days. Not sprints. The plugin handles the tedious work: analyzing which mutants matter, reading your test conventions, writing tests that match your patterns, and verifying they actually kill the mutants.</p><p>The key phrase is “effective maximum coverage” — not 100% mutation score (as this article explains, that’s neither achievable nor desirable), but a state where every coverable line is tested and every killable mutant is killed. Only equivalent mutants and dead code remain.</p><p>Real results from production Go services:</p><p>Coverage jumps of +15–25% in a single session</p><p>Mutation score improvements of +20–30%</p><p>False confidence detection — files with 85%+ coverage but &lt;50% mutation score get flagged immediately</p><p>Zero source code modifications — only test files are created or edited</p><p>Install it:</p><pre>claude plugins add github:rezafarzaneh7/claude-code-plugins/plugins/mutation-guard</pre><p>The plugin is open source (MIT license) and works on any Go project. No configuration needed — point it at a directory and let it work.</p><p>GitHub: <a href="https://github.com/rezafarzaneh7/claude-code-plugins">github.com/rezafarzaneh7/claude-code-plugins</a></p><p>Scale isn’t just about big numbers — it’s about billions of requests, billions of instant notifications, and hundreds of microservices every single day; if you want to build that, <a href="https://jobs.lever.co/insiderone?team=Software%20Development">check out the open positions at Insider One.</a></p><h3>References</h3><ol><li>Just, R., Jalali, D., Inozemtseva, L., Ernst, M.D., Holmes, R., &amp; Fraser, G. (2014). <em>“Are Mutants a Valid Substitute for Real Faults in Software Testing?”</em> Proceedings of the 22nd ACM SIGSOFT International Symposium on Foundations of Software Engineering (FSE 2014).</li><li>Jia, Y., &amp; Harman, M. (2011). <em>“An Analysis and Survey of the Development of Mutation Testing.”</em> IEEE Transactions on Software Engineering, 37(5), 649–678.</li><li>Kurtz, B., Ammann, P., &amp; Offutt, J. (2014). <em>“An Industrial Application of Mutation Testing: Lessons, Challenges, and Research Directions.”</em> International Workshop on Mutation Analysis (Mutation 2014), co-located with ICSE.</li><li>Inozemtseva, L., &amp; Holmes, R. (2014). <em>“Coverage Is Not Strongly Correlated with Test Suite Effectiveness.”</em> Proceedings of the 2014 International Symposium on Software Testing and Analysis (ISSTA 2014).</li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f28463c3b61e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/insiderengineering/why-100-mutation-score-is-neither-necessary-nor-achievable-and-why-thats-perfectly-fine-f28463c3b61e">Why 100% Mutation Score Is Neither Necessary Nor Achievable — And Why That’s Perfectly Fine</a> was originally published in <a href="https://medium.com/insiderengineering">Insider One Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How We Achieved a 50% Speed Increase Using the Torque Methodology]]></title>
            <link>https://medium.com/insiderengineering/how-we-achieved-a-50-speed-increase-using-the-torque-methodology-7124d5192b9d?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/7124d5192b9d</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[torque-squad]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[generative-ai-tools]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Sun, 22 Feb 2026 10:43:30 GMT</pubDate>
            <atom:updated>2026-02-22T10:43:30.102Z</atom:updated>
            <content:encoded><![CDATA[<p>The Complete Engineering Methodology Behind Our 50% Speed Guarantee</p><p><strong>Reza Farzaneh</strong> — Staff Software Engineer</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8oTlhBXldLBDNbZd542vfg.png" /></figure><blockquote>We built this methodology over a one-week experimental AI workshop, iterating across different teams, combining elements from various methodologies with our own internal best practices. The result was a 50% improvement in delivery speed — and that’s just the starting point. As teams mature and AI usage deepens, more will come naturally.</blockquote><p>• • •</p><p><em>In physics, </em><strong><em>torque</em></strong><em> is what happens when a small force, applied at the right distance from a pivot point, creates massive rotational movement. A wrench doesn’t need to be strong. It needs to be long, and it needs to grip at the right place.</em></p><p>If you’ve read <a href="https://medium.com/insiderengineering/50-faster-guaranteed-3a962fd59d42">Part 2 of this series</a>, you already know the story. Six teams. Five days. Features estimated at a month each under traditional sprint planning — completed in hours. A methodology that worked so well it scared us. And the honest decision to go back to Scrum because our teams weren’t ready for the full shift.</p><p>You also know the name.</p><p><strong>Torque.</strong></p><p>We picked the name as <strong>Torque</strong> with <strong>Talha Siviş</strong>, the Product Manager on our team (AgentOne) — someone that I called him our Bill Gates :), because he’s always inventing something. We decided to use physics metaphor: a small force, applied at the right leverage point, creates massive movement. It stuck.</p><p>What you don’t know yet is how it works. Not the story. Not the emotions. The actual methodology — the principles, the phases, the rules, the metrics. Everything an engineering team would need to understand it, evaluate it, and — if they’re ready — try it.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*faKiQ65cJep2u9R5euwqjg.png" /></figure><p><strong>This is that document.</strong></p><p>• • •</p><h3>Why This Exists</h3><p>After years of operating with Scrum across multiple teams, we kept hitting the same walls. Not engineering walls. Process walls.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2Onv2N74v8kygBsvyMM13w.png" /></figure><p><strong>Ceremony overhead</strong> was consuming 6–10 hours per week per developer — standups, grooming, planning, retros — with diminishing returns. <strong>Context switching</strong> from scattered meetings destroyed deep work blocks. <strong>Async communication noise</strong> turned 10-minute questions into day-long Slack threads. <strong>Unclear phase ownership</strong> left features drifting without clear gates. <strong>Cross-team dependencies</strong> created multi-day blockers with no urgency protocol. And our <strong>metrics</strong> — velocity, story points — measured effort, not outcomes.</p><p>These aren’t unique problems. Every engineering organization running Scrum at scale knows them. The question is whether you accept them as the cost of doing business, or whether you build something that eliminates them structurally.</p><p>We built Torque.</p><p>• • •</p><h3>Five Core Principles</h3><p>Torque runs on five principles. Everything else in the methodology flows from these.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vjZwX9PRQcPu3_yekFACFQ.png" /></figure><p><strong>1. The 3 or 4 Hour Focus Block. </strong>Every team has a mandatory 3 or 4 hour daily overlap block. All members fully present. Slack, email, notifications OFF. All planning, discussion, pairing, and problem-solving happens here. This is the engine. Not a suggestion. A hard rule.</p><p><strong>2. Phase-Gated Delivery. </strong>Every feature moves through defined phases with clear entry and exit criteria. No phase begins without the previous phase being complete. Phases are gated by outcomes, not by calendar dates.</p><p><strong>3. Feature-Aligned Teams. </strong>Small, cross-functional squads — max 8, optimal 6 — assembled per feature. Each squad has all the skills needed to ship independently.</p><p><strong>4. Zero Ceremony Overhead. </strong>No daily standups. No grooming. No sprint planning. Everything happens organically within the 4-hour block. The team documents plans as markdown files instead of meeting notes.</p><p><strong>5. AI-Accelerated Execution. </strong>In the AI era, changes that used to take days should take hours or minutes. Cross-team dependencies, design iterations, bug fixes — all should reflect this speed.</p><p>• • •</p><h3>Team Structure</h3><p>Each feature squad: (can be AI Agents with good skills and knowledge base)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ncCrITFE42WlYkH_S9grdA.png" /></figure><ul><li><strong>Product Manager (1): </strong>Owns PRD (Product Requirements Document), prioritization, stakeholder communication.</li><li><strong>Backend Engineer (1–2): </strong>Scale to 2 for heavy API/infrastructure features.</li><li><strong>Frontend Engineer (1–2): </strong>Scale to 2 for complex UI-heavy features.</li><li><strong>QA Engineer (1): </strong>Embedded from Phase 1; writes test plans during design.</li><li><strong>Designer (0.5–1): </strong>Can be shared across 2 squads if workload allows.</li></ul><p>Total team size must <strong>never exceed 8</strong>. The constraint ensures communication overhead stays low and accountability stays high. It could be changed by team dynamic — you can just use Agents, not human resource, but with good skill and learning.</p><p>• • •</p><h3>The Four Phases</h3><p>Every feature follows four phases, from Phase 0 (pre-discovery) through Phase 3 (ship).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3sgpRB2hLHnuJnR15hSyBA.png" /></figure><h3>Phase 0 — Pre-Discovery</h3><p><em>Owner: PM + Designer. This happens before the feature enters the team pipeline.</em></p><p>The goal: ensure the feature arrives at the team fully validated. Clear problem definition. Legal clearance. Design readiness.</p><p>The PM identifies and documents the exact customer problem — with data, user research, and business justification. Any regulatory or compliance requirements are resolved upfront. The designer creates initial concepts, user flows, and wireframes. Stakeholders are aligned on scope and expected outcome.</p><p><strong>Exit criteria: </strong>Validated customer problem with data. Legal/compliance clearance. Initial design direction. Stakeholder sign-off. Draft PRD ready for team review.</p><p><strong>Why Phase 0 matters: </strong>Without it, teams spend the first days asking “why are we building this?” and “has legal approved this?” Phase 0 eliminates these questions entirely. When a feature reaches Phase 1, the team’s only job is to figure out HOW — the WHAT and WHY are already resolved.</p><p><em>This is the hidden variable. The reason we could compress development to hours wasn’t just the methodology or the AI. It was the preparation.</em></p><h3>Phase 1 — Discovery &amp; Alignment</h3><p><em>Goal: Ensure the entire team has a shared understanding of what will be built and why.</em></p><p>The full team discusses UX/UI approach, user flows, and technical feasibility during the 4-hour block. The PM presents requirements. Engineers validate scope and raise concerns. The PRD is collaboratively refined and finalized.</p><p><strong>Exit criteria: </strong>Signed-off PRD. Agreed technical approach. Identified dependencies. Initial task breakdown.</p><h3>Phase 2 — Build &amp; Integrate</h3><p><em>Goal: Complete all backend and frontend development, resolve blockers in real-time.</em></p><p>Backend and frontend development happens in parallel. Daily progress is reviewed during the 4-hour block. Blockers are surfaced and resolved immediately — no waiting for async responses. If a cross-team dependency exists, it’s escalated as URGENT. The team gathers the relevant people into a focused alignment session — resolve it, agree on the contract, move on.</p><p><strong>Exit criteria: </strong>Feature is code-complete, integrated, and marked “Ready to Test.”</p><h3>Phase 3 — Validate &amp; Ship</h3><p><em>Goal: Ensure quality, release confidently, confirm it works.</em></p><p>The whole squad participates in rapid testing — not just QA. Issues found are fixed immediately. Edge case discussions happen in the 4-hour block. Then: deploy with appropriate feature flags and monitoring.</p><p>Post-release monitoring runs on time-based windows. We recommend starting with 4-hour, 24-hour, and 72-hour checkpoints as a baseline — but teams should adjust these intervals based on feature risk, traffic patterns, and their own comfort level. The important thing is having defined checkpoints, not the exact timing. Monitoring runs passively — the team enters cool-down while monitoring continues in parallel.</p><p><strong>Exit criteria: </strong>Feature released. First monitoring checkpoint clean. Monitoring dashboards configured.</p><p>• • •</p><h3>Real Timeline: Phase Ratios, Not Fixed Hours</h3><p>One of the things that separates Torque from Scrum is phase-level visibility. In Scrum, a 2-week sprint is a black box — you know the total output, but you have no idea how much time went to discovery, how much to build, how much to testing. Velocity measures throughput. It doesn’t tell you where the bottleneck is.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ekvenmQrZNO3r_dMsmsBcg.png" /></figure><p>In Torque, every phase has a measurable ratio within the Cycle Bet. This gives teams — and leadership — a structural view of where time goes and where it gets stuck.</p><h3>The Phase Ratio Framework</h3><p><strong>Phase 1 (Discovery &amp; Alignment): </strong>~10–15% of the Cycle Bet</p><p><strong>Phase 2 (Build &amp; Integrate): </strong>~60–65% of the Cycle Bet</p><p><strong>Phase 3 (Validate &amp; Ship): </strong>~20–25% of the Cycle Bet</p><p>These are starting ratios. After 5–10 cycles, each team will have their own baseline. The ratios matter more than the absolute hours — they reveal structural patterns that fixed estimates never show.</p><h3>What This Looks Like in Practice</h3><p><strong>8-hour Cycle Bet (Small feature):</strong></p><p><strong>Phase 1: </strong>~1h | Discovery, PRD handshake, tech approach agreed.</p><p><strong>Phase 2: </strong>~5h | BE + FE build, pairing, integration. Blockers resolved live.</p><p><strong>Phase 3: </strong>~2h | Test camp, bug fixes, release.</p><p><strong>40-hour Cycle Bet (Large feature):</strong></p><p><strong>Phase 1: </strong>~4–6h | Deeper discovery, dependency mapping, design review.</p><p><strong>Phase 2: </strong>~24–26h | Parallel BE/FE streams, cross-team alignment sessions.</p><p><strong>Phase 3: </strong>~8–10h | Comprehensive testing, staged rollout, monitoring setup.</p><p>After the active cycle is done, monitoring checkpoints run passively. We used 4h–24h–72h intervals, but teams should define their own cadence based on feature risk and traffic. The team enters cool-down while monitoring continues in parallel. (these can be days/week — regarding to team manifest)</p><h3>Why Phase Ratios Matter</h3><p>Fixed hour estimates tell you whether you were fast or slow. Phase ratios tell you why.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aLCRtPl6SyMGPSXi-aY5Ow.png" /></figure><p><strong>Phase 1 consistently above 20%? </strong>Phase 0 preparation is probably insufficient — features are arriving at the team with unclear requirements or unresolved dependencies.</p><p><strong>Phase 2 pushing past 75%? </strong>Build is expanding, which usually means scope creep or technical unknowns that weren’t surfaced in discovery.</p><p><strong>Phase 3 shrinking below 15%? </strong>Testing is getting squeezed — this is where bug escape rates start climbing.</p><p><strong>Phase 3 growing past 30%? </strong>Quality issues in build — the team is finding too many problems too late.</p><p>In Scrum, these patterns are invisible. You see velocity go up or down, but you don’t know which phase caused it. Phase ratios make the diagnosis structural, not anecdotal.</p><h3>Phase Ratio as a Team Health Metric</h3><p>Over time, each team develops a “healthy ratio” baseline. When the ratio drifts, it’s an early signal — before the Cycle Bet is missed, before bugs escape, before the team feels the pressure. It turns retrospective firefighting into proactive calibration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_Xrv00Nh5F4M0ebtJVAhhQ.png" /></figure><p>Track these per cycle: <strong>actual hours per phase</strong>, <strong>phase ratio vs. baseline</strong>, and <strong>phase transition time</strong> (how long between phase completion and next phase start — target: less than 1 business day). These three numbers give you more diagnostic power than velocity and story points combined.</p><p>• • •</p><h3>The 4-Hour Focus Block: The Engine</h3><p>This deserves its own section because it’s the single most important element of the methodology.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aqYozzqqUdZLgMdyask1pQ.png" /></figure><p><strong>The rules: </strong>Slack/Teams/email OFF. All team members present. Camera on (remote) or co-located. No external meetings allowed. Plans documented as .md files.</p><p><strong>What happens here: </strong>Daily planning &amp; progress review. Blocker resolution. Design discussions &amp; PRD work. Bug triage &amp; security reviews. Cross-team dependency escalation.</p><p>Imagine you’re debugging a cross-service issue. In Scrum, you hit the bug at 10 AM. You post in Slack. The backend engineer is in grooming until 11. They see your message at 11:30. You’re in your own standup at noon. By 2 PM you’ve exchanged six messages and still haven’t been in the same conversation at the same time.</p><p>In a Torque focus block, you turn to the backend engineer — who is right there, focused on the same feature — and solve it in 20 minutes. That’s not a productivity hack. It’s a <strong>structural elimination of communication overhead.</strong></p><h3>Cross-Team Dependency Handling</h3><p>When a team identifies a cross-team dependency during the focus block, they don’t wait or send a Slack message into the void.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*z0hM1qLOKOWRQPsgvsQniw.png" /></figure><ol><li><strong>Identify </strong>the dependency and the people needed to resolve it.</li><li><strong>Pull </strong>those people into a short, focused alignment session — 15–30 minutes.</li><li><strong>Agree </strong>on the contract (API spec, data format, timeline) and document it.</li><li><strong>Continue </strong>independently. No follow-up meetings needed.</li></ol><p>The alignment session is not a ceremony — it’s a surgical intervention. It involves only the people who can resolve it and ends with a documented agreement.</p><p>• • •</p><h3>Interruption Handling: The Peel-Off Pattern</h3><p>The most common objection to any focused methodology: “What happens when something urgent comes in?”</p><p>Torque has a clear answer: urgent work enters the pipeline without breaking the cycle.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MdZCMPm-uVT-cBRigm6FgQ.png" /></figure><h3>Production Incidents — Peel-Off &amp; Rejoin</h3><p>During our experiment, we had 2 production incidents and 2 urgent ad-hoc requests. Here’s the pattern:</p><ol><li><strong>Detect &amp; Assess. </strong>Incident detected. Team briefly assesses severity together — less than 5 minutes.</li><li><strong>Peel Off. </strong>1–2 team members peel off and take full ownership.</li><li><strong>Investigate &amp; Fix. </strong>They work independently. They do NOT attend the focus block.</li><li><strong>Rejoin. </strong>Once resolved, they rejoin with a brief 5-min handoff.</li></ol><p>The feature cycle never stops. Total disruption across four interruptions during our experiment: <strong>zero.</strong></p><h3>Urgent Requests — Quick Peel-Off</h3><p>A single team member peels off for approximately 1 hour, handles the request, and rejoins. No cycle disruption.</p><p><strong>The philosophy: </strong>Nothing is blocked, everything has a path. The team’s primary cycle delivers the highest-value outcome without losing momentum.</p><p>• • •</p><h3>Cycle Estimation: The Cycle Bet</h3><p>Torque doesn’t use story points. It uses a structured approach based on complexity tiers and historical data.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gyQGeUx0NbLCfsjgm2r19w.png" /></figure><h3>Step 1: Classify Feature Complexity</h3><p><strong>S — Small: </strong>Single domain, no cross-team deps, clear requirements. Add a filter, new API endpoint. Typical cycle: 3–5 working days.</p><p><strong>M — Medium: </strong>Multi-domain (BE + FE), 1–2 deps, some design complexity. New product page, payment flow update. Typical cycle: 1–2 weeks.</p><p><strong>L — Large: </strong>Full-stack, multiple deps, new infrastructure. New product vertical, major architecture change. Typical cycle: 2–4 weeks.</p><p><strong>Rule: </strong>If a feature exceeds 4 weeks, it must be split. No single feature runs longer than 4 weeks end-to-end.</p><h3>Step 2: Place the Bet</h3><p>The team commits to a specific hour budget for the entire cycle. Not a guess — a team commitment based on the tier, historical data, and the feature’s specifics. During execution, actual hours per phase are tracked with a simple log at the end of each focus block. When done, actual hours are compared to the bet and feed back into the baseline.</p><h3>Practical Example</h3><p>Feature 1 from our experiment was originally estimated at 2 sprints (4 weeks) under traditional method:</p><p><strong>Team: </strong>2 BE, 1 FE, 1 QA</p><p><strong>Complexity: </strong>L — Large</p><p><strong>Cycle Bet: </strong>2 weeks</p><p><strong>Actual: </strong>12 Days ✓</p><p>The Cycle Bet measures wall-clock hours (elapsed time), not person-hours. The bet is about delivery speed, not effort allocation.</p><h3>Why This Is Better Than Story Points</h3><p>Story points measure in abstract units. The Cycle Bet measures in hours — universally understood. Story points are decided by planning poker, often dominated by the loudest voice. The Cycle Bet is discussed during the Phase 1 focus block. Story points have no real commitment. The Cycle Bet is a commitment: beat it or learn why you didn’t.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5Sem7avZJWYyMGOYmGaCuA.png" /></figure><p>After 5–10 features, each team has a reliable per-tier baseline. <em>“Our last 4 Medium features averaged 8 working days”</em> is far more useful than “we do ~40 points per sprint.”</p><p>• • •</p><h3>The Team Manifest: Know Your Engine Before You Race</h3><p>Not every team is the same. And in an AI-accelerated methodology, the differences become more visible — not less.</p><p>One team might have engineers who’ve built custom AI skills, automated repetitive workflows, and can ship a medium feature in 3 days. Another team might still be figuring out how to use AI effectively for code generation, spending more time reviewing AI output than writing from scratch. Both teams are competent. But their cycle capacities are different — and pretending otherwise leads to unrealistic bets and frustration.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EyiwIHl7fJceKnJ0Yiw4gw.png" /></figure><p><strong>The Team Manifest makes this explicit.</strong></p><h3>What Is the Team Manifest?</h3><p>Before a team starts its first Torque cycle, they create a short, honest self-assessment document — the Team Manifest. It captures who the team is, how they work, and what their current AI capability looks like. It’s not a performance review. It’s a calibration tool.</p><p>The manifest is revisited and updated after every 5 cycles. It’s a living document that grows with the team.</p><h3>What Goes Into the Manifest</h3><p><strong>1. Team Composition &amp; Skills. </strong>Who’s on the team, what are their strengths, where are the gaps. Not just roles — actual capabilities. “We have 2 senior backend engineers comfortable with distributed systems” is more useful than “2 BE.”</p><p><strong>2. AI Maturity Level. </strong>This is the critical variable. The team honestly assesses where they are:</p><ul><li><strong>Level 1 — Exploring: </strong>Using AI for basic code completion, occasional question-answering. AI saves some typing but doesn’t fundamentally change the workflow.</li><li><strong>Level 2 — Integrating: </strong>AI is part of the daily workflow. Code generation, test writing, debugging assistance. Engineers review and refine AI output rather than writing everything from scratch.</li><li><strong>Level 3 — Accelerating: </strong>Custom prompts, project-specific AI skills, automated workflows. AI handles boilerplate and repetitive patterns. Engineers focus on architecture, edge cases, and integration.</li><li><strong>Level 4 — Multiplying: </strong>AI agents handle significant portions of implementation. The team has built reusable skills and templates. Feature development time is measured in hours, not days, for most complexity tiers.</li></ul><p><strong>3. Cycle Bet Baseline. </strong>Based on the AI maturity level and team skills, the team sets their initial Cycle Bet expectations per complexity tier. A Level 2 team might bet 2 weeks on a Medium feature. A Level 4 team might bet 4 days on the same feature. Both bets are valid — because they’re calibrated to reality.</p><p><strong>4. Known Constraints. </strong>Dependencies on other teams, shared designers, infrastructure limitations, domain knowledge gaps. Anything that affects cycle speed beyond the team’s direct control.</p><p><strong>5. Growth Targets. </strong>Where does the team want to be in 5 cycles? What specific AI capabilities or workflow improvements are they working toward? This turns the manifest from a snapshot into a trajectory.</p><h3>How the Manifest Changes the Conversation</h3><p>Without the manifest, you get two failure modes:</p><p><strong>Failure mode 1: </strong>Leadership sees one team shipping in 3 days and asks why another team takes 2 weeks for similar work. Without context, this becomes pressure instead of understanding.</p><p><strong>Failure mode 2: </strong>Teams compare themselves to each other and either overcommit (leading to quality issues) or get demoralized (leading to disengagement).</p><p>The manifest prevents both. When a team’s Cycle Bet is grounded in their documented AI maturity and skill profile, the conversation shifts from “why are you slow?” to “what do you need to get faster?”</p><p>It also creates a natural improvement path. A Level 2 team isn’t failing — they’re at Level 2 and working toward Level 3. The manifest tracks that progression with concrete evidence: cycle times shortening, phase ratios stabilizing, AI usage expanding.</p><h3>Manifest as a Living Document</h3><p>The manifest isn’t a one-time exercise. After every 5 cycles:</p><ul><li><strong>Update AI Maturity Level </strong>based on actual usage patterns and cycle results.</li><li><strong>Recalibrate Cycle Bet baselines </strong>with real data from completed features.</li><li><strong>Review growth targets </strong>— were they met? What’s next?</li><li><strong>Adjust team composition notes </strong>if members changed or new skills were acquired.</li></ul><p>Over time, the manifest becomes a team’s engineering identity — not imposed from above, but built from within. It’s the team saying “this is who we are, this is what we can deliver, and this is where we’re headed.”</p><p>• • •</p><h3>Cool-Down: The Space Between Cycles</h3><p>After Phase 3 and before the next feature, the team enters cool-down. Not idle time — the work that keeps the codebase healthy.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*itEVw0HcKapCZSZm5Zuzog.png" /></figure><ul><li><strong>Tech Debt: </strong>Refactor code flagged during the cycle. Improve test coverage. Optimize slow queries.</li><li><strong>Security: </strong>Apply patches. Resolve vulnerability findings. Update dependencies.</li><li><strong>UX Improvements: </strong>Polish rough edges. Fix visual inconsistencies. Address usability feedback.</li><li><strong>Tooling &amp; DX: </strong>Improve CI/CD. Update dev tooling. Automate repetitive tasks.</li><li><strong>Knowledge Sharing: </strong>Document decisions. Update runbooks. Share learnings.</li></ul><p><strong>Duration: </strong>Small features: 1 week. Medium: 2 weeks. Large: 4 weeks. (depending on team manifest)</p><p><strong>Cool-down is not optional.</strong> It is not skippable under deadline pressure. A team that ships without cool-down has deferred work that will slow the next cycle.</p><h3>The Organizational Debt Warning</h3><p>Torque + AI driven development gives engineering unprecedented shipping speed. But your organization is not just engineering. Customer Success, Sales, Support, Marketing, Documentation — they all need to absorb every feature you ship.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*uIeHmFgYFLURaWVgJARZNw.png" /></figure><p>If you push features at maximum velocity without cool-down, you create organizational debt. CSMs can’t onboard fast enough. Sales can’t learn new capabilities. Support gets buried in tickets for features they haven’t been trained on.</p><p>That said, this is variable for every company. Not every organization has these dynamics. Some teams operate with lean support structures where engineering ships directly to users. Some have strong self-serve documentation cultures where the gap between shipping and adoption is small. The point isn’t that every company will experience organizational debt the same way — the point is to be aware of it as a risk and calibrate your cool-down accordingly.</p><p>Torque enables you to build features both fast <em>and</em> with high quality. That’s the real superpower — not just speed alone. Protect the balance.</p><p>• • •</p><h3>Product Validation: See It Used, Feel the Impact</h3><p>Shipping is not the finish line. The team that built it should see it being used by real users.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UGjZtjAnr795AKzHsuUKMA.png" /></figure><p>In traditional frameworks, the engineer who built a feature never sees whether it solved the problem. This disconnects effort from impact. In Torque, we allocate time deliberately:</p><ul><li><strong>Usage Observation — </strong>After 72h monitoring is clean, review real user interactions: analytics, session recordings, feedback.</li><li><strong>Outcome Check — </strong>Does it solve the Phase 0 problem? Are success metrics moving? Within 1 week.</li><li><strong>User Feedback Loop — </strong>Direct feedback from users or customer-facing teams. First 2 weeks.</li><li><strong>Impact Debrief — </strong>15–30 min in a focus block. Not a retrospective — a data review. After 1–2 weeks.</li></ul><p><strong>The cycle is not complete when code is in production. It is complete when the team has confirmed it delivers value.</strong></p><p>• • •</p><h3>Metrics &amp; KPIs</h3><p>These replace traditional velocity and story points (depending on the team manifest):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6fyweRM9AfRYJRV4_DB-hg.png" /></figure><ul><li><strong>Feature Cycle Time: </strong>Phase 1 → Phase 3 Done. Target: 30–40% reduction vs. Agile within 2 quarters.</li><li><strong>Phase Ratio Baseline: </strong>Actual phase ratio vs. team baseline (starting point: ~10–15% / ~60–65% / ~20–25%). Drift signals structural issues.</li><li><strong>Phase Transition Time: </strong>Handoff delays between phases. Target: &lt; 1 business day.</li><li><strong>Blocker Resolution Time: </strong>Target: &lt; 4 hours.</li><li><strong>Bug Escape Rate: </strong>Production bugs after Phase 3. Target: &lt; 5%.</li><li><strong>Focus Block Utilization: </strong>All members present. Target: &gt; 90%.</li><li><strong>Cross-Team Dependency SLA: </strong>Alignment within 4 hours; delivery same day.</li><li><strong>Ceremony Time Saved: </strong>Target: 4–6 hours/week per engineer.</li><li><strong>Post-Release Stability: </strong>Zero P1 incidents within the monitoring window (we default to 72h).</li><li><strong>Estimation Accuracy: </strong>Actual vs. estimated. Target: ±15% after 5 cycles.</li><li><strong>Cool-Down Completion: </strong>100%. Never skipped.</li><li><strong>Team Manifest Review: </strong>Updated every 5 cycles. AI maturity level tracked and progressing.</li><li><strong>Product Validation: </strong>100% impact debrief within 2 weeks.</li></ul><p>• • •</p><h3>We Are Still Agile — Just Without the Ceremonies</h3><p>Torque does not abandon Agile. It IS Agile — in the truest sense.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kCLGYciRW1r00cxpUcrtsA.png" /></figure><p>When a partner sends an urgent request, we pull it into the phase pipeline immediately. When a critical bug surfaces, it enters the same flow. When a design change is needed mid-Phase 3, we accept it — because AI-assisted development makes rapid iteration possible.</p><p>The difference: we deliver this responsiveness through focused collaboration blocks and phase gates, not through ceremonies that have become bureaucratic overhead.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4a08zpfH8PFlD_lgM8q67A.png" /><figcaption>Scrum vs <strong>Torque</strong></figcaption></figure><p>Important Note :</p><p>We say optimal 6 because in the AI era, every additional person adds more alignment overhead than execution power. AI handles the throughput that used to require extra hands — what it can’t handle is the communication complexity that grows with every new voice in the room. Fewer people, more focus, faster decisions. And honestly, as teams mature in their AI usage and manifests evolve, we expect this number to go even lower.</p><p>• • •</p><h3>The Experimental Results</h3><p>This methodology has been validated across 6 engineering teams at Insider One. The full story is in <a href="https://medium.com/insiderengineering/50-faster-guaranteed-3a962fd59d42">Part 2</a>, but here are the numbers:</p><p>6 features across 6 teams. Each had existing sprint estimates under traditional Agile planning. Development cycles compressed from weeks to hours.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rQm-Y866iZMaYLS-Gd0W4g.png" /></figure><p><strong>Total Agile estimate: </strong>2 sprints (4 weeks).</p><p><strong>Total actual development: </strong>2 weeks across 6 teams.</p><p>The development cycle compressed far beyond 50%. But when you account for the full production pipeline — reviews, staging, rollout — <strong>50% end-to-end improvement is what we guarantee.</strong></p><p>These results reflect the combined effect of Torque + AI-driven development. Torque provides structure and focus. AI provides execution speed. The multiplier is in the combination.</p><p>• • •</p><h3>The Honest Status</h3><p>If you’ve read <a href="https://medium.com/insiderengineering/50-faster-guaranteed-3a962fd59d42">Part 2</a>, you know we went back to Scrum after the experiment. Not because the methodology failed — the numbers make that argument impossible. Because we weren’t ready yet, lessons were learned. Process change is identity change, and identity change takes time.</p><p>But we’re not going back to the same Scrum. AI-driven development runs inside every sprint.</p><p><strong>The methodology is proven. The rollout is phased. When the people say they’re ready, we’ll make the full switch.</strong></p><p>• • •</p><h3>Try It</h3><p>If you’re reading this and thinking “this sounds like what my team needs” — start small.</p><ol><li><strong>Protect one 3 or 4 hours focus block per day. </strong>Slack off. Notifications off. Everyone present. See what happens to blocker resolution. (You can define it in your team manifest)</li><li><strong>Try Phase 0 on your next feature. </strong>Have PM and designer fully validate the problem before it reaches engineering. See how much faster Phase 1 goes.</li><li><strong>Run a Cycle Bet alongside your story points. </strong>Estimate in hours and track accuracy. Compare to velocity predictions. With all team members and with exact details about feature.</li><li><strong>Add a cool-down day at the end of your sprint. </strong>Half a day. Tech debt, security, polish. See if the next sprint goes faster.</li></ol><p><strong>Or — if you’re building a new team from scratch:</strong></p><p>If you’re hiring a new team or forming a new squad within your department, this is actually the easiest path to Torque. New hires don’t carry the habits of your existing process. They don’t need to unlearn standups, story points, or sprint rituals. They start with focus blocks, phase gates, and Cycle Bets as their default — it’s just how they work from day one. You skip the hardest part of any methodology change: breaking old patterns.</p><p>You don’t need to abandon Scrum overnight. That’s the lesson we learned. But you can start gripping the lever at the right point — and see what moves.</p><p>• • •</p><p><em>&gt;50% faster KR (Key Result) delivery. That’s our guarantee.</em></p><p><strong>Small force. Big movement. That’s Torque.</strong></p><p><em>The methodology is open. The results are real. The only question is readiness.</em></p><p>• • •</p><p><em>This is the companion piece to </em><a href="https://medium.com/insiderengineering/50-faster-guaranteed-3a962fd59d42"><em>Part 2: 50% Faster. Guaranteed.</em></a><em> — which tells the story of the experiment. This article documents the methodology itself.</em></p><p><em>Read </em><a href="https://medium.com/insiderengineering/we-stopped-sprinting-and-bet-on-shipping-00b5d281a2fc"><strong><em>Part 1</em></strong></a><em> for the origin story — how we pulled a team out of Scrum and started the experiment that led to </em><strong><em>Torque</em></strong><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7124d5192b9d" width="1" height="1" alt=""><hr><p><a href="https://medium.com/insiderengineering/how-we-achieved-a-50-speed-increase-using-the-torque-methodology-7124d5192b9d">How We Achieved a 50% Speed Increase Using the Torque Methodology</a> was originally published in <a href="https://medium.com/insiderengineering">Insider One Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[50% Faster. Guaranteed.]]></title>
            <link>https://medium.com/insiderengineering/50-faster-guaranteed-3a962fd59d42?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/3a962fd59d42</guid>
            <category><![CDATA[software-development]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Fri, 20 Feb 2026 19:20:18 GMT</pubDate>
            <atom:updated>2026-02-20T19:20:18.092Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>How AI-Driven Development Changed Our Engineering Velocity</strong></p><p><strong>Reza Farzaneh</strong> — Staff Software Engineer</p><p><em>Part 2 of 3— The experiment is over. Here are the results.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eQ1YDEhdRWGRmIiNcdahUQ.png" /></figure><p><em>In 212 BC, Archimedes reportedly told King Hieron: “Give me a lever long enough and a fulcrum on which to place it, and I shall move the world.” He wasn’t bragging about strength. He was making a point about physics — that the right mechanism, applied at the right point, produces movement wildly disproportionate to the force applied.</em></p><p>Twenty-two centuries later, engineers are still trying to move the world. Except now we call the lever “process,” the fulcrum “planning,” and the force “headcount.” And when things don’t move fast enough, we add more people, more sprints, more ceremonies — more force — instead of questioning whether we’re pushing at the right point.</p><p><strong>This isn’t a thought experiment. This is what happened when I sat with six teams for five days, elbow to elbow, and watched everything we assumed about engineering velocity fall apart.</strong></p><h3>The Promise We Made</h3><p>In Part 1, we told you we were pulling a team out of Scrum. We told you about ByteMaster — our guinea pig team. We told you about Shape Up’s philosophy, our curated backlog, our first shaped cycle. And we made a promise: whatever happened — success, failure, or something messy in between — you’d get the truth.</p><p>We also said the experiment might produce something with its own name.</p><p>It did.</p><p><strong>We call it Torque.</strong></p><p>And if you’re wondering which of the three outcomes this is — “it worked,” “it partially worked,” or “it failed” — the honest answer is the most complicated one. The numbers were extraordinary. The methodology proved itself. But the humans inside it? They weren’t ready. And that’s the story worth telling.</p><h3>Five Days, Elbow to Elbow</h3><p>Let me tell you what actually happened in that room.</p><p>We had been planning an AI workshop — a company initiative to accelerate AI-driven development across the engineering org. Six teams. Five days. Hands-on AI tooling. That was the original plan. But the ByteMaster results from Part 1 changed the conversation. What if the workshop wasn’t just about AI tools? What if it was about the methodology that makes AI tools actually productive?</p><p>So we made the call. Six teams. Six features pulled from their current roadmaps — features that each had roughly a month of sprint estimates under traditional Agile planning. Each team would run Torque combined with AI-driven development for the full five days. The goal was clear: measure how much we could compress the development cycle when you remove the ceremony overhead and let AI do what AI does best.</p><p>And I would be there. Not managing. Not observing from a dashboard. Sitting with them. Working alongside them. Watching every decision, every blocker, every moment of confusion and every moment of clarity.</p><h3>The Setup</h3><p>Here’s what each team walked in with on Day 1:</p><ul><li><strong>A ready PRD. </strong>The product requirement document was written, reviewed, and finalized before the workshop started. No one had to ask “what are we building?” on Day 1.</li><li><strong>Mock designs in Figma. </strong>Not pixel-perfect finals, but clear enough to build from. The design direction was set. User flows were mapped. The team knew what the feature should look and feel like.</li><li><strong>A clear problem to solve. </strong>Every team knew which customer problem their feature addressed. The “why” was resolved. The “what” was defined. The only open question was “how fast can we build it?”</li><li><strong>AI tooling at their fingertips. </strong>Every developer had access to AI-assisted code generation, automated test creation, and intelligent code review. The tools were ready. The question was whether the process would let the tools breathe.</li></ul><p>The plan was straightforward: start with a 4-hour focused discussion to align on the technical approach, then immediately move into execution and quality phases. No standups. No grooming. No sprint planning. Just build.</p><h3>The Numbers: Month-Long KRs, Done in a Day</h3><p>Here’s what happened. Each of these features was estimated at roughly one month of sprint work under our existing Agile planning. The table shows how long the actual development cycle took with Torque + AI-driven development.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8fNIU_gmaKE2rySNjQFLAA.png" /><figcaption>Six features. Six teams. Development cycles compressed from weeks to days. The 50% improvement guarantee is the floor, not the ceiling.</figcaption></figure><p>Read that again. Features estimated at a month each under traditional sprint planning. Development cycles completed in half a day to a day and a half. Six teams. Six features.</p><p><strong>A critical clarification before we go further: </strong>these numbers represent the development cycle only — from the first discussion through code-complete. Not production. None of these features shipped to production during the five-day workshop. The design was ready in Figma as mocks. The PRD was written. The problem was understood. What we measured was how fast teams could go from “aligned on what to build” to “code-complete and tested.” That was the whole purpose of this experiment: to measure the compression in the development cycle.</p><p><strong>The road to production is longer. </strong>Code reviews, integration testing, staging validation, feature flag configuration, monitoring setup, stakeholder sign-off, gradual rollout — the full path from code-complete to live-in-production takes roughly one week on average at our org. That hasn’t changed. What changed is the development cycle that feeds into that pipeline.</p><p><strong>So here’s the real claim — and it’s one we’re confident enough to guarantee: </strong>AI-driven development delivers a minimum 50% improvement in KR delivery speed. That’s the floor, not the ceiling. If a KR takes a month today, it should take two weeks with this approach. The development cycle itself compressed far beyond 50% in our experiment. But when you account for the full production pipeline — reviews, staging, rollout — 50% end-to-end is what we’d stake our reputation on. The actual results in the workshop exceeded that number. But we’re not here to sell you on best-case scenarios. We’re here to tell you what we can guarantee.</p><p>The speed comes from focused methodology and AI-driven development working together. We believe neither factor alone produces this result. The methodology provides the structure and focus. AI provides the execution speed. The multiplier is in the combination.</p><h3>What I Saw in the Room</h3><p>The numbers tell you what happened. They don’t tell you what it felt like to watch it happen. I was there for all five days, sitting with each team, and what I observed was more revealing than any spreadsheet.</p><h3>The First Four Hours Changed Everything</h3><p>Day 1 started with the 4-hour focus block. Every team gathered — backend, frontend, QA, PM — in one room, one call, one shared context. Slack off. Notifications off. For the first time in months, maybe years, these people were in the same conversation at the same time with no competing meetings.</p><p>The effect was immediate and visible. A backend engineer on Team 1 raised an API design question that, in a normal sprint, would have gone to Slack, waited two hours for a response, generated three follow-up questions, and taken a day to resolve. In the focus block, the frontend engineer heard it, the QA engineer weighed in on testability, the PM clarified the business constraint, and the whole thing was resolved in twelve minutes. I timed it.</p><p>This wasn’t an exception. It was the pattern. Across all six teams, decisions that normally take days of async back-and-forth were happening in minutes. Not because people were working harder. Because they were finally in the same room at the same time, focused on the same problem.</p><h3>The AI Multiplier</h3><p>When the focus block established alignment, the AI tooling did something remarkable: it made execution almost instantaneous. Engineers weren’t writing boilerplate. They weren’t spending hours on CRUD endpoints or repetitive test cases. The AI handled the scaffolding, and the engineers spent their cognitive energy on architecture, edge cases, and the decisions that actually require human judgment.</p><p>One frontend engineer on Team 3 told me something that stuck with me: “I spent the whole day thinking about the hard problems instead of typing the easy ones.” That’s the shift. AI didn’t replace the engineer. It freed the engineer to be an engineer.</p><h3>Blockers Died in Real Time</h3><p>In a normal sprint week, the average blocker takes one to three days to resolve. Someone raises it in standup. Someone promises to look into it. The Slack thread grows. A meeting gets scheduled. By the time the blocker is cleared, the developer has context-switched to something else and needs time to ramp back up.</p><p>During the five days, I watched blockers surface and resolve in the same hour. One team hit a cross-service dependency issue on Day 2. In a Scrum world, that’s a multi-day blocker — you need someone from the other team, you need a meeting, you need alignment. In the focus block, we pulled the relevant person from the other team into a 15-minute targeted call, agreed on the API contract, documented it, and both teams continued independently. Total time lost: 20 minutes.</p><h3>Interruptions Didn’t Break the Flow</h3><p>The most common objection to any focused methodology is “What about production incidents?” Fair question. We had two during the workshop, plus two urgent ad-hoc requests from the existing production environment.</p><p>For each one, one or two team members peeled off, took full ownership, resolved it, and rejoined the feature cycle. The remaining team members never stopped building. The feature pipeline continued uninterrupted. Total disruption across four interruptions: zero.</p><p>This was the moment I knew the methodology was sound. Not the speed numbers. The interruption handling. Because every real-world engineering team has production incidents. If Torque couldn’t handle them without breaking the cycle, it would be a nice theory and nothing more. It handled them. <strong>Cleanly.</strong></p><h3>The Emotional Shift</h3><p>This one surprised me more than the numbers. By the middle of the workshop, engineers were visibly different. Less tired, more engaged. There was an energy in the room that I hadn’t seen in our sprint cycles.</p><p>When I asked people about it, the answers were consistent: “I feel like I’m actually building something.” “I didn’t open Slack once today.” “I solved a problem in 20 minutes that would have taken me days.” “I don’t feel like I’m running in a hamster wheel.”</p><p>Process fatigue is real. Engineers don’t burn out from coding. They burn out from the overhead that surrounds the coding — the ceremonies, the status updates, the context switches, the async noise that fragments every deep thought. Remove the overhead, and people remember why they became engineers in the first place.</p><h3>And Then I Saw the Other Thing</h3><p>For the first two days, I was watching a methodology validate itself in real time. The numbers were landing. The energy was high. The development cycles were compressing. I was mentally drafting the victory article.</p><p>Then I started noticing the cracks.</p><h3>The Scrum Muscle Memory</h3><p>Our teams have been running Scrum for years. It’s not just a process — it’s wired into how people think about work. And when you take away the scaffolding that people have relied on for years, something unexpected happens: they don’t feel liberated. They feel lost.</p><p>I watched it happen in real time. The focus block would start, and someone would ask: “So… do we do a standup first?” No. There is no standup. Just start working. But that answer didn’t land. People had been starting their day with a standup for years. Removing it didn’t just remove 15 minutes of ceremony. It removed a psychological anchor. They didn’t know how to begin.</p><p>In Phase 2, when parallel build was happening, I’d see engineers instinctively reach for Jira. Not because they needed it — but because they were used to the comfort of seeing their work broken into tickets, assigned, and tracked on a board. Torque doesn’t use tickets for in-cycle work. The PRD is the artifact. The focus block is the coordination mechanism. But the absence of the ticket board created a low-level anxiety that surprised me.</p><p>One engineer said it plainly: “I know we’re moving faster, but I feel like I don’t know where I am.”</p><h3>The Ceremony Comfort Zone</h3><p>Here’s the thing nobody tells you about Scrum ceremonies: they’re not just overhead. They’re also safety nets.</p><p>Sprint planning gives people a sense of control — “I know what I’m supposed to do for the next two weeks.” Daily standups give people visibility — “At least everyone knows what I’m working on.” Retrospectives give people a voice — “At least I can say what’s wrong.”</p><p>When you remove all of that and replace it with “everything happens in the focus block,” you’re asking people to trust a fundamentally different structure. And trust doesn’t build in five days. It builds over months, through repeated cycles of “we tried this, it worked, let’s trust it more.”</p><p>I saw team leads who were used to running standups suddenly unsure of their role. I saw QA engineers who were used to receiving a ticket to test suddenly having to lean into the conversation and self-direct. I saw senior developers who had mastered the sprint rhythm feel uncomfortable with the open-ended nature of the focus block.</p><p><strong>The methodology worked. The people weren’t ready for the methodology.</strong></p><h3>The Confusion Wasn’t Technical</h3><p>Nobody struggled with the AI tools. Nobody struggled with the technical work. The features were well-scoped. The code got written. The tests passed. The deployments went smoothly.</p><p>The confusion was emotional and structural. People didn’t know how to operate without the rhythm they’d relied on for years. And when you’re confused about the process, even if you’re shipping faster, the experience feels unstable. It’s the difference between driving fast on a road you know and driving fast on a road you’ve never seen. Same speed. Very different confidence levels.</p><p>By Day 5, some teams had adapted. Others were still finding their footing. Every single feature reached code-complete — but the journey was bumpier than the results table suggests.</p><h3>The Honest Decision</h3><p>After the workshop, I sat with the data in one hand and the observations in the other. And they told two different stories.</p><p>The data said: <em>AI-driven development works. The development cycle compressed from weeks to days. End-to-end, we’re looking at a guaranteed 50% or more improvement in KR delivery speed. A month becomes two weeks. That’s the floor.</em></p><p>The observation said: <em>The teams are not ready. The muscle memory is too deep. The comfort zone is too strong. Forcing this at scale right now would create more confusion than velocity.</em></p><p>Both things are true at the same time. And when both things are true, you have to make a pragmatic call.</p><p><strong>We’re going back to Scrum.</strong></p><p>Not because Scrum is better. The numbers make that argument impossible. We’re going back because our teams need the scaffolding they know while they build the muscles they don’t have yet.</p><h3>But We’re Not Going Back to the Same Scrum</h3><p>The Scrum framework stays. But how we operate inside it is fundamentally different. The workshop didn’t just teach us about speed — it rewired how we think about work itself. We can now deliver with quality at a pace we didn’t think was possible. That changes everything about how we plan, how we break down work, and how we spend our time.</p><h3>Stop Slicing Features into Dozens of Tiny Tasks</h3><p>This is the biggest behavioral shift. Before the workshop, our instinct was to decompose every feature into as many small tickets as possible. A single KR would generate fifteen, twenty, sometimes thirty Jira tickets. The logic was sound on paper: smaller tasks, easier estimation, better tracking. In practice, it created a different problem — the overhead of managing, coordinating, and context-switching between thirty tickets was eating more time than the actual coding.</p><p>The workshop proved something we should have realized earlier: <strong>when the team is aligned on the problem, focused on execution, and equipped with AI tooling, a feature doesn’t need thirty tasks. It needs two or three.</strong></p><p>Here’s the new rule. Look at the KR. Understand its scope. Then break it into two or three meaningful chunks — not micro-tasks, but substantial pieces of work that a developer can own end-to-end. One chunk might be the backend API and data layer. Another might be the frontend integration. A third might be the testing and edge case coverage. That’s it. No more decomposition theater. No more tickets that take longer to write than to build.</p><p>This sounds risky if you’re used to the old way. It’s not. Because when you pair this with AI-driven development, each chunk gets done faster than any three micro-tasks used to. And the cognitive overhead of managing thirty tickets? Gone.</p><h3>Listen Harder in Groomings</h3><p>The second shift is in how we run groomings. Before the workshop, grooming sessions had a predictable rhythm: someone presents the ticket, someone asks a question, someone gives an estimate, we move on. Half the room is mentally somewhere else. The other half is waiting for their turn to talk.</p><p>That changes now. Groomings are where alignment happens. And alignment is the <strong>single biggest accelerator</strong> we discovered in the workshop. Remember that API design question on Team 1 that got resolved in twelve minutes because everyone was present and listening? That’s what a good grooming should feel like.</p><p>The new expectation: when a feature is being discussed in grooming, you listen as if you’re about to build it in the next four hours. Because with AI-driven development, you might be. Ask the edge case questions now. Raise the dependency concerns now. Challenge the design assumptions now. Don’t wait for Day 3 of the sprint to discover what you should have caught in grooming.</p><p>Better groomings mean fewer surprises in build. Fewer surprises mean fewer blockers. Fewer blockers mean faster delivery. The math is simple. The discipline is hard. But we’ve seen what happens when people actually listen, and we’re not going back.</p><h3>Create Focus Time</h3><p>We can’t do a full 4-hour Torque focus block inside Scrum. Not yet. But we can protect time for deep work.</p><p>Starting now, every team designates <strong>dedicated focus windows</strong> during the sprint — blocks of 2–3 hours where Slack goes quiet, meetings don’t get scheduled, and engineers can actually build. This isn’t a suggestion. It’s a rule. No one schedules a “quick sync” during focus time. No one pings someone on Slack for something that can wait two hours.</p><p>The workshop proved that synchronous, focused collaboration is where the magic happens. We can’t replicate the full workshop environment every day — but we can carve out islands of focus inside the sprint ocean. Even two hours of protected deep work per day is a radical improvement over the current state, where a developer’s day is fragmented into thirty-minute slots between ceremonies, Slack threads, and “quick questions.”</p><h3>What Else Changes</h3><p>Beyond these three shifts, we’re also carrying forward:</p><ul><li><strong>AI-driven development becomes the default. </strong>Every team, every sprint, every feature. The AI tooling we validated in the workshop — code generation, automated tests, intelligent reviews — gets embedded into the daily workflow. This alone compresses delivery cycles inside existing sprints.</li><li><strong>KRs ship faster. </strong>With fewer tasks, better groomings, focus time, and AI tooling combined — the same sprint that used to deliver one key result now targets two or three. We ship more value per sprint without changing the sprint container.</li><li><strong>The curated backlog stays. </strong>Items expire by default. If nobody champions a ticket within two sprints, it’s pruned. This has already eliminated the backlog bloat that made grooming sessions feel like archaeological digs.</li><li><strong>Cool-down thinking stays. </strong>A half-day at the end of each sprint for tech debt, tooling improvements, and UX polish. Not as structured as Torque’s cool-down, but protecting the same principle: speed without maintenance is debt in disguise.</li><li><strong>Cycle Bet experiments run in parallel. </strong>Two teams are tracking hour estimates alongside story points to build historical data. If the Cycle Bet proves more accurate and transparent, it replaces story points org-wide. Early signals are promising.</li></ul><p>We’re taking the engine out of the race car and putting it into the family sedan. The engine is the same. The car just needs to be one the driver is comfortable with — for now.</p><h3>What I Learned in Those Five Days</h3><p>Sitting with six teams for five days taught me things that no planning document or metrics dashboard ever could.</p><ol><li><strong>The speed bottleneck was never technical. </strong>It was communication overhead. When you put a team in the same room, focused on the same problem, with no competing meetings, they move at a speed that makes sprint estimates look absurd. The issue was never “can we build this fast?” It was always “will the process let us build this fast?”</li><li><strong>AI multiplies focus, not chaos. </strong>AI-driven development in a fragmented process is fast chaos. AI-driven development in a focused process is fast execution. The combination of Torque’s structure and AI’s speed is what produced the numbers. Neither alone gets there.</li><li><strong>Process change is identity change. </strong>Engineers don’t just follow Scrum. They’ve built their professional identity around it. Their daily rhythm. Their sense of progress. Their definition of “a productive day.” Asking them to abandon that overnight is asking them to abandon how they see themselves as professionals. That takes time and trust, not a five-day workshop.</li><li><strong>Preparation is the hidden variable. </strong>The reason we could compress development to hours wasn’t just the methodology or the AI. It was the preparation. The PRD was ready. The Figma mocks were ready. The problem was understood. Phase 0 — the pre-discovery work — is where the real leverage lives. Without it, even Torque would struggle.</li><li><strong>You can’t skip the middle. </strong>Torque is where we want to be. Scrum is where we are. The path between them isn’t a switch you flip — it’s a road you walk. AI-driven Scrum is the middle of that road. We’re walking it now.</li></ol><h3>Give Me a Lever Long Enough</h3><p>Let’s be honest about the boundaries. This was a workshop context. Five days. Six teams that knew they were testing something new, with the energy and focus that comes from novelty. The pre-conditions were ideal — PRDs ready, designs mocked, problems understood. A normal Tuesday doesn’t look like that. And to be clear: the development cycle compressed to days, but the full path to production still takes about a week. Our guaranteed number is 50% improvement in KR delivery speed — and we’re confident in that, though the ceiling is likely much higher.</p><p>Would the results hold over six months? I believe yes — ByteMaster’s longer-running results support that — but we haven’t proven it at scale. The thing Archimedes understood that modern engineering organizations keep forgetting: <strong>force isn’t the bottleneck. Leverage is.</strong></p><p>Torque is not a radical invention. It’s an obvious correction. Replace fragmented ceremonies with concentrated collaboration. Gate work by outcomes, not by the calendar. Measure in hours, not in abstractions. Give teams the structure to focus and the space to recover.</p><p>But an obvious correction applied to an organization that isn’t ready for it is just disruption by another name. And I’d rather have a team that ships consistently with Scrum + AI than a team that ships in bursts with Torque but feels lost between them.</p><h3>The Door Is Open</h3><p><em>If we arrive at a different conclusion — </em>if the teams mature into readiness, if the Cycle Bet data validates what we suspect, if the focus block discipline takes root in the small experiments we’re running — you’ll hear about it. That’s what Part 3 is for.</p><p>For now, the plan is simple. Run Scrum. Ship fast with AI. Absorb the Torque principles that fit. Build the muscle memory one sprint at a time. And when the teams are ready — not when the numbers say we should, but when the people say they can — we’ll make the switch.</p><p>Because the one thing those five days proved beyond any doubt is this: the speed is there. The methodology is there. The tools are there. The only thing between us and that future is readiness. And readiness, unlike a feature, can’t be compressed by 50%.</p><p><strong>&gt;50% faster KR delivery. That’s our guarantee.</strong></p><p><em>AI-driven development changed how fast we can build. The rest is about readiness.</em></p><p><em>The lever is ready. The fulcrum is set. The teams need time to learn how to grip.</em></p><p><em>We’re walking the road, not flipping the switch.</em></p><p><strong>And when we’re ready — you’ll be the first to know.</strong></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3a962fd59d42" width="1" height="1" alt=""><hr><p><a href="https://medium.com/insiderengineering/50-faster-guaranteed-3a962fd59d42">50% Faster. Guaranteed.</a> was originally published in <a href="https://medium.com/insiderengineering">Insider One Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[We Stopped Sprinting and Bet on Shipping]]></title>
            <link>https://medium.com/insiderengineering/we-stopped-sprinting-and-bet-on-shipping-00b5d281a2fc?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/00b5d281a2fc</guid>
            <category><![CDATA[ai-development]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[agile]]></category>
            <category><![CDATA[kanban]]></category>
            <category><![CDATA[scrum]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Mon, 16 Feb 2026 15:13:22 GMT</pubDate>
            <atom:updated>2026-02-16T15:13:22.926Z</atom:updated>
            <content:encoded><![CDATA[<p>Reza Farzaneh — Staff Software Engineer</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iOFOJTRm4opfqZYTzaJ3dA.png" /><figcaption>Insider One — AgentOne Team</figcaption></figure><p><em>Part 1 of 2 — How we’re replacing sprint ceremonies with a new methodology — inspired by Shape Up, built on our own best practices, accelerated by AI. Part 2 comes after the experiment.</em></p><p>This isn’t a thought piece. This isn’t “5 reasons Scrum is dead.” This is a live experiment.</p><p>But it’s not a blind leap.</p><p>Before committing a team to a full cycle, we ran proof-of-concept experiments across three teams — ByteMaster, Vikings, and Qmech. Each team tested different elements borrowed from Shape Up against their existing Scrum workflow: appetite-based scoping instead of story points, shaped pitches instead of ticket factories, hill charts instead of burndown tracking. Not the full framework — isolated pieces, applied to real work, measured against real outcomes.</p><p>The most important signal came from one POC where a team took a feature from start to finish — not a prototype, not a spike, a production-ready feature delivered end-to-end. Shaped with an appetite, scoped with explicit no-gos, built without sprint ceremonies. And the quality held. Code reviews passed clean. QA didn’t flag regressions. The feature shipped and stayed shipped — no hotfix trail, no “we’ll clean it up next sprint” debt. That single data point changed the conversation from “should we try this?” to “which team goes first?”</p><p>The results across the three POCs weren’t uniform — some principles clicked immediately, others needed adaptation — but the signal was clear enough to place a real bet.</p><p>Starting this month, we’re pulling one of our engineering teams out of Scrum entirely. No more sprints. No more daily standups. No more story points. No more backlog grooming. No more velocity tracking.</p><p>Instead, we’re building something new. The foundation is Shape Up — the product development framework created by Basecamp/37signals. But we’re not adopting it as a religion. We’re taking its core principles, merging them with our own battle-tested best practices that we’ve accumulated over years of shipping at scale, and layering in AI-driven development workflows that didn’t exist when Shape Up was written.</p><p>The result? Something that will eventually get its own name under Insider One. The ingredients are deliberate: Shape Up’s shaping and betting philosophy as the starting point, our own battle-tested operational instincts as the backbone, cases where we need to adapt fast as the stress test, and AI-augmented development as the accelerant. It’s not Shape Up. It’s ours.</p><p>This is the expanded rollout. The POC results across three teams gave us enough signal to commit one team to a full cycle. If this works, we go wider. If multiple teams validate the approach, we go company-wide.</p><p>This is Part 1 — the plan, the reasoning, and our first shaped cycle. Part 2 comes after the experiment with raw, unfiltered results. Whatever happens — success, failure, or something messy in between — we’re publishing it.</p><p>Let’s go.</p><h3>Why We’re Doing This</h3><p>We run multiple Scrum teams. They ship. They’re not broken. But we’ve been noticing friction patterns — the kind that most engineering organizations encounter once they’ve been running Scrum at scale for long enough. And rather than patching the framework one more time, we decided it was time to rethink it.</p><p><strong>The ceremonies had drifted from their original purpose.</strong> Our standups had gradually shifted toward status reporting — a pattern so common in scaling teams that it barely needs explaining. Sprint planning had become more about estimation negotiation than about aligning on what matters. Retrospectives were surfacing recurring themes that pointed to structural friction, not problems solvable within the current framework. The overhead-to-value ratio of our ceremonies had shifted, and we recognized it was time to evolve.</p><p><strong>The backlog had outgrown its usefulness.</strong> Like most mature product teams shipping continuously over several years, our backlog had grown organically to several hundred items. Some reflected priorities from quarters ago. Others had accumulated naturally without a cleanup mechanism. Every grooming session, the team spent energy navigating items that no longer reflected active priorities rather than focusing on what mattered now. The backlog had become a planning artifact rather than a prioritization tool.</p><p><strong>Two-week sprints are too short for meaningful work.</strong> By the time you plan it, groom it, estimate it, start building, hit a blocker, wait for a review, and demo it — you’ve shipped a fragment. Not a feature. A fragment. Then you carry the rest into the next sprint, and the next, and suddenly a “2-sprint project” has been dragging for 3 months across 6 sprints with no clear end in sight.</p><p><strong>AI changed the math, but the process didn’t.</strong> This is the part nobody talks about. Our developers are using AI coding assistants — Claude, Copilot, Cursor. A senior developer’s throughput has fundamentally changed. Tasks that took 3 days now take 3 hours. But we’re still planning in 2-week sprints, still estimating in story points, still assigning individual tickets. The process is designed for a pace that no longer exists. It’s like putting a jet engine on a bicycle and keeping the training wheels.</p><p>We needed something different. Not a tweak. A different operating system.</p><h3>What Is Shape Up?</h3><p>Shape Up was born at Basecamp (now 37signals), refined over 15 years of shipping products with small teams. Ryan Singer documented it in a free book that’s become quietly influential among product teams who are fed up with Agile theater.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5iVGWsrVdosduhttkdP6UQ.png" /></figure><p>The core rhythm is dead simple:</p><p><strong>6-week cycles</strong> of focused, uninterrupted building. Then <strong>2-week cooldowns</strong> for bugs, tech debt, breathing, and planning the next cycle.</p><p>That’s Shape Up’s default recipe. But here’s the thing — we’re not following the recipe to the letter.</p><p>We’re building this as Insider One, not replicating Basecamp. Our scale is different, our market is different, our team dynamics are different. We’re borrowing Shape Up’s philosophy — appetite over estimation, betting over backlog grooming, shaping over ticket factories — but combining it with our own best practices and the operational realities of shipping at our pace. Cycle length, cooldown structure, how we handle urgent production work mid-cycle, what ceremonies we keep and what we kill — many of these will look nothing like what Ryan Singer wrote. Because they’re not Shape Up decisions. They’re Insider One decisions.</p><p>We’ll address the biggest divergence — our curated backlog — later in this post. For now, just know that what you’re reading isn’t a Shape Up adoption story. It’s the birth of something new — built on Shape Up’s foundations, yes, but shaped by our own experience, our own failures, and our own instinct for what works at our scale. Part 2 will reveal how each design choice performed — which ones were genius and which ones we regret.</p><p>With that caveat, here are the Shape Up principles we’re borrowing wholesale — because they’re too good to reinvent:</p><p><em>A note for Shape Up purists: If you’re thinking “that’s not how Basecamp does it” — you’re right. And that’s the point. We believe the strongest frameworks are the ones you make your own. Part 2 will be our honest scorecard on how every deviation performed in practice.</em></p><h3>Shaping — The Work Before the Work</h3><p>Before anything enters a cycle, it must be shaped. This is the most important — and most demanding — part of Shape Up.</p><p>A shaped piece of work (called a pitch) lives at a very specific level of abstraction. It’s concrete enough that the team knows what to build, but rough enough that they decide how to build it. Think of it as the difference between handing someone a GPS destination versus handing them turn-by-turn directions. Both get you there. One trusts the driver.</p><p>Every pitch has five ingredients:</p><ul><li><strong>Problem</strong> — What’s hurting, and for whom?</li><li><strong>Appetite</strong> — How much time is this worth? (Not how long will it take — a crucial distinction)</li><li><strong>Solution</strong> — A rough sketch of the approach. Breadboards and fat marker drawings, not wireframes</li><li><strong>Rabbit Holes</strong> — Traps that could swallow the project whole</li><li><strong>No-Gos</strong> — What we explicitly will NOT build</li></ul><p>The appetite concept is where Shape Up breaks most sharply from Scrum. Instead of asking “how many story points is this?” and getting a number that’s wrong, you ask “is this problem worth 6 weeks of our team’s time?” That question forces a completely different conversation — one about value, not velocity.</p><h3>Betting — Not Planning</h3><p>In pure Shape Up, there’s no backlog. None. Pitches that don’t get bet on are gone. If an idea is important, someone will champion it again — probably shaped better the second time. The philosophy is simple: if nobody cares enough to re-pitch it, it wasn’t worth building.</p><p><strong>This is where we diverge.</strong></p><p>We keep a backlog. But not the kind you’re imagining — not the 400-item graveyard where feature requests go to haunt sprint planning sessions. We run a curated backlog. Every cycle, it gets actively pruned. Only items that have a champion — someone willing to shape a pitch and argue for it at the betting table — survive. Everything else gets archived. Not carried forward as guilt. Not left to accumulate as “we’ll get to it someday.” Archived. Gone from the active conversation.</p><p>The difference between this and Scrum’s backlog is the direction of the burden. In Scrum, items persist by default and require effort to remove. In our model, items expire by default and require effort to keep. That single inversion changes the entire psychology of planning.</p><p>Why didn’t we go full “no backlog” like Basecamp? Because at our scale — multiple product lines, cross-team dependencies, enterprise clients with contractual commitments — completely discarding institutional memory creates its own problem. We watched teams re-discover the same customer needs, re-surface the same technical debt, re-debate decisions that were already made and forgotten. A curated backlog with aggressive pruning gives us the benefits of Shape Up’s fresh-eyes approach without the institutional amnesia.</p><p>Before each cycle, a small group of senior people holds a betting table. They review the shaped pitches — some new, some carried forward by their champions — and decide which ones to bet on. This is a strategic conversation, not a planning ritual. The question isn’t “how many points fit in the sprint?” It’s “given everything we know right now, what’s the smartest bet we can make with the next six weeks?”</p><p>Now, this is important to clarify — because it’s the most misunderstood principle: neither Shape Up’s “no backlog” nor our curated version means “we ignore urgent issues from the field.”</p><p>Production bugs, security incidents, SLA-bound fixes — these flow through a separate urgent track, just like in any responsible engineering organization. A P0 at 2 PM doesn’t wait for the next betting table. What both approaches eliminate is the feature backlog as a passive dumping ground — that ever-growing list of “someday” ideas that nobody actively champions but everyone feels obligated to maintain.</p><p>In traditional Scrum, a P0 production bug sits next to a feature idea from several quarters ago, and both compete for sprint capacity. In our model, urgent work has its own lane. It doesn’t pollute strategic decisions, and strategic work doesn’t block urgent responses.</p><h3>Building — With a Circuit Breaker</h3><p>Once a bet is placed, the team gets six weeks of uninterrupted time. No scope changes. No stakeholder check-ins. No one asking for status updates. The team owns the problem and discovers the tasks as they go — because real tasks only emerge when you start building, not when you’re sitting in a planning meeting imagining what you’ll need.</p><p>Progress is tracked with hill charts instead of burndown charts. Every scope sits on a hill: the left side is “figuring it out” (unknowns, exploration, risk), the right side is “making it happen” (execution, known work). A scope stuck on the uphill side for too long is a red flag — even if a burndown chart would show “progress.”</p><p>And here’s the most radical rule: if it’s not done in six weeks, it doesn’t get extended. It gets killed. The circuit breaker trips. This sounds brutal, but it’s actually the most humane policy in the entire framework — it prevents the slow soul-crushing death of projects that drag on for months with no end in sight.</p><h3>Cooldown — The Part Scrum Forgot</h3><p>Between every cycle, there’s a two-week cooldown. Developers fix bugs, tackle tech debt, explore ideas, or just breathe. Shapers prepare pitches for the next betting table.</p><p>This is the thing Scrum teams dream about but never get. Back-to-back sprints create a relentless pace that leads to burnout and mountains of technical debt. Cooldown periods acknowledge what everyone knows but nobody says: you can’t sprint forever. That’s not how humans work.</p><h3>Where We Fork From Shape Up</h3><p>We said earlier this isn’t a copy-paste adoption. Here’s the most significant place where we break from the original framework — and why we’re telling you about it now instead of saving it for Part 2.</p><p><strong>The curated backlog.</strong> We described this in the betting section above, but it deserves emphasis as a deliberate architectural decision. Pure Shape Up says: no backlog. Period. If an idea doesn’t get bet on, it dies. If it matters, someone will re-pitch it.</p><p>We tried this during our POC phase. It didn’t survive contact with our reality.</p><p>At Basecamp’s scale — a single product, a tight team with deep shared context — the “no backlog” philosophy works because nothing truly important gets lost. The people who care about an idea are the same people at the betting table. Institutional knowledge lives in a small number of heads.</p><p>At our scale — multiple product lines, dozens of teams, enterprise clients across different verticals — ideas that don’t get bet on in one cycle can genuinely disappear. Not because nobody cares, but because the person who championed it rotated teams, or the context shifted, or the customer need got buried under three months of other priorities. We watched it happen during the POC. Important patterns re-emerged months later, re-discovered from scratch, as if the original work had never existed.</p><p>So we made a conscious choice: keep the backlog, but invert the default. Items expire unless someone actively fights for them. Every cycle, the backlog gets pruned — not groomed, pruned. The difference matters. Grooming is maintenance. Pruning is editing. You’re not asking “is this still accurate?” You’re asking “does anyone still care enough to shape this into a pitch?”</p><p>This is our biggest fork. Part 2 will tell you whether it was the right call — or whether we should have trusted the original philosophy and accepted the discomfort.</p><h3>Why This Methodology + AI-Driven Development Is the Combination Nobody’s Talking About</h3><p>Here’s where our experiment gets interesting.</p><p>Shape Up was designed in 2019 — before AI coding assistants existed. It was built for human-only teams. But something unexpected happens when you combine Shape Up’s principles with AI-augmented development.</p><p><strong>The appetite math changes.</strong> When your developers are 3–5x more productive with AI tools, a “6-week appetite” feature in 2023 might be a “2-week small batch” in 2026. This means you can bet on more ambitious work per cycle — or ship the same scope with smaller teams. Shape Up’s appetite-based thinking adapts to this naturally. Story points don’t. Story points are calibrated to a fixed human pace that no longer exists.</p><p><strong>Shaping gets sharper.</strong> AI assistants are extraordinary at executing well-defined work and terrible at navigating ambiguity. This makes shaping more important, not less. A well-shaped pitch with clear boundaries, identified rabbit holes, and explicit no-gos is exactly the kind of input that a developer + AI pair can crush in 6 weeks. A vaguely scoped Jira ticket? The AI amplifies the confusion.</p><p><strong>The circuit breaker becomes less scary.</strong> One of the biggest objections to Shape Up is “but what if we waste 6 weeks?” With AI-augmented development, the team can explore and prototype faster in the first week, hit the uphill unknowns earlier, and make the “kill or continue” decision sooner. The hill chart becomes even more honest because the downhill execution phase compresses dramatically.</p><p><strong>Sprint cycles feel even more absurd.</strong> If a developer can prototype a feature in a day with AI assistance, spend two days refining it, and have it production-ready by Thursday — what exactly is the point of a 2-week sprint with Monday planning, daily standups, and Friday demos? The overhead-to-work ratio becomes grotesque.</p><p>We’re not adopting Shape Up. We’re not just adding AI tools. We’re building a new methodology — Shape Up’s philosophy as the starting inspiration, our own operational DNA as the muscle, rapid adaptability as the reflex, and AI-driven development as the nervous system. Something that will earn its own name. For now, we’re calling it “the experiment.” By Part 2, we might be calling it something else entirely.</p><h3>The Missing Piece: Teaching Your Team to Think With AI</h3><p>There’s a hidden prerequisite that most “AI-driven development” articles skip entirely: your team needs to know how to talk to these models.</p><p>I wrote about this in <a href="https://bit.ly/4krvahv"><em>The Philosophy of Prompting</em></a> — the idea that prompting an AI isn’t just a technical skill, it’s a thinking skill. The way you articulate a problem to a machine reveals how well you actually understand the problem yourself. Garbage in, garbage out isn’t just a cliche — it’s the fundamental law of AI-augmented development. You need to translate your intent clearly and completely, or the output will be technically functional but strategically wrong.</p><p>This is where Shape Up and AI-driven development connect at a deeper level than most people realize. <strong>Shaping is prompting at the project level.</strong> A well-shaped pitch — with a clear problem, bounded appetite, rough solution, identified rabbit holes, and explicit no-gos — is essentially a perfectly structured prompt for a team of humans + AI. The same discipline that makes a good pitch also makes a good AI interaction: clarity of intent, explicit constraints, and knowing what you don’t want.</p><p>The teams that get this right won’t just be faster. They’ll be building a fundamentally different relationship with their tools — one where the quality of human thinking determines the quality of AI output, not the other way around.</p><h3>The Guinea Pig: ByteMasters</h3><p>We chose ByteMasters for this experiment. They build conversational commerce experiences — the AI-powered shopping assistant that helps users discover, explore, and purchase products through natural conversation.</p><p>Why this team? Start with the data: ByteMasters was one of our three POC teams — and the one that delivered the strongest results. During the proof-of-concept phase, they took a feature end-to-end using shaped pitches and appetite-based scoping. No sprints, no story points, no grooming sessions. The feature shipped to production with clean code reviews, no QA regressions, and zero post-release hotfixes. Their POC cycles finished with less scope creep and fewer carry-over items than equivalent Scrum sprints would have produced. They didn’t just test the methodology — they proved it could deliver real, production-quality work. They earned the right to go first.</p><p>Beyond the POC results, the team profile fits. They’re autonomous, experienced, and hungry for change. They’ve been running Scrum for years and feeling the same friction patterns we described above. They own a distinct product area with minimal cross-team dependencies — the ideal conditions for piloting a new methodology.</p><p>They also had a backlog that perfectly illustrates what we’re trying to fix: an epic that had evolved well beyond its original scope over multiple quarters of active development. A handful of items were actively in progress, but the majority reflected earlier priorities that no longer aligned with current direction — a clear candidate for reshaping rather than continued grooming.</p><h3>Our First Bet: A Feature That Would Normally Take 5 Sprints</h3><p>We can’t share the details of what we’re building — not yet. What we can tell you is this:</p><p>Under our current Scrum process, this feature was estimated at approximately 5 sprints — that’s 10 weeks of sprint time, plus the overhead of 5 planning sessions, 50 daily standups, 5 sprint reviews, 5 retrospectives, and countless grooming sessions in between. In reality, with carry-overs and context switching, it would probably stretch to 12–14 weeks before it actually shipped. We’ve all seen how “5 sprints” becomes “4 months” in practice.</p><p>We shaped it into one 6-week cycle.</p><p>Not by cutting corners. Not by removing scope. By shaping it properly — defining the problem with brutal clarity, setting an appetite that reflects the feature’s actual strategic value, sketching a solution at the right level of abstraction, identifying the rabbit holes that could swallow the timeline, and explicitly declaring what we will NOT build.</p><p>The same feature. The same team. A fundamentally different approach to framing, planning, and executing the work.</p><p>We held a betting table — four people, forty-five minutes. The pitch got bet on. No 200-ticket backlog. No estimation poker. No velocity charts. One well-shaped pitch, one strategic conversation, and a team that knows exactly what they’re building, why it matters, what’s out of scope, and when they’re done.</p><p>That’s it. The feature details? You’ll see them in Part 2 — along with whether shaping a “5-sprint feature” into a single cycle was genius or delusion.</p><h3>How We’re Tracking Progress</h3><p>No burndown charts. No story points. No percentage-complete theater.</p><p>We’re using hill charts. Every meaningful scope of work sits on a hill:</p><p>The left side is “figuring it out” — unknowns, open questions, architectural decisions that haven’t been made yet. The right side is “making it happen” — the unknowns are resolved, you’re just executing.</p><p>Here’s why this matters more than any Scrum metric: a scope stuck on the uphill side at Week 4 is a visible, specific, actionable red flag. You can see exactly which piece of the project is stuck in the unknown zone and intervene — either simplify the scope or escalate the blocker. In Scrum, the same situation hides behind “75% of story points completed” and nobody realizes there’s a problem until the last day of the sprint.</p><p>The hill chart doesn’t just track progress. It tracks honesty.</p><h3>What We’ll Measure in Part 2</h3><p>When the experiment wraps, we’re publishing Part 2 with raw results. No spin. Here’s what we’ll track:</p><p><strong>Delivery.</strong> Did the feature ship in one cycle? Did the circuit breaker trip? How much scope was cut versus the original pitch?</p><p><strong>The 5-sprint question.</strong> Did shaping a “5-sprint feature” into one 6-week cycle actually work — or did we just compress the pain into a shorter window?</p><p><strong>New methodology vs. Scrum.</strong> Ceremony hours per week. Cycle time from idea to production. Carry-over rate. Team satisfaction survey — same questions, both methodologies.</p><p><strong>AI-driven development.</strong> How did AI tools change appetite calculations? Which scopes moved downhill faster? Where did AI NOT help?</p><p><strong>Our design choices.</strong> Did the curated backlog earn its keep, or should we have gone full “no backlog”? Which of our additions beyond Shape Up’s foundations added value? Which ones created friction? What would we keep, drop, or change for Cycle 9?</p><p><strong>The human stuff.</strong> How does the team feel? Did the cooldown actually happen, or did we cheat? Did anyone miss standups? (Seriously.)</p><h3>The Honest Risks</h3><p><strong>Shaping at full scale is a skill we’re still building.</strong> We wrote pitches during the POC phase — smaller-scoped, lower-stakes versions that helped us learn the format. But a full 6-week cycle pitch is a different animal. The appetite is bigger, the rabbit holes are deeper, and the consequences of a badly shaped pitch are six weeks of a team’s time, not a two-week experiment. Our first full-cycle pitches might miss something that blows up the timeline.</p><p><strong>The circuit breaker might break us.</strong> If the feature doesn’t ship and we have to kill it, that’s a real emotional hit. The policy exists for good reasons, but living through it for the first time will test our conviction.</p><p><strong>5 sprints into 1 cycle is an ambitious claim.</strong> Maybe the Scrum estimate was inflated. Maybe our shaping cut too much scope. Maybe 6 weeks isn’t enough and we’re about to learn that the hard way. We’ll know when the cycle ends.</p><p><strong>We’re combining multiple experiments at once.</strong> New framework and AI-driven development. If something fails, isolating the variable will be hard. We’re accepting this risk because we believe they’re complementary — but we might be wrong.</p><p><strong>Cross-team sync.</strong> Our other teams are still running Scrum. A 6-week cycle doesn’t align with 2-week sprints. If there are dependencies we missed, we’ll feel the friction.</p><h3>Why We’re Publishing This</h3><p>Because everyone writes about methodologies in retrospect. “We switched to X and it was great!” Nobody shows you the moment before the jump — the uncertainty, the incomplete plan, the genuine risk of public failure.</p><p>We’re showing you that moment. Right now.</p><p>The pitch is written. The bet is placed. The team starts building on Monday.</p><p>When the experiment is done, Part 2 drops with one of three stories:</p><p><strong>It worked.</strong> The methodology is the future and here’s the proof. And yes — we gave it a name.</p><p><strong>It partially worked.</strong> Some borrowed principles were gold, some of our own additions missed, some need tuning. The nuanced answer that’s probably most useful.</p><p><strong>It failed.</strong> We went back to Scrum — or we evolved into something else entirely. Here’s what we learned.</p><p>Whatever the answer is, you’ll get the truth.</p><p>See you in Part 2.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=00b5d281a2fc" width="1" height="1" alt=""><hr><p><a href="https://medium.com/insiderengineering/we-stopped-sprinting-and-bet-on-shipping-00b5d281a2fc">We Stopped Sprinting and Bet on Shipping</a> was originally published in <a href="https://medium.com/insiderengineering">Insider One Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Stop Using AI. Start Delegating to It.]]></title>
            <link>https://medium.com/@reza.farzaneh/stop-using-ai-start-delegating-to-it-cdfb7d0da6be?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/cdfb7d0da6be</guid>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[ai-agent]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Sat, 14 Feb 2026 20:28:03 GMT</pubDate>
            <atom:updated>2026-02-14T20:28:03.424Z</atom:updated>
            <content:encoded><![CDATA[<p>Reza Farzaneh — Staff Software Engineer</p><p><em>The difference between people who get 10x results from AI and those who don’t isn’t talent — it’s how they think about the work.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RoQXIzg1zq6bKR9J2qJzWw.png" /></figure><p>In 1913, Henry Ford didn’t invent the car. He didn’t even invent the assembly line. What he invented was a way of thinking about work — break it into pieces, give each piece to a specialist, and let the system produce something no individual could.</p><p>A century later, we’re watching the same revolution happen again. Except this time, the specialists aren’t people on a factory floor. They’re AI agents. And the assembly line isn’t a physical conveyor belt — it’s the skills and instructions you feed them.</p><p>Here’s the uncomfortable truth: most people are still using AI like a fancy search engine. They type a prompt, get an answer, and move on. That’s like hiring four world-class engineers and asking them all to answer emails.</p><p>The game is shifting right now. And where we stand today — February 2026 — it’s all about <strong>agents</strong> and <strong>skills</strong>. Not prompts. Not chat. Delegation.</p><h3>What Most People Get Wrong</h3><p>Here’s a problem we actually had. Every time a candidate applied to an engineering role at our company, someone — usually a team lead or senior engineer — had to stop what they were doing and review the candidate’s code project. On average, we waited <strong>three days</strong> to get a response. Three days where the candidate sits in limbo. Three days where your best engineers are doing hiring work instead of engineering work.</p><p>Now imagine you open ChatGPT and paste in a candidate’s GitHub repo. “Review this project and tell me if they’re good enough.” You get a response. It’s… vague. Generic. It doesn’t know your team’s standards, your tech stack, or what “good enough” means for a backend role versus a QA role versus a mobile role.</p><p>That’s what most people do with AI.</p><p>They open a chat window, dump their entire problem into it, and expect magic. They prompt. They tweak. They retry. They give up.</p><p>The irony is that the more powerful the tool, the worse people use it. Because most of the time, they get something mediocre — not because AI isn’t capable, but because a generalist doing everything will always lose to specialists doing what they do best.</p><blockquote><em>The secret isn’t a better prompt. It’s a better org chart.</em></blockquote><h3>The Agent Model: Give AI a Job Title</h3><p>Instead of one AI doing everything, you define <strong>agents</strong> — each with a clear role, a specific set of tools, and instructions that match the job.</p><p>So we built a candidate review pipeline. Instead of one overloaded chat prompt, we set up:</p><ul><li><strong>A Repo Analyzer</strong> — clones the candidate’s project, detects the tech stack, and analyzes the structure. Their job ends when the analysis is done.</li><li><strong>A Team Reviewer</strong> — takes that analysis and evaluates the code against <em>that specific team’s</em> standards. The backend team reviews for Go patterns and API design. The mobile team reviews for Flutter architecture and state management. The QA team reviews for test coverage and automation frameworks. Each team has its own agent with its own criteria.</li><li><strong>A Security Reviewer</strong> — scans for hardcoded secrets, vulnerable dependencies, and security anti-patterns. Cross-team. Every candidate gets this.</li><li><strong>A Report Generator</strong> — calculates the final score, detects AI-generated code, and produces a structured hire/no-hire recommendation with evidence.</li></ul><p>Four core agents. Seven teams plugged in. One pipeline.</p><p>Each agent is good at their piece because they’re <em>only</em> doing their piece. The repo analyzer doesn’t judge code quality. The team reviewer doesn’t scan for secrets. The report generator doesn’t re-analyze — it synthesizes.</p><p>This is not hypothetical. This is running in production at our company right now. HR types one command, and <strong>two minutes later</strong> they have a structured evaluation. The same review that used to take three days.</p><h3>Skills: The Instructions That Make Agents Smart</h3><p>An agent without skills is like a new hire on day one — capable, but directionless.</p><p><strong>Skills</strong> are the playbooks you give your agents. They’re not vague. They’re specific. They tell the agent:</p><ul><li>What to do when invoked</li><li>What format to produce</li><li>What quality bar to hit</li><li>What tools to use</li><li>What to hand off and to whom</li></ul><p>Here’s what makes this powerful: each team at our company defines their <em>own</em> skills. The backend team’s Go review skill checks for proper error handling, clean API design, and concurrency patterns. The mobile team’s Flutter review skill checks for widget architecture, state management, and platform-specific conventions. The QA team even has a completely different scoring system — a 50-point direct scale instead of the standard weighted categories.</p><p>You wouldn’t hire a senior engineer and say “review stuff.” You’d say: “Here’s our coding standards. Here’s our scoring rubric. Here’s what a strong candidate looks like for <em>this team</em>. Now evaluate.”</p><p>That specificity is the difference between AI output you throw away and AI output you ship.</p><p>Here’s what the candidate review pipeline looks like:</p><pre>Step 1: Clone &amp; analyze the repo       → detects tech stack and structure<br>Step 2: Review against team standards   → evaluates code quality per team criteria<br>Step 3: Security scan                   → checks for secrets and vulnerabilities<br>Step 4: Generate report                 → produces score and recommendation</pre><p>And here’s another one — the article you’re reading right now was produced by a content pipeline:</p><pre>Step 1: Research the topic        → produces a research brief<br>Step 2: Write the draft           → produces a full article<br>Step 3: Edit for quality          → polishes in-place<br>Step 4: Optimize for discoverability → adds SEO and structure</pre><p>Same pattern. Different domain. Each step is a skill. Each skill invokes a specific agent. Each agent has tools and instructions tailored to their job.</p><p>No step tries to do another step’s job. And honestly, defining good skills is harder than it sounds — our first versions produced output that needed heavy rework. But each iteration makes the pipeline sharper.</p><h3>Why This Matters More Than You Think</h3><p>In 2–3 months, the specific tools will change. The interfaces will evolve. New models will drop. But the <em>pattern</em> — break work into roles, give each role clear instructions, chain them together — that pattern is here to stay.</p><p>It’s the same pattern behind every scalable system humans have ever built. Assembly lines. Microservices. Unix philosophy. Org charts.</p><blockquote><em>Pipe small, specialized things together. That’s how you build something bigger than any one piece.</em></blockquote><p>If you’re still using AI as a single chat window, you’re leaving most of its power on the table. It’s like having a Kubernetes cluster (a system designed to run hundreds of specialized containers) and running everything on one pod.</p><h3>The Real Skill Is Knowing What to Delegate</h3><p>Here’s the paradox that trips people up: <strong>the better AI gets, the more your human judgment matters.</strong></p><p>Not less. More.</p><p>Because when you can spin up agents that analyze repos, review code, scan for security issues, and generate reports — the bottleneck isn’t execution anymore. It’s <em>direction</em>. It’s knowing:</p><ul><li>What criteria define a strong candidate for <em>this</em> team?</li><li>What scoring thresholds make sense?</li><li>When should a human override the recommendation?</li><li>What’s the quality bar for the review itself?</li></ul><p>That’s you. That’s the human in the loop. Not doing the work — <em>directing</em> it.</p><p>The people who will thrive in this era aren’t the ones who learn the most prompts. They’re the ones who learn to think like managers of AI teams. Who can break a fuzzy goal into clear tasks. Who can define “done” for each task. Who can look at the output and know whether it hits the bar.</p><h3>A Practical Framework You Can Use Today</h3><p>If you want to start working this way, here’s the simplest version:</p><h3>1. Map Your Workflow to Roles</h3><p>Take any recurring task. Break it into stages. Each stage becomes an agent.</p><p>Reviewing candidates? Analyze Repo → Review Code → Scan Security → Generate Report. Writing a blog? Research → Write → Edit → Optimize. Building a feature? Design → Implement → Review → Test.</p><h3>2. Define the Skills for Each Role</h3><p>For each agent, write down:</p><ul><li><strong>What</strong> they produce (a brief, a draft, a review, a report)</li><li><strong>How</strong> they should produce it (format, tone, length, structure)</li><li><strong>What tools</strong> they need (web search, file access, code execution)</li><li><strong>What quality looks like</strong> (examples, checklists, constraints)</li></ul><h3>3. Chain Them Together</h3><p>The output of one agent becomes the input of the next. Research feeds writing. Writing feeds editing. Editing feeds optimization.</p><p>Each handoff should be clean — the next agent shouldn’t need to guess what happened before.</p><h3>4. Review the Output, Not the Process</h3><p>Your job is quality control at the end, not micromanagement in the middle. Trust the pipeline. Check the result. Adjust the skills if the output consistently misses the bar.</p><h3>The Cards Are Being Reshuffled</h3><p>Until six months ago, the game was about prompt engineering — crafting the perfect input to get a good output. That still matters, but it’s table stakes now.</p><p>Today, the game is about <strong>architecture</strong>. How you structure the work. How you define the roles. What instructions you encode as skills. How you chain agents into pipelines that produce consistent, high-quality output.</p><p>Tomorrow? Maybe agents become more autonomous. Maybe they start defining their own skills. But right now, the leverage is in the design — and that design is yours to create.</p><p>Henry Ford didn’t build better cars by working harder. He built them by thinking differently about how work gets done — who does what, in what order, with what tools.</p><p>That’s the exact same opportunity sitting in front of you right now. The AI models are your specialists. The skills are your playbooks. And you? You’re the one who decides what gets built.</p><p>Stop prompting. Start delegating. Define the agents. Write the skills. Build the pipeline. And let the system produce something no single prompt ever could.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cdfb7d0da6be" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Philosophy of Prompting: How Asking Questions to Machines Reveals How We Think]]></title>
            <link>https://medium.com/insiderengineering/the-philosophy-of-prompting-how-asking-questions-to-machines-reveals-how-we-think-c7cf82f6a2ef?source=rss-813b8980f972------2</link>
            <guid isPermaLink="false">https://medium.com/p/c7cf82f6a2ef</guid>
            <category><![CDATA[claude-code]]></category>
            <category><![CDATA[aiera]]></category>
            <category><![CDATA[writing-prompts]]></category>
            <dc:creator><![CDATA[Reza Farzaneh]]></dc:creator>
            <pubDate>Wed, 11 Feb 2026 06:50:40 GMT</pubDate>
            <atom:updated>2026-02-11T06:50:40.864Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>Reza Farzaneh</strong> — Staff Software Engineer</p><p><strong><em>Why prompt engineering isn’t just a technical skill — it’s a mirror for human thought itself.</em></strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*iFS95IWo-I5UOSmk_WcbFA.png" /></figure><h3>Socrates Never Needed an API Key</h3><p>Twenty-four centuries ago, a man wandered the streets of Athens asking people uncomfortable questions. He didn’t lecture. He didn’t hand out scrolls. He just… asked. And through those questions, he peeled back layers of assumption until his interlocutors — sometimes painfully — arrived at something closer to truth.</p><p>Today, millions of people sit in front of a blinking cursor, trying to get an AI to do what they want. Most of them don’t realize it, but they’re engaged in the same fundamental act Socrates was: the art of formulating the right question.</p><p>We call it “prompt engineering.” But strip away the Silicon Valley branding and what you’re left with is something ancient: the struggle to externalize thought into language precise enough to be understood by another mind — except this time, the other mind is artificial.</p><p>This isn’t an article about how to write better prompts. There are plenty of those. This is about what the act of prompting reveals about us — about how we think, what we fail to communicate, and why learning to structure your thinking for a machine might be the most valuable professional skill of the 21st century.</p><h3>You Don’t Know What You Want (Until You Have to Say It)</h3><p>Here’s a common experience: you open ChatGPT or Claude, type “help me with my project,” and get back something vaguely useful but mostly generic. You frown. You try again. You add details. You specify. By the fifth attempt, you realize something unsettling:</p><p><strong>You didn’t know what you actually wanted until you were forced to articulate it.</strong></p><p>This is an epistemological problem — a question about the nature of knowledge itself. Philosophers have long distinguished between tacit knowledge (things you know but can’t easily express) and explicit knowledge (things you can clearly state). Michael Polanyi captured this beautifully: “We know more than we can tell.”</p><p>Prompting an AI is, in a very real sense, an exercise in converting tacit knowledge into explicit language. And it turns out we’re shockingly bad at it. Not because we’re unintelligent, but because most human communication relies on shared context, body language, tone, implication, and a thousand unspoken assumptions that no prompt can carry.</p><p>When you write a prompt, you’re forced to confront the gap between what’s in your head and what you can put into words. That gap — that uncomfortable space — is where philosophy has lived for millennia.</p><h3>The Wittgenstein Problem: Your Prompt Is Your World</h3><p>Ludwig Wittgenstein, arguably the most influential philosopher of language in the 20th century, wrote: “The limits of my language mean the limits of my world.”</p><p>He meant that we can only think about what we can express in language. If you lack the vocabulary for a concept, that concept effectively doesn’t exist in your cognitive world.</p><p>Now apply this to prompting.</p><p>A software engineer prompting an AI about system architecture will naturally produce richer, more specific prompts in their domain than a marketing manager would. Not because one is smarter, but because one has the linguistic framework — the vocabulary, the mental models, the conceptual scaffolding — to articulate what they need.</p><p>This creates a fascinating paradox: <strong>the people who need AI’s help the most are often the least equipped to ask for it effectively.</strong> A junior developer doesn’t know enough to describe the architecture they need. A first-time founder can’t articulate the business model they haven’t yet learned to name.</p><p>Prompting, then, is not a neutral skill. It’s bounded by your existing knowledge and language. The richer your mental models, the better your prompts. The better your prompts, the more useful the AI’s output. Which then enriches your mental models further.</p><p>It’s a virtuous cycle — but only if you have enough to start with. And that’s a problem worth thinking about.</p><h3>What Do You Mean? The Grice Problem</h3><p>In 1975, philosopher Paul Grice proposed a theory about how human communication actually works. He argued that successful conversation depends on a set of unspoken rules — what he called “conversational maxims.” Things like: be relevant, don’t say more than necessary, be clear, and be truthful.</p><p>But here’s the crucial insight: <strong>Grice showed that meaning is not just about words. It’s about intention.</strong></p><p>When you tell a friend “it’s cold in here,” you’re probably not delivering a weather report. You’re asking them to close the window. Humans navigate this effortlessly. We infer intention from context, relationship, and a lifetime of social learning.</p><p>AI models don’t have this luxury. They process your words — all of them, literally. When your prompt says “make it better,” the AI doesn’t know if you mean more formal, more concise, more creative, or more accurate. It doesn’t have access to the intention behind your words. It only has the words themselves.</p><p>This is why the gap between a bad prompt and a good one is so dramatic. A bad prompt assumes the AI can read between the lines. A good prompt makes the lines themselves carry all the meaning. In Gricean terms: a good prompt explicitly encodes the intention that human-to-human conversation carries implicitly.</p><p>Every time you rewrite a prompt because the AI “didn’t understand,” you’re essentially discovering — in real time — all the unspoken intentions your original words failed to convey.</p><h3>The Mirror: Your Prompt Quality Is Your Thinking Quality</h3><p>Here’s the uncomfortable truth that prompt engineering tutorials rarely mention:</p><p><strong>The quality of your prompts is a direct reflection of the quality of your thinking.</strong></p><p>A vague prompt doesn’t mean you’re bad at prompting. It means your thinking about the problem is still vague. A disorganized prompt means your thoughts about the task are disorganized. A prompt that produces irrelevant results often means you haven’t yet clarified — to yourself — what’s actually relevant.</p><p>This is why the most effective prompt engineers aren’t necessarily the most technical people. They’re the clearest thinkers. They’re the people who can decompose a complex problem into discrete, well-defined sub-problems. They can anticipate ambiguity and preempt it. They know what they want before they ask for it.</p><p>In this way, prompting is less like coding and more like writing a philosophy paper. The legendary writing advice from philosophy professors — be clear, define your terms, structure your argument, anticipate objections — maps almost perfectly onto prompting best practices.</p><p>Jim Pryor, a philosophy professor at UNC Chapel Hill, tells students: “Be concise but explain yourself fully. Make the structure obvious. Use plenty of examples.”</p><p>OpenAI’s prompting guide says: “Be specific and detailed. Split complex tasks into simpler subtasks. Use examples.”</p><p>These are not coincidental overlaps. They emerge from the same root challenge: taking the messy, nonlinear, associative chaos inside a human mind and flattening it into clear, sequential language.</p><h3>The Five-Prompt Journey: What Happens When You Think Out Loud</h3><p>There’s a pattern that almost everyone who uses AI regularly will recognize, even if they’ve never named it.</p><p>Your first prompt reflects what you think you want. Your second prompt corrects what you said wrong. By the third, you realize you’ve been framing the problem incorrectly all along. The fourth is a genuine reframing — you’re no longer editing your words, you’re restructuring your understanding. And by the fifth, for the first time, you actually know what you need. Not because the AI taught you, but because the act of repeatedly failing to articulate it forced your thinking to crystallize.</p><p>This is not a flaw of the process. It is the process. And the people who understand this use AI very differently from those who don’t.</p><p>But here’s what most people miss: this same dynamic doesn’t just apply to a single prompt in a chat window. It scales — and where it scales most painfully is in the world of AI agents.</p><h3>The Agent Illusion: When Unclear Thinking Meets Unlimited Delegation</h3><p>We’re now living in the era of AI agents — systems that don’t just answer questions but execute multi-step tasks, use tools, write code, search the web, and orchestrate entire workflows. The promise is seductive: describe what you want, and let the agent figure out how to get it done.</p><p>But here’s what actually happens when you delegate to an agent without first clarifying your own thinking: the agent runs. It consumes context. It makes tool calls. It generates intermediate outputs. And somewhere around the third or fourth step, things start to drift. The agent fills in ambiguity with assumptions — reasonable-sounding but misaligned assumptions. By the time you see the final output, you’ve burned through your context window and what you’re looking at isn’t a hallucination in the technical sense. It’s the inevitable consequence of vague delegation meeting infinite execution capacity.</p><p>We blame the AI. We say it “hallucinated.” We say it “went off the rails.” But what actually happened is more uncomfortable: <strong>we asked something we hadn’t fully thought through, and the machine dutifully followed our confusion to its logical conclusion.</strong></p><p>This is the Mirror Hypothesis at scale. A single vague prompt produces a single vague answer — minor damage. A vague instruction to an autonomous agent produces a cascade of compounding misalignment — each step drifting slightly further from what you actually needed but never articulated.</p><p>The teams and practitioners who get the most out of AI agents aren’t the ones with the fanciest tools. They’re the ones who invest in something far less glamorous: <strong>defining the architecture of thought before the architecture of execution.</strong> They clarify what each agent is responsible for. They define the boundaries of each role — what it should do, what it should never do, what it should escalate. They design the communication protocols between agents the same way a good engineering leader designs communication protocols between teams: with clarity, with constraints, and with an explicit understanding of what “done” looks like.</p><p>In other words, they don’t just delegate tasks. They think through the task first — and then encode that thinking into the structure of the system itself.</p><p>This is the deepest practical implication of the philosophy we’ve been exploring. Whether you’re writing a single prompt or orchestrating a team of AI agents, the bottleneck is never the AI’s capability. The bottleneck is the clarity of the human thought that set it in motion.</p><p>The agents are only as good as the thinking that designed them. The prompts are only as good as the understanding behind them. And both are mirrors — not of artificial intelligence, but of the real kind.</p><h3>The Recursive Loop: When AI Writes the Questions</h3><p>Now things get interesting.</p><p>We’ve established that prompting is an act of externalizing thought — translating internal cognition into explicit language. But what happens when the AI starts doing this too?</p><p>We’re already there. Meta-prompting systems — AI writing prompts for other AI — are becoming standard practice. Frameworks like DSPy automatically optimize prompts. Companies use AI to evaluate AI outputs and refine the instructions that produced them.</p><p>This creates a recursive loop:</p><ol><li>Humans externalize thought into prompts.</li><li>AI processes those prompts and produces outputs.</li><li>AI systems analyze those outputs and generate better prompts.</li><li>Those better prompts produce better outputs.</li><li>Repeat.</li></ol><p>Philosophically, this is fascinating and slightly vertigo-inducing. If a machine can formulate questions better than we can, what does that say about the nature of questioning itself? Is the Socratic method something uniquely human, or is it a pattern — a structure of inquiry — that any sufficiently sophisticated system can learn?</p><p>There’s a pragmatic limit here: AI-generated prompts optimize for measurable outcomes. They get better at producing outputs that score well on defined metrics. But the most interesting questions — the ones Socrates asked, the ones that make philosophy philosophy — aren’t the ones with clear metrics. They’re the ones that make you reconsider the metrics themselves.</p><p>A machine can learn to ask “What’s the most efficient architecture for this system?” It’s far less clear whether it can learn to ask “Should we build this system at all?”</p><h3>Prompting as a New Liberal Art</h3><p>The medieval university organized knowledge into the “trivium” — grammar, logic, and rhetoric. These weren’t just academic subjects. They were the foundational skills of clear thinking: understanding language (grammar), reasoning correctly (logic), and communicating persuasively (rhetoric).</p><p>Prompting sits at the intersection of all three.</p><p>It requires <strong>grammar</strong> — not in the pedantic sense, but in the sense of understanding how language structure carries meaning. It requires <strong>logic</strong> — decomposing problems, structuring arguments, maintaining coherence. And it requires <strong>rhetoric</strong> — persuading the AI (or more precisely, steering it) toward the output you want by choosing the right framing, examples, and emphasis.</p><p>Maybe we should stop calling it “prompt engineering.” Engineering implies a technical skill — something you learn once and apply mechanically. What prompting actually demands is closer to a liberal art: a cultivated capacity for clear thinking, precise expression, and structured inquiry that improves with practice and deepens with wisdom.</p><h3>Conclusion: The Question Is the Answer</h3><p>The irony of the AI age is this: we built machines that can generate answers at superhuman speed, and discovered that the hard part was always the question.</p><p>A practical note: by the time you read this, the word “prompt” may already feel dated. The interfaces are evolving fast, and six months from now, the friction may be invisible. But the thinking discipline we’ve described here isn’t about prompts — it’s about clarity. And clarity compounds. The people who learn to structure their thinking now, using the tools already in their hands, will move faster today and adapt faster tomorrow. AI is evolving — we’ll see where it goes. But clear thinking never goes out of style.</p><p>Every time you sit in front of that blinking cursor and struggle to articulate what you want, you’re not just doing “prompt engineering.” You’re engaging in one of the oldest human activities there is — the attempt to make your own thinking legible, first to yourself, then to another mind.</p><p>Socrates believed that the unexamined life is not worth living. In the age of AI, we might update that:</p><p><strong>The unexamined prompt is not worth sending.</strong></p><p>Not because the AI won’t respond — it will, dutifully and instantly. But because the act of examining it, refining it, and making it precise is where the real value is created. The AI’s answer is just the receipt. The prompt was the work.</p><p>And maybe that’s the deepest lesson of all. AI is not broken. It’s not overhyped. It’s an extraordinarily powerful tool that rewards structured thinking. The people who say “AI doesn’t work” are almost always the people who haven’t invested in clarifying what they actually need. Structure your thinking — define your rules, your constraints, your context — and the results will speak for themselves.</p><p><strong><em>AI gave you a mirror. If you don’t like what you see, don’t blame the glass. Learn the tools, follow best practices, structure your thinking — and make sure you’re using the right tools to translate that thinking into AI effectively. Do that, and AI will compound your value exponentially.</em></strong></p><h3>References</h3><p>Polanyi, M. (1966). <em>The Tacit Dimension</em>. University of Chicago Press. — “We can know more than we can tell.” (p. 4)</p><p>Wittgenstein, L. (1921/1922). <em>Tractatus Logico-Philosophicus</em>. Translated by C.K. Ogden. Routledge &amp; Kegan Paul. — “The limits of my language mean the limits of my world.” (Proposition 5.6)</p><p>Grice, H.P. (1975). “Logic and Conversation.” In P. Cole &amp; J.L. Morgan (Eds.), <em>Syntax and Semantics, Vol. 3: Speech Acts</em> (pp. 41–58). New York: Academic Press.</p><p>Pryor, J. “Guidelines on Writing a Philosophy Paper.” Department of Philosophy, UNC Chapel Hill. Available at:<a href="http://www.jimpryor.net/teaching/guidelines/writing.html"> jimpryor.net/teaching/guidelines/writing.html</a></p><p>OpenAI. “Prompt Engineering Guide.” OpenAI Platform Documentation. Available at:<a href="https://platform.openai.com/docs/guides/prompt-engineering"> platform.openai.com/docs/guides/prompt-engineering</a></p><p>Khattab, O., Singhvi, A., Maheshwari, P., Zhang, Z., et al. (2024). “DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines.” <em>The Twelfth International Conference on Learning Representations (ICLR 2024)</em>. Stanford NLP. Available at:<a href="https://github.com/stanfordnlp/dspy"> github.com/stanfordnlp/dspy</a></p><p>Plato. <em>Apology</em> (38a). — “The unexamined life is not worth living.” (Attributed to Socrates.)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c7cf82f6a2ef" width="1" height="1" alt=""><hr><p><a href="https://medium.com/insiderengineering/the-philosophy-of-prompting-how-asking-questions-to-machines-reveals-how-we-think-c7cf82f6a2ef">The Philosophy of Prompting: How Asking Questions to Machines Reveals How We Think</a> was originally published in <a href="https://medium.com/insiderengineering">Insider One Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>