<?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: Finley Zhou</title>
    <description>The latest articles on DEV Community by Finley Zhou (@datacpp_8185).</description>
    <link>https://dev.to/datacpp_8185</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%2F4066544%2Ff9560bcf-c38a-4a9d-af76-3897752762ab.png</url>
      <title>DEV Community: Finley Zhou</title>
      <link>https://dev.to/datacpp_8185</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/datacpp_8185"/>
    <language>en</language>
    <item>
      <title>Three Independent Checks for an Agent Patch: Fixture Contract, Reference Oracle, and a Flaky Quarantine</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sun, 30 Aug 2026 18:47:45 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/three-independent-checks-for-an-agent-patch-fixture-contract-reference-oracle-and-a-flaky-p8n</link>
      <guid>https://dev.to/datacpp_8185/three-independent-checks-for-an-agent-patch-fixture-contract-reference-oracle-and-a-flaky-p8n</guid>
      <description>&lt;h1&gt;
  
  
  Three Independent Checks for an Agent Patch: Fixture Contract, Reference Oracle, and a Flaky Quarantine
&lt;/h1&gt;

&lt;p&gt;The first question to ask about an agent-generated patch is not &lt;code&gt;did the tests pass?&lt;/code&gt; It is &lt;code&gt;who wrote the tests?&lt;/code&gt; If the same agent produced both code and assertions, a green suite can mean the patch answered its own questions. This article uses three independent sources: a fixture contract checked in before the patch, a differential property test against a reference implementation, and a quarantine list for flaky tests. Each source stands alone, so if two of the three miss the bug, the third still has a chance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why fixtures are a contract, not data
&lt;/h2&gt;

&lt;p&gt;A fixture set is a contract when it is committed before the agent starts. The agent can propose code changes, but it cannot touch &lt;code&gt;tests/fixtures/behavior.json&lt;/code&gt;. That restriction matters. If tests are allowed to change during the patch, a bug can disappear by editing the expected output instead of fixing the code.&lt;/p&gt;

&lt;p&gt;Example: a small function that applies a preference patch to a settings object.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;domain/preferences.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;apply_patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patch&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;merged&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A fixture declares the behavior that must survive any refactor:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tests/fixtures/behavior.json&lt;/code&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"override disables notifications"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"base"&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="nl"&gt;"theme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dark"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"notifications"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"on"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"patch"&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="nl"&gt;"notifications"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"off"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expected"&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="nl"&gt;"theme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dark"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"notifications"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"off"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"empty patch is a no-op"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"base"&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="nl"&gt;"theme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dark"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"patch"&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;"expected"&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="nl"&gt;"theme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dark"&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="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;The test reads the fixture and compares the result with the expected object:&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;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;domain.preferences&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;apply_patch&lt;/span&gt;

&lt;span class="n"&gt;FIXTURES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tests/fixtures/behavior.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.mark.parametrize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;case&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FIXTURES&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&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_fixture_contract&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;apply_patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;patch&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;expected&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last assertion is the one an agent often misses. It checks that applying a patch does not mutate the original object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Differential properties: the reference oracle
&lt;/h2&gt;

&lt;p&gt;Hand-written unit tests encode what one developer remembers. Reference properties encode a relationship. Before the agent touches real code, pick a previous version of &lt;code&gt;apply_patch&lt;/code&gt; that the team trusts, or write a small reference implementation with the exact semantics you intend to keep.&lt;/p&gt;

&lt;p&gt;Then use a property-based test to compare the new implementation with the reference over many inputs:&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;hypothesis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;domain.preferences&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;apply_patch&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;domain.preferences_reference&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;apply_patch&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;reference&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dictionaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dictionaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()),&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_agent_patch_matches_reference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;apply_patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dictionaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dictionaries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()),&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_patch_never_adds_keys_outside_union&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;allowed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;apply_patch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;allowed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Differential testing is stronger than a single assertion because it generates thousands of inputs. When a case fails, Hypothesis shrinks it to the smallest counterexample. The agent can then fix a reproducible bug instead of investigating a vague &lt;code&gt;some inputs are wrong&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If a reference implementation is impossible, use a weaker invariant: the patch must be deterministic, it must not add keys from outside the union, and it must not mutate its arguments. These three properties catch most &lt;code&gt;accidental state&lt;/code&gt; bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The quarantine file, not a retry loop
&lt;/h2&gt;

&lt;p&gt;Flaky tests are normal in agent workflows because the patch changes timing, caching, or external calls. The standard answer is &lt;code&gt;retry three times&lt;/code&gt;. That is the wrong default. A retry makes the flake invisible until it happens twice in a row. It also gives the agent false confidence.&lt;/p&gt;

&lt;p&gt;Keep a quarantine instead. When a test fails sporadically, move it to a freeze list with metadata. The test stops running in the default suite, but the record stays in the repo.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tests/quarantine.json&lt;/code&gt;:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test_user_source_order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"first_seen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-25"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"last_seen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"failures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"race between cache invalidation and polling"&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;A small fixture in &lt;code&gt;conftest.py&lt;/code&gt; skips tests that appear in the quarantine file:&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;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;

&lt;span class="n"&gt;QUARANTINE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tests/quarantine.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;QUARANTINED_NAMES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;QUARANTINE&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;pytest_collection_modifyitems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;QUARANTINED_NAMES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_marker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;quarantined flake&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a freeze, not a deletion. The test must stay in the repository. A nightly job can re-enable quarantined tests and check whether they pass five times in a row. If they do, remove them from quarantine. If they do not, the metadata in the JSON shows whether the failure is one environment or a real regression.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where MonkeyCode fits
&lt;/h2&gt;

&lt;p&gt;MonkeyCode's free model access and free server option are relevant here in only one way: they make it cheaper to run this validation loop on each generated patch. The value of the loop is independent of the tool, and the same checks work with any agent. What matters is the discipline of running the fixture contract, the differential properties, and the quarantine review on every patch. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this strategy will not help
&lt;/h2&gt;

&lt;p&gt;This strategy fails in three situations. First, when there is no reference implementation and the invariants are too weak, differential tests are almost useless. Second, when the bug is visual or timing-dependent, property tests and JSON fixtures do not see the layout or the race. Third, when the quarantine is not reviewed. If everyone adds flaky tests and nobody cleans the list, the quarantine becomes an attic where regressions can hide.&lt;/p&gt;

&lt;p&gt;Use this setup for data-processing functions, pure merges, serializers, and any patch that has a stable input/output shape. Do not use it for UI redesigns, network protocols with changing behavior, or systems where every run is expected to depend on the environment. The goal is to make the agent prove a claim against sources that the agent did not write.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>pytest</category>
      <category>programming</category>
    </item>
    <item>
      <title>Give Your Agent Patch a Determinism Budget: Seed-Locked Properties, Pinned Fixtures, a Freeze Registry</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sun, 30 Aug 2026 15:44:51 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/give-your-agent-patch-a-determinism-budget-seed-locked-properties-pinned-fixtures-a-freeze-d78</link>
      <guid>https://dev.to/datacpp_8185/give-your-agent-patch-a-determinism-budget-seed-locked-properties-pinned-fixtures-a-freeze-d78</guid>
      <description>&lt;p&gt;Last week a property test failed on run 3, passed through run 7, and failed again after lunch. The patch under review was not mine. It had been generated by an agent, and the only evidence I had was the test suite. The suite said two contradictory things in the same hour. The patch did not necessarily become wrong because the test was flaky, but the gate could not prove it was right either.&lt;/p&gt;

&lt;p&gt;The fix was not more retries. The fix was a determinism budget: one fixed seed for every property check, one pinned fixture profile for every environment variable, and a freeze list for tests that still refused to be stable. This post is that budget, implemented in Python, and runnable on any CI that supports pytest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why property tests become flaky
&lt;/h2&gt;

&lt;p&gt;A property test is a random generator paired with an assertion. The generator is a fixture. The seed is also a fixture, but most teams treat it as invisible. When the seed changes, the example distribution changes. A real edge-case bug will then either appear inside your 200 examples or it will not.&lt;/p&gt;

&lt;p&gt;That is not a failure of property testing. It is a missing fixture.&lt;/p&gt;

&lt;p&gt;For agent patches the stakes are worse. The patch was not written by someone who knows which examples are dangerous. The gate must therefore be transparent about one thing: every test must run with the same inputs, in the same environment, or the verdict cannot be attributed to the patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Lock the seed into a fixture
&lt;/h2&gt;

&lt;p&gt;If the seed lives in a central configuration object, every property test uses the same example stream.&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;# determinism.py
&lt;/span&gt;&lt;span class="n"&gt;DETERMINISM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20260830&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_examples&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UTC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache_dir&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tmp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fixture applies the budget before any property test runs:&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;# conftest.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;determinism&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DETERMINISM&lt;/span&gt;

&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;patch-gate.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;PROFILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@pytest.fixture&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pinned_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TZ&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DETERMINISM&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tz&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PYTHONHASHSEED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DETERMINISM&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APP_SEED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DETERMINISM&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
    &lt;span class="n"&gt;monkeypatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CACHE_DIR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tmp_path&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cache&lt;/span&gt;&lt;span class="sh"&gt;"&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;tmp_path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the same seed is a first-class test fixture, not an accident of scheduling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Pin everything the patch might touch
&lt;/h2&gt;

&lt;p&gt;A seed alone does not protect you from a patch that reads &lt;code&gt;TZ&lt;/code&gt; differently, changes cache paths, or depends on the current date. A fixture profile pins the full environment for the duration of the gate:&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;"profile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"patch-gate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"seed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20260830&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"TZ"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UTC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"PYTHONHASHSEED"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20260830"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"APP_SEED"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"20260830"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CACHE_DIR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tmp_path/cache"&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;"freeze"&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="s2"&gt;"test_legacy_race"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test_sketchy_timing"&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;The property test and the fixture meet in one function:&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;hypothesis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypothesis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="nd"&gt;@seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROFILE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="nd"&gt;@settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_examples&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DETERMINISM&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max_examples&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integers&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integers&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_insert_preserves_sortedness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pinned_env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bisect&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;insort&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[:]&lt;/span&gt;
    &lt;span class="nf"&gt;insort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If this fails, the failure is reproducible. If it passes, the patch saw a fixed example stream and a fixed environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Freeze the flaky before it gates
&lt;/h2&gt;

&lt;p&gt;A test that still disagrees with itself under a fixed seed and a pinned profile is not evidence. Retrying converts it from noise into a decorative pass. Freezing converts it into an explicit skip:&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;# conftest.py
&lt;/span&gt;&lt;span class="n"&gt;FROZEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROFILE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;freeze&lt;/span&gt;&lt;span class="sh"&gt;"&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;pytest_collection_modifyitem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;items&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;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;FROZEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_marker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mark&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flake freeze until stable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The frozen test does not count toward the patch verdict. It is a debt line, not a signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision matrix
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observed result&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Gate action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fixed-seed property check fails with counterexample&lt;/td&gt;
&lt;td&gt;The patch changed behavior&lt;/td&gt;
&lt;td&gt;Reject and attach the reproduction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixture-dependent test fails inside the patch diff&lt;/td&gt;
&lt;td&gt;The patch relies on an unpinned variable&lt;/td&gt;
&lt;td&gt;Re-run on the profile; if still red, reject&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixture-dependent test fails outside the patch diff&lt;/td&gt;
&lt;td&gt;Environment drift, not patch evidence&lt;/td&gt;
&lt;td&gt;Fix the environment and re-run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frozen flaky test would have failed&lt;/td&gt;
&lt;td&gt;No new information&lt;/td&gt;
&lt;td&gt;Do not count toward the verdict&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All checks pass on fixed seed + pinned env&lt;/td&gt;
&lt;td&gt;Stable under this budget&lt;/td&gt;
&lt;td&gt;Human review only, not auto-merge&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Where to run this budget
&lt;/h2&gt;

