<?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: Morgan Zhou</title>
    <description>The latest articles on DEV Community by Morgan Zhou (@devio_4040).</description>
    <link>https://dev.to/devio_4040</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%2F4060973%2F017b80bf-77df-4d46-9d48-92a3dbdfb31d.png</url>
      <title>DEV Community: Morgan Zhou</title>
      <link>https://dev.to/devio_4040</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/devio_4040"/>
    <language>en</language>
    <item>
      <title>A Repeatable Harness for Catching Regressions in AI-Generated Code</title>
      <dc:creator>Morgan Zhou</dc:creator>
      <pubDate>Wed, 05 Aug 2026 10:11:51 +0000</pubDate>
      <link>https://dev.to/devio_4040/a-repeatable-harness-for-catching-regressions-in-ai-generated-code-2fd0</link>
      <guid>https://dev.to/devio_4040/a-repeatable-harness-for-catching-regressions-in-ai-generated-code-2fd0</guid>
      <description>&lt;p&gt;AI coding assistants are great at producing plausible diffs. They are less great at telling you whether the diff quietly broke an edge case three files away. After a few rounds of "looks fine, ship it, roll it back," I stopped trusting eyeball reviews of generated patches and built a small, repeatable harness that any AI-generated change has to survive before I merge it.&lt;/p&gt;

&lt;p&gt;This post walks through that harness: a golden-input test set, a diff-aware check script, and a decision table for when free hosted model access is enough versus when you need your own infrastructure. It works with any model provider, but I'll note where free tiers (including MonkeyCode's free model access and free server option) fit naturally, since cost is usually what stops people from running this loop on every change.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: generated code fails in boring ways
&lt;/h2&gt;

&lt;p&gt;The failures I actually see from AI-assisted changes are not dramatic. They're things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A refactored parser that now trims whitespace it used to preserve.&lt;/li&gt;
&lt;li&gt;A "simplified" retry loop that dropped the jitter, so retries thunder in sync.&lt;/li&gt;
&lt;li&gt;An off-by-one in pagination that only triggers when the result count is an exact multiple of the page size.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these show up in a casual read of the diff. All of them show up if you run the change against a fixed set of known-tricky inputs and compare behavior before and after.&lt;/p&gt;

&lt;h2&gt;
  
  
  The artifact: a three-part harness
&lt;/h2&gt;

&lt;p&gt;The harness has three pieces, each boring on its own:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Golden inputs&lt;/strong&gt;: a checked-in directory of inputs that historically broke things, plus the expected behavior for each.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A runner&lt;/strong&gt;: a script that executes the current code against every golden input and diffs the output against expectations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A gate&lt;/strong&gt;: CI (or a pre-merge script) that fails if the runner reports a mismatch the author didn't explicitly bless.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a minimal runner in Python. It's deliberately dependency-free so it works anywhere:&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;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;golden_run.py — run golden inputs, diff against expected outputs.

Layout:
  golden/
    case_001.input.txt
    case_001.expected.txt
