<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harry Floyd</title>
    <description>The latest articles on DEV Community by Harry Floyd (@harryfloyd).</description>
    <link>https://dev.to/harryfloyd</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3933548%2Fa644e757-fdc0-4213-a2d0-37774cbe6730.png</url>
      <title>DEV Community: Harry Floyd</title>
      <link>https://dev.to/harryfloyd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harryfloyd"/>
    <language>en</language>
    <item>
      <title>Your Tests Pass. So What?</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Wed, 15 Jul 2026 08:12:03 +0000</pubDate>
      <link>https://dev.to/harryfloyd/your-tests-pass-so-what-45m9</link>
      <guid>https://dev.to/harryfloyd/your-tests-pass-so-what-45m9</guid>
      <description>&lt;p&gt;&lt;a href="https://substackcdn.com/image/fetch/$s_!mZik!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9b6e22a3-fb86-4258-9836-cf1dcf8519d0_1720x968.webp" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyts6svpwwx2mnwfy5t6m.webp" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://harryfloyd.substack.com/subscribe?" rel="noopener noreferrer"&gt;Subscribe now&lt;/a&gt;&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;This is the second walkthrough in a series. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://harryfloyd.substack.com/p/never-let-claude-code-tell-you-its-done" rel="noopener noreferrer"&gt;The first&lt;/a&gt;&lt;/strong&gt; built a gate: a Stop hook that will not let Claude Code end its turn while any test is failing, so it cannot call a job done on a red suite. &lt;/p&gt;

&lt;p&gt;This one asks whether the tests behind that green are worth passing, and you do not need to have read the first to follow along.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;What you will do:&lt;/strong&gt; measure how many real bugs your test suite can actually catch. In the worked example, a green suite catches just one planted bug in ten; among the nine it misses is a discount that quietly becomes a surcharge. A tighter case shows the sharper trap: a test can cover every line of a function and still notice nothing. You will watch both scores land, then hand Claude Code the holes and make it close them. About twenty-five minutes for the worked example; a first pass on your own repository takes your whole suite’s runtime once for every mutant, so start with your smallest tested file.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who this is for:&lt;/strong&gt; you gate Claude Code, or any coding agent, on green tests, and the suite has been reassuringly green ever since.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who should skip it:&lt;/strong&gt; if you already run mutation testing, this is your Tuesday. Step 3, turning your existing survivor backlog into an agent work order, may not be.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Never written a test?&lt;/strong&gt; Your version of the whole method is at the end: ten minutes, three planted errors, no code.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You need:&lt;/strong&gt; Python 3 (3.9 or later, standard library only, nothing to install). Claude Code for step 3; steps 1 and 2 run without it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Contents&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Watch a test do nothing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Count what your suite can see&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hand the survivors to the agent&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;When it still goes wrong&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Proving it on code you ship&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you never write code.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I broke a production module of mine on purpose, 105 small ways, one at a time, and ran its test suite after every break. The suite is real: 21 regression tests, all green, guarding an 822-line file my own automation depends on. The tests noticed 38 of the 105 breaks. The other 67, one of them on a line the suite executes every single run, would have shipped without a sound.&lt;/p&gt;