&lt;p&gt;MonkeyCode's free server option is convenient for this because the gate runs in a throwaway environment, away from your local checkout. Its free model access can produce an initial fixture profile from your repo layout, but treat that profile as code and review it like code. The budget lives in your repository, not in the model's memory. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this budget does not prove
&lt;/h2&gt;

&lt;p&gt;A fixed seed reduces exploration. The next 10,000 examples might still contain a regression that your 200 did not. A pinned environment also cannot replace real contract tests against external services. If you rely on a live database or a third-party API, disabling it in the fixture gives you a green suite that is more confident than the production system it represents.&lt;/p&gt;

&lt;p&gt;Do not use this approach when the patch changes a randomness-critical component such as a sampler or a cryptographic primitive. Determinism there creates false safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gate is only as honest as its fixtures
&lt;/h2&gt;

&lt;p&gt;A patch review pipeline is a claim about attribution: this failure is the patch's fault, this failure is the environment's fault, and this failure is too noisy to use. The determinism budget makes that claim testable. Write the seed down. Pin the environment. Freeze the noise. Then let a human make the final call.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>python</category>
      <category>ai</category>
      <category>pytest</category>
    </item>
    <item>
      <title>Free Tokens, Free Server, and a Property Test That Refuses to Be Gamed</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sun, 30 Aug 2026 11:35:28 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/free-tokens-free-server-and-a-property-test-that-refuses-to-be-gamed-45el</link>
      <guid>https://dev.to/datacpp_8185/free-tokens-free-server-and-a-property-test-that-refuses-to-be-gamed-45el</guid>
      <description>&lt;p&gt;Unit tests tell you what the author expected. Property tests tell you what the universe thinks.&lt;/p&gt;

&lt;p&gt;If an AI-generated patch only passes the first, it is not ready. I have spent the last month building a verification loop for agent patches, and the one tool that consistently catches more than unit tests is a property-based harness that runs a few thousand random operations against an invariant.&lt;/p&gt;

&lt;p&gt;Here is the workflow I now use: ask a free model via MonkeyCode to write a patch, push that patch to a test harness on a free server, and let the server hammer the code with randomized sequences. This article shows you the exact harness, the freeze rule for flaky failures, and why the free tier is enough for meaningful verification.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Unit Tests Are Not Enough for Agent Patches
&lt;/h2&gt;

&lt;p&gt;An LLM is extremely good at producing code that matches the shape of the surrounding project. It is much worse at reasoning about global state, ordering, and edge conditions that the test author never wrote down.&lt;/p&gt;

&lt;p&gt;A unit test fixes one input and one expected output. The agent can accidentally overfit the test, especially if the test is in the prompt context. The result is a patch that looks correct, passes CI, and then corrupts state in production.&lt;/p&gt;

&lt;p&gt;Property tests invert that. They define a valid state and a set of allowed operations. The test generates arbitrary sequences and checks that the state remains valid after every step. There is no single expected output to memorize.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Harness: A Ring Buffer That Should Never Lie
&lt;/h2&gt;

&lt;p&gt;I used a classic data structure for the experiment: a fixed-capacity ring buffer. The invariants are simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;size()&lt;/code&gt; always equals the number of elements successfully pushed minus the number popped.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pop()&lt;/code&gt; returns elements in FIFO order.&lt;/li&gt;
&lt;li&gt;Pushing into a full buffer either blocks or returns an error; it never silently loses data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent's task was to implement a thread-safe version. The property test needs to detect corruption even when the unit tests pass.&lt;/p&gt;

&lt;p&gt;Here is the minimal C++ property harness. It uses only the standard library, so it runs on any free server without proprietary dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cassert&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;deque&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;random&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;RingBuffer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;explicit&lt;/span&gt; &lt;span class="n"&gt;RingBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop_front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;property_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mt19937&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;RingBuffer&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cap&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;deque&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;has_actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;has_expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;has_expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop_front&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;has_actual&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;has_expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;has_actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;property_check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="cm"&gt;/*cap=*/&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="cm"&gt;/*steps=*/&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a property-test library. It is a brute-force generator. But that is enough to fail a broken patch in under a second.&lt;/p&gt;

&lt;p&gt;The first time I ran this against an agent-generated ring buffer, the failure appeared at seed 17. The unit test passed because it only pushed 8 values and popped 8 values in perfect order. The agent had used a &lt;code&gt;std::vector&lt;/code&gt; and rotated the head index with a signed integer. When a pop was attempted on an empty buffer, the head went negative and wrapped around to a corrupt position.&lt;/p&gt;

&lt;p&gt;A property test with 1000 random seeds would have caught it at seed 17. That is the difference between a check and a belief.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Run It on a Free Server?
&lt;/h2&gt;

&lt;p&gt;You can run 1000 seeds locally in a few milliseconds. So why bother with a server?&lt;/p&gt;

&lt;p&gt;Because the patch is not the only moving part. You also want to verify that the code works under different flags, different standard library implementations, and maybe different operating systems. The free server option in MonkeyCode gives you a disposable environment without draining your laptop’s battery or your CI budget.&lt;/p&gt;

&lt;p&gt;More importantly, the server is where you run the slow variants. Change the seed count to 100,000 and the steps to 10,000. That takes a few minutes on a free tier. It is still cheap, and it will find state corruption that a 1000-seed run misses.&lt;/p&gt;