&lt;/span&gt;&lt;span class="gp"&gt;    ...&lt;/span&gt;
&lt;span class="sh"&gt;"""&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;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&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="n"&gt;GOLDEN&lt;/span&gt; &lt;span class="o"&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;golden&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;BLESSED&lt;/span&gt; &lt;span class="o"&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;golden/blessed_changes.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# diffs a human approved
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_path&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="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="c1"&gt;# Swap this for whatever invokes your code path under test.
&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;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&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="n"&gt;executable&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/transform.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_path&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;capture_output&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="n"&gt;text&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="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&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="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&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="n"&gt;blessed&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="n"&gt;BLESSED&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;BLESSED&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exists&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="n"&gt;failures&lt;/span&gt; &lt;span class="o"&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;inp&lt;/span&gt; &lt;span class="ow"&gt;in&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;GOLDEN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.input.txt&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inp&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="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.input.txt&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="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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GOLDEN&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;case&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.expected.txt&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;actual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_case&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inp&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;actual&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;case&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;blessed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;failures&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;Unblessed regressions:&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;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;failures&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;1&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;All golden cases pass (or are explicitly blessed).&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="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;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="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;blessed_changes.json&lt;/code&gt; file is the important part. When the AI's change &lt;em&gt;intentionally&lt;/em&gt; alters behavior, you don't just update the expected file — you add the case name plus a one-line reason, which forces a human to acknowledge the behavioral delta in code review:&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;"case_014"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Whitespace trim is intentional; parser contract updated in docs/parser.md"&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;h2&gt;
  
  
  Where the AI fits in the loop
&lt;/h2&gt;

&lt;p&gt;The harness changes how I use the assistant. Instead of "generate the fix and I review it," the loop becomes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Describe the bug and ask the model for a fix &lt;strong&gt;plus a new golden input that reproduces it&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Run the harness. The new case should fail on the old code and pass on the new code. If it passes on both, the repro case is wrong — very common, and catching it here saves a bad merge.&lt;/li&gt;
&lt;li&gt;If other cases fail, feed the mismatch output back to the model and iterate, or fix by hand.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 2 is where iteration cost matters. Verifying that a repro case actually reproduces often takes three or four round trips with the model, and that adds up on metered APIs. This is where free-tier access is genuinely useful: I route these exploratory iterations through MonkeyCode, which offers free model access and a free server option, and keep paid capacity for nothing. The verification loop doesn't need the strongest model — it needs a cheap, fast one you don't hesitate to re-run.&lt;/p&gt;

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

&lt;p&gt;One practical note: because the free server is shared infrastructure, I keep golden inputs free of secrets and customer data regardless of provider. That's a habit worth having anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  When free hosted access is enough, and when it isn't
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Free hosted model + free server&lt;/th&gt;
&lt;th&gt;Your own infra / paid tier&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Repro-case verification, small patches&lt;/td&gt;
&lt;td&gt;Yes — cost is the whole point&lt;/td&gt;
&lt;td&gt;Overkill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nightly full-harness runs in CI&lt;/td&gt;
&lt;td&gt;Fine if latency is acceptable&lt;/td&gt;
&lt;td&gt;Better if you need SLAs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inputs contain proprietary code or PII&lt;/td&gt;
&lt;td&gt;No — sanitize first or don't&lt;/td&gt;
&lt;td&gt;Yes, with controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load/perf regression testing&lt;/td&gt;
&lt;td&gt;No — shared infra skews timing&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need a pinned model version for reproducibility&lt;/td&gt;
&lt;td&gt;Check what's guaranteed; assume not&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The last two rows are the real limitations. Shared or free servers are the wrong place for timing-sensitive benchmarks, and "free" usually comes with no guarantee about which exact model version you hit, so don't treat outputs as reproducible across weeks. For behavior-diff testing that's fine — your golden expectations are the source of truth, not the model. For anything where the model's output &lt;em&gt;is&lt;/em&gt; the artifact, pin a version somewhere you control.&lt;/p&gt;

&lt;p&gt;Also: if your golden set has fewer than a dozen cases, this harness is ceremony. The payoff starts when the set grows into the dozens and manual re-checking stops being realistic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations, honestly
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The harness catches behavioral diffs against cases you thought of. It says nothing about cases you didn't. Property-based tests complement it well.&lt;/li&gt;
&lt;li&gt;Golden expected files rot when behavior changes frequently; the blessing mechanism mitigates this but depends on reviewers actually reading the reasons.&lt;/li&gt;
&lt;li&gt;Free tiers change. Anything built on "this costs nothing today" should degrade gracefully to a paid or local fallback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;The shift that made AI-generated code reliable enough for me wasn't a better model — it was making every generated change prove itself against a fixed, growing set of nasty inputs, with a human sign-off on any intentional behavior change. If you want to try the loop without committing budget, MonkeyCode's free tier is a reasonable place to run the iterative steps; the harness itself is provider-agnostic and yours to keep either way.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>Stop Trusting Vibes: A Repeatable Harness for Testing LLM-Generated Code on a Free Server</title>
      <dc:creator>Morgan Zhou</dc:creator>
      <pubDate>Wed, 05 Aug 2026 06:39:39 +0000</pubDate>
      <link>https://dev.to/devio_4040/stop-trusting-vibes-a-repeatable-harness-for-testing-llm-generated-code-on-a-free-server-n08</link>
      <guid>https://dev.to/devio_4040/stop-trusting-vibes-a-repeatable-harness-for-testing-llm-generated-code-on-a-free-server-n08</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'endraw'&lt;/p&gt;
</description>
      <category>ai</category>
      <category>testing</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