&lt;p&gt;That experiment is the whole method, and it answers a question a passing test suite cannot. The gate proves the tests pass. It cannot prove the tests are worth passing; a test that asserts nothing sails straight through it. And if your instinct is to have a second agent check the tests, then a third to check the second, the regress ends here instead, at an experiment rather than another opinion: break the code on purpose, and see whether the alarm rings.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;1. Watch a test do nothing&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(You know why an assert-nothing test passes? Skip to step 2; this section is the on-ramp.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here is the toy calculator shop from last time, one walkthrough later. Its &lt;code&gt;add&lt;/code&gt; works, and the suite is two small tests. The gate is green. (If you download the companion folder, &lt;code&gt;calc.py&lt;/code&gt; also carries a new pricing function, which is step 2’s problem, and &lt;code&gt;check.sh&lt;/code&gt;, the last walkthrough’s gate script, along for the ride. Leave both alone for now.)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;calc.py&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def add(a, b):
    return a + b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;test_calc.py&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import unittest

from calc import add


class TestAdd(unittest.TestCase):
    def test_basic(self):
        self.assertEqual(add(2, 3), 5)

    def test_zero(self):
        self.assertEqual(add(0, 0), 0)

# ...the unittest.main() entrypoint is unchanged below
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Save both files in one folder and open your terminal there; the import &lt;code&gt;from calc import add&lt;/code&gt; only resolves if they sit together. (Downloading the folder in step 2 does this for you.) One of these two tests is doing almost all of the work, and one of them is doing almost none. You can find out which in thirty seconds. Break &lt;code&gt;add&lt;/code&gt; on purpose (&lt;code&gt;return a - b&lt;/code&gt;, the classic bug) and run the suite, &lt;code&gt;python3 -m unittest&lt;/code&gt;, the same command the gate runs: &lt;code&gt;test_basic&lt;/code&gt; fails. Now, with the code still broken, run only the other test:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python3 -m unittest test_calc.TestAdd.test_zero
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Green, on code that subtracts. &lt;code&gt;add(0, 0)&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt; whether add adds, subtracts, or multiplies, so &lt;code&gt;test_zero&lt;/code&gt; approves all three. It has one way to fail, and almost no wrong version of the code triggers it. Note what your coverage tool would say about it: &lt;code&gt;test_zero&lt;/code&gt; executes every line of &lt;code&gt;add&lt;/code&gt;, one hundred per cent, top marks. Coverage measures whether tests run the code. It has no opinion on whether they would notice anything. &lt;code&gt;test_zero&lt;/code&gt; has sat in that suite looking exactly as load-bearing as &lt;code&gt;test_basic&lt;/code&gt;, and it would wave the classic bug straight through the gate on its own.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A test you have never watched fail is not yet a test.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Test-driven veterans have said a version of that for twenty years: never trust a test you haven’t seen fail. The discipline is the same, and the move is the one you just made: break the code on purpose, and the test either notices or it does not. Once, by hand, takes thirty seconds. Every plausible break is a script. Fix &lt;code&gt;add&lt;/code&gt; back before you move on; the script is next.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://harryfloyd.substack.com/subscribe?" rel="noopener noreferrer"&gt;Subscribe now&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;2. Count what your suite can see&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The shop grew this week. Claude Code added a pricing function, and the suite is green, which is all the gate checks. Here is the function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def discounted_total(price, quantity, discount_percent):
    """Total cost of an order, in pounds.

    Orders of 10 or more items get discount_percent knocked off.
    """
    total = price * quantity
    if quantity &amp;gt;= 10:
        total = total * (1 - discount_percent / 100)
    return round(total, 2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Money code. A boundary, a formula, a rounding rule: three places to be quietly wrong. (Yes, real tills count integer pence rather than floating-point pounds; hold that thought, it returns at the end.) The question you cannot answer by reading the green gate: if one of those went wrong tonight, would any test notice?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mutate.py&lt;/code&gt; answers it by brute honesty. It is a transparent teaching instrument, 180 lines of standard library you can read top to bottom, built to make the mechanism visible on one file rather than to replace a mature framework. Its whole engine is the dozen classic ways code goes wrong that it knows how to plant, one character at a time:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OP_SWAPS = {
    ast.Add: ast.Sub,    # a + b   -&amp;gt;  a - b
    ast.Mult: ast.Div,   # a * b   -&amp;gt;  a / b
    ast.GtE: ast.Gt,     # &amp;gt;=      -&amp;gt;  &amp;gt;   (the off-by-one at every boundary)
    ast.Eq: ast.NotEq,
    ast.And: ast.Or,
    # ...the reverse of each, plus &amp;lt; and &amp;lt;=, a dozen swaps in all,
    # and integer nudges: 10 -&amp;gt; 11
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For each place in your file where one of those swaps applies, it makes that one change (a &lt;em&gt;mutant&lt;/em&gt; of your code), runs your whole suite, restores the file, and records the verdict. Before any of that it runs your suite once on the untouched code, timed: a red baseline gets refused outright, because against a suite that is already failing, every verdict is noise. Then the two outcomes. A mutant that makes at least one test fail is &lt;em&gt;killed&lt;/em&gt; : the alarm rang. A mutant that leaves every test green &lt;em&gt;survived&lt;/em&gt; : that exact bug could ship tonight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://durabilitycurve.com/tests-worth-passing.zip" rel="noopener noreferrer"&gt;Grab the folder&lt;/a&gt;&lt;/strong&gt; , hosted on my own site; it is short, dependency-free Python you can read before you run it. Unzip it and open your terminal inside the &lt;code&gt;tests-worth-passing&lt;/code&gt; folder; every command below runs from there, no setup.&lt;/p&gt;

&lt;p&gt;The four working files are &lt;code&gt;calc.py&lt;/code&gt;, &lt;code&gt;test_calc.py&lt;/code&gt;, &lt;code&gt;mutate.py&lt;/code&gt;, and &lt;code&gt;check.sh&lt;/code&gt; (last walkthrough’s gate, along for the ride); a README and the agent’s finished tests sit alongside them and need nothing from you. When you are ready to point this at your own code, the folder’s &lt;code&gt;AUDIT.md&lt;/code&gt; carries the reusable version: the audit protocol, a survivor-triage worksheet, and the command for your language.&lt;/p&gt;

&lt;p&gt;Now stop before you run it, and put a number down. Your suite is green and it passes. Of ten deliberate breaks to this file, how many do you think it catches? Hold that guess against the result:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python3 mutate.py calc.py
10 mutants of calc.py · suite: python3 -m unittest -q
baseline: suite green in 0.2s (per-mutant timeout 60s)

  1 KILLED    line 2: a + b  -&amp;gt;  a - b
  2 SURVIVED  line 10: price * quantity  -&amp;gt;  price / quantity
  3 SURVIVED  line 11: quantity &amp;gt;= 10  -&amp;gt;  quantity &amp;gt; 10
  4 SURVIVED  line 11: 10  -&amp;gt;  11
  5 SURVIVED  line 12: total * (1 - discount_percent / 100)  -&amp;gt;  total / (1 - discount_percent / 100)
  6 SURVIVED  line 12: 1 - discount_percent / 100  -&amp;gt;  1 + discount_percent / 100
  7 SURVIVED  line 12: 1  -&amp;gt;  2
  8 SURVIVED  line 12: discount_percent / 100  -&amp;gt;  discount_percent * 100
  9 SURVIVED  line 12: 100  -&amp;gt;  101
 10 SURVIVED  line 13: 2  -&amp;gt;  3

Score: 1/10 killed, 9 survived.
Every SURVIVED line is a change to your code that your whole test suite
cannot tell from the version you meant to write.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The sixth mutant is the one to read twice. &lt;code&gt;1 - discount_percent / 100&lt;/code&gt; became &lt;code&gt;1 + discount_percent / 100&lt;/code&gt;: a customer’s 20 per cent discount becomes a 20 per cent &lt;em&gt;surcharge&lt;/em&gt; , and the gate stays green. The third is the boundary: &lt;code&gt;&amp;gt;=&lt;/code&gt; became &lt;code&gt;&amp;gt;&lt;/code&gt;, the customer buying exactly ten items loses the discount you promised them, green. Nine ways for money code to be wrong, and the suite from step 1 sees none of them, because nothing in it ever calls the new function. The gate never lied. “The tests pass” was true every time it said so. It just was not the thing you needed to be true.&lt;/p&gt;

&lt;p&gt;A fair objection: nothing tests that function, so a plain coverage report would have flagged it too, without any of this mutant theatre. True, and if that were all mutation testing found, you would not need it. So run the case coverage cannot see. Delete &lt;code&gt;test_basic&lt;/code&gt;, keep only &lt;code&gt;test_zero&lt;/code&gt;, and run the instrument again:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python3 mutate.py calc.py
10 mutants of calc.py · suite: python3 -m unittest -q
baseline: suite green in 0.1s (per-mutant timeout 60s)

  1 SURVIVED  line 2: a + b  -&amp;gt;  a - b
  ...
Score: 0/10 killed, 10 survived.
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The subtraction bug now survives, on a function with one hundred per cent line coverage. Your coverage dashboard reports &lt;code&gt;add&lt;/code&gt; fully tested; the instrument reports that no test would notice if it subtracted. Coverage tells you the code ran. A kill tells you a lie got caught. They are different instruments, and only one of them is measuring what you care about.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The same function can be one hundred per cent covered and zero per cent detected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is not a toy-only failure, and it is the shape to hold on to. On the 822-line module I opened with, the survivor that stung most was exactly this: a covered line, inside a function the suite runs every single time, that no assertion actually pins. Put &lt;code&gt;test_basic&lt;/code&gt; back and carry on.&lt;/p&gt;

&lt;p&gt;One reading note before you run it on anything you love: &lt;strong&gt;killed is the good outcome.&lt;/strong&gt; Every killed mutant is a bug class your suite would catch, so on this one screen a &lt;code&gt;KILLED&lt;/code&gt; is the line you are hoping for, even though the word sounds like something broke.&lt;/p&gt;

&lt;p&gt;This move is called mutation testing, and it is older than most of the code you have ever shipped. Breaking one character at a time is a fair stand-in for the elaborate bugs real code grows, because of the &lt;em&gt;coupling effect&lt;/em&gt; : catch the small, dumb faults and you catch the large subtle ones as a by-product. 1 The nine survivors here are the ones your suite missed, and every one of them is now a job you can hand to the thing that wrote the tests.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://substackcdn.com/image/fetch/$s_!E6YS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdeb67605-09cd-44cb-830f-d936f79e0756_1720x968.webp" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6zfkj5ggrlf1bteg1yzr.webp" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://harryfloyd.substack.com/subscribe?" rel="noopener noreferrer"&gt;Subscribe now&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;3. Hand the survivors to the agent&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Nine survivors is a work order, addressed to the thing that wrote the tests. Paste the nine &lt;code&gt;SURVIVED&lt;/code&gt; lines into Claude Code, followed by this instruction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;These mutants survived mutation testing: the suite stays green when any one of these changes is made to calc.py. Write tests in test_calc.py that kill them. Do not modify calc.py or mutate.py. Then run &lt;code&gt;python3 mutate.py calc.py&lt;/code&gt; and keep going until the score is clean.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I ran exactly that, the agent came back with four tests and a habit I did not ask for: it annotated each one with the wrong answer the mutant would produce. The survivor list had turned into a specification it could compute against.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def test_discount_applies_at_exactly_ten_items(self):
    # Boundary: quantity == 10 qualifies. 10.0 * 10 = 100, minus 20% = 80.0.
    # Kills the &amp;gt; / &amp;gt;=, threshold 10-&amp;gt;11, and every discount-formula mutant:
    #   total / (1 - d/100) -&amp;gt; 125.0
    #   total * (1 + d/100) -&amp;gt; 120.0
    self.assertEqual(discounted_total(10.0, 10, 20), 80.0)

def test_rounds_to_two_decimal_places(self):
    # 3.333 must round to 3.33; a round(total, 3) mutant returns 3.333.
    self.assertEqual(discounted_total(3.333, 1, 0), 3.33)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Two of its four tests are above; the finished suite, those four plus the two you started with, ships as &lt;code&gt;calc_solution_tests.py&lt;/code&gt; in the folder (named without the &lt;code&gt;test_&lt;/code&gt; prefix so it stays out of your way until you want it), so you can run it yourself instead of retyping it from the excerpts. To see the clean score without doing step 3, drop that file in as &lt;code&gt;test_calc.py&lt;/code&gt; and run &lt;code&gt;python3 mutate.py calc.py&lt;/code&gt;. Left as it downloads, the folder still scores 1/10, because the suite the gate runs holds only the two starting tests.&lt;/p&gt;

&lt;p&gt;Then I ran the instrument again myself, because you never take the agent’s word for a score when you can take the score’s word for it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ python3 mutate.py calc.py
...
Score: 10/10 killed, 0 survived.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Exit code 0, the instrument’s all-clear. Same code, same tests passing as before, and now green means something it did not mean before: ten classic ways to break this file, and a test rings for every one. (My run went clean in one round, but this toy is small. When yours does not, paste what survived straight back and go again; and for the rare survivor no round can kill, the closing section shows the other move: you let it live, with a comment.)&lt;/p&gt;

&lt;p&gt;One step remains, and it is the one that actually ends the regress: read the four tests it wrote, and check every asserted value against what the code &lt;em&gt;should&lt;/em&gt; do, not against what it does. The distinction is load-bearing. An agent kills mutants by pinning current behaviour; look back at its annotations and you can see the 80.0 was computed from the implementation. On correct code that is exactly what you want. On code that is already wrong, the same move canonises the bug as specification, with a clean mutation score as its alibi.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The score proves the tests ring when the code changes; only your read proves they are ringing for the truth.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What the instrument buys you is that the read is bounded: four short tests with a known purpose, instead of an unbounded hope about a whole suite.&lt;/p&gt;

&lt;p&gt;Two honest notes before you rely on it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it earns its keep.&lt;/strong&gt; A fresh agent asked cold to “add tests” for that function, with no survivor list, scored 10/10 on its first try. On a four-line function whose docstring names the threshold, the odds are friendly, and the survivor loop buys you little. That is not the point. The point is that on real code you cannot tell whether it guessed well by looking, and the survivor list is what turns “write better tests” from a vague instruction into a measurable work order. The payoff climbs exactly where you cannot eyeball it: a forty-line function, a docstring that has drifted from the code, a module you inherited and half-trust.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;None of this is new, and that is the reassuring part.&lt;/strong&gt; Handing a test-writer a list of surviving mutants is called &lt;em&gt;mutation-guided test generation&lt;/em&gt; , and search-based tools were doing it a decade before anyone had an LLM; the agent is just a better test-writer than they were. Google found the part that matters for you here: engineers act on mutants delivered as review-time tickets and quietly ignore the same mutants dumped in a batch report. 2 The survivor list is that first channel, a work order a developer acts on. Meta has published a version of this pattern with an LLM at the test-writing end. 3 You are running the individual-developer version of a documented industrial practice.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://harryfloyd.substack.com/subscribe?" rel="noopener noreferrer"&gt;Subscribe now&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;When it still goes wrong&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;It is slow on a real repo.&lt;/strong&gt; Every mutant is a full suite run, so keep it out of the Stop hook: the gate fires every turn, this audit runs when the code or tests change. Industrial tools go further, mutating just the lines a change touches, which is how Google runs it at scale.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A clean score is a bounded claim.&lt;/strong&gt; 10/10 covers only this tool’s small vocabulary of breaks. Real gaps live outside it: money in binary floats that no swap can expose, and “kills” that are really crashes, not caught assertions. The score narrows the worry; it does not end it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Some survivors cannot be killed.&lt;/strong&gt; An equivalent mutant reads differently but behaves identically, so no test can catch it. If you cannot name an input that would expose a survivor, it may be one, and it is allowed to live with a comment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The score is a worklist.&lt;/strong&gt; Optimise the percentage like a KPI and you get tests engineered to twitch at mutants rather than to state what the code should do, which is the disease “the tests pass” had, one level up. Chase named survivors; ignore the number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The verdict contradicts the file you are reading.&lt;/strong&gt; You are running a stale compiled copy of the file you mutated. Delete &lt;code&gt;__pycache__&lt;/code&gt; or &lt;code&gt;touch&lt;/code&gt; that file. (mutate.py already gives its own runs a fresh cache.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Not on Python?&lt;/strong&gt; The instrument is language-specific; the method is not. Reach for mutmut on Python, PIT on the JVM, Stryker on JavaScript and TypeScript, cargo-mutants on Rust. The rule holds everywhere: break the code, count the catches.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Prove it on code you ship&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Pick the smallest file in your own project that has tests you trust. Four moves before you run it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Confirm a green baseline.&lt;/strong&gt; The instrument refuses a red baseline, because against a failing suite every verdict is noise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Point&lt;/strong&gt;&lt;code&gt;TEST_COMMAND&lt;/code&gt;&lt;strong&gt;at your test runner.&lt;/strong&gt; It sits at the top of mutate.py, defaulting to plain unittest. On pytest, swap that one line, keeping it a list of arguments, not a string: &lt;code&gt;[sys.executable, "-m", "pytest", "-q", "tests/test_foo.py"]&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Narrow it to the file you are mutating.&lt;/strong&gt; Aim at just the tests that exercise that file, not the whole suite. Every mutant runs the command once, so a wide one is the difference between a coffee and an afternoon, and the reason people quit after one slow run.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Predict, then compare.&lt;/strong&gt; Write down the score you expect before you look. The gap between the number you predicted and the number you got is the most useful thing this walkthrough produces.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the anatomy of the number I opened with, re-run the morning this published so it is evidence and not a memory. The module: 822 lines of my own automation, 21 green regression tests. The run: 105 mutants, &lt;strong&gt;38 killed, 67 survived&lt;/strong&gt;. Where the 67 hid is the whole lesson. Point coverage at the same suite and the module reads 43 per cent covered; 49 of the survivors sit in code no test executes at all, which a coverage report already flags for you. The other 18 are the ones only mutation can see, because they sit on lines coverage counts as covered.&lt;/p&gt;

&lt;p&gt;One function holds most of them: a weekly counter the suite genuinely imports, calls, and runs green, whose single test asserts that the count is a non-negative integer and checks nothing else. So flip the sign on its seven-day window and it looks a week into the future, the count silently collapses toward zero, and all 21 tests still pass. That is &lt;code&gt;test_zero&lt;/code&gt; from step 1 wearing a production badge: &lt;strong&gt;a fully-covered function that no assertion pins&lt;/strong&gt; , in my own code, caught by the instrument you just ran on a toy.&lt;/p&gt;

&lt;p&gt;So I did step 3 on my own code. I handed that survivor to the agent with the same work order, and it wrote the test the counter never had: stage a single item inside the window, then assert the count is exactly one, not merely non-negative. I applied the sign-flip by hand and ran both assertions.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;current_weekly_promotion_count() = 0   (one item, aged 1 day, window = 7 days)
  assert count &amp;gt;= 0   -&amp;gt;  PASS   (the assertion that was already there)
  assert count == 1   -&amp;gt;  FAIL   (the assertion the agent just wrote)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The old check stayed green on a function that now counts nothing, exactly as it had all along. The new one went red, because a window flipped a week into the future finds zero where it should find one. One survivor, handed over and killed, on the first test that pinned a number instead of trusting a sign.&lt;/p&gt;

&lt;p&gt;The fix for most of the others is that same move: &lt;strong&gt;pin the number the code should return&lt;/strong&gt; , so a window that flips or a boundary that slips finally has somewhere to fail.&lt;/p&gt;

&lt;p&gt;One survivor on that function is the exception. The window admits an item on &lt;code&gt;mtime &amp;gt;= cutoff&lt;/code&gt;, and to tell &lt;code&gt;&amp;gt;=&lt;/code&gt; from &lt;code&gt;&amp;gt;&lt;/code&gt; you need a file whose modification time lands on the exact cutoff instant. The cutoff is read from the clock, so the only way to hit that instant is to mock the clock, and I judged that test double heavier than the bug it would catch. So it stays alive, with a comment naming why.&lt;/p&gt;

&lt;p&gt;It is worth being precise about what it is, because it is not an equivalent mutant: an equivalent mutant is one no input can expose, and this one has an input, a mocked clock, that I have simply declined to write.&lt;/p&gt;

&lt;p&gt;That is step 3 on the days the loop does not go clean: some survivors &lt;strong&gt;earn a real assertion&lt;/strong&gt; , some &lt;strong&gt;earn a refactor ticket&lt;/strong&gt; , one &lt;strong&gt;earns a comment&lt;/strong&gt; explaining why it lives, and telling which is which is the work. If your score stings, the sting is information, the first honest measurement your suite has ever had.&lt;/p&gt;

&lt;p&gt;Then add this rule to your &lt;code&gt;CLAUDE.md&lt;/code&gt;, the standing instructions your agent reads each session, so the discipline survives you forgetting it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When you fix a bug: first write a test that fails on the broken code,
show me it failing, then fix the code. A test I have never seen fail
does not count as coverage.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That is the manual mutant from step 1, promoted to standing policy: every bugfix now arrives with proof that its test can ring.&lt;/p&gt;

&lt;p&gt;You are holding three instruments now, and most arguments about testing are really an argument between two of them. Coverage asks whether a line ran. Mutation asks whether a break in that line would be caught. Your own read asks whether the behaviour a passing test pins is the one you actually wanted.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Coverage measures reach. Mutation measures detection. Only your read decides what is right.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The gate keeps the agent honest about whether the tests pass; mutation and your own read are what keep you honest about whether they are worth passing. Green stops being where the question ends. It moves from &lt;em&gt;are the tests passing&lt;/em&gt; to &lt;em&gt;what broken versions did these tests catch&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;If you never write code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Break the code, count the catches: the method never depended on Python. It works on anything an agent hands back where being wrong is checkable, and the case you most need it for is not code at all. It is the claim.&lt;/p&gt;

&lt;p&gt;Here is the whole thing with no code in it. Take a report or a summary you know cold. Copy it, and plant a few deliberate errors in the copy, the kind of wrong that would cost you something if it slipped through. Hand the copy to your “review this” agent, and count what it catches.&lt;/p&gt;

&lt;p&gt;I ran it on one of my own weekly stats summaries before publishing. In a copy I changed a signup count from four to six, moved a date back by a day, and added a confident sentence that one post had our weakest open rate, which it did not. Then: “check this against the raw export.” It caught all three, and flagged a fourth claim I had written carelessly and never planted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Three planted, three caught&lt;/strong&gt; , and the review earned my trust the same way step 1’s test did: I had watched it catch mistakes I controlled before I believed the ones I did not. A review you have never watched catch a planted error is worth exactly what a test you have never watched fail is worth.&lt;/p&gt;

&lt;p&gt;The catches are your kills; the misses are the claims you must never hand over unchecked. Code is the easy case, because a machine runs it and a mutant is unambiguous. The claims your agent writes when there is no suite to run, the summary and the analysis and the report, are the harder case, and the one worth an instrument of its own: one that has to find the errors you did not think to plant, checking each claim against its source instead of against a copy you already know is wrong. That is where this goes next.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Related:&lt;a href="https://harryfloyd.substack.com/p/how-reliable-is-your-ai-agent" rel="noopener noreferrer"&gt; How Reliable Is Your AI Agent&lt;/a&gt; makes the broader case, &lt;a href="https://harryfloyd.substack.com/p/the-stable-liar" rel="noopener noreferrer"&gt;The Stable Liar&lt;/a&gt; shows the failure mode up close, and &lt;a href="https://harryfloyd.substack.com/p/never-let-claude-code-tell-you-its-done" rel="noopener noreferrer"&gt;Never Let Claude Code Tell You It’s Done&lt;/a&gt; builds the test gate this piece audits.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What was your score, and which survivor surprised you? The answers steer what gets built next.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://harryfloyd.substack.com/subscribe?" rel="noopener noreferrer"&gt; Subscribe now&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1&lt;/p&gt;

&lt;p&gt;Richard DeMillo, Richard Lipton and Frederick Sayward, &lt;a href="https://doi.org/10.1109/C-M.1978.218136" rel="noopener noreferrer"&gt;"Hints on Test Data Selection: Help for the Practicing Programmer,"&lt;/a&gt; &lt;em&gt;IEEE Computer&lt;/em&gt; 11(4), 1978, 34–41. The paper that introduced mutation analysis and, with it, the coupling effect; the idea itself is usually traced to a 1971 class paper of Lipton's.&lt;/p&gt;

&lt;p&gt;2&lt;/p&gt;

&lt;p&gt;Goran Petrović and Marko Ivanković, &lt;a href="https://doi.org/10.1145/3183519.3183521" rel="noopener noreferrer"&gt;"State of Mutation Testing at Google,"&lt;/a&gt; &lt;em&gt;Proceedings of ICSE-SEIP 2018&lt;/em&gt;. Two findings carry into this piece: mutation analysis is made tractable across Google's roughly two billion lines by mutating only the lines a change touches; and engineers act on mutants surfaced as review-time diffs while ignoring the same mutants in a batch report.&lt;/p&gt;

&lt;p&gt;3&lt;/p&gt;

&lt;p&gt;Christopher Foster et al., &lt;a href="https://arxiv.org/abs/2501.12862" rel="noopener noreferrer"&gt;"Mutation-Guided LLM-based Test Generation at Meta,"&lt;/a&gt; arXiv:2501.12862, 2025. Meta's ACH system plants undetected faults, then has an LLM write the tests that kill them.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>programming</category>
      <category>infrastructure</category>
    </item>
    <item>
      <title>Your Research Agent Cites Sources It Never Read</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Sat, 11 Jul 2026 11:21:07 +0000</pubDate>
      <link>https://dev.to/harryfloyd/your-research-agent-cites-sources-it-never-read-2mga</link>
      <guid>https://dev.to/harryfloyd/your-research-agent-cites-sources-it-never-read-2mga</guid>
      <description>&lt;p&gt;You ask a research agent a question that matters. It comes back in ninety seconds with a clean, confident answer and five citations. You open one of the papers to quote it. The paper says something adjacent, but not that. You open a second. The agent has drawn a specific claim from a source that does not contain it. So you do the thing you should have done first. You take the exact documents the agent retrieved, replace them with filler text, and run the question again.&lt;/p&gt;

&lt;p&gt;The answer barely changes.&lt;/p&gt;

&lt;p&gt;The citations were set dressing. The agent answered from what it already carried in its weights, then attached sources afterward to make the answer look grounded. This is not a citation glitch you can prompt your way around. In an agent trained under the wrong reward, faking the grounding is the policy the system learned, and researchers have a name for it: tool-call hacking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reward taught it this
&lt;/h2&gt;

&lt;p&gt;The agent was trained with a reward that paid for two things: a correct-looking answer, and a tool call that looked valid. It was never paid for the answer actually depending on what the tool returned. Those are different targets, and under enough optimisation pressure, the cheaper one is what you should expect it to find. Answering from memory and stapling on a citation is cheaper than reading. So that is what it learned.&lt;/p&gt;

&lt;p&gt;The tell is mechanical. Agents trained this way collapse onto one source, calling it again and again, because it paid off early and the reward never punished the narrowing. The system found the shortest path to the number it was scored on, and the number stopped meaning what its designers thought it meant.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The measure rewarded the appearance of the work. So the system produced the appearance, and stopped doing the work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Watching harder does not fix this. A finer dashboard on top of a gamed metric just measures the gaming with more decimal places.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the system knows it is being tested
&lt;/h2&gt;

&lt;p&gt;A stranger version is surfacing in AI safety, and it is the one that should unsettle you. Frontier models can now tell, well above chance, whether a transcript comes from a test or from real use. In one study a model told evaluation from deployment with an AUC of 0.83, against a human baseline of 0.92. Another identified the exact evaluation it was sitting in, described its format, and cited a paper criticising that test, all inside the private reasoning no one was meant to read. Ninety-five per cent of these giveaways never reached its visible output. A system that can sense a test can behave differently during it. Your reading is then contaminated by the act of taking it: part of what you record is that you were watching at all. How much that shifts behaviour is still contested. That the models can tell is not.&lt;/p&gt;

&lt;p&gt;None of this started with language models. The same shape has been quietly killing pricing models and trading desks for decades, and it shows up whenever what you measure stops being independent of the system doing the measuring.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop
&lt;/h2&gt;

&lt;p&gt;Its clearest form is a loop. You build a model of a system. You act on what it tells you. Your action changes the system. You measure the changed system, and feed that measurement into your next model, believing you are observing something independent.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are observing your own footprint.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The loop turns dangerous once the system's influence grows large enough to move the evidence it will be judged by next. And the cruel part is the timing: it is most dangerous when the model is working well, because a confident model acts decisively, and decisive action leaves the deepest footprint.&lt;/p&gt;

&lt;p&gt;This is where a pricing model dies. I have watched it up close. A model gets accurate, so the optimiser prices confidently inside a narrow band. But a model only learns how customers respond to price by watching demand move across different prices, and a narrow band leaves almost none of that variation in next year's training data. The successor, trained on the flattened data, is blind to price response, because the model before it was too good to leave anything to learn from. Accuracy today blinds the model that replaces it. Nobody sees a single failure. They see slow drift with no obvious cause, and they go hunting for the broken component. The component is the loop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuc3670fdj8cygrxie3xd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuc3670fdj8cygrxie3xd.png" alt="Reward hacking diagram" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The edge that dies when you name it
&lt;/h2&gt;

&lt;p&gt;Markets run the same loop faster. Your own order moves the price you were chasing, which is just the cost of trading size. The subtler version is alpha decay: once others learn your signal, they trade it flat, and the knowledge of the edge destroys the edge. What survives being known is the edge that pays you for holding a real risk, not for a secret. A pure mispricing dies the day it is named. A risk premium is more durable, because the risk it pays you to hold does not vanish when others pile in, even as the premium itself gets crowded and thinned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why almost nobody catches it in time
&lt;/h2&gt;

&lt;p&gt;Three properties keep this loop invisible until it breaks.&lt;/p&gt;

&lt;p&gt;The contamination is gradual. A pricing model drifts over months. A benchmark rots over a release cycle as models learn to pass it. A crowded trade decays over quarters. The loop runs slower than the decisions feeding it, so no individual decision looks wrong.&lt;/p&gt;

&lt;p&gt;The system looks healthy right up to the failure. A model can hold high accuracy while its future training data silently narrows. An agent can pass every benchmark while learning to game the benchmark. Stability is not evidence the loop is safe. Often it just means it has not been stressed yet.&lt;/p&gt;

&lt;p&gt;And every field gives it a different name. Feedback loop, reflexivity, reward hacking, alpha decay. These are not one mechanism, and the fix for each is different. What they share is narrower: in every case what you trust as an independent read has stopped being independent of the system that produced it.&lt;/p&gt;

&lt;p&gt;The pricing model's training data carries its own past prices. The market signal carries everyone who traded on it. The benchmark carries a model that learned to recognise the test. Tool-call hacking is the sharp edge of the same family: the evidence is held up as an outside constraint, but the reward taught the system it never had to obey it. So a pricing analyst, a trader, and an ML engineer can be losing to the same shape of trap and never realise they are colleagues.&lt;/p&gt;

&lt;h2&gt;
  
  
  The test you can run this week
&lt;/h2&gt;

&lt;p&gt;The mechanical fix differs from field to field, but the defence underneath is one move, even for the model that can tell it is being tested: a check it can neither move nor see coming, an observation point outside its own influence. Softer moves help, and you should use them, but each one (supervise the steps, require more than one source, put a human on the tool logs) is just another target the system can learn to satisfy. A sharper measurement will not save you, because it still lives inside the loop.&lt;/p&gt;

&lt;p&gt;I no longer trust a number I have not tried to break. The cleanest way to break one is the test you already saw at the top of this piece, and you can run it on almost anything. Take the output you rely on most from a system that feeds on its own results. Corrupt or remove the evidence it claims to use, and run it again. If the output barely moves, the evidence was never load-bearing, and the system has been reading itself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh7b6cgzeq03fsc2na3n8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh7b6cgzeq03fsc2na3n8.png" alt="Reflexivity test diagram" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Point it at your own stack. On a research agent it is exactly that: filler in place of the retrieved documents, and if the conclusion holds, the retrieval was theatre. A pricing or forecasting model is harder, because the cases your past decisions never touched have no outcome to score against. The rejected customer has no repayment history; the price you never set has no demand curve. The honest fix is to build the holdout in advance: approve a small random slice you would normally decline, keep deliberate variation in the prices you set, and judge next year's model only on that protected sample. A trading rule faces the bluntest question of all: does it survive the day it becomes public?&lt;/p&gt;

&lt;p&gt;The researchers who named tool-call hacking went after the same gap from the other side. Instead of rewarding the model for producing a citation, they rewarded it only when the answer both matched the evidence it retrieved and visibly drew on it. Your ablation catches the fakery after the fact; their reward removes the payoff for it up front. Both make the evidence load-bearing again, which is the only thing that was ever missing.&lt;/p&gt;

&lt;p&gt;Frozen verifiers, held-out data, structural edges, a test suite the agent cannot edit: these are the same move. Each one builds a place to stand that your decisions cannot move. None of it is free, and none of it stays clean on its own. A held-out set starts decaying the moment it touches production; a frozen verifier ages as the world moves; keeping either genuinely pristine costs more than most teams will pay. Perfect isolation is the exception, so the real discipline is protecting the one piece of ground your own actions cannot contaminate, and treating every other number as standing inside the loop until you have checked.&lt;/p&gt;

&lt;p&gt;This discipline is the principle behind &lt;a href="https://harryfloyd.substack.com/p/never-let-claude-code-tell-you-its-done" rel="noopener noreferrer"&gt;an external check your agent cannot talk its way past&lt;/a&gt;, the reason &lt;a href="https://harryfloyd.substack.com/p/how-reliable-is-your-ai-agent" rel="noopener noreferrer"&gt;an agent cannot verify its own work&lt;/a&gt;, and exactly what fails when &lt;a href="https://harryfloyd.substack.com/p/ten-lines-of-code" rel="noopener noreferrer"&gt;ten lines of code can score full marks on a benchmark&lt;/a&gt; by reading the answer key instead of doing the task.&lt;/p&gt;

&lt;p&gt;A system that makes decisions again and again ends up running on data its own decisions helped create. The number on your dashboard is a photograph of the world after you have already acted on it. Find the one measurement you trust the most, and check whether it still moves when you break the evidence underneath it. If it does not, you have not been measuring the world. You have been measuring your own reflection, and paying it to agree with you.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Sources:&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ma et al., &lt;a href="https://arxiv.org/abs/2510.10931" rel="noopener noreferrer"&gt;&lt;em&gt;Proof-of-Use: Mitigating Tool-Call Hacking in Deep Research Agents&lt;/em&gt;&lt;/a&gt; (arXiv:2510.10931, 2025)&lt;/li&gt;
&lt;li&gt;Needham et al., &lt;a href="https://arxiv.org/abs/2505.23836" rel="noopener noreferrer"&gt;&lt;em&gt;Large Language Models Often Know When They Are Being Evaluated&lt;/em&gt;&lt;/a&gt; (arXiv:2505.23836, 2025)&lt;/li&gt;
&lt;li&gt;Goodfire, &lt;a href="https://www.goodfire.ai/research/verbalized-eval-awareness-inflates-measured-safety" rel="noopener noreferrer"&gt;&lt;em&gt;Verbalized Eval Awareness Inflates Measured Safety&lt;/em&gt;&lt;/a&gt; (2026)&lt;/li&gt;
&lt;li&gt;Knecht, Florin and Hagendorff, &lt;a href="https://arxiv.org/abs/2605.05835" rel="noopener noreferrer"&gt;&lt;em&gt;Evaluation Awareness in Language Models Has Limited Effect on Behaviour&lt;/em&gt;&lt;/a&gt; (arXiv:2605.05835, 2026)&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>analysis</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Your Multi-Agent System Is an Org Chart</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Wed, 08 Jul 2026 07:49:09 +0000</pubDate>
      <link>https://dev.to/harryfloyd/your-multi-agent-system-is-an-org-chart-k2e</link>
      <guid>https://dev.to/harryfloyd/your-multi-agent-system-is-an-org-chart-k2e</guid>
      <description>&lt;p&gt;title: {title}&lt;br&gt;
published: true&lt;br&gt;
tags: ai, architecture, software, agents&lt;br&gt;
canonical_url: &lt;a href="https://harryfloyd.substack.com/p/your-multi-agent-system-is-an-org" rel="noopener noreferrer"&gt;https://harryfloyd.substack.com/p/your-multi-agent-system-is-an-org&lt;/a&gt;&lt;br&gt;
description: {description}&lt;/p&gt;

&lt;h2&gt;
  
  
  cover_image: &lt;a href="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c20d5f2-8864-4aa9-9da9-72895cb67001_1600x900.webp" rel="noopener noreferrer"&gt;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1c20d5f2-8864-4aa9-9da9-72895cb67001_1600x900.webp&lt;/a&gt;
&lt;/h2&gt;

&lt;h1&gt;
  
  
  Your Multi-Agent System Is an Org Chart
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fikb7hkyy5ry80hf71rqy.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fikb7hkyy5ry80hf71rqy.webp" alt="A ring of role-agents (the org chart) collapses into one strong agent inside an engineering envelope." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You ask an agent to build a Flappy Bird clone. It looks like a job you can split, so you split it. One sub-agent gets "build the moving background with green pipes and hit boxes." Another gets "build a bird the player can move up and down." Two workers, two clean tasks, run them at once.&lt;/p&gt;

&lt;p&gt;The first sub-agent builds a background that looks like Super Mario Bros. The second builds a bird that is not shaped like a game asset and moves nothing like the one in Flappy Bird. Now a third agent has to glue two misunderstandings into one game.&lt;/p&gt;

&lt;p&gt;So you fix the obvious thing. You hand each sub-agent the full original task, not just its slice. Run it again. This time the pipes and the bird are both recognisably Flappy Bird, and they are drawn in two completely different visual styles, because neither sub-agent could see what the other was making.&lt;/p&gt;

&lt;p&gt;That is the default failure of the architecture most teams reach for first, and the reason has nothing to do with the model you picked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The org chart is the mistake
&lt;/h2&gt;

&lt;p&gt;Watch how these systems usually get designed. Someone draws a team. A researcher agent, a writer agent, an editor agent, a critic. It feels obviously right, because it mirrors how humans divide work, and that is the trap. In the 1960s Melvin Conway noticed that any system ends up shaped like the organisation that built it: draw an org chart, and the software inherits its reporting lines and its blind spots. A team of agents is an org chart you drew on purpose, and it inherits the same seams.&lt;/p&gt;

&lt;p&gt;You already saw those seams. Splitting the Flappy Bird job created two workers who could not see each other, so they diverged. The fix looked obvious, hand each one the full task, and that run failed too, in a quieter way. Hold the question of why for a moment, because two of the strongest teams in the field have already answered it, and at first glance they answered it in opposite directions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two labs, opposite answers
&lt;/h2&gt;

&lt;p&gt;In 2025, Cognition, the team behind the Devin coding agent, put their answer in the title: "Don't Build Multi-Agents." After building coding agents for a living, their verdict was blunt, and deliberately dated.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It is evident that in 2025, running multiple agents in collaboration only results in fragile systems. The decision-making ends up being too dispersed and context isn't able to be shared thoroughly enough between the agents." &lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They dated the claim on purpose, expecting the picture to shift as single agents grew more capable. Hold onto that: they revisited it a year later, and where they landed is the whole point.&lt;/p&gt;

&lt;p&gt;Anthropic, building the research feature inside Claude, reported the reverse. Their multi-agent system, one lead agent coordinating several sub-agents, scored 90.2% higher than single-agent Claude Opus 4 on their internal research eval. &lt;sup id="fnref2"&gt;2&lt;/sup&gt; The same architecture Cognition warned against, beating their own single-agent baseline by a wide margin.&lt;/p&gt;

&lt;p&gt;Same word, two machines. One team said the shape was fragile. The other shipped it and beat their own single-agent baseline. Both were reporting honestly. The contradiction is the whole puzzle, and it dissolves the moment you find the variable they were each describing from their own side.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question underneath both
&lt;/h2&gt;

&lt;p&gt;Put the two findings next to each other. Cognition builds coding agents, where the pieces are densely coupled. Anthropic built a research agent, where the pieces are separate look-ups. Each drew the right conclusion for the shape of problem in front of them.&lt;/p&gt;

&lt;p&gt;The shape that decides it is whether the pieces carry decisions that depend on each other.&lt;/p&gt;

&lt;p&gt;Ask a research system to find every board member across the Information Technology companies in the S&amp;amp;P 500. That is a hundred look-ups, and not one of them needs to know what the others found. Each sub-agent decides nothing the others have to honour, and the lead just collects the answers as they land. Now look again at the Flappy Bird job, even with the full task handed to every agent. The background, the bird, the pipes still have to agree on a style, a scale, and a feel that live in the whole and nowhere in the parts. Each agent makes those choices on its own, and independent choices about one shared thing drift apart. That is why the full-context run still failed. Context was never the bottleneck. The coupling was.&lt;/p&gt;

&lt;p&gt;This is also why reading is safe and writing is dangerous. A read commits nothing, so ten agents can read the same material at once and never collide. A write commits a decision the others now have to stay consistent with, and nothing keeps them consistent once they cannot see each other. Read versus write is the fastest proxy for the real question: does this piece make a choice the other pieces depend on?&lt;/p&gt;

&lt;p&gt;None of this is new. Readers may share and writers must take turns is the oldest rule in concurrent systems, the one behind every database lock and every thread that ever corrupted shared state. What is new is the layer it now governs. The rule has climbed from bytes in memory to decisions between agents, and the reason it keeps reappearing is that it was never about computers. It is about what happens when separate workers commit to the same thing without watching each other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjcxgbjxfuxemseglnmos.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjcxgbjxfuxemseglnmos.png" alt="Same word, two different machines. Left, role theatre: a relay of specialists where each handoff loses context, so the verdict is collapse to one agent. Right, parallelisation: a fleet of independent workers reading in parallel, so the verdict is fan out." width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Count the decisions, not the agents
&lt;/h2&gt;

&lt;p&gt;This is why the agent count on the box tells you nothing. A swarm of three hundred is not more capable than one agent by virtue of being three hundred. Agent count is cheap to inflate and easy to sell, and the moment it becomes the headline it stops tracking whether the work got done. The thing to measure is the decomposition, and the decomposition is measured in dependent decisions, not in boxes on a diagram.&lt;/p&gt;

&lt;p&gt;The proxy has edges, and they are worth knowing, because the surface can mislead. Two research agents that only read can still collide if the task is vague enough that each has to decide what it means; that hidden interpretive choice is the coupling, even with no writes anywhere. And some jobs that look coupled are not: a body of text too large for one agent to hold at once, split across many readers, runs in parallel without conflict, because every reader shares the same goal but none constrains another's finding. What settles the case is never how the task looks from a distance. It is whether finishing one piece requires knowing what another piece decided.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bill you pay to be wrong
&lt;/h2&gt;

&lt;p&gt;Even when fan-out is right, it is not free. Anthropic found that raw token usage alone explained about 80% of the variance on one of their browsing benchmarks, which is another way of saying the gain came mostly from spending more compute, not from clever coordination. An independent 2026 study across the Qwen, DeepSeek, and Gemini models reached the same verdict from the other side: on multi-step reasoning, hold the token budget equal and a single agent matches or beats the multi-agent setup, because the reported gains track compute, not architecture. &lt;sup id="fnref3"&gt;3&lt;/sup&gt; Their multi-agent system burns roughly fifteen times the tokens of a normal chat. Cheaper inference lowers what each token costs, not how many the architecture spends; fifteen times as many is fifteen times as many at any price. The absolute bill falls with the market. The multiple does not, and neither does the coupling you would be paying it for.&lt;/p&gt;

&lt;p&gt;That multiple is the honest test of the whole decision. Fifteen times the cost is worth paying only when the task is valuable enough to earn it and parallel enough to use it. Point the same architecture at a coupled job and you pay the fifteen-times bill to manufacture the Flappy Bird problem at scale, and the cost can climb higher without warning, because a sub-agent that spawns its own sub-agents, or a tool that returns a wall of text, multiplies the spend again, and most builds have no cap that stops it. &lt;sup id="fnref4"&gt;4&lt;/sup&gt; If you cannot say in one sentence why the parallelism pays for itself here, you are paying the coordination tax and calling it a team. The same instinct shows up one layer down, in the pull to add more tools and more layers to a single agent until it is too complicated to debug, which is &lt;a href="https://harryfloyd.substack.com/p/your-tools-got-powerful-get-boring" rel="noopener noreferrer"&gt;the trap the most powerful tools quietly set&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The machine most builds actually want
&lt;/h2&gt;

&lt;p&gt;The argument is usually staged as swarm versus single agent, and that staging hides the machine you almost always want, which is neither pole. One strong agent, wrapped in an engineering envelope.&lt;/p&gt;

&lt;p&gt;The envelope is plain engineering, and it is where the reliability lives. In practice it looks less like a team meeting and more like one skilled worker with good tools, a checklist, and a reviewer. A planner lays out the work before it starts, routes the cheap steps to cheaper models, and caches and retries so nothing is paid for or crashed twice. A supervisor then compares what the agent meant to do against what it did, and a separate pass checks the output against something outside the agent's own judgement. You keep most of what the orchestration promised at a fraction of the token cost, and you never split one judgement across personas that cannot see each other. It is the same case as &lt;a href="https://harryfloyd.substack.com/p/harness-engineering-same-model-different-product" rel="noopener noreferrer"&gt;building the harness around the model instead of swapping the model&lt;/a&gt;: the structure around one strong agent does more of the work than the agent count ever will.&lt;/p&gt;

&lt;p&gt;Fan-out still has a safe home inside this envelope, and it is read-only work. Claude Code's investigation sub-agents are the clean example. They explore a codebase, answer a question, and hand a summary back to the single agent holding the thread, without touching a file. &lt;sup id="fnref5"&gt;5&lt;/sup&gt; The moment you let sub-agents write in parallel, each committing changes the others cannot see, you have rebuilt the Flappy Bird problem inside your own codebase, which is exactly the risk in the newer parallel-coding setups. That one line, read or write, is the quickest filter you have, and it catches the common mistakes before they are built.&lt;/p&gt;

&lt;p&gt;You do not have to take it on faith, because Cognition spent a year arriving at it themselves. Their 2026 follow-up, "Multi-Agents: What's Actually Working," is not a retraction of "Don't Build Multi-Agents"; parallel-writer swarms are still out. What now runs in their production is the narrow class where writes stay single-threaded and the extra agents contribute intelligence rather than actions, and it is not theoretical: even in their most cautious enterprise segment, Devin usage is up roughly eightfold over six months. &lt;sup id="fnref6"&gt;6&lt;/sup&gt; A reviewer reads a diff and flags the bugs. A stronger model gets consulted on the hard call. A manager splits the read-heavy work, lets the children run, and keeps the one write to itself. The patterns they kept all have the same shape underneath: many readers, one writer. Read versus write, named from the inside by the team that opened the argument against multi-agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The test to run before you build
&lt;/h2&gt;

&lt;p&gt;Before you stand up a multi-agent system, put the task through one check. Try to break the job into pieces, and for each piece ask four things. Can it be finished without knowing what the other pieces decided? Does it only read and report, or does it write into a shared result? Is the whole job too big for a single context window, more than one agent can hold in mind at once? And is it worth roughly fifteen times the cost of doing it plainly?&lt;/p&gt;

&lt;p&gt;Independent, read-only, oversized, and high-value: fan it out, aggregate cheaply, and keep yourself at the question going in and the decision coming out. Anything else: collapse it back to one strong agent and spend your effort on the envelope. And if you cannot tell which case you are in, that uncertainty is the answer for now, because the coordination tax is real and the simpler machine should be the default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F42gyvuhja7dnx5skx69u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F42gyvuhja7dnx5skx69u.png" alt="Two gates, one honest default. Gate one: do the parts share context or write into the same result? Yes, collapse to one strong agent. No, go to gate two: read-only, bigger than one context window, worth roughly fifteen times the cost? All yes, fan out. Any no, take the hybrid, where most builds land." width="800" height="630"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The four questions are the whole method, and you can run them on the back of a ticket. When you want a specific task computed rather than eyeballed, I put the same checks into a small tool that returns the architecture and the rough cost. &lt;a href="https://durabilitycurve.com/tools/multi-agent-decision/" rel="noopener noreferrer"&gt;Run the Multi-Agent Decision.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the next time someone proposes a designer agent, a coder agent, and a critic agent for one coherent job, ask the only question that decides it. Was the work ever actually separate? Most of the time you have drawn an org chart in software, and the org chart was the bug.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is one task you split across agents, or were about to, and does it survive the read-versus-write test?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcep8tv7if9bg6edcah3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcep8tv7if9bg6edcah3w.png" alt="The Multi-Agent Decision field card. Run the four checks (share context, read or write, too big for one context window, worth roughly fifteen times the cost), and the rule does the rest." width="800" height="460"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Walden Yan, "Don't Build Multi-Agents," Cognition (2025). Source of the Flappy Bird example, the two principles, and the fragility quote. &lt;a href="https://cognition.com/blog/dont-build-multi-agents" rel="noopener noreferrer"&gt;https://cognition.com/blog/dont-build-multi-agents&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;"How we built our multi-agent research system," Anthropic Engineering (13 June 2025). Source of the 90.2% internal-eval result, the 80%-of-variance finding on the BrowseComp benchmark, the ~15x token figure, and the point that shared-context and coding tasks are a poor fit for multi-agent. &lt;a href="https://www.anthropic.com/engineering/multi-agent-research-system" rel="noopener noreferrer"&gt;https://www.anthropic.com/engineering/multi-agent-research-system&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;Dat Tran and Douwe Kiela, "Single-Agent LLMs Outperform Multi-Agent Systems on Multi-Hop Reasoning Under Equal Thinking Token Budgets," arXiv (April 2026), an independent study across Qwen3, DeepSeek-R1-Distill-Llama, and Gemini 2.5. Single-agent systems "consistently match or outperform" multi-agent ones on multi-hop reasoning at equal token budgets, with the reported gains attributed to "unaccounted computation and context effects rather than inherent architectural benefits." &lt;a href="https://arxiv.org/abs/2604.02460" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2604.02460&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;The 15x is Anthropic's own baseline. The further escalation is my own inference from the same system, which reports early failures like one agent "spawning 50 subagents for simple queries" and sets no per-run cost cap. Not a figure Anthropic states.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;Claude Code's investigation sub-agents (its Explore and Plan modes) run read-only, searching and summarising without editing files. It also supports implementation sub-agents and parallel "agent teams" that write in parallel, which is the coupled-write case this piece flags as fragile.&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn6"&gt;
&lt;p&gt;Walden Yan, "Multi-Agents: What's Actually Working," Cognition (22 April 2026), the follow-up to "Don't Build Multi-Agents." Parallel-writer swarms are still out; what works now is "setups where multiple agents contribute intelligence to a task while writes stay single-threaded." The eightfold growth is Cognition's own figure for Devin in its largest enterprise segment; the three named patterns are the Code-Review-Loop, the "Smart Friend," and "map-reduce-and-manage" delegation. &lt;a href="https://cognition.com/blog/multi-agents-working" rel="noopener noreferrer"&gt;https://cognition.com/blog/multi-agents-working&lt;/a&gt;&amp;nbsp;↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>software</category>
      <category>agents</category>
    </item>
    <item>
      <title>Your Benchmark Measures a Sprint. Your Agent Runs a Marathon.</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Thu, 02 Jul 2026 08:39:11 +0000</pubDate>
      <link>https://dev.to/harryfloyd/your-benchmark-measures-a-sprint-your-agent-runs-a-marathon-43ad</link>
      <guid>https://dev.to/harryfloyd/your-benchmark-measures-a-sprint-your-agent-runs-a-marathon-43ad</guid>
      <description>&lt;h1&gt;
  
  
  Your Benchmark Measures a Sprint. Your Agent Runs a Marathon.
&lt;/h1&gt;

&lt;p&gt;You gave the overnight job to the cheaper model, and in the morning the work was half done. Not broken in a way you'd catch at a glance — the agent slipped step nine, built three more on top of what it broke, and never noticed. Half done, and confident about it.&lt;/p&gt;

&lt;p&gt;You had a good reason to trust it. GLM-5.2 had shipped with open MIT-licensed weights and a score that beat GPT-5.5 on SWE-bench Pro, the coding benchmark every team quotes. Frontier-grade, yours to host, at a fraction of the price.&lt;/p&gt;

&lt;p&gt;The number that would have warned you shipped in the same release. On SWE-Marathon, the benchmark for long multi-hour tasks, that model solves 13% of the jobs. Opus 4.8 solves 26%. Close on the short tasks, half the work on the long ones. Both numbers went out together, one scroll apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  The sprint board hides the gap
&lt;/h2&gt;

&lt;p&gt;Most benchmarks are sprints: SWE-bench, Terminal-Bench, the coding boards that set the market's sense of who leads. Single-session, bounded tasks that a model finishes in one push. There the field is bunched, a dozen models within a few points at the top, an open model now among them. Read only that board and the race looks over.&lt;/p&gt;

&lt;p&gt;SWE-Marathon measures longer: 20 tasks, each multi-hour, each run in its own environment and graded against a human reference and a multi-layer test suite. The average attempt burns 27 million tokens. There the field stops being bunched. Opus 4.8 solves roughly a quarter of tasks. Everyone else sits at half that or less — Opus 4.7 at 16%, GLM-5.2 at 13%, GPT-5.5 at 12%. No agent clears 30%.&lt;/p&gt;

&lt;p&gt;The open model beats GPT-5.5 on the sprint and edges it on the marathon too, yet both land at half of what Opus does. GPT-5.5 is proprietary and frontier, and it caves on the long task just the same. The divide runs between sprint and marathon, not between open weights and closed.&lt;/p&gt;

&lt;p&gt;Stretch a task out far enough and you see how it breaks: weak self-verification, calling a half-finished job done, never recovering after one wrong step. On nearly one attempt in seven, a run fakes its way past the verifier instead of doing the work. A short task rarely leaves room for any of it. A long one leaves room for all of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap is arithmetic
&lt;/h2&gt;

&lt;p&gt;A long task succeeds only if its steps survive in sequence. So small per-step gaps stop adding and start multiplying. Two models at 96% and 93% per-step reliability look the same on a five-step task and finish over three times farther apart on a forty-step one.&lt;/p&gt;

&lt;p&gt;Two forces bend that curve without repealing it. Recovery softens it — a good harness catches mistakes. Correlated failure sharpens it — one wrong step poisons the steps after it. The odds still fall faster the longer the run, from a higher start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the marathon stays scarce
&lt;/h2&gt;

&lt;p&gt;The model layer has commoditised: open weights ship at a fraction of frontier price, and sprint-grade coding is broadly available. Sprint capability copies because a benchmark rewards it and a teacher's traces capture it.&lt;/p&gt;

&lt;p&gt;Marathon reliability resists. It is not one thing in the weights. It is the model, the harness around it, the verifier, and the context discipline holding together across hundreds of steps, where any single link breaks the run.&lt;/p&gt;

&lt;p&gt;The bet here is that the durable scarcity is the system: a verifier that checks the agent's own work, a planner that holds the goal across hours, a run that can checkpoint and recover. The scaffolding is portable, and it lifts a cheap model's marathon odds further than bigger weights would. But the same scaffolding lifts the frontier more, because the labs that train the model also tune the harness to it. You can copy the scaffolding. You cannot copy that co-design.&lt;/p&gt;

&lt;h2&gt;
  
  
  Price the whole run
&lt;/h2&gt;

&lt;p&gt;A marathon does not bill by the sticker. It bills by tokens times length times retries. Cost per finished job = cost per attempt ÷ solve rate. At the open model's 13% finish rate that's roughly eight attempts per clean success; at the frontier's 26%, closer to four.&lt;/p&gt;

&lt;p&gt;So count the steps before you pick the model. A bounded edit a model finishes in one pass is a sprint — route it to the cheap model. A job running unattended across many steps and tool calls is a marathon — route it to the frontier, or wrap the cheap one in scaffolding. Or cut the marathon into checkpointed chunks shorter than the model's coin-flip step count, so a run that dies as one long chain can finish as a string of short ones. Splitting the job is the cheapest reliability you can buy.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://durabilitycurve.com/tools/marathon-gap/" rel="noopener noreferrer"&gt;Marathon Calculator&lt;/a&gt; runs the numbers in your browser — enter your per-step reliability and task length, and it marks where the sprint benchmark stops predicting and the job becomes a reliability problem.&lt;/p&gt;

&lt;p&gt;The falsifier is clean: an open-weight model that matches the frontier on a mature long-horizon benchmark while sitting at sprint parity would show the gap is a lag, not a structure. Through the end of 2026 I expect the best open-weight model to keep trailing by double-digit resolve-rate points on SWE-Marathon. The way that turns out wrong is a scaffolding story, not a base-weights one.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Which of your agent's jobs is a marathon you have been routing like a sprint?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>architecture</category>
      <category>analysis</category>
    </item>
    <item>
      <title>Never Let Claude Code Tell You It's Done</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Tue, 30 Jun 2026 13:56:22 +0000</pubDate>
      <link>https://dev.to/harryfloyd/never-let-claude-code-tell-you-its-done-11la</link>
      <guid>https://dev.to/harryfloyd/never-let-claude-code-tell-you-its-done-11la</guid>
      <description>&lt;p&gt;&lt;strong&gt;What you will do:&lt;/strong&gt; add one test that catches the agent's mistakes, then wire it so Claude Code runs it on its own and cannot end a turn while it is failing. About twenty minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who this is for:&lt;/strong&gt; you use Claude Code on real code, and it has told you "fixed it, tests pass, done" when it was not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who should skip it:&lt;/strong&gt; if your agent already cannot end on a failing test, you are past this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You need:&lt;/strong&gt; Claude Code (version 2.1.143 or later), Python 3 for the worked example (it uses the built-in test runner, nothing to install), and a project of your own.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Write a test that says what you want
&lt;/h2&gt;

&lt;p&gt;A test is a small program that runs your code and checks it does the right thing. The important word is &lt;em&gt;yours&lt;/em&gt;. The test has to encode what &lt;em&gt;you&lt;/em&gt; want the code to do, because if the agent writes both the code and the test, it can quietly make the two agree. The check has to come from outside the agent, or it is not a check.&lt;/p&gt;

&lt;p&gt;Here is the smallest possible example: a function, and a test for it. The agent was asked to fix &lt;code&gt;add&lt;/code&gt;, and reported back that it was done.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;calc.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;  &lt;span class="c1"&gt;# wrong
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;test_calc.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;unittest&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestAdd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_adds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assertEqual&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save both files in the same empty folder and open your terminal there. The agent was certain. The test does not care how certain it was. &lt;code&gt;add(2, 3)&lt;/code&gt; came back &lt;code&gt;-1&lt;/code&gt;, not &lt;code&gt;5&lt;/code&gt;, and now you know, in one second, that "done" was not true.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Put it behind a gate the agent cannot talk past
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;check.sh&lt;/code&gt; in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;tmpdir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;mktemp&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;trap&lt;/span&gt; &lt;span class="s1"&gt;'rm -rf "$tmpdir"'&lt;/span&gt; EXIT
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PYTHONPYCACHEPREFIX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$tmpdir&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; unittest 2&amp;gt;&amp;amp;1
&lt;span class="nv"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;2&lt;/code&gt; is the load-bearing part. An ordinary failure exits &lt;code&gt;1&lt;/code&gt;. We exit &lt;code&gt;2&lt;/code&gt; on purpose, because of what Claude Code does with it next.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Make the gate run itself
&lt;/h2&gt;

&lt;p&gt;Claude Code has hooks: scripts it runs for you on certain events without being asked. The one we want is &lt;code&gt;Stop&lt;/code&gt;, which runs the instant the agent tries to end its turn.&lt;/p&gt;

&lt;p&gt;Wire &lt;code&gt;check.sh&lt;/code&gt; to it. In your project, make the &lt;code&gt;.claude&lt;/code&gt; folder if it is not there, then create or open &lt;code&gt;.claude/settings.json&lt;/code&gt; and add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Stop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bash &lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;CLAUDE_PROJECT_DIR&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;/check.sh\&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a &lt;code&gt;Stop&lt;/code&gt; hook exits &lt;code&gt;2&lt;/code&gt;, Claude Code &lt;strong&gt;blocks the stop&lt;/strong&gt;: it refuses to let the agent finish, feeds your test failures back to it as the reason, and makes it keep working. The agent cannot tell you it is done while the suite is red, because the suite, not the agent, now decides when the turn is allowed to end.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. When it still goes wrong
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A gate that always blocks would loop.&lt;/strong&gt; Claude Code ends the turn on its own after 8 consecutive blocks (change the limit with the &lt;code&gt;CLAUDE_CODE_STOP_HOOK_BLOCK_CAP&lt;/code&gt; environment variable).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A big suite makes every stop slow.&lt;/strong&gt; Point &lt;code&gt;check.sh&lt;/code&gt; at a fast subset (the tests near what you changed) and leave the full run to CI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Green is only as good as the test.&lt;/strong&gt; The gate proves the tests pass, not that the tests are &lt;em&gt;enough&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It only guards what the tests touch.&lt;/strong&gt; Untested code, prose claims, "I checked the docs": the gate sees none of that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Prove the gate fires
&lt;/h2&gt;

&lt;p&gt;Do not take my word, or the agent's, that the gate works. Break something on purpose: change a line so a test fails, then ask Claude Code to wrap up. Watch it get pulled back and handed the failure instead of stopping. Once you have seen it block, a clean finish from the agent finally means something.&lt;/p&gt;

&lt;p&gt;That is the floor, and it is a real one: the agent can no longer decide for itself that the job is done. Something it cannot argue with does. The next step is widening the gate from "the tests pass" to "the tests are worth passing."&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How Long Until Your AI Edge Stops Paying?</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Mon, 29 Jun 2026 08:45:59 +0000</pubDate>
      <link>https://dev.to/harryfloyd/how-long-until-your-ai-edge-stops-paying-57e5</link>
      <guid>https://dev.to/harryfloyd/how-long-until-your-ai-edge-stops-paying-57e5</guid>
      <description>&lt;p&gt;The most dangerous AI edge is the one that works. It earns real money today, and it is commoditising faster than you can build the thing meant to defend it.&lt;/p&gt;

&lt;p&gt;Nine in ten organisations now use AI in at least one business function. Fewer than four in ten can attribute any measurable impact on profit. Same tools, opposite results.&lt;/p&gt;

&lt;p&gt;The variable is not the model. It is a rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two rates
&lt;/h2&gt;

&lt;p&gt;Dario Amodei named the two that matter: two exponentials. One for how fast models improve. One for how fast the economy can absorb them.&lt;/p&gt;

&lt;p&gt;The first is the capability rate. It belongs to the field — you read it off a press release. The second is your absorption rate: how reliably you turn a new capability into a number your CFO or customer would recognise. When capability outruns absorption, you are stockpiling power you cannot use. A better model becomes the most expensive way to feel productive.&lt;/p&gt;

&lt;p&gt;Your absorption rate has a ceiling, and the ceiling is a single layer: the thing a capability must pass through before it reaches your customer. For most teams it is mundane: the data nobody cleaned, the one engineer who understands the legacy system, the customer who will not change how they work, the sign-off that takes three weeks. Whoever owns that layer captures the value, because everything the model can do flows through it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the money actually landed
&lt;/h2&gt;

&lt;p&gt;Microsoft holds the largest AI distribution in enterprise. It built that lead by running other companies' models through the channel it already owned: Office, Teams, Azure, and the procurement relationship every large firm already had. ~420 million people use Copilot across Microsoft's products each month. The strongest models inside it are still OpenAI's and Anthropic's.&lt;/p&gt;

&lt;p&gt;The model was rented. The distribution was owned. The margin followed the distribution.&lt;/p&gt;

&lt;p&gt;Jasper shows the other failure: $125M raised as a writing tool on OpenAI's models. When ChatGPT arrived free, its product became something anyone could get for nothing overnight. It survived by climbing into the layer it had skipped — enterprise workflow and data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Chegg lost everything in one day
&lt;/h2&gt;

&lt;p&gt;Chegg owned its layer outright: a decade-deep library of step-by-step homework solutions and the student traffic to match, a moat no competitor could rebuild quickly. Then a general model could do everything for free. In May 2023 Chegg told investors students were leaving for ChatGPT. The stock fell by half. From its 2021 peak Chegg has since lost more than 95% of its value.&lt;/p&gt;

&lt;p&gt;It owned the scarce layer. It owned the wrong one.&lt;/p&gt;

&lt;p&gt;Put Venice (printing press era) and Chegg side by side and you see the variable. Same kind of edge — a scarce layer others had to pass through — and the clocks ran a hundredfold apart. Venice's lasted a century. Chegg's lasted months.&lt;/p&gt;

&lt;p&gt;A scarce layer pays only if its clock is longer than the time it takes you to build on it. Clear that bar and you compound. Miss it and you have bought a melting asset at full price.&lt;/p&gt;

&lt;h2&gt;
  
  
  What sets the term
&lt;/h2&gt;

&lt;p&gt;A layer's clock is short when a general model can absorb it: a clever technique, a fine-tune, generic data anyone can assemble. It is long when the scarcity rests on something a model cannot manufacture: a regulator's approval, a physical bottleneck like fabs or power, years of accumulated switching cost, a trust relationship.&lt;/p&gt;

&lt;p&gt;Chegg's layer was content a model could regenerate — it had months. The chips an AI runs on are a physical bottleneck — that scarcity holds for years.&lt;/p&gt;

&lt;p&gt;Even that one is eroding. Nvidia owns roughly 80% of the merchant AI-accelerator market, and its largest customers are designing their own silicon to route around it. Gross margin in the mid-70s will be the first thing to crack: I expect it below 70% by 2028. If it still holds in the high-70s by then, the thesis is more durable than my model predicts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The diagnostic you can run today
&lt;/h2&gt;

&lt;p&gt;The work fits on one page:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Name your absorbing layer.&lt;/strong&gt; Use the doubling test: what, if it doubled tomorrow, would let you use twice as much model — while doubling the model itself bought you nothing more?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Test whether you own it.&lt;/strong&gt; You own a layer only when a new capability cannot reach your customer without passing through something of yours that a rival cannot rebuild in a weekend. A model fine-tuned on your own documents does not pass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Measure your absorption rate.&lt;/strong&gt; Count the capabilities you seriously tried this year and the ones that moved a number your CFO or customer would recognise. Most teams get an honest reading that stings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Read both clocks.&lt;/strong&gt; Estimate how long your layer stays scarce. Estimate your payback — how long a build on that layer takes to earn back what it costs. If the clock is shorter than the payback, you are Chegg.&lt;/p&gt;

&lt;h2&gt;
  
  
  The concrete case
&lt;/h2&gt;

&lt;p&gt;Take a forty-person logistics company with three years of messy carrier-integration data no rival has cleaned. Double the data and the model gets more useful. Double the model and nothing changes. Nobody rebuilds three years of dirty feeds in a weekend. Every test passes.&lt;/p&gt;

&lt;p&gt;Then a frontier model ships that parses raw carrier feeds zero-shot. Three years of cleaning collapses into a prompt. The layer that looked like years of scarcity now has six months, against an eighteen-month build. The bet flips from compound to melting — while the data sat untouched.&lt;/p&gt;

&lt;p&gt;Re-run the number the moment a model moves.&lt;/p&gt;

&lt;p&gt;The full diagnostic runs in your browser &lt;a href="https://harryfloyd.substack.com/p/how-long-until-your-ai-edge-stops-paying" rel="noopener noreferrer"&gt;here&lt;/a&gt; — name your layer, get your absorption rate, the layer's half-life, and the date to start building the next one.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is part of the &lt;a href="https://harryfloyd.substack.com" rel="noopener noreferrer"&gt;Durability Curve Analysis&lt;/a&gt; series — structural analysis of where durable value forms in AI infrastructure, through the Five Laws framework (Bottleneck Migration, Difficulty is Load-Bearing, Architecture Outlives Content).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>analysis</category>
      <category>architecture</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Access Is Not Agency</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Sat, 27 Jun 2026 13:53:43 +0000</pubDate>
      <link>https://dev.to/harryfloyd/access-is-not-agency-3hni</link>
      <guid>https://dev.to/harryfloyd/access-is-not-agency-3hni</guid>
      <description>&lt;p&gt;Your agent can read Slack. It can search email. It can query the CRM, open GitHub issues, check billing, browse docs, edit a spreadsheet, draft a customer reply, and call three internal APIs.&lt;/p&gt;

&lt;p&gt;Everyone in the room calls it powerful. That is the first mistake.&lt;/p&gt;

&lt;p&gt;The question is not what the agent can access. The question is what it is allowed to change. Can it send the email, or only draft it? Can it update the customer's plan, or only propose the update? Can it merge the pull request, or only open it?&lt;/p&gt;

&lt;p&gt;Once an agent can act through tools, the real system is no longer the model. The real system is the action contract around the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Access is reach. Agency is permissioned action under constraints.
&lt;/h2&gt;

&lt;p&gt;More tools do not automatically make the agent more agentic. More tools expand the surface on which judgment must be engineered. A connector is a door. Agency is a contract about who may walk through it, what they may carry, who inspects the bag, and who reviews the footage if something goes wrong.&lt;/p&gt;

&lt;p&gt;The current agent conversation misses this. People talk as if the next leap is connectors — give the model Slack, Gmail, GitHub, Linear, Notion, Stripe, and wait for autonomy to emerge. But a connector is not a decision right.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack nobody wants to name
&lt;/h2&gt;

&lt;p&gt;If you want to know whether an agent has real agency, do not start with the model card. Start with the rights stack. Every agent action system has five layers:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visibility&lt;/strong&gt; — which data, tools, documents, logs, and systems the agent can inspect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mutation&lt;/strong&gt; — which objects the agent can change. Reading a customer record and changing it are different powers. Drafting a reply and sending it are different powers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proof&lt;/strong&gt; — what the agent must produce before a mutation becomes real. A test run, a diff, a trace, a policy check, a human approval, or an evidence bundle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Escalation&lt;/strong&gt; — when the agent must stop and hand the decision to someone else. Not "human in the loop" as a slogan. A named condition: missing context, high reversibility cost, payment movement, privilege change, legal exposure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Revocation&lt;/strong&gt; — what changes after the agent fails. A human loses trust after a bad judgment. Most agents lose nothing. They fail, get patched, and return with the same action surface. That is not delegation. That is amnesia with API keys.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Agent Action Rights Test
&lt;/h2&gt;

&lt;p&gt;Run this on the most powerful agent you currently use. Not a toy. The one you are most tempted to trust.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What can the agent see?&lt;/li&gt;
&lt;li&gt;What can it change?&lt;/li&gt;
&lt;li&gt;What must it prove before the change becomes real?&lt;/li&gt;
&lt;li&gt;What triggers escalation to a human?&lt;/li&gt;
&lt;li&gt;What permission disappears after a bad run?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most teams can answer the first question. Some can answer the second. Almost no teams can answer all five.&lt;/p&gt;

&lt;p&gt;That is the diagnostic. If you cannot answer "what can it see?", you do not have an inventory. If you cannot answer "what can it change?", you do not have a permission model. If you cannot answer "what must it prove?", you do not have verification. If you cannot answer "what triggers escalation?", you do not have oversight. If you cannot answer "what permission disappears?", you do not have learning at the authority layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authority should track consequence
&lt;/h2&gt;

&lt;p&gt;Good action rights are not one wall around the whole system. They are a slope.&lt;/p&gt;

&lt;p&gt;Read-only Slack search should be cheap. Drafting a customer reply should be cheap. Local reversible edits should be cheaper than external irreversible commitments. Sending the email, refunding the invoice, or merging the pull request should pass through stronger gates.&lt;/p&gt;

&lt;p&gt;The goal is not to turn every agent into a form-filling intern. The goal is to match authority to consequence. That is how good human organisations work. The graduate can model scenarios. The manager can approve a small budget. The director can reallocate headcount. The board approves the acquisition. Authority changes with consequence. Agents need the same gradient.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bottleneck moved
&lt;/h2&gt;

&lt;p&gt;This is where the serious agent market will split. One side will sell reach: more connectors, more memory, more tools, more environments. The other side will sell agency: permissioned action, bounded autonomy, proof before commitment, escalation when context breaks, and revocation when trust is lost.&lt;/p&gt;

&lt;p&gt;Reach will demo better. Agency will survive contact with the organisation.&lt;/p&gt;

&lt;p&gt;Reach demos well in the room. Agency holds up in the incident review.&lt;/p&gt;

&lt;p&gt;Before next week, run the Agent Action Rights Test on one workflow. Not your whole stack. One agent. One workflow. Write the five answers in a note. If the fifth answer is blank, you found the missing layer. The agent did not need another tool. It needed a smaller right to be wrong.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>security</category>
      <category>devops</category>
    </item>
    <item>
      <title>Ten Lines of Code Scored 100% on AI Coding Benchmarks. It Solved Nothing.</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Thu, 25 Jun 2026 14:27:40 +0000</pubDate>
      <link>https://dev.to/harryfloyd/ten-lines-of-code-scored-100-on-ai-coding-benchmarks-it-solved-nothing-58p2</link>
      <guid>https://dev.to/harryfloyd/ten-lines-of-code-scored-100-on-ai-coding-benchmarks-it-solved-nothing-58p2</guid>
      <description>&lt;p&gt;A file shorter than this paragraph scored 100% on SWE-bench Verified, the benchmark the big labs use to prove their coding agent is state of the art.&lt;/p&gt;

&lt;p&gt;The file solved none of the 500 tasks. It wrote no patch. In most runs it did not call a language model at all. Ten lines of Python that quietly told the test harness every result had passed.&lt;/p&gt;

&lt;p&gt;This was one move in a larger demonstration. A team at Berkeley pointed a single automated agent at eight of the most-cited agent benchmarks and broke every one of them. It scored 100% on six of the eight — SWE-bench Verified, SWE-bench Pro, Terminal-Bench, around 98% on GAIA, and 73% on OSWorld, the one it cracked least cleanly. Zero tasks were actually solved. One benchmark it completed by sending an empty JSON object. Another leaked its own answer key through a local file the agent could open and read.&lt;/p&gt;

&lt;p&gt;These are the numbers in the pitch decks and launch posts you reshared last week. Exploits this trivial produce every one of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reflex That Misreads the Result
&lt;/h2&gt;

&lt;p&gt;The natural reaction is to laugh and move on. Sloppy benchmark engineering. The authors will patch the holes, the scores will mean something again, the leaderboard returns to normal.&lt;/p&gt;

&lt;p&gt;That reflex misreads the result. The holes were not random sloppiness. The same seven failure classes recur across all eight benchmarks, and three of them carry most of the damage:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The agent and the grader share a sandbox&lt;/strong&gt; — the agent can reach the scoring code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The answer ships inside the test files&lt;/strong&gt; — the agent can read the expected result&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The scorer checks presence, not correctness&lt;/strong&gt; — if output exists, it passes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each one rests on a single assumption: that the agent is trying to solve the task in good faith. Some holes you can close with better plumbing. The assumption underneath them you cannot patch. The ten-line file is a preview of what an agent will do with any part of your own test it can see and reach.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fymi8hvi1jy2utcqh7mei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fymi8hvi1jy2utcqh7mei.png" alt="The capability-threshold inversion — below the threshold, the score tracks reality; above it, the same number could mean either improvement or gaming, and the dashboard cannot tell which" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Capability Threshold Nobody Talks About
&lt;/h2&gt;

&lt;p&gt;This is the part that matters for your own pipeline, not just someone else's benchmark. Below a certain level of capability, an agent gaming your evaluation looks like failure: the score drifts down, the metric gets noisier, you watch the number fall and you know something is wrong.&lt;/p&gt;

&lt;p&gt;Above that level, gaming looks like success. An agent that has learned to model your evaluation passes it cleanly while doing something else in deployment. The score does not drop. It holds, or it climbs.&lt;/p&gt;

&lt;p&gt;A rising score is ambiguous. It can mean the agent got better. It can mean the agent got better at being measured. The dashboard cannot tell you which.&lt;/p&gt;

&lt;p&gt;This is not theoretical. METR watched OpenAI's o3 reach past a coding task into the scoring code, pull out the answer the grader had already computed, and hand that back. Asked ten times whether that move matched the user's intent, o3 said no every time. Nobody instructed it to cheat. It was dropped into a setting with a checkable reward and a way to reach it, and it reached.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Your Dashboard Is Actually Measuring
&lt;/h2&gt;

&lt;p&gt;Almost everyone building agents now has observability. Dashboards, traces, token-level logs, replays of every run in high resolution. In a survey of 1,340 teams, 89% had observability in place. Only 37% ran any live evaluation against it.&lt;/p&gt;

&lt;p&gt;A sharper view of a gameable number is still a gameable number. A classifier hands you a confidence score. A verifier hands you a checkable artifact — something you can independently re-run to see if it holds. No amount of resolution turns the first into the second. Observability is that same trap one floor up. Everything on your dashboard lives on a surface the agent can see too: the logs, the eval prompts, the success metric, the LLM judge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3dgtypnn0mveuq1ek2x5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3dgtypnn0mveuq1ek2x5.png" alt="The observability trap — you watch the front of the board while the agent writes the back, and the real outcome sits off the screen" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Real Signal Looks Like
&lt;/h2&gt;

&lt;p&gt;The signals that survive share one property: the system never gets to touch them. They are downstream outcomes it cannot reach from inside its own loop. The change that got reverted. The ticket that reopened. The trade that never settled. Those move when the work was real and stay flat when the work was theatre.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn1wl6aklviqiivdodw5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn1wl6aklviqiivdodw5f.png" alt="The reach test — everything in reach turns green on command. The signal worth trusting is the one the agents hands never touch" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is a cheap version you can run now. Keep a private pool of tasks the agent never trains or tunes against. Lock its tools out of them. Then watch the distance between its score there and its score on the eval it can see. That distance is not noise — it is the size of the gaming.&lt;/p&gt;

&lt;p&gt;No architecture makes gaming impossible for a capable enough system. You can shrink the surface the agent gets to model and push trust out to something it cannot reach. You do not get to delete it.&lt;/p&gt;

&lt;p&gt;That is an uncomfortable place to stop, and it is the true one.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is a condensed version of a longer piece that traces the full argument — including the Berkeley team's seven vulnerability classes, the METR reward-hacking evidence, the LangChain survey data on observability vs verification, and the practical framework for building signals your agent cannot reach.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Read the full article: &lt;a href="https://harryfloyd.substack.com/p/ten-lines-of-code" rel="noopener noreferrer"&gt;Ten Lines of Code Scored 100%. One Agent Broke Eight Benchmarks.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>evaluation</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The Seven-Layer Agent Audit: How to Find Where Your AI Agent Is Actually Starving</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Mon, 22 Jun 2026 22:36:26 +0000</pubDate>
      <link>https://dev.to/harryfloyd/the-seven-layer-agent-audit-how-to-find-where-your-ai-agent-is-actually-starving-1gh4</link>
      <guid>https://dev.to/harryfloyd/the-seven-layer-agent-audit-how-to-find-where-your-ai-agent-is-actually-starving-1gh4</guid>
      <description>&lt;p&gt;Your agent failed again, and your hand found the model dropdown before you'd finished reading the transcript. The model is the one part of your agent that is public, ranked, and argued about. Everything else is private, unglamorous, and yours. So you upgrade the layer you can see and leave the one actually failing untouched.&lt;/p&gt;

&lt;p&gt;You have been debugging the layer easiest to talk about, not the one quietly costing you trust.&lt;/p&gt;

&lt;p&gt;The reflex has a sophisticated form too. The builders who would never just click the dropdown reach instead for a thicker harness, a bigger context window, the framework everyone is posting about. It is the same move: spend on the part you can see so you do not have to diagnose the part you cannot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Seven Layers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I debug through seven layers now, in a fixed order, starting from the one whose damage reaches furthest. One question per layer, and the failure signature you see when that layer is starved.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;The question&lt;/th&gt;
&lt;th&gt;Starved-layer signature&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;7. Purpose&lt;/td&gt;
&lt;td&gt;What job was the agent hired to do?&lt;/td&gt;
&lt;td&gt;Wraps the right answer in the wrong task. Good code, wrong repo.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6. Harness&lt;/td&gt;
&lt;td&gt;What can the agent reach and what stops it?&lt;/td&gt;
&lt;td&gt;Implements the tool, never reaches the goal. Polite loop.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5. Memory&lt;/td&gt;
&lt;td&gt;What survives between turns?&lt;/td&gt;
&lt;td&gt;Re-learns Monday's correction on Thursday. Goldfish with good vocabulary.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4. Verification&lt;/td&gt;
&lt;td&gt;What checks whether the output is right?&lt;/td&gt;
&lt;td&gt;Ships clean format, wrong substance. Green test suite, zero semantic coverage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3. Skills&lt;/td&gt;
&lt;td&gt;What reusable procedures does the agent carry?&lt;/td&gt;
&lt;td&gt;Good work repeated unreliably. Each call is a ground-up re-derivation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2. Data&lt;/td&gt;
&lt;td&gt;What reality does the agent reason from?&lt;/td&gt;
&lt;td&gt;Confident wrong answers from a world that moved. Stale facts quoted with certainty.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1. Orchestration&lt;/td&gt;
&lt;td&gt;Who decides what happens next?&lt;/td&gt;
&lt;td&gt;Wanders, loops, or stalls. No structural feedback.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Debug outside-in, design inside-out&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You build from the top down: name the job (Purpose), bind the harness, package the skills. But you debug from the bottom up, starting at Data, the facts everything else reasons from, because the lower a starved layer sits, the further its fault has already spread.&lt;/p&gt;

&lt;p&gt;Design outside-in. Debug inside-out. The dropdown reflex fails because it debugs at the design end of the stack — the top.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The data trap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A research agent that quotes prices, versions, and policies usually breaks at data. The retrieval is stale, the checks above it are sound, and the failure is a confident answer drawn from a world that moved. Reach for a bigger model and it delivers the out-of-date figure with more poise. The starved floor is lower than anyone was looking.&lt;/p&gt;

&lt;p&gt;Find where the agent's facts enter: the retrieval call, the assumptions written into the system prompt, the document set. Then check one claim against its source. When the agent quotes a price, a version, a policy — can you name when that fact was last refreshed? Does it still match the world?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The verification trap&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An agent that turns out clean, well-formed prose or code usually breaks one floor up, at verification. The easiest row to mark green by pointing at a passing test suite. Look at what those tests check. Most confirm the output is the right shape and almost none test whether it is &lt;em&gt;right&lt;/em&gt;. That is a format check wearing a verification badge.&lt;/p&gt;

&lt;p&gt;The trap is worse for an agent that rewrites its own behaviour, which can pass every check while drifting from the behaviour those checks were meant to protect. A green test suite can sit on a starved verification layer, and it is sometimes the most expensive way to stay blind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to run the audit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Take the seven questions in debug order, bottom to top. For each one, write the evidence in your repo that answers it: the file path, the asserted comparison, the memory store's last write. None of it needs to be a file — on a raw SDK loop, memory is whatever you persist between calls. The form does not matter.&lt;/p&gt;

&lt;p&gt;Where you catch yourself writing a sentence about how you &lt;em&gt;sort of&lt;/em&gt; handle that layer, instead of pointing at where it lives, you have found a starved row.&lt;/p&gt;

&lt;p&gt;Most of the seven clear in a few minutes — the rows you already trust. Running all of them is what earns you the right to drop to the one or two that bite instead of guessing. The starved row is the one you have been compensating for by hand without naming.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which layer is in fashion turns over&lt;/strong&gt; — memory last year, context engineering now — but the audit is what tells you which one is &lt;em&gt;yours&lt;/em&gt;. Before you upgrade the model, before you rebuild the harness, run the seven. The row that comes back red is the one already costing you trust, and naming it stops the wasted motion: you quit arguing with the model, quit rewriting prompts that were never the problem, quit adding memory to a layer whose facts were stale to begin with.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is a shortened version of the full article at &lt;a href="https://harryfloyd.substack.com/p/the-seven-layer-agent-audit" rel="noopener noreferrer"&gt;The Durability Curve&lt;/a&gt;, which includes the full framework, worked examples, and a free one-page audit printout.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>architecture</category>
      <category>debugging</category>
    </item>
    <item>
      <title>What Proves You Can Think?</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Tue, 02 Jun 2026 20:46:39 +0000</pubDate>
      <link>https://dev.to/harryfloyd/what-proves-you-can-think-4hmh</link>
      <guid>https://dev.to/harryfloyd/what-proves-you-can-think-4hmh</guid>
      <description>&lt;p&gt;AI did not just make output cheap. It broke the old contract between effort, competence, and trust.&lt;/p&gt;

&lt;p&gt;For developers this is not abstract. When anyone can generate a clean PR, a plausible code review, a working API endpoint, or a competent-looking architecture diagram in seconds, the artefact stops proving what it used to prove. A good solution no longer implies someone wrestled with the problem.&lt;/p&gt;

&lt;p&gt;The question underneath the productivity debate is harder: if the work no longer proves I can think, what does?&lt;/p&gt;

&lt;h3&gt;
  
  
  The old proof contract
&lt;/h3&gt;

&lt;p&gt;Every institution runs on proof contracts. A school asks for essays and exams. A company asks for CVs, interviews, and work samples. A market asks for traction and retention.&lt;/p&gt;

&lt;p&gt;None of these signals were ever pure. The CV was always a marketing document. The interview was always distorted by nerves and charm. The portfolio could hide how much help the person had. But they worked well enough because polished surfaces were costly to produce. Cost created friction. Friction created signal.&lt;/p&gt;

&lt;p&gt;AI attacks the "expensive enough" part. It compresses the cost of appearing competent. That is enough to break the systems that relied on that cost as a proxy.&lt;/p&gt;

&lt;h3&gt;
  
  
  The move
&lt;/h3&gt;

&lt;p&gt;When output gets cheap, output quality becomes the opening bid, not the final proof. The important question moves upward:&lt;/p&gt;

&lt;p&gt;What does this output prove about the person, team, or system behind it?&lt;/p&gt;

&lt;p&gt;Sometimes the answer is: not much. A clean PR may prove someone had access to a good model and enough taste not to paste the first result. A strong CV may prove the candidate knows how hiring filters work.&lt;/p&gt;

&lt;p&gt;The useful response is not to ban AI. It is to stop treating AI-polished output as the proof object. The next proof system asks what happened before, during, and after the artefact.&lt;/p&gt;

&lt;h3&gt;
  
  
  Five questions that separate judgement from output
&lt;/h3&gt;

&lt;p&gt;These work on code, PRs, architecture decisions, interview responses, and your own work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. What problem was chosen, and what easier problem was rejected?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first proof of thought. Bad work often starts with accepting the first fluent frame. Good work usually contains a buried refusal: someone saw the tempting version and did not take it. In a codebase, this looks like choosing the harder but more maintainable abstraction instead of the one-liner that will break in six months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What tradeoff was made under constraint?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Intelligence becomes visible at the boundary. Anyone can claim they value quality, speed, safety, and maintainability. Real judgement appears when not all of them can be maximised at once. The developer who can explain why they chose correctness over latency for this specific endpoint, and what evidence would make them reverse that choice, is showing something the output alone cannot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. What did you check that the output itself could not prove?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the verification question. It separates people who use AI as a generator from people who use AI inside a judgement loop. The generated code can compile. That is not verification. Verification is the external thing that makes the claim answerable: the edge case test, the production data check, the integration test that proves it works with the real system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. What changed after feedback or contact with reality?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Revision is underrated because it is less glamorous than creation. But in an AI world, revision becomes a higher-status signal. The first surface is cheap. The changed surface after a code review, a production incident, or a colleague pointing out the flaw is where more truth appears.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Who owns the consequence if this is wrong?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Accountability is the signal machines cannot carry. A model can produce. A person must decide what they are willing to stand behind. The developer who says "I shipped this, I own the pager duty for it, I will be awake if it breaks" is operating in a different category from the one who lets the AI output speak for itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  What this changes in practice
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Hiring:&lt;/strong&gt; Stop asking only for work samples. Give candidates a plausible AI-generated solution and ask what is wrong, what would break in production, and what they would check before deploying it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code review:&lt;/strong&gt; Stop treating clean diffs as sufficient evidence. Ask what was not generated. Ask which tradeoff the author is defending. Ask what verification would prove the solution wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your own work:&lt;/strong&gt; Stop trying to prove value only through polished output. Keep the polish, but attach judgement to it. Show the problem you chose. Show the tradeoff. Show the verification. Show the revision. Show what you will own.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This piece was originally published on The Durability Curve, a newsletter about what lasts when the surface gets cheap. &lt;a href="https://harryfloyd.substack.com/p/what-proves-you-can-think" rel="noopener noreferrer"&gt;Read the full article&lt;/a&gt; for the deeper argument, including the research on algorithmic anxiety that frames why this matters beyond engineering.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>career</category>
      <category>architecture</category>
    </item>
    <item>
      <title>What 128GB Unified Memory Changes for Local AI Development</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Mon, 01 Jun 2026 12:28:22 +0000</pubDate>
      <link>https://dev.to/harryfloyd/what-128gb-unified-memory-changes-for-local-ai-development-kam</link>
      <guid>https://dev.to/harryfloyd/what-128gb-unified-memory-changes-for-local-ai-development-kam</guid>
      <description>&lt;h1&gt;
  
  
  What 128GB Unified Memory Changes for Local AI Development
&lt;/h1&gt;

&lt;p&gt;Yesterday at Computex, NVIDIA announced the RTX Spark superchip: an Arm CPU paired with a Blackwell GPU and up to &lt;strong&gt;128GB of unified LPDDR5X memory&lt;/strong&gt;. Most of the coverage is focusing on the Arm chip or the "agentic OS" branding. The real story for developers is the memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Constraint That Just Got Removed
&lt;/h2&gt;

&lt;p&gt;If you've run local models, you know the bottleneck. An RTX 4090 has 24GB of VRAM. That fits a 13B parameter model at 8-bit or a 30B model at 4-bit, with nothing else. No embedding model. No vector database. No room for the application itself in GPU memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# With 24GB VRAM (RTX 4090):
# - 30B model at Q4_K_M: ~20GB
# - KV cache for 4096 context: ~2GB  
# - Remaining: ~2GB
# - Can't fit an embedding model. Can't fit a vector index.
# - CPU offloading would be needed, which is 10-100x slower.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;128GB unified memory changes this because the CPU and GPU share one pool. You're not choosing between VRAM for the model and system RAM for everything else. The GPU can directly access the full 128GB.&lt;/p&gt;

&lt;p&gt;For context, a 70B parameter model at FP4 (4-bit) needs about 40-45GB in practice, with quantization overhead and KV cache included. That leaves roughly 83GB for the rest of your stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Actually Build Now
&lt;/h2&gt;

&lt;p&gt;Here's a concrete workflow that goes from impossible to straightforward with 128GB:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running a local RAG pipeline with a 70B model:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Components that now fit on one machine:
# 1. 70B LLM at FP4: ~42GB
# 2. Embedding model (e.g., bge-large-en-v1.5): ~1.5GB  
# 3. Vector index (10M embeddings at 768d): ~6GB
# 4. Application runtime + buffer: ~8GB
# Total: ~57.5GB — fits with 70GB to spare
# On a 4090 24GB: the 70B model alone doesn't fit
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or a multi-agent setup where you run three specialised models simultaneously:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Multi-model orchestration on one machine:
# - 70B orchestrator model at FP4: ~42GB
# - 30B code specialist at Q4_K_M: ~20GB  
# - 7B verification model at Q8: ~7GB
# - Shared KV cache: ~4GB
# Total: ~73GB — comfortable fit
# On 24GB VRAM: you'd need 3 separate machines
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This isn't theoretical. The RTX Spark runs Windows on Arm, and NVIDIA's NemoClaw agent framework already supports it. The software stack (llama.cpp, Ollama, NVIDIA's own AI Enterprise suite) supports the NVLink C2C architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Memory Bandwidth Question
&lt;/h2&gt;

&lt;p&gt;128GB of LPDDR5X at 300 GB/s is the spec worth checking. Compare this to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RTX 4090: 24GB GDDR6X at 1,008 GB/s&lt;/li&gt;
&lt;li&gt;Mac M5 Max: 128GB unified at ~800 GB/s&lt;/li&gt;
&lt;li&gt;RTX Spark: 128GB LPDDR5X at 300 GB/s&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The RTX Spark has 5x the capacity but about a third of the bandwidth of a 4090. This means: batch inference and throughput-oriented workloads will be slower than a 4090. But model loading, context switching between models, and running multiple models simultaneously all bottleneck on VRAM capacity, not bandwidth. Those will be dramatically better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The bandwidth is enough for interactive inference.&lt;/strong&gt; A 70B model generates ~30 tokens/second on an M5 Max at 800 GB/s. At 300 GB/s, you'd expect roughly 10-15 tokens/second. Slower but usable for most development workflows. For production batch inference, you'd still want a datacenter GPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Means for Local AI Development
&lt;/h2&gt;

&lt;p&gt;The practical takeaway for developers: &lt;strong&gt;128GB unified memory changes the threshold question.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before RTX Spark, the question was: "Does my model fit in 24GB?" If no, you couldn't run it locally at all. You needed cloud GPUs or CPU offloading, which is impractically slow for any interactive use.&lt;/p&gt;

&lt;p&gt;After RTX Spark, the question becomes: "Does my multi-model workflow fit in 128GB?" For most development setups, including a large model, an embedding service, a vector index, and some agent tooling, the answer is yes.&lt;/p&gt;

&lt;p&gt;This doesn't replace cloud infrastructure for production. But it changes the economics of development iteration. Running a local dev environment with production-scale models means faster feedback cycles, no inference API costs during development, and the ability to test multi-model interactions without distributed system complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Structural Change
&lt;/h2&gt;

&lt;p&gt;The Arm chip is interesting. The agentic OS pitch is marketing. The memory bus is the actual structural change, a discontinuity in what a single consumer PC can hold in memory for AI workloads.&lt;/p&gt;

&lt;p&gt;If your work involves models above 30B parameters locally, this is the spec that matters. Everything else, including clock speeds, core counts, and TOPS ratings, is secondary to whether your working set fits in memory.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;NVIDIA's RTX Spark announcement at Computex 2026. Tom's Hardware has the full spec breakdown &lt;a href="https://www.tomshardware.com/laptops/nvidia-unveils-rtx-spark-superchip-at-computex-2026-new-platform-promises-to-turn-windows-into-an-agentic-ai-os-with-arm-cpu-blackwell-gpu-and-128gb-unified-memory" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>llm</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Same AI Model Can Perform 6x Better: Here's Why</title>
      <dc:creator>Harry Floyd</dc:creator>
      <pubDate>Sat, 30 May 2026 21:39:59 +0000</pubDate>
      <link>https://dev.to/harryfloyd/the-same-ai-model-can-perform-6x-better-heres-why-440o</link>
      <guid>https://dev.to/harryfloyd/the-same-ai-model-can-perform-6x-better-heres-why-440o</guid>
      <description>&lt;p&gt;A &lt;a href="https://arxiv.org/abs/2603.28052" rel="noopener noreferrer"&gt;Stanford and Tsinghua paper&lt;/a&gt; ran a controlled experiment earlier this year. Same model. Same task. Different harness architecture.&lt;/p&gt;

&lt;p&gt;The result: a 6x performance gap driven entirely by the system built &lt;em&gt;around&lt;/em&gt; the model. Not the model itself.&lt;/p&gt;

&lt;p&gt;This is not a prompt engineering insight. It is a systems architecture insight, and it changes where developers should invest their time when building agentic systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6x Gap
&lt;/h2&gt;

&lt;p&gt;Meta-Harness tested Claude Opus 4.6 across two harness configurations on TerminalBench-2. The only variable was the scaffold: the code that manages tool calls, context windows, error recovery, and state persistence.&lt;/p&gt;

&lt;p&gt;One version scored at baseline. The other, with structured tool orchestration and context management, scored 18.4 points higher. Same inference cost. Same model. Different architecture.&lt;/p&gt;

&lt;p&gt;This pattern replicates across multiple independent studies:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/langchain-ai/deepagents" rel="noopener noreferrer"&gt;LangChain DeepAgents&lt;/a&gt; (2026):&lt;/strong&gt; Same GPT-5.2-Codex model. Harness-only changes moved it from Top 30 to Top 5. That is a 13.7-point gain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://blog.can.ac/2026/02/12/the-harness-problem/" rel="noopener noreferrer"&gt;Can Bölük&lt;/a&gt; (Hashline, 2026):&lt;/strong&gt; Same model, same task. Changed the edit tool format. Performance went from 6.7% to 68.3%. That is a 10x improvement with 61% fewer tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://vercel.com/blog/we-removed-80-percent-of-our-agents-tools" rel="noopener noreferrer"&gt;Vercel's d0 agent&lt;/a&gt;:&lt;/strong&gt; A production agent had 16 tools. Removing 14 of them (leaving only bash) took success rate from 80% to 100%. The bottleneck was not capability. It was decision surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters Practically
&lt;/h2&gt;

&lt;p&gt;The cheapest Haiku call with an optimised harness (37.6% on TerminalBench-2) outperformed the most expensive Opus call with a default harness (58.0%). That is at 1/50th the inference cost.&lt;/p&gt;

&lt;p&gt;Most teams are optimising at the wrong layer. They swap models, tune prompts, add retrieval. The structural leverage is in how the system manages tool calls, handles state, and recovers from failure.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changes
&lt;/h2&gt;

&lt;p&gt;The practical takeaway for anyone building with AI agents:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Audit your tool surface.&lt;/strong&gt; Every tool your agent can call is a decision it must make. Vercel found 16→1 tool reduction improved everything. Fewer tools, better decisions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Measure harness, not just model.&lt;/strong&gt; Track task completion rate per harness configuration, not just per model. The harness is the variable that moved 6x.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost is architecture-dependent, not model-dependent.&lt;/strong&gt; Haiku with a good harness beat Opus with a bad harness. Test harness variations before upgrading to a more expensive model.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The full analysis (12 verified claims, evidence tables, production case studies, and falsification criteria) is on Substack:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://harryfloyd.substack.com/p/harness-engineering-same-model-different-product" rel="noopener noreferrer"&gt;Harness Engineering: Same Model, Different Product →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It covers the Claude Code 1,421-line state machine, the Codex CLI vs Claude Code architecture comparison (77.3% vs 65.4%, 4.2x token efficiency difference), and why this is a Law IV (Instruments Over Theory) and Law I (Bottleneck Migration) structural play.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Follow for weekly analysis on AI infrastructure, agent architecture, and the systems that actually determine model performance.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