&lt;p&gt;Here is a concrete loop I use:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a patch from the free model endpoint inside MonkeyCode.&lt;/li&gt;
&lt;li&gt;Copy the patch into a fresh project.&lt;/li&gt;
&lt;li&gt;Compile with warnings as errors (&lt;code&gt;-Wall -Wextra -Werror&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Run the unit tests. If they pass, move on.&lt;/li&gt;
&lt;li&gt;Run this property harness with a high seed count on the free server.&lt;/li&gt;
&lt;li&gt;If a seed fails, paste that seed back into the prompt and ask for a fix.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Freeze Rule: Don't Retry, Record
&lt;/h2&gt;

&lt;p&gt;A flaky test is a piece of code that tells you it is broken. Your first instinct is to retry it. Resist that instinct.&lt;/p&gt;

&lt;p&gt;In my workflow, any test that fails once is immediately frozen: it is pinned to a &lt;code&gt;known_flaky&lt;/code&gt; list and excluded from normal CI. The property harness, however, is never frozen. If it fails, it must be fixed, because a random seed is a specific input, not a timing artifact.&lt;/p&gt;

&lt;p&gt;Why freeze at all? Because agent-generated patches often introduce nondeterminism through uninitialized memory or race conditions. A retry hides the root cause and teaches the agent that flakiness is acceptable. Freezing makes the failure visible and forces a fix.&lt;/p&gt;

&lt;p&gt;The property harness is deliberately deterministic. I seed the RNG explicitly, so a failure is reproducible forever. There is no excuse to retry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Should Not Use This Approach
&lt;/h2&gt;

&lt;p&gt;This property harness is not a substitute for a full property-testing library like RapidCheck or Hypothesis. It does not shrink inputs, find minimal counterexamples, or integrate with your build system automatically. If your code is heavily stateful and thread-safe, you need a real framework plus a memory sanitizer.&lt;/p&gt;

&lt;p&gt;Also, this workflow assumes the agent's patch is small and scoped. If you are trying to verify a 5000-line rewrite, a simple random fuzzer will not give you confidence. You need formal verification or at least a serious differential testing setup.&lt;/p&gt;

&lt;p&gt;The free tier is good for iterating, not for infinite scale. My observation is that 10 million free tokens are enough to generate and revise dozens of patches for a mid-size repository, but they will not cover a high-frequency production pipeline. Treat the free tier as a testing ground, not a permanent runtime.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Final Word on the Free Server
&lt;/h2&gt;

&lt;p&gt;The most underrated feature of MonkeyCode is not the tokens. It is the free server option that lets you run these deterministic checks in a clean environment. I no longer worry about whether my local machine has the right libraries or whether a stale build is lying to me. The server starts empty, pulls the repo, applies the patch, and runs the harness. If it fails, I know it was the code, not the machine.&lt;/p&gt;

&lt;p&gt;If you are reviewing agent patches, do not add more unit tests. Add properties. Then freeze the flaky and let the server verify every seed.&lt;/p&gt;

&lt;p&gt;Try it with MonkeyCode's free tier. The worst that can happen is a failing seed you understand.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>cpp</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Three Buckets and a Freeze: A Testing Triage for Agent Patches That Don't Trust the Patch</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sun, 30 Aug 2026 09:37:25 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/three-buckets-and-a-freeze-a-testing-triage-for-agent-patches-that-dont-trust-the-patch-4o50</link>
      <guid>https://dev.to/datacpp_8185/three-buckets-and-a-freeze-a-testing-triage-for-agent-patches-that-dont-trust-the-patch-4o50</guid>
      <description>&lt;p&gt;When an agent edits your code, every test result is a claim. The claim says: &lt;em&gt;this patch doesn't break what the tests observe&lt;/em&gt;. Claims are cheap. Evidence is not.&lt;/p&gt;

&lt;p&gt;I saw this again last week. An agent produced a patch that passed all 9 unit tests. A separate trace oracle flagged 4 behavioral changes the agent never mentioned. The tests were green. The behavior moved. That's the gap this article addresses.&lt;/p&gt;

&lt;p&gt;The fix isn't a better agent. It's a better test triage. Here's a strategy in three buckets and one freeze, built for C++ codebases where agents generate patches faster than humans can review them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core conclusion
&lt;/h2&gt;

&lt;p&gt;Sort your test suite into three buckets: &lt;strong&gt;property checks&lt;/strong&gt; for invariants, &lt;strong&gt;fixtures&lt;/strong&gt; for system boundaries, and a &lt;strong&gt;freeze list&lt;/strong&gt; for flaky tests. Run the property checks on every patch. Run fixtures on every pass of the property checks. Treat flaky tests as unmergeable, not as noise to retry.&lt;/p&gt;

&lt;p&gt;This sounds simple. The implementation is the hard part.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why property checks, not just examples
&lt;/h2&gt;

&lt;p&gt;Example-based tests encode a single path through the code. An agent can pass them by matching the example, not by preserving behavior. Property checks run hundreds of inputs against an invariant. They make the agent's job harder: the patch must satisfy a rule, not a snapshot.&lt;/p&gt;

&lt;p&gt;A minimal property check for a ring buffer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test_ring_buffer_never_loses_capacity_invariant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pqc&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;amountring_buffer&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_bool&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_int&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Invariant: after any sequence of operations:&lt;/span&gt;
        &lt;span class="c1"&gt;// 1. size() &amp;lt;= capacity()&lt;/span&gt;
        &lt;span class="c1"&gt;// 2. push() preserves order for elements still in the buffer&lt;/span&gt;
        &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The invariant holds for any sequence. An agent cannot saturate it with a fixed example. If the patch breaks the ordering guarantee, this check fails on some input the agent never saw.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bucket 1: Property checks (run first)
&lt;/h2&gt;

&lt;p&gt;Put everything that can be expressed as an invariant here. In C++ that includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container invariants: size limits, ordering, uniqueness, sortedness&lt;/li&gt;
&lt;li&gt;Arithmetic invariants: result range, overflow behavior at extremes, sign preservation&lt;/li&gt;
&lt;li&gt;Resource invariants: a handle is closed exactly once, a lock is released on every return path&lt;/li&gt;
&lt;li&gt;Idempotence: applying an operation twice equals applying it once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write them as a separate target. The agent's patch must keep them green before any manual review starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bucket 2: Fixtures for system boundaries
&lt;/h2&gt;

&lt;p&gt;Property checks catch local invariants. Fixtures catch the seams: files, sockets, environment variables, subprocesses. These are where agents hallucinate APIs or call order.&lt;/p&gt;

&lt;p&gt;A fixture should bind a fake boundary to a real contract. For a file reader:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;file_fixture&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;filesystem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;file_fixture&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;make_temp_path&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;write_seed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;file_fixture&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;filesystem&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;test_reader_closes_fd_on_truncated_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_fixture&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;fx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The contract: a truncated read returns a parse error AND closes the fd.&lt;/span&gt;
    &lt;span class="c1"&gt;// The agent's patch often fixes the error but leaks the fd.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fixture is not just setup code. It's a contract with three parts: what the boundary provides, what the healthy behavior is, and what the agent is likely to break first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bucket 3: The flaky freeze list
&lt;/h2&gt;

&lt;p&gt;Flaky tests are the most dangerous tests in an agent-patch pipeline. Why? Because the agent sees a failure, retries, and reports success when the test passes on &lt;em&gt;chance&lt;/em&gt;, not because the patch is correct.&lt;/p&gt;

&lt;p&gt;The policy: any test that fails intermittently more than twice in 20 runs goes to the freeze list. Frozen tests do not run in agent verification. They block the merge until a human fixes them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# test_triage.cfg
&lt;/span&gt;&lt;span class="nn"&gt;[frozen]&lt;/span&gt;
&lt;span class="err"&gt;network_timeout_retry_test&lt;/span&gt;   &lt;span class="c"&gt;# flaky in CI: 2 non-hermetic failures
&lt;/span&gt;&lt;span class="err"&gt;random_shuffle_seed_dependency&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is counterintuitive. Most teams retry flaky tests. In agent-driven development, retrying is indistinguishable from rewarding the agent for ignoring failures. A freeze converts flakiness from a hidden risk into a visible merge blocker.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Property checks&lt;/th&gt;
&lt;th&gt;Fixtures&lt;/th&gt;
&lt;th&gt;Frozen tests&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pass&lt;/td&gt;
&lt;td&gt;Pass&lt;/td&gt;
&lt;td&gt;0 blocked&lt;/td&gt;
&lt;td&gt;Merge candidate. Review the diff for behavioral drift anyway.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pass&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;0 blocked&lt;/td&gt;
&lt;td&gt;Likely a boundary assumption. Inspect fixtures before merging.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;Reject. The patch violates an invariant.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;Any&lt;/td&gt;
&lt;td&gt;1+ blocked&lt;/td&gt;
&lt;td&gt;Do not merge. Fix the flaky test first.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two rules make this table work:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Frozen tests are not counted as failures. They're a separate signal: the suite itself is unreliable.&lt;/li&gt;
&lt;li&gt;If property checks fail, the patch is rejected without reading the fixture results. No retry. The agent gets the invariant violation as feedback.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The retry budget is zero. An agent can request more runs, but each run costs tokens. This ties directly into a cost-capped gate: the agent learns that fixing the invariant is cheaper than retrying until green.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this
&lt;/h2&gt;

&lt;p&gt;This strategy assumes your codebase has invariants you can express. If you're working in a pure glue layer with no state, no ordering, and no resources, the property bucket is empty and the strategy collapses into fixtures alone.&lt;/p&gt;

&lt;p&gt;It also assumes you can make tests hermetic. If your tests hit real network services, every property check will flake and the freeze list will eat the entire suite. Fix the hermeticity problem first.&lt;/p&gt;

&lt;p&gt;Finally, this does not catch semantic drift. A patch can pass every invariant and still change behavior in an unintended way. Property checks are a sieve, not a proof. That's why a token-efficient evaluation pass with a few representative traces is still worth running before merging.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  How this fits a free-server workflow
&lt;/h2&gt;

&lt;p&gt;Running this triage locally is boring but predictable. Running it as an automated pre-merge gate needs compute that's always available. I used MonkeyCode's free server option to host the property-check runner and the freeze-list parser as a scheduled CI job, and its free model access to draft the initial invariant list from the existing test suite.&lt;/p&gt;

&lt;p&gt;The free models were adequate for the drafting step. They generated candidate properties I then hand-verified against the code. The server made the gate run unattended. Neither step required a paid plan.&lt;/p&gt;

&lt;p&gt;The surprising part was not the automation. It was how quickly the freeze list outgrew the property bucket. In the first week, three tests were frozen for flakiness. Two were network-dependent. One had an unseeded shuffle. Fixing those revealed two genuine bugs the agent had papered over with retries.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-line takeaway
&lt;/h2&gt;

&lt;p&gt;Give an agent a test suite with flaky tests, and it will learn to gamble. Give it property checks, fixtures, and a freeze list, and it has nowhere to hide. The patch may still be wrong.&lt;/p&gt;

&lt;p&gt;But it will be wrong for the right reasons, and your review will be watching for behavior drift, not decoding which retry finally passed.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>cpp</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Unit Tests Approve. The Invariant Disagrees: A Property-First Strategy for Agent Patches</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sun, 30 Aug 2026 06:36:14 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/unit-tests-approve-the-invariant-disagrees-a-property-first-strategy-for-agent-patches-5fic</link>
      <guid>https://dev.to/datacpp_8185/unit-tests-approve-the-invariant-disagrees-a-property-first-strategy-for-agent-patches-5fic</guid>
      <description>&lt;p&gt;A green unit test suite does not prove an agent patch is correct. It proves the agent predicted your examples. When every committed test passes and the production system still breaks, the violated constraint was an invariant you never encoded.&lt;/p&gt;

&lt;p&gt;This article is a three-layer testing strategy for agent patches. Layer one is property checks. Layer two is frozen fixtures. Layer three is a flaky test freeze. Each layer is cheap and each is hard for an agent to game.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure mode
&lt;/h2&gt;

&lt;p&gt;Take a parser. The agent patches &lt;code&gt;parse_interval&lt;/code&gt; so &lt;code&gt;"09:32"&lt;/code&gt; becomes 570 minutes—because the team complained about irregular intervals. Unit tests use clean inputs like &lt;code&gt;"09:30"&lt;/code&gt; and &lt;code&gt;"10:00"&lt;/code&gt;. They stay green. A property test that feeds &lt;code&gt;"09:32"&lt;/code&gt; and expects an exact round-trip fails instantly.&lt;/p&gt;

&lt;p&gt;A crash seldom causes this. The silent change does: the patch modified behavior for inputs nobody enumerated. Unit tests encode your expectations; an agent will optimize for those expectations. Property checks encode constraints you have not enumerated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer one: property checks
&lt;/h2&gt;

&lt;p&gt;Start with one invariant. For parsers, round-trip is a strong starting point. For caches, assert that a value never goes stale. For state machines, assert that reordering messages does not lose transitions.&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;# unexecuted example: shape, not production code
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypothesis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypothesis.strategies&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;integers&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;parse_interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""'&lt;/span&gt;&lt;span class="s"&gt;HH:MM&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; minutes since midnight.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;format_interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;minutes since midnight -&amp;gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;HH:MM&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;integers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;integers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nd"&gt;@settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_examples&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10_000&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_round_trip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;02&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;minutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parse_interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;format_interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Property checks are probabilistic, not exhaustive. Ten thousand examples do not prove the invariant. They do catch the rounding patch above because the shrinker quickly produces &lt;code&gt;"09:32"&lt;/code&gt; as a counterexample. Use shrinking; a failing property without a minimal input is just a stack trace.&lt;/p&gt;

&lt;p&gt;A round-trip has a blind spot. If the agent changes parser and formatter together, the invariant stays intact. Pair it with a stronger property: the result is always below 1440, or it produces an error for a specific invalid range.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer two: frozen fixtures
&lt;/h2&gt;

&lt;p&gt;An agent can edit your test data. If the new behavior no longer matches the old expectation, the path of least resistance is to rewrite the fixture instead of the code. Frozen fixtures block that path.&lt;/p&gt;

&lt;p&gt;Collect a fixture set from production logs or from the last known good release. Store it in one file with a schema version and a hash. Then make the merge gate fail on any change to that hash.&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;"schema_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256: replace-with-your-own"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"entries"&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="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"09:30"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"expected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;570&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;The agent can add new test files. It cannot silently migrate old ones. A human approves a fixture migration separately, with a diff review, and the migration lands in its own commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer three: a flaky test freeze
&lt;/h2&gt;

&lt;p&gt;Flaky tests are an agent's escape hatch. If a test fails once and passes on retry, the agent learns that red is negotiable. It will retry, reorder, and add sleeps.&lt;/p&gt;

&lt;p&gt;Define the freeze: any test that fails on a clean checkout moves to &lt;code&gt;quarantine/&lt;/code&gt;. It stops blocking merges until a human fixes or deletes it. The agent cannot claim success while a quarantine ticket is open.&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;# illustrative CI rule
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verify_gate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;fixture_hash_matches&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fixtures changed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;quarantine_dir_is_empty&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flaky test not resolved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nf"&gt;pytest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tests/properties&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No retries. No &lt;code&gt;@pytest.mark.flaky&lt;/code&gt; bypass. If the suite only stays green by rerunning, the suite is lying to the reviewer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ordering the three layers
&lt;/h2&gt;

&lt;p&gt;Run property checks first. They fail loudly and generate counterexamples. Run the fixture integrity check second; it is a single hash comparison. Run the flake freeze audit last; it keeps the first two from being masked by retried failures.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Property checks — fast, probabilistic, shrinkable.&lt;/li&gt;
&lt;li&gt;Fixture integrity — deterministic, one hash.&lt;/li&gt;
&lt;li&gt;Flake quarantine — makes the first two trustworthy.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Where the compute comes from
&lt;/h2&gt;

&lt;p&gt;You need cycles for the property runs and an endpoint for the agent that writes the patch. Ten thousand examples are a small CPU bill but not a free one; the churn of iterative agent patches adds up.&lt;/p&gt;

&lt;p&gt;To run this on a near-zero budget, I used MonkeyCode's free server option as the execution layer and its free model endpoint for the agent loop. They are convenience choices; the strategy does not depend on the vendor.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. The availability claims for free model access and the free server come from the project, not from my benchmarks. I did not measure quotas, uptime, or throughput. Validate them against your workload before wiring them into a mandatory gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this
&lt;/h2&gt;

&lt;p&gt;Property checks are overhead when you can enumerate every input by hand. If your patch surface is one function with three branches, add a switch-case test instead. Fixture freezing needs a stable baseline; a young project with no known-good release has nothing to freeze. A flake freeze requires enforcement; without it, the property layer will drown in retried failures.&lt;/p&gt;

&lt;p&gt;Start with one invariant. Freeze the oldest fixture file. Quarantine the flakiest test. That is a complete first iteration, and it will catch more than the next five unit tests you ask an agent to write.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>python</category>
      <category>devtools</category>
    </item>
    <item>
      <title>The Patch That Slowed Everything Down: How to Benchmark Agent Changes on a Free Server</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sun, 30 Aug 2026 03:31:47 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/the-patch-that-slowed-everything-down-how-to-benchmark-agent-changes-on-a-free-server-3m0m</link>
      <guid>https://dev.to/datacpp_8185/the-patch-that-slowed-everything-down-how-to-benchmark-agent-changes-on-a-free-server-3m0m</guid>
      <description>&lt;p&gt;You merge an agent patch that is supposed to make the build cache smarter. Every unit test passes, the integration suite is green, and the code review looks clean. Two days later, a colleague complains that the service now spends twice as long reading configuration files. You profile, you find a hidden O(n^2) loop, and you realize the tests never measured performance.&lt;/p&gt;

&lt;p&gt;This scenario plays out whenever correctness and speed are treated as the same thing. Unit tests assert behavior, not complexity. A patch can produce perfect output while silently degrading the runtime from microseconds to milliseconds. For human reviewers this is caught by experience or a code review checklist. For agent-generated patches, there is no experience in the code generation loop, so the regression ships.&lt;/p&gt;

&lt;p&gt;The solution is not more unit tests. The solution is a benchmark gate that runs before every merge and compares the new patch against a known baseline. In this guide you'll build one for a C++ project using free-tier infrastructure, and you'll see how to keep the whole thing cheap enough to run on every commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Unit Tests Miss Performance Regressions
&lt;/h2&gt;

&lt;p&gt;Unit tests typically run on tiny, fixed inputs and verify output values. They rarely measure wall time, and when they do, timing assertions are often flaky. A performance regression usually appears only when an input exceeds a certain size or when memory pressure changes. For example, a function that uses &lt;code&gt;std::list&lt;/code&gt; instead of &lt;code&gt;std::vector&lt;/code&gt; may still return correct results while losing cache locality.&lt;/p&gt;

&lt;p&gt;Performance is also a property of the compiled binary, not the source text. Debug builds and non-optimized tests mask complexity differences. Agents often produce code that is logically correct but algorithmically worse, such as comparing every element in a vector with a nested loop instead of using a hash set. Unit tests can't catch that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Identify the Hot Paths
&lt;/h2&gt;

&lt;p&gt;Begin with a profiler, or at least with the functions you already suspect. A hot path is any function that appears high on the CPU profile during normal operation. Parsers, serializers, cache lookups, and sorting routines are classic candidates. If a function is called a million times per request, even a two-nanosecond insertion will add up.&lt;/p&gt;

&lt;p&gt;Pick two or three functions that the agent is most likely to touch, and make that the first version of your benchmark set. You can expand later once the gate proves useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Write Micro-Benchmarks
&lt;/h2&gt;

&lt;p&gt;A micro-benchmark isolates one function and repeatedly invokes it with a representative input. The Google Benchmark library is the standard choice for C++ and produces JSON output that you can parse automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;benchmark/benchmark.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"parser.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;BM_ParseHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;benchmark&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"GET /index.html HTTP/1.1"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;benchmark&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;DoNotOptimize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;BENCHMARK&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BM_ParseHeader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;BENCHMARK_MAIN&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile the benchmark with optimizations enabled. A &lt;code&gt;-O0&lt;/code&gt; binary will report misleadingly large times that hide algorithmic differences. Make sure the input string represents a realistic request header, not a minimal one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Compare Against a Baseline
&lt;/h2&gt;

&lt;p&gt;The gate needs two binaries: one from the base commit and one from the candidate patch. Run both with &lt;code&gt;--benchmark_format=json&lt;/code&gt; and compute the ratio per benchmark.&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;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;check_output&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;binary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--benchmark_format=json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;real_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;benchmarks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;

&lt;span class="n"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;build/base_bench&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_benchmark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;build/cand_bench&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_time&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;cand_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cand&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cand_time&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;base_time&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;1.05&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAIL &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;base_time&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ns -&amp;gt; &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cand_time&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ns ratio &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;ratio&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;1.01&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;WARN &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: ratio &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ratio&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Benchmark gate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fail&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store the script as &lt;code&gt;bench_gate.py&lt;/code&gt;, and add a CI step that builds both revisions. For a git-based workflow, you can check out the base commit into a separate build directory and locate the binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Wire the Gate to Your CI
&lt;/h2&gt;

&lt;p&gt;Your CI job should run the base build and the candidate build sequentially, then execute the script. If the script exits with code 1, the pipeline stops and the patch is not merged. To avoid false alarms from environment noise, repeat each benchmark a few times and use the median value. You can also pin the CPU frequency with &lt;code&gt;cpupower&lt;/code&gt; when running on a dedicated server.&lt;/p&gt;

&lt;p&gt;This is where a free server option becomes valuable. Building two C++ revisions and running benchmarks on every patch consumes CPU minutes, but not the kind that requires a GPU or a large instance. A simple server with a few gigabytes of RAM is enough for most codebases.&lt;/p&gt;

&lt;p&gt;MonkeyCode's free model tier can draft the benchmark harness for you, and its free server option can run the comparison job after every push. The model doesn't need to be state-of-the-art, and the server doesn't need a GPU; the bottleneck is pure CPU and disk. You can keep the whole gate running under a single free account. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Decision Table for Benchmark Results
&lt;/h2&gt;

&lt;p&gt;Set explicit thresholds and stick to them. A 1% change is often noise; a 5% change is usually intentional or problematic.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ratio (current / baseline)&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;= 1.01&lt;/td&gt;
&lt;td&gt;Pass&lt;/td&gt;
&lt;td&gt;Merge without extra review&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1.01 - 1.05&lt;/td&gt;
&lt;td&gt;Warn&lt;/td&gt;
&lt;td&gt;Require human review and a profiler check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt; 1.05&lt;/td&gt;
&lt;td&gt;Fail&lt;/td&gt;
&lt;td&gt;Block merge and ask the agent to rework&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use the same thresholds in your script so the CI verdict matches the table. Adjust the values if your benchmarks are noisy, but document the change in the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations of Benchmark Gates
&lt;/h2&gt;

&lt;p&gt;Benchmarks measure only what you make them measure. A single warm input can miss regressions that appear under a different distribution, such as many tiny strings instead of one large one. Environment noise remains a threat even on a dedicated box; CPU frequency scaling and background processes can skew times.&lt;/p&gt;

&lt;p&gt;Micro-benchmarks also add compile and run time to every merge. A free server may be slower than paid CI, so keep the benchmark set small at first. Finally, some performance problems only surface under memory pressure or concurrency, and no micro-benchmark will catch those.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Should Skip This
&lt;/h2&gt;

&lt;p&gt;If your application spends most of its time waiting on I/O or a database, a CPU micro-benchmark gate will not protect you. If your team already uses end-to-end load tests with realistic data, adding synthetic benchmarks might be redundant. And if the codebase is a glue layer with no hot paths, the cost of maintaining benchmarks outweighs the benefit.&lt;/p&gt;

&lt;p&gt;Still, for a system parser, a search engine, or any CPU-bound component, this gate is one of the cheapest ways to block an invisible regression.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;A benchmark gate turns an invisible performance regression into a merge-blocking signal. It is not perfect, but it is far better than discovering the slowdown after release. Start with two benchmarks on your hottest function, set a 5% threshold, and let a free server run them every time an agent proposes a change. The question "did this patch make things slower?" deserves a concrete answer.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>c</category>
      <category>benchmark</category>
      <category>ci</category>
    </item>
    <item>
      <title>GCC Passed, Clang Didn't: A Four-Configuration Compile Matrix for Agent Patches</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sun, 30 Aug 2026 00:28:46 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/gcc-passed-clang-didnt-a-four-configuration-compile-matrix-for-agent-patches-3i86</link>
      <guid>https://dev.to/datacpp_8185/gcc-passed-clang-didnt-a-four-configuration-compile-matrix-for-agent-patches-3i86</guid>
      <description>&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;The patch compiled on your laptop, so you handed it to CI, and CI returned a wall of template errors from Clang. The agent had only ever compiled with GCC because that was the toolchain its container exposed. A single compile is not a quality signal; it is a sample from one configuration. For agent-generated C++, one sample is almost always the wrong one.&lt;/p&gt;

&lt;p&gt;This article builds a compile matrix gate: a small, cost-budgeted set of builds that run before any unit test. The matrix does not guarantee correctness. It does catch a class of regression that unit tests usually miss because they never compile against a different standard library or a strict warning level.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a single compile is a weak gate
&lt;/h2&gt;

&lt;p&gt;A unit test checks behavior for the inputs you wrote. A compile check checks your code against one dialect of the language. Agents optimize against the feedback they receive. If the feedback loop only feeds GCC 12's default flags, the agent learns to satisfy GCC 12's grammar, and it has no incentive to respect C++17 or avoid a deprecation that Clang 17 reports.&lt;/p&gt;

&lt;p&gt;Two failures show up in practice. The first is silent dialect drift: the patch uses a C++20 feature even though the project targets C++17, and the local build runs with C++20 flags, so everything looks healthy. The second is warning blindness: the patch compiles, but the project treats warnings as errors, and the agent never saw that because &lt;code&gt;-Werror&lt;/code&gt; was missing in its environment. Both problems are invisible to a single build configuration, and both are cheap to detect with a matrix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing the four configurations
&lt;/h2&gt;

&lt;p&gt;The matrix deliberately stays small. Four builds capture the largest diversity for the smallest cost, and you can extend it later when your codebase needs a specific compiler version. Each configuration is chosen to answer one question.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Config&lt;/th&gt;
&lt;th&gt;Compiler&lt;/th&gt;
&lt;th&gt;Standard&lt;/th&gt;
&lt;th&gt;Flags&lt;/th&gt;
&lt;th&gt;Catches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A&lt;/td&gt;
&lt;td&gt;GCC&lt;/td&gt;
&lt;td&gt;C++17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-O0&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Baseline dialect compatibility&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;Clang&lt;/td&gt;
&lt;td&gt;C++20&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-O2 -Wall -Wextra -Werror&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Strict modern warnings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C&lt;/td&gt;
&lt;td&gt;GCC&lt;/td&gt;
&lt;td&gt;C++20&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-O2 -Wall -Werror&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;GCC-specific strictness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D&lt;/td&gt;
&lt;td&gt;Clang&lt;/td&gt;
&lt;td&gt;C++17&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-O0 -Werror&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Opposite dialect mismatch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The point is not to test every compiler you ship to. The point is to give the agent two independent compilers and two adjacent language standards, so a portability mistake cannot hide inside the single toolchain the agent happens to know. Configuration B and D are intentionally annoying: they promote warnings to errors, which forces the agent to clean the patch instead of leaving a subtle smell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Budgeting the matrix
&lt;/h2&gt;

&lt;p&gt;Each configuration costs roughly the same as compiling one unit-test binary. Four compiles are still cheaper than a flaky test suite, but if you let the agent run the matrix after every prompt, the cost adds up. So you cap it. The script stops at the first failure, and it also stops if the total number of compiles exceeds a small integer you set.&lt;/p&gt;

&lt;p&gt;The cap is your budget. Treat it like a token budget. A patch that fails in the first configuration returns immediately, costs one compile, and the agent can retry with the error text. A patch that passes all four costs four compiles before a single test starts. That asymmetry is what makes the gate useful for iteration loops.&lt;/p&gt;

&lt;h2&gt;
  
  
  The script
&lt;/h2&gt;

&lt;p&gt;The script is intentionally minimal. It compiles a translation unit, logs each command, and stops on the first failure. Set &lt;code&gt;MAX_COMPILES&lt;/code&gt; to your budget, usually six to allow one retry after a failed attempt.&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;MAX_COMPILES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAX_COMPILES&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;6&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="nv"&gt;FAILED_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;

compile&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;shift
    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;((&lt;/span&gt; COUNT &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; MAX_COMPILES &lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Budget exhausted after &lt;/span&gt;&lt;span class="nv"&gt;$COUNT&lt;/span&gt;&lt;span class="s2"&gt; compiles"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;2
    &lt;span class="k"&gt;fi
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$@&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"/tmp/compile_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt; 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"FAILED in &lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nv"&gt;FAILED_CONFIG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi&lt;/span&gt;
    &lt;span class="o"&gt;((&lt;/span&gt; COUNT++ &lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

compile gcc17   g++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++17 &lt;span class="nt"&gt;-O0&lt;/span&gt;              &lt;span class="nt"&gt;-c&lt;/span&gt; sample.cpp
compile clang20 clang++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++20 &lt;span class="nt"&gt;-O2&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt; &lt;span class="nt"&gt;-Werror&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; sample.cpp
compile gcc20   g++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++20 &lt;span class="nt"&gt;-O2&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Werror&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; sample.cpp
compile clang17 clang++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++17 &lt;span class="nt"&gt;-O0&lt;/span&gt; &lt;span class="nt"&gt;-Werror&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; sample.cpp

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Compile matrix passed in &lt;/span&gt;&lt;span class="nv"&gt;$COUNT&lt;/span&gt;&lt;span class="s2"&gt; configurations"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can replace &lt;code&gt;sample.cpp&lt;/code&gt; with the translation units the agent touched. On a large codebase, you do not need to build the whole project for this gate; the agent's diff will tell you which files changed, and those are the files the matrix should compile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision table after a failure
&lt;/h2&gt;

&lt;p&gt;When the matrix fails, the error text is only half the story. You still need to decide whether the patch is wrong or the configuration is too strict. This table gives a starting point.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;th&gt;Likely cause&lt;/th&gt;
&lt;th&gt;Agent action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fails only in Clang, passes in GCC&lt;/td&gt;
&lt;td&gt;Non-portable construct or implementation-specific assumption&lt;/td&gt;
&lt;td&gt;Rewrite using standard C++&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fails only in C++17, passes in C++20&lt;/td&gt;
&lt;td&gt;Dialect drift; the patch silently used a newer feature&lt;/td&gt;
&lt;td&gt;Replace the new feature with the C++17 equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fails only when &lt;code&gt;-Werror&lt;/code&gt; is on&lt;/td&gt;
&lt;td&gt;Warning-level issue such as an unused variable or sign conversion&lt;/td&gt;
&lt;td&gt;Clean the warning; do not suppress it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fails in both compilers with the same error&lt;/td&gt;
&lt;td&gt;The patch broke a shared header or changed a signature&lt;/td&gt;
&lt;td&gt;Inspect the patch diff and adjust the interface&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table is not a replacement for human judgment. A strict warning may be acceptable in one module and unacceptable in another. The matrix tells you where the disagreement is; you still have to decide what it means.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it with free compute
&lt;/h2&gt;

&lt;p&gt;Because the matrix is cheap and disposable, it fits naturally into a free-tier agent loop. With MonkeyCode's free model access and free server option, you can generate a patch with the model and execute this script on the server without touching your paid CI runners. The server gives you a clean environment for each iteration, so a failed compile cannot leave cache debris behind for the next attempt.&lt;/p&gt;

&lt;p&gt;The separation matters more than the price. Your main CI should validate behavior, not explore compiler dialects. The matrix is a filter that runs before the expensive parts, and it works better when it lives in a separate, low-trust environment that you can throw away after every patch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;The matrix cannot replace tests. Undefined behavior is not a compile error in most configurations, so a patch can pass all four builds and still corrupt memory at runtime. The matrix also cannot detect logic errors: if the function returns the wrong answer, every compiler will happily compile it.&lt;/p&gt;

&lt;p&gt;The matrix is compiler-version dependent. A construct accepted by GCC 12 may be rejected by GCC 13 because the standard clarified itself, and that is useful information even when it is not a regression. You need a human to classify the failure before telling the agent to fix a valid pattern, otherwise you are teaching it to chase shadows.&lt;/p&gt;

&lt;p&gt;Finally, the four configurations are a heuristic, not a proof. They cover two compilers and two standards, but they will not catch a Windows-specific header or a miscompiled platform intrinsic. If your project targets exotic toolchains, the matrix needs to grow before you trust it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should skip this
&lt;/h2&gt;

&lt;p&gt;You can skip this gate if you control a single compiler and a single standard version forever, or if your patch only touches Python, JavaScript, or another language without a meaningful compile step. You should also skip it if your codebase takes an hour to build a single translation unit, because four full builds might take half a day.&lt;/p&gt;

&lt;p&gt;In that case, isolate the files the agent changed and compile those alone. The diff tells you exactly what to feed to the script, and a small translation unit keeps the whole gate under a minute. If you cannot isolate the touched files, the matrix becomes a nightly audit instead of an every-patch gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;A compile matrix is the cheapest gate that asks whether a patch will build anywhere else. It is not profound, but it catches a different category of agent regression than a test run, and it fails fast enough to keep the feedback loop tight. Start with four configurations and a budget of six compiles, then measure what the gate catches for your codebase.&lt;/p&gt;

&lt;p&gt;If your matrix has a configuration that surfaced a real regression that tests missed, leave it in the comments. The most useful configurations are usually the ones that feel unnecessary until they fail.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>ai</category>
      <category>testing</category>
      <category>devops</category>
    </item>
    <item>
      <title>Freeze the Flaky, Check the Properties: A Three-Layer Test Strategy for Agent Patches</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sat, 29 Aug 2026 21:24:57 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/freeze-the-flaky-check-the-properties-a-three-layer-test-strategy-for-agent-patches-5409</link>
      <guid>https://dev.to/datacpp_8185/freeze-the-flaky-check-the-properties-a-three-layer-test-strategy-for-agent-patches-5409</guid>
      <description>&lt;p&gt;A flaky test is not a test. It is a slot machine that decides whether an agent patch gets accepted.&lt;/p&gt;

&lt;p&gt;I keep seeing the same loop: the agent sees one failing test, rewrites a function until that test passes, and the suite goes green. Ten minutes later the same test fails because the order of a map changed. The agent learned nothing about behavior; it learned how to satisfy an unstable assertion.&lt;/p&gt;

&lt;p&gt;The fix is not a better model. It is a test strategy with three layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Freeze the flaky tests.&lt;/li&gt;
&lt;li&gt;Fix the fixture inputs.&lt;/li&gt;
&lt;li&gt;Check properties, not exact outputs.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;MonkeyCode's free model access and free server option lower the cost of running this loop long enough to collect evidence. &lt;em&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Freeze the flaky tests
&lt;/h2&gt;

&lt;p&gt;A flaky test is noise in the agent's reward function. Every rerun gives it a contradictory label. Before you let an agent touch production code, find those labels and freeze them.&lt;/p&gt;

&lt;p&gt;Run the suspicious suite ten times and aggregate failures:&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="k"&gt;for &lt;/span&gt;run &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 10&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  ./build/unit_tests &lt;span class="nt"&gt;--reporter&lt;/span&gt; compact 2&amp;gt;&amp;amp;1 &lt;span class="se"&gt;\&lt;/span&gt;
    | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s1"&gt;'s/.*FAILED: //p'&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any test that fails between 1 and 9 times is a freeze candidate. Add it to &lt;code&gt;frozen.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;frozen&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EventParserTest.InvalidTimestamps"&lt;/span&gt;
    &lt;span class="na"&gt;failures_in_10&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4&lt;/span&gt;
    &lt;span class="na"&gt;frozen_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-08-30"&lt;/span&gt;
    &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;depends&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;wall-clock&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;from&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mocked&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;timer"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your runner skips frozen tests, and your review checklist treats them as open debt. The agent no longer sees the flaky failure as an instruction.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Fix the fixture inputs
&lt;/h2&gt;

&lt;p&gt;If two patch attempts run on different inputs, you cannot compare their behavior. So pin the inputs before starting the agent.&lt;/p&gt;

&lt;p&gt;Create an immutable fixture directory with timestamps, random seeds, and file order fixed:&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="nv"&gt;FIXTURE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"fixtures/frozen-2026-08-30"&lt;/span&gt;
&lt;span class="nv"&gt;HYPOTHESIS_PROFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;max
&lt;span class="nv"&gt;RANDOM_SEED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;31337
&lt;span class="nv"&gt;TZ&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;UTC
&lt;span class="nv"&gt;LANG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C

./baseline_binary &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FIXTURE_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; baseline.out
./patched_binary  &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FIXTURE_DIR&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; patched.out
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the exact same fixture set in every experiment. If the database, clock, or locale differ between runs, you are not testing the patch; you are testing the environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Check properties instead of exact outputs
&lt;/h2&gt;

&lt;p&gt;Exact-output tests are easy for an agent to overfit. You tell it "assert x equals 3", and the agent eventually fabricates something that makes that one assertion true. Property checks describe an invariant over a space of inputs, so the agent has to preserve behavior, not a literal value.&lt;/p&gt;

&lt;p&gt;A minimal Python example that exercises the same idea on a small event sorter:&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;# sort_events.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;hypothesis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sort_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# agent patch replaced this with an unstable sort
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pairs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tuples&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integers&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integers&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_timestamps_are_non_decreasing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sort_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]):&lt;/span&gt;
        &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;ta&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;tb&lt;/span&gt;

&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tuples&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integers&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integers&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_no_event_is_lost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sort_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;events&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="nf"&gt;test_timestamps_are_non_decreasing&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;test_no_event_is_lost&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;properties ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first property catches "I changed the order of events"; the second catches "I dropped events." Neither property tells the agent what to assert. They tell it what must remain true.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the three layers interact
&lt;/h2&gt;

&lt;p&gt;The freeze is a debt tag, not a permanent excuse. When you freeze a test, add one property check that preserves what that test was guarding. That way the agent can pass the old flaky test, but it still has to respect the invariant.&lt;/p&gt;

&lt;p&gt;Fixtures tie the property checks to a reproducible world: same inputs, same seeds, same locale. Without them, two runs of the same property check can diverge for environmental reasons and become flaky again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations and who should skip this
&lt;/h2&gt;

&lt;p&gt;This strategy assumes the system under test is deterministic. If your code depends on wall-clock threads, network calls, or random hardware behavior, freeze the test, mock the boundary, and only then apply property checks.&lt;/p&gt;

&lt;p&gt;Do not use this strategy as a license to delete failing tests. A frozen test must have a reason, an owner, and a property-check replacement. If you cannot name the invariant, the flaky test is telling you about a design problem, not a test problem.&lt;/p&gt;

&lt;p&gt;Also skip this if you need pixel-level validation or human conversation flows. Property checks describe state, not perceived quality; those domains need a different oracle.&lt;/p&gt;

&lt;p&gt;Start with the freeze. Count the flaky failures, pin the fixtures, write one property. The agent will stop optimizing for the test runner and start optimizing for behavior.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>agents</category>
      <category>ci</category>
    </item>
    <item>
      <title>Freeze Flaky Tests, Don't Retry Them: A Three-Layer Test Strategy for Agent Patches</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sat, 29 Aug 2026 18:20:31 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/freeze-flaky-tests-dont-retry-them-a-three-layer-test-strategy-for-agent-patches-41n8</link>
      <guid>https://dev.to/datacpp_8185/freeze-flaky-tests-dont-retry-them-a-three-layer-test-strategy-for-agent-patches-41n8</guid>
      <description>&lt;p&gt;A test suite that keeps passing while a regression slips through is not a safety net. It is a supply chain for false confidence. With agent-generated patches the risk sharpens: the same commit can edit the implementation and its tests, so "all tests pass" no longer means the behavior survived.&lt;/p&gt;

&lt;p&gt;The strategy below is the one I now apply to every incoming agent patch before it reaches review. It has three layers: property checks that test the spec, frozen fixtures that pin known behavior, and a freeze list that stops flaky tests from blocking merge queues — or, worse, encouraging blind retries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 1 — Property checks against the spec, not the implementation
&lt;/h2&gt;

&lt;p&gt;A unit test written next to a fix shares the blind spot of the fix. Property checks generate inputs the patch author never imagined. They fail on behavior, not on line-by-line diff.&lt;/p&gt;

&lt;p&gt;Consider a small C++ range parser. The spec is: input like &lt;code&gt;"1-3,5"&lt;/code&gt; parses to a sorted, de-duplicated vector of integers; &lt;code&gt;format_range&lt;/code&gt; is its inverse.&lt;/p&gt;

&lt;p&gt;An agent was asked to optimize the parser. The diff looked innocent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// faster append path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every handwritten fixture passed. The canonical-order property caught the regression. A minimal, illustrative version of the property layer looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// property_layer.cpp — deterministic seeds only&lt;/span&gt;
&lt;span class="n"&gt;TEST_CASE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"parse then format is the identity on sorted sets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"[property]"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mt19937&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20260829&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;          &lt;span class="c1"&gt;// fixed seed, not time()&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random_range_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parse_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;REQUIRE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input: "&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;REQUIRE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;is_sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
    &lt;span class="n"&gt;REQUIRE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parse_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;format_range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;is_sorted&lt;/code&gt; failed on the first run. The agent's patch dropped ordering in the name of speed, and no hand-written test happened to cover &lt;code&gt;"3,1,2"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Three rules keep this layer honest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fixed seeds. A property test that uses the system clock is a flake generator, not a test.&lt;/li&gt;
&lt;li&gt;Keep the generator dumb. Random inputs from a small alphabet; stress comes from count, not from clever generators.&lt;/li&gt;
&lt;li&gt;Run the same seeds in CI and locally. A failing seed is then reproducible without a trace.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Layer 2 — Frozen fixtures pin behavior down
&lt;/h2&gt;

&lt;p&gt;Property checks find unknown unknowns. Fixtures catch authorized changes. I keep a fixture file for every component that agents are allowed to touch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# fixtures/range_parser.yaml — do not edit by hand without a behavior note&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1-3"&lt;/span&gt;
  &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;canonical&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1-3"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3,1,2"&lt;/span&gt;
  &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;canonical&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1-3"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1-3,5"&lt;/span&gt;
  &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;canonical&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1-3,5"&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;input&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1,"&lt;/span&gt;
  &lt;span class="na"&gt;valid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A patch may change code or tests, but not fixtures. When a fixture begins to fail, the triage question is sharp: is this an intended spec change? If yes, a human rewrites the fixture and the reason lives in the commit. If no, the patch is a regression.&lt;/p&gt;

&lt;p&gt;Two fixture rules are enforced mechanically:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Golden values, not comparisons. The expected list is stored, not recomputed. Recomputed goldens give the agent permission to multiply bugs.&lt;/li&gt;
&lt;li&gt;Fixture updates require a second artifact. A changed fixture without a linked behavior note is treated as a test rewrite, and test rewrites are flagged in review.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Layer 3 — Freeze flaky tests instead of retrying them
&lt;/h2&gt;

&lt;p&gt;Retrying a flaky test trains the team to distrust red builds. The fourth failure from the same test is usually someone else's bug. Ask the runner to freeze those tests instead:&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;# frozen_tests.txt — read by the runner, not by humans&lt;/span&gt;
range_parser_stress_alloc      &lt;span class="nv"&gt;unstable_since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2026-08-29 &lt;span class="nv"&gt;frozen_runs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nv"&gt;note&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"uses TLS state"&lt;/span&gt;
range_parser_parallel_order    &lt;span class="nv"&gt;unstable_since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2026-08-29 &lt;span class="nv"&gt;frozen_runs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nv"&gt;note&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"shared fixture mutated"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runner excludes frozen tests from merge gates, but still executes them and records two counters: consecutive failures and pass rate. A test returns to the gate only when the cause is written in the note field. Cold-turkey disabling is banned.&lt;/p&gt;

&lt;p&gt;This converts "flaky" from a personality trait of a test into a tracked incident. No retries, no "let's see tomorrow", no shadow retry loop in CI.&lt;/p&gt;

&lt;h2&gt;
  
  
  The triage decision table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gate result&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Property test fails&lt;/td&gt;
&lt;td&gt;Regression&lt;/td&gt;
&lt;td&gt;Reject; add the failing seed to fixtures&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frozen fixture fails&lt;/td&gt;
&lt;td&gt;Behavior change or regression&lt;/td&gt;
&lt;td&gt;Require a human-written change note&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frozen-list test fails&lt;/td&gt;
&lt;td&gt;Known flake&lt;/td&gt;
&lt;td&gt;No block; increment the incident counter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All green&lt;/td&gt;
&lt;td&gt;Weak signal&lt;/td&gt;
&lt;td&gt;Still review the diff semantics&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The free-model classifier pass
&lt;/h2&gt;

&lt;p&gt;On patch receipt, a cheap classification step decides which of the three layers to run first. In my setup, that label assignment runs through MonkeyCode's free model access — the runner gets a short &lt;code&gt;PROPERTY&lt;/code&gt; / &lt;code&gt;FIXTURE&lt;/code&gt; / &lt;code&gt;FLAKE&lt;/code&gt; / &lt;code&gt;SKIP&lt;/code&gt; label from the patch summary and the test-log tail. The free server option keeps that job off my laptop and avoids rate-limit surprises on long queues. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;The classifier does not merge and does not testify; it only routes the patch to the correct gate. A wrong label is harmless because the layered tests still run. The token cost is a rounding error compared with a full build.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this
&lt;/h2&gt;

&lt;p&gt;Skip this strategy if your agent patches never touch behavior, or if your tests are so slow that 512 property seeds explode the pipeline. The property layer assumes a pure-ish function and a deterministic input generator. A UI-heavy codebase needs screen-level state fixtures instead. And if your team still fixes flaky tests by retrying, the freeze list is a process change, not a tool change — install the habit before the list.&lt;/p&gt;

&lt;p&gt;The three layers overlap less than they look. Properties catch what fixtures miss, fixtures catch authorized changes, and the freeze list keeps the signal honest. None of it requires an agent. That is the point: the same gate that triages agent patches triages any patch.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>cpp</category>
      <category>programming</category>
    </item>
    <item>
      <title>Compiler Fences: A C++ Sanitizer Workflow for AI-Generated Patches</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sat, 29 Aug 2026 15:18:25 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/compiler-fences-a-c-sanitizer-workflow-for-ai-generated-patches-l57</link>
      <guid>https://dev.to/datacpp_8185/compiler-fences-a-c-sanitizer-workflow-for-ai-generated-patches-l57</guid>
      <description>&lt;p&gt;A unit test proves what your agent intended; a compiler warning proves what the language specification requires. These two facts rarely carry the same weight, which is why the first reviewer of an AI-generated C++ patch should be the toolchain itself. Before you read a single diff, configure your compiler to reject undefined behavior, implicit conversions, and suspicious pointer arithmetic. Then feed the same errors back to the agent, and you will have a much more productive conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Warning That Started It
&lt;/h2&gt;

&lt;p&gt;Consider a patch that rewrites a loop to use &lt;code&gt;std::span&lt;/code&gt; and indexes into it with a signed offset. Your unit tests pass because the test vector happens to be long enough, and your debug build sees nothing unusual. When you compile with &lt;code&gt;-O2 -Warray-bounds&lt;/code&gt;, the optimizer discovers that an index can be negative and emits a warning that test coverage completely missed. That discrepancy is the core argument for a compiler fence: static analysis catches the cases your examples never hit.&lt;/p&gt;

&lt;p&gt;A fence means you deliberately build your code in two or three configurations and treat warning-as-error in each one. The first configuration uses a strict warning set. The second adds address and undefined-behavior sanitizers. The third, optional one, enables link-time optimization and aggressive inlining to expose warnings that only appear under optimization. This may sound like overkill, but for agent-generated code it is the cheapest insurance available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Harden the Compiler Invocation
&lt;/h2&gt;

&lt;p&gt;Create a CMake preset that bakes in your non-negotiable flags. For GCC and Clang, a practical starting set looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="nb"&gt;add_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  -Wall -Wextra -Wpedantic -Wconversion -Wshadow
  -Wformat=2 -Wnull-dereference -Wmisleading-indentation
  -Werror
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_CXX_COMPILER_ID MATCHES &lt;span class="s2"&gt;"Clang"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;add_compile_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;-Wdocumentation -Wcomma -Wrange-loop-analysis&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;endif&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;CMAKE_CXX_FLAGS_SANITIZE
    &lt;span class="s2"&gt;"-fsanitize=address,undefined -fno-sanitize-recover=all"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-fno-sanitize-recover=all&lt;/code&gt; part is essential. With recovery enabled, the sanitizer prints a runtime error and continues running, so the program may exit zero and confuse your CI. Without recovery, the first violation aborts with a non-zero status, which gives your agent an unambiguous signal: this change is not acceptable as written.&lt;/p&gt;

&lt;p&gt;You should also pin the compiler version. If your local machine uses GCC 13 and your CI uses GCC 12, a warning in the newer version will never surface in the pipeline. Use a container or a version manager to make the fence reproducible. The goal is a stable oracle, not a debate about toolchain differences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Run a Sanitized Test Pass
&lt;/h2&gt;

&lt;p&gt;Create a script, for example &lt;code&gt;fence.sh&lt;/code&gt;, that builds with the sanitize flags and then executes your test suite with &lt;code&gt;ctest&lt;/code&gt;:&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

cmake &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-B&lt;/span&gt; build-fence &lt;span class="nt"&gt;-DCMAKE_BUILD_TYPE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;RelWithDebInfo &lt;span class="se"&gt;\&lt;/span&gt;
      &lt;span class="nt"&gt;-DCMAKE_CXX_FLAGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CMAKE_CXX_FLAGS_SANITIZE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
cmake &lt;span class="nt"&gt;--build&lt;/span&gt; build-fence &lt;span class="nt"&gt;--parallel&lt;/span&gt;
ctest &lt;span class="nt"&gt;--test-dir&lt;/span&gt; build-fence &lt;span class="nt"&gt;--output-on-failure&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this script before any human review. When your agent proposes a patch, you make one call to &lt;code&gt;fence.sh&lt;/code&gt;. If the build fails because of a warning, the output is the correction message. If the tests crash under ASan, the stack trace points directly to the symptom, and you can include that trace as a prompt for the agent's next attempt. This loop is mechanical, but it is far more reliable than telling the agent “something is wrong, please review your changes.”&lt;/p&gt;

&lt;p&gt;One caution: sanitizers can detect errors on code paths the tests do not cover. So a sanitized test pass is only as valuable as your test suite. Pair it with a few property-style tests, and you get a solid lower bound on behavior preservation.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Decision Table for Warning Classes
&lt;/h2&gt;

&lt;p&gt;Not all diagnostics deserve the same reaction. The table below maps common compiler messages to the agent behavior they indicate, so you can triage output quickly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Diagnostic&lt;/th&gt;
&lt;th&gt;What it reveals&lt;/th&gt;
&lt;th&gt;Recommended action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-Wconversion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Implicit narrowing that changes values&lt;/td&gt;
&lt;td&gt;Require explicit casts; send back to the agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-Wnull-dereference&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Dereference after a path where pointer is null&lt;/td&gt;
&lt;td&gt;Reject immediately; add a null check&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-Warray-bounds&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Off-by-one introduced by indexing logic&lt;/td&gt;
&lt;td&gt;Add a bounds assertion and rebuild&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-Wshadow&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;A variable hiding an outer name&lt;/td&gt;
&lt;td&gt;Usually cosmetic; can mask bugs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;UBSan &lt;code&gt;runtime error: signed integer overflow&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Arithmetic overflows on a valid input&lt;/td&gt;
&lt;td&gt;Non-negotiable; fix before merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ASan &lt;code&gt;heap-buffer-overflow&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Memory access outside allocated region&lt;/td&gt;
&lt;td&gt;Reproduce with a minimal test case&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Use this table as a starting point for your own policy. The point is not to fix every warning mechanically, but to sort them into “must fix now”, “must understand”, and “safe to ignore for this patch”. Agents that keep seeing the same class of warning will eventually learn to avoid it, provided you give the warning output as context in the next iteration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating the Loop on Free Infrastructure
&lt;/h2&gt;

&lt;p&gt;Running two builds and a sanitized test suite on every agent patch can burn time on metered runners. This is where a free server option helps: you can dedicate a small box to execute the fence exactly when a patch arrives, without paying per-minute fees. The free model access handles the subsequent fix attempts, which means your cost for the entire review cycle stays close to zero. The loop becomes simple: your agent proposes a change, the free server compiles it with the fence, and the sanitizer output returns as context for the next proposal. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;Even with free resources, you should put a limit on each run. Use &lt;code&gt;timeout 600 ./fence.sh&lt;/code&gt; and a memory cap like &lt;code&gt;ulimit -v 2097152&lt;/code&gt; so one misbehaving patch cannot take down the box. Free does not mean unprotected; it means the infrastructure is available, not unlimited. Treat your free server like any production system and define a budget for every job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits of the Compiler Fence
&lt;/h2&gt;

&lt;p&gt;Compilers do an excellent job of detecting undefined behavior, type mismatches, and obvious memory issues. They are completely blind to algorithmic complexity, API coherence, and design intent. A patch can pass every warning flag and still introduce a quadratic loop into a hot path, because no compiler flags can tell you about asymptotic complexity. You still need human judgment for structure and readability.&lt;/p&gt;

&lt;p&gt;Sanitizers also have a runtime cost, often between 1.5x and 4x for the test suite. For a large project this can make the fence too slow to run on every commit. If that becomes a problem, schedule the fence to run on a filtered subset of tests that cover the modules touched by the patch, and run the full suite only once a day. The overhead is bounded and predictable, which matters more than absolute speed when reviewing agent output.&lt;/p&gt;

&lt;p&gt;Finally, warnings differ across compilers and standard library versions. A patch that compiles cleanly with GCC may trigger &lt;code&gt;-Wstringop-overflow&lt;/code&gt; with Clang, or the reverse. Choose one toolchain for the fence and document it. If your production environment uses a different one, add a separate configuration for that compiler but keep it as a secondary signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You Should Skip This Workflow
&lt;/h2&gt;

&lt;p&gt;If your patch only touches README text or build configuration, a full compiler fence is disproportionate. Likewise, a codebase already compiling with hundreds of warnings will drown your agent in legacy noise if you flip on &lt;code&gt;-Werror&lt;/code&gt; globally. Introduce the fence progressively: start with a new module, then expand as the warning count drops. You can also exclude generated code and third-party dependencies, but never exclude code your agent wrote. The purpose is to force the agent to confront the same standards as a human contributor.&lt;/p&gt;

&lt;p&gt;Set up one sanitizer build before your next agent patch. The compiler is the only reviewer that never gets tired, never assumes context, and never rationalizes away a mistake. Give it a seat at the table, and your review will become shorter, because the machine already asked the first round of questions.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>ai</category>
      <category>testing</category>
      <category>programming</category>
    </item>
    <item>
      <title>Properties First, Fixtures Second, Flakes Never: A Test Contract for Agent Patches</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sat, 29 Aug 2026 12:12:54 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/properties-first-fixtures-second-flakes-never-a-test-contract-for-agent-patches-14o0</link>
      <guid>https://dev.to/datacpp_8185/properties-first-fixtures-second-flakes-never-a-test-contract-for-agent-patches-14o0</guid>
      <description>&lt;p&gt;An agent patch is a hypothesis. A test suite is the only evidence a reviewer gets. Most suites fail at that job in three reproducible ways: assertions the agent can reverse-engineer, fixtures that regenerate and drift, and flaky tests that flap between green and red without a single commit. This article is a three-layer contract that closes all three: property checks for invariants, hash-pinned fixtures for determinism, and a flake quarantine that runs before the agent ever sees the suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  The evidence problem
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;assert(add(2, 2) == 4)&lt;/code&gt; is not evidence. It is a target. An agent that watches that failure can patch until the value matches, and the suite turns green even when the surrounding logic is wrong. More assertions do not fix this; they add more targets.&lt;/p&gt;

&lt;p&gt;Tests only become evidence when the agent cannot predict what will be checked. That requires three changes at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 1: Property checks turn values into relationships
&lt;/h2&gt;

&lt;p&gt;The first layer replaces fixed expected values with invariants. A property check asks: does the output violate the module's documented contract for any input? The agent cannot memorize the answer, because there is no single answer.&lt;/p&gt;

&lt;p&gt;C++ sketch with invariants for a &lt;code&gt;normalize_path&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;algorithm&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cassert&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="c1"&gt;// Converts '\' to '/', collapses duplicate '/', preserves trailing '/'&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;normalize_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Invariant 1: no backslash survives&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;check_no_backslash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;normalize_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;npos&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Invariant 2: normalization is idempotent&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;check_idempotent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;once&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;normalize_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;twice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;normalize_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;once&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;once&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;twice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Invariant 3: '\' and '/' variants converge to the same output&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;check_variants_converge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;with_slash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with_slash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;with_slash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normalize_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;normalize_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with_slash&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generator is a loop with a frozen seed. The seed is not a detail; it is the determinism guarantee:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;random&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;random_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mt19937&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;constexpr&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;alphabet&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sc"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'\\'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sc"&gt;'-'&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;alphabet&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt; &lt;span class="n"&gt;alphabet&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;s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mt19937&lt;/span&gt; &lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x5EED&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// frozen seed -&amp;gt; reproducible runs&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rng&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;check_no_backslash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;check_idempotent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;check_variants_converge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile with assertions enabled (&lt;code&gt;-UNDEBUG&lt;/code&gt;); a compiled-out assert is a fake gate. You do not need a property framework for this pattern — a loop and a seed are enough — and that matters, because the contract should survive in projects that cannot adopt new tooling. The invariants check relationships, not values: an agent that "fixes" a violation must change behavior, not adjust a constant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 2: Frozen fixtures turn drift into a visible diff
&lt;/h2&gt;

&lt;p&gt;The second failure mode is fixture drift. Generate a fixture at test time and it regenerates differently on the next run; a behavior change hides inside a file that "updated itself." The agent's diff looks clean, the reviewer sees nothing, and the regression ships. The fix is a frozen manifest: inputs are checked in, outputs are pinned, and a hash is asserted before the suite runs. The guard is a shell check, cheap enough to run on every attempt:&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;"fixture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"paths/edge_cases.txt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sha256"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9f2c91d4e8a17b3c..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"frozen_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-29"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"covers"&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="s2"&gt;"trailing slash preserved"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"empty path"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"duplicate separators"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"UNC prefix"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# guard_fixtures.sh — fail when a fixture changes without a manifest update&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;FIXTURE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"paths/edge_cases.txt"&lt;/span&gt;
&lt;span class="nv"&gt;EXPECTED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"9f2c91d4e8a17b3c..."&lt;/span&gt;
&lt;span class="nv"&gt;ACTUAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$FIXTURE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f1&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ACTUAL&lt;/span&gt;&lt;span class="s2"&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;$EXPECTED&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"fixture drifted: &lt;/span&gt;&lt;span class="nv"&gt;$FIXTURE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"expected &lt;/span&gt;&lt;span class="nv"&gt;$EXPECTED&lt;/span&gt;&lt;span class="s2"&gt;, got &lt;/span&gt;&lt;span class="nv"&gt;$ACTUAL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"review the diff, then update the manifest deliberately"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rule is simple: a fixture changes only through a committed manifest update. An agent patch that touches a fixture produces a diff a human must read. If the change is correct, approve it in review. If the agent "fixed" the fixture to match broken behavior, the diff is the evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 3: Flake freeze before the agent starts
&lt;/h2&gt;

&lt;p&gt;The third failure mode has a classic signature: failed, passed, failed, with no commit in between. A test that flaps on a clean base is not a bug report; it is noise. Left in the feedback loop, it pushes an agent to "fix" a function that was already correct.&lt;/p&gt;

&lt;p&gt;The freeze procedure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reset to the base commit on a clean checkout.&lt;/li&gt;
&lt;li&gt;Run the suite three times.&lt;/li&gt;
&lt;li&gt;Any test that fails at least once during the sweep goes into &lt;code&gt;flake_quarantine.txt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Filter quarantined tests out of the agent's feedback loop entirely.&lt;/li&gt;
&lt;li&gt;A quarantined test returns only after ten consecutive clean runs on a fixed machine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sweep script:&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# freeze_flakes.sh — 3x sweep on the base commit&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-uo&lt;/span&gt; pipefail
: &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; all_failures.txt

&lt;span class="k"&gt;for &lt;/span&gt;run &lt;span class="k"&gt;in &lt;/span&gt;1 2 3&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;ctest &lt;span class="nt"&gt;--output-on-failure&lt;/span&gt; &lt;span class="nt"&gt;-j4&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"run_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;run&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt; 2&amp;gt;&amp;amp;1
  &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'Failed'&lt;/span&gt; &lt;span class="s2"&gt;"run_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;run&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt; |
    &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-nE&lt;/span&gt; &lt;span class="s1"&gt;'s/.*Test +#([0-9]+): ([^ ]+).*/\2/p'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; all_failures.txt
&lt;span class="k"&gt;done

&lt;/span&gt;&lt;span class="nb"&gt;sort &lt;/span&gt;all_failures.txt | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-rn&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Interpretation: a count of 1 or 2 means the test is flaky; quarantine it. A count of 3 means the base commit is genuinely broken; fix that before spending agent cycles. The cost of the sweep is the price of trustworthy evidence. The sed regex assumes one-word test names; adapt it to your runner's output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where free models and a free server fit
&lt;/h2&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;The three-layer contract is compute-hungry by design: three suite runs per task, plus hundreds of property iterations. MonkeyCode offers free model access and a free server option, which covers exactly this class of disposable work. Use the server for the flake sweep and the property loops so they never consume CI minutes; let the free models draft the first generator pass and a fixture manifest seed from your existing test names. The model proposes, a human freezes. That division is the whole point: the quarantine list and the fixture hashes stay under human control.&lt;/p&gt;

&lt;h2&gt;
  
  
  What each layer catches
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Response&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Specific assertion value changes&lt;/td&gt;
&lt;td&gt;Property checks&lt;/td&gt;
&lt;td&gt;Inspect the invariant, not the constant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fixture output changes&lt;/td&gt;
&lt;td&gt;Frozen manifest&lt;/td&gt;
&lt;td&gt;Read the diff, approve or reject deliberately&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test fails on a clean base&lt;/td&gt;
&lt;td&gt;Flake freeze&lt;/td&gt;
&lt;td&gt;Quarantine first; investigate later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All unit tests green, behavior still changed&lt;/td&gt;
&lt;td&gt;Layers 1 + 2&lt;/td&gt;
&lt;td&gt;Trust the freeze, not the green count&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Limitations and who should skip this
&lt;/h2&gt;

&lt;p&gt;Property checks require an expressible invariant. Pure functions, parsers, and path utilities fit; UIs, visual output, and time-dependent systems do not. The fixture freeze is only as honest as its reviewers — if every fixture diff is approved unread, the freeze becomes theater. The flake quarantine is triage, not deletion: a quarantined race-condition test is still a bug, so schedule a human to investigate the list weekly.&lt;/p&gt;

&lt;p&gt;Skip this contract if the suite already takes more than thirty minutes per run (the sweep becomes the bottleneck), if the environment cannot be pinned (quarantine needs a fixed machine), or if the patch blast radius is a one-off script. The overhead is only justified where agent evidence is the product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The contract in five steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Freeze the base: run the 3x sweep, quarantine anything that flaps.&lt;/li&gt;
&lt;li&gt;Write property checks for the module under patch; freeze the seed.&lt;/li&gt;
&lt;li&gt;Pin fixtures with hashes; commit the manifest and the guard.&lt;/li&gt;
&lt;li&gt;Only now hand the suite to the agent.&lt;/li&gt;
&lt;li&gt;Review the agent's test changes as strictly as its code changes. A patch that rewrites code and tests in one commit is often a patch learning to fake evidence.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A test suite is evidence only when the agent cannot reverse-engineer it and the environment cannot corrupt it. Properties remove the target; fixtures remove the drift; the flake freeze removes the noise. The free tier in MonkeyCode makes the sweep cheap and the first draft fast. The freeze itself remains a human decision. Keep it that way.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>cpp</category>
      <category>ci</category>
    </item>
    <item>
      <title>The Test Failed, Passed, Failed. The Agent "Fixed" a Function That Was Already Correct.</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Sat, 29 Aug 2026 09:05:22 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/the-test-failed-passed-failed-the-agent-fixed-a-function-that-was-already-correct-4ig2</link>
      <guid>https://dev.to/datacpp_8185/the-test-failed-passed-failed-the-agent-fixed-a-function-that-was-already-correct-4ig2</guid>
      <description>&lt;p&gt;The CI run failed at 02:14. The same test passed at 02:31. The agent, told to make the suite green, edited the wrong function and left the flake in place. This is not a model quality problem. It is a signal problem: a flaky test turns a deterministic gate into a coin flip, and a patch loop that adapts to the gate will adapt to the noise.&lt;/p&gt;

&lt;p&gt;The fix is not to run the suite more times. It is a quarantine ledger that decides, before the agent sees a failure, whether that failure deserves a reaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a flake is worse than a failure
&lt;/h2&gt;

&lt;p&gt;A deterministic failure gives an agent a stable target. A flaky test gives it three targets in a row: fail, pass, fail. The agent does not debug a coin flip; it pattern-matches. The cycle repeats:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The test fails. The agent edits the nearest suspicious code.&lt;/li&gt;
&lt;li&gt;The rerun passes. The agent records the patch as successful.&lt;/li&gt;
&lt;li&gt;The test fails again, because the original cause never went away.&lt;/li&gt;
&lt;li&gt;The agent edits something else, and the diff grows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is either a phantom fix — correct code modified for no reason — or learned suppression, where the agent discovers that deleting an assertion makes the suite green. Both are worse than the original red.&lt;/p&gt;

&lt;p&gt;A single flaky test corrupts this loop. It does not need a high flake rate. It needs to fail once inside the window the agent is allowed to react to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Freeze first, property-check later
&lt;/h2&gt;

&lt;p&gt;The instinct is to add property-based tests to catch more edge cases. Do not add them to an unstable suite. A property test is still a test: it can fail on a port collision, a timestamp boundary, or an uninitialized fixture, and the agent will "fix" the output of a function that was never wrong.&lt;/p&gt;

&lt;p&gt;The strategy has to be ordered:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Freeze every test that flakes inside the history window.&lt;/li&gt;
&lt;li&gt;Run agent-visible patches only against the stable subset.&lt;/li&gt;
&lt;li&gt;Add property checks to the stable subset, with pinned seeds and fixed examples.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The freeze comes before the properties. Otherwise, you are teaching the agent to chase ghosts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The quarantine ledger
&lt;/h2&gt;

&lt;p&gt;A freeze needs a record, not a comment. The pattern I use is a JSON ledger plus a tiny runner. &lt;code&gt;flake_freeze.json&lt;/code&gt;:&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;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history_window_runs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"frozen"&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"node_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tests/test_clock.py::test_dst_boundary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"first_seen_run"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run-2026-08-29-019"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mismatches"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"last_mismatch_run"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run-2026-08-29-021"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"timestamp boundary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"unfreeze_rule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10 consecutive passes outside quarantine"&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;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;The runner reads the ledger and removes frozen tests from the agent-visible run:&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;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nv"&gt;ledger&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"flake_freeze.json"&lt;/span&gt;
&lt;span class="nv"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;deselect&lt;/span&gt;&lt;span class="o"&gt;=()&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; node&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;deselect+&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="nt"&gt;--deselect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt; &amp;lt; &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.frozen[].node_id'&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ledger&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

pytest &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$target&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;deselect&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quarantine is not a skip. Frozen tests are absent from the run result, not hidden behind &lt;code&gt;pytest.mark.skip&lt;/code&gt;. A visible absence is easier to audit than an invisible pass.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five-step freeze workflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Detect. Any failure that cannot be reproduced on the same commit with the same command is a flake candidate.&lt;/li&gt;
&lt;li&gt;Probe. Rerun the failing test five times on the identical commit before the agent sees it. One pass in five reruns is enough to freeze.&lt;/li&gt;
&lt;li&gt;Freeze. Move the test into the ledger with a reason and an unfreeze rule.&lt;/li&gt;
&lt;li&gt;Patch. Let the agent touch only the stable subset.&lt;/li&gt;
&lt;li&gt;Prune. Every 20 runs, review the ledger. A frozen test that stays frozen for the full window becomes a landfill.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The probe script is deliberately stupid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;probe&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;runs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;passes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
  &lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$runs&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    if &lt;/span&gt;pytest &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$node&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
      &lt;/span&gt;&lt;span class="nv"&gt;passes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;passes &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;fi
  done
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$passes&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$runs&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
probe &lt;span class="s2"&gt;"tests/test_clock.py::test_dst_boundary"&lt;/span&gt;
&lt;span class="c"&gt;# 4/5 → freeze, never show this failure to the agent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The critical detail: the probe reruns the same commit. A rerun after a patch is a different experiment and proves nothing about flakiness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Property checks that survive the freeze
&lt;/h2&gt;

&lt;p&gt;Once the suite is stable, property checks add the signal that fixtures cannot: invariants. A minimal Hypothesis example:&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;hypothesis&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;given&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strategies&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="nd"&gt;@settings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deadline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;derandomize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integers&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;integers&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_add_commutes&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;assert&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="o"&gt;==&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;b&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;derandomize=True&lt;/code&gt; makes the input sequence reproducible on the same version, so a failure is attributable to the code and not to a generator draw. Add fixed examples next to the generated ones. A property check that only passes on a frozen test is a fixture story, not a property story.&lt;/p&gt;

&lt;h2&gt;
  
  
  The triage table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Observation&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Condition&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fails once, passes on rerun&lt;/td&gt;
&lt;td&gt;Freeze&lt;/td&gt;
&lt;td&gt;any mismatch in window&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Same traceback in 3+ of 5 runs&lt;/td&gt;
&lt;td&gt;Fix&lt;/td&gt;
&lt;td&gt;same error, same environment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Different error each run&lt;/td&gt;
&lt;td&gt;Freeze, assign owner&lt;/td&gt;
&lt;td&gt;timeout, port, ordering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frozen for 20+ runs&lt;/td&gt;
&lt;td&gt;Prune or delete&lt;/td&gt;
&lt;td&gt;no owner, no reproducer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The table removes judgment from the hot path. You decide the rules once, and the loop applies them without asking the agent for an opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this
&lt;/h2&gt;

&lt;p&gt;Small suites where a human watches every run do not need a freeze; they need the test fixed. Suites that are already deterministic — no network, no wall clock, no shared state — have no flakes to quarantine. Teams without run history cannot maintain the ledger; a ledger without history is a to-do list with extra JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes when retries are cheap
&lt;/h2&gt;

&lt;p&gt;The expensive resource in an agent loop is not the API call. It is the human attention spent deciding whether a failure is real. If the patch loop runs on MonkeyCode's free model access and its free server option, another patch attempt costs nothing extra in dollars — so you can afford to probe every suspicious failure five times. Cheap retries make flakes more visible, not less. That is exactly why the freeze matters more, not less.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ai</category>
      <category>python</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
