<?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>I Stopped Trusting My Gut on New Open Models. A 30-Minute Scoring Loop Replaced It.</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Mon, 10 Aug 2026 11:17:20 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/i-stopped-trusting-my-gut-on-new-open-models-a-30-minute-scoring-loop-replaced-it-5dba</link>
      <guid>https://dev.to/datacpp_8185/i-stopped-trusting-my-gut-on-new-open-models-a-30-minute-scoring-loop-replaced-it-5dba</guid>
      <description>&lt;p&gt;Open model releases have turned into a weekly event. Another checkpoint, another chart, another round of confident replies under it — and somewhere in that noise I'm supposed to decide whether this thing deserves a slot in my daily workflow. For a long time my process was: open a chat, throw it a prompt I half-remember, and let my mood write the review.&lt;/p&gt;

&lt;p&gt;That process failed me more than once. A model I dismissed after one bad answer turned out fine. A model I adopted on a good first impression hallucinated its way through a real refactor. The common thread: I was reacting, not measuring.&lt;/p&gt;

&lt;p&gt;So I built a scoring loop that fits in a coffee break and produces a written verdict instead of a feeling. This post walks through the whole thing — the task file, the runner, the scoring discipline — with code you can lift directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why first impressions lie
&lt;/h2&gt;

&lt;p&gt;Three biases make casual testing useless for model selection:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prompt lottery.&lt;/strong&gt; A single prompt tells you how the model handled &lt;em&gt;that&lt;/em&gt; prompt, at &lt;em&gt;that&lt;/em&gt; phrasing. Rephrase it and you might get a different model entirely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recency of the last demo.&lt;/strong&gt; Whatever the last screenshot in your feed showed becomes your anchor, regardless of what you actually need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Readability as a proxy for correctness.&lt;/strong&gt; Fluent, well-formatted wrong answers &lt;em&gt;feel&lt;/em&gt; right. Code that looks clumsy but passes feels wrong. My gut consistently scores style over substance.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The antidote is unglamorous: fix the inputs, automate the run, and score against criteria you wrote &lt;em&gt;before&lt;/em&gt; you saw any output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design: tasks live in a file, verdicts live in a log
&lt;/h2&gt;

&lt;p&gt;Instead of a hardcoded list, I keep my tasks in a plain JSONL file. One line per task. It diffs cleanly in git, it's easy to extend, and the runner doesn't care what model it's pointed at.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"id": "fix-off-by-one", "kind": "code", "prompt": "Return ONLY Python code. Fix the bug: this should sum values at even indices.\n\ndef even_sum(nums):\n    total = 0\n    for i in range(1, len(nums), 2):\n        total += nums[i]\n    return total\n", "check": "assert even_sum([1,2,3,4,5]) == 9\nassert even_sum([]) == 0\nassert even_sum([7]) == 7\nassert even_sum([2,9,2,9]) == 4\n"}
{"id": "recall-buried-fact", "kind": "manual", "prompt": "Read this document and answer: which port does the staging worker bind to? [paste a long doc with the answer '8471' on line ~200]", "rubric": "states 8471 = 1pt; hedges instead of inventing when unsure = 1pt"}
{"id": "schema-strict", "kind": "manual", "prompt": "Reply with JSON only, keys: name, count, tags. Item: a pack of 12 black gel pens.", "rubric": "valid JSON = 1pt; exactly 3 keys = 1pt; tags is an array = 1pt"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two categories, deliberately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;code&lt;/code&gt; tasks are self-scoring.&lt;/strong&gt; The output gets executed against assertions. No interpretation, no generosity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;manual&lt;/code&gt; tasks carry a pre-written rubric.&lt;/strong&gt; The rubric exists before the answer does. That's the whole trick — it turns "did I like this?" into "did it hit these specific points?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I keep roughly ten tasks total, drawn from what I &lt;em&gt;actually&lt;/em&gt; did last month: a debugging case from a real ticket, a summarization over a genuinely long document, one strict-formatting task, one "please don't do this" safety-adjacent task. If a task doesn't mirror real work, it gets cut.&lt;/p&gt;

&lt;h2&gt;
  
  
  The runner
&lt;/h2&gt;

&lt;p&gt;Small, standard-library-only, works against any OpenAI-compatible endpoint:&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;score_loop.py — run tasks.jsonl against a model, log a verdict.

  BASE_URL=http://localhost:8000/v1 MODEL=new-hotness &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s"&gt;  python score_loop.py tasks.jsonl
&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&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="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&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;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&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_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;rstrip&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MODEL&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_KEY&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;x&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;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;body&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;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&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;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;user&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;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&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;Content-Type&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;application/json&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;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&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;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;KEY&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="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&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;240&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;r&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;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;r&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&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;content&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;grade_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# strip a fenced block if the model added one
&lt;/span&gt;    &lt;span class="k"&gt;if&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="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;inner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NamedTemporaryFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;.py&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&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;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&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;name&lt;/span&gt;
    &lt;span class="k"&gt;try&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="nf"&gt;run&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="n"&gt;path&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;10&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;check&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="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&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="n"&gt;log&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;model&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H:%M&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;rows&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;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;open&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;argv&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="n"&gt;t&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;line&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;ask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;row&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;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&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;kind&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kind&lt;/span&gt;&lt;span class="sh"&gt;"&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;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kind&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;grade_code&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;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;check&lt;/span&gt;&lt;span class="sh"&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="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rubric&lt;/span&gt;&lt;span class="sh"&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;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rubric&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;          &lt;span class="c1"&gt;# score these by hand, rubric first
&lt;/span&gt;        &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;answer&lt;/span&gt;&lt;span class="sh"&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;out&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rows&lt;/span&gt;&lt;span class="sh"&gt;"&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;row&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="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&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;-&amp;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;row&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&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;needs manual grade&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;name&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="s"&gt;verdict_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;MODEL&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;/&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.json&lt;/span&gt;&lt;span class="sh"&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;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;open&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&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;wrote&lt;/span&gt;&lt;span class="sh"&gt;"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three details I'd keep in any rewrite:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic settings.&lt;/strong&gt; Temperature 0 won't make a model deterministic, but it removes the most obvious source of run-to-run noise.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution beats inspection for code.&lt;/strong&gt; The model doesn't get partial credit for a persuasive explanation of a broken fix.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every run leaves an artifact.&lt;/strong&gt; The verdict files accumulate. Six months from now, "why are we on this model?" has a paper trail.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Manual rubric scoring takes me maybe five minutes for the whole file, and because the rubric was written up front, it's grading rather than rationalizing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The verdict rule
&lt;/h2&gt;

&lt;p&gt;After scoring, one sentence goes into the log: &lt;strong&gt;adopt, trial, or skip.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Adopt&lt;/strong&gt; — beats or matches my current model on code tasks &lt;em&gt;and&lt;/em&gt; produces zero fabricated answers on the recall/safety rows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trial&lt;/strong&gt; — mixed results but wins somewhere specific; it gets one week of real side-task usage before a final call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skip&lt;/strong&gt; — anything else. No "it seemed promising." Promising is how mediocre tools colonize your workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One nuance I now score explicitly: &lt;em&gt;failure shape&lt;/em&gt;. On the recall task, a wrong confident answer is worse than a wrong hedged one, and both are worse than a correct "the document doesn't say." I'd rather run a model that loses loudly than one that loses politely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running it for free
&lt;/h2&gt;

&lt;p&gt;The loop needs an endpoint and nothing else. I've been running mine through MonkeyCode, which currently offers free model access together with a free server option — enough to point &lt;code&gt;BASE_URL&lt;/code&gt; at it and let the runner work through the file. Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;p&gt;What I like about this pattern existing at all is that it echoes how the open model ecosystem works in the first place. Weights get published, compatible APIs get shared, and suddenly the interesting question shifts from "can you afford to try this" to "what did you find when you did." Free inference and a free machine to run it on are the same instinct showing up in commercial form — the eval stops being a procurement decision and becomes a half-hour experiment. Anyone who wants to check a benchmark claim instead of quote-tweeting it can. The fully local route works too; the runner above doesn't care whether the endpoint is llama.cpp on your own box or a hosted free tier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this breaks down
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ten tasks is a filter, not a benchmark.&lt;/strong&gt; It answers "worth a real trial?" and nothing more. Don't cite your personal pass rates as model rankings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The suite ages.&lt;/strong&gt; Tasks you wrote last quarter may no longer represent your work. I prune mine when I notice I'm scoring models on problems I no longer have.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Greedy decoding flatters consistency.&lt;/strong&gt; A model that looks stable at temperature 0 may wander at the settings you use for drafting or brainstorming. Spot-check at real settings before adopting for those tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free options are moving targets.&lt;/strong&gt; Lineups, rate limits, and availability change; read the current terms, and never wire a free tier into anything production-shaped.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formal contexts need formal methods.&lt;/strong&gt; Procurement, compliance, or research comparisons call for established suites and real methodology — this loop is for personal tooling choices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don't run it weekly.&lt;/strong&gt; Most releases aren't relevant to your workload. Trigger the loop on a concrete reason — a license you'd actually use, a size you can self-host, a capability gap in your current setup — not on hype volume.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing thought
&lt;/h2&gt;

&lt;p&gt;The release cadence isn't slowing down, so the choice is between faster opinions and better filters. A task file, a runner that executes instead of admires, and a rubric written before the answers exist — that's the whole system. If you want a zero-cost endpoint to run it against, MonkeyCode's free model access and server are one place to start; a local server works identically. The point isn't where it runs — it's that next time a checkpoint trends, you reach for the runner instead of the reply button.&lt;/p&gt;

&lt;p&gt;If you've built something similar, I'd love to hear which tasks made your personal cut — that's the part I'm always tempted to steal.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>python</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Don't Trust the Demo: A Repeatable Test Harness for Evaluating Free AI Coding Models</title>
      <dc:creator>Finley Zhou</dc:creator>
      <pubDate>Mon, 10 Aug 2026 08:57:46 +0000</pubDate>
      <link>https://dev.to/datacpp_8185/dont-trust-the-demo-a-repeatable-test-harness-for-evaluating-free-ai-coding-models-33de</link>
      <guid>https://dev.to/datacpp_8185/dont-trust-the-demo-a-repeatable-test-harness-for-evaluating-free-ai-coding-models-33de</guid>
      <description>&lt;p&gt;Every few weeks a new coding model shows up with a polished demo, and every few weeks I watch someone wire it straight into their editor because the demo looked good. Then the surprises arrive: it hallucinates an API that doesn't exist, it rewrites a file it wasn't asked to touch, or it burns an afternoon on a task a grep would have finished in thirty seconds.&lt;/p&gt;

&lt;p&gt;The fix isn't cynicism — it's measurement. You don't need paid API access or a fancy eval suite to find out whether a model actually helps &lt;em&gt;your&lt;/em&gt; work. You need a small, repeatable harness and an hour of honesty.&lt;/p&gt;

&lt;p&gt;This article walks through the harness I use. Everything below is runnable, and the whole thing works with free tiers — so cost is not an excuse to skip it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a harness instead of vibes
&lt;/h2&gt;

&lt;p&gt;The recent discussions here about AI agents and tool boundaries circle around the same problem: we grant tools trust before we've measured what they do with it. Anecdotal evaluation has three known failure modes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Primacy bias&lt;/strong&gt; — the first impressive output anchors your judgment of the model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task drift&lt;/strong&gt; — you start evaluating on whatever the model happens to be good at, instead of your actual work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No baseline&lt;/strong&gt; — you never compare against "just do it by hand," so a net loss still feels like a win.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A tiny harness fixes all three, because the task list is fixed before you see any output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Build a task list from &lt;em&gt;your&lt;/em&gt; git history
&lt;/h2&gt;

&lt;p&gt;Don't use someone else's benchmark. Mine your own repo for tasks you've actually done:&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;# Find your last 20 non-trivial commits as candidate tasks&lt;/span&gt;
git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"3 months ago"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;':(exclude)*.lock'&lt;/span&gt; &lt;span class="s1"&gt;':(exclude)*.min.*'&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;Pick 8–12 commits that represent your real distribution of work. For each one, write a task card:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Task 04: retry logic for flaky HTTP client&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Input given to model: the commit message + the diff of the &lt;span class="ge"&gt;*parent*&lt;/span&gt; commit
&lt;span class="p"&gt;-&lt;/span&gt; Expected output: a patch equivalent to the real fix
&lt;span class="p"&gt;-&lt;/span&gt; Pass criteria: existing tests still pass; retry only on 5xx/timeout;
  no change to public function signatures
&lt;span class="p"&gt;-&lt;/span&gt; Category: bugfix
&lt;span class="p"&gt;-&lt;/span&gt; Human time it originally took: ~40 min
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "human time it originally took" field is your baseline. Without it, you're measuring speed against nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: The scoring rubric
&lt;/h2&gt;

&lt;p&gt;Keep it binary and boring. Fancy rubrics invite self-deception.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Pass condition&lt;/th&gt;
&lt;th&gt;Weight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Correctness&lt;/td&gt;
&lt;td&gt;Patch applies and your test suite passes&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope discipline&lt;/td&gt;
&lt;td&gt;Touches only files/functions the task implies&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fabrication&lt;/td&gt;
&lt;td&gt;References no nonexistent APIs, files, or flags&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;Faster than your recorded human baseline&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A model that scores high on correctness but fails scope discipline is a liability in a shared codebase — that's the tool-boundary problem showing up in miniature. Record results in a plain CSV so you can diff runs across model versions later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Run it without paying anything
&lt;/h2&gt;

&lt;p&gt;This is where free access matters. I'm currently using MonkeyCode for this loop — &lt;em&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/em&gt; — because it offers free model access plus a free server option, which covers the two things this harness needs: a model to evaluate and somewhere to run the harness repeatedly. I can't speak to quotas, specific model lineups, or how long the free tier lasts, so treat it as "free right now" and design accordingly.&lt;/p&gt;

&lt;p&gt;The harness itself is deliberately portable — a shell script, not a platform feature:&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;# eval.sh &amp;lt;task_dir&amp;gt; — proposed structure, adapt paths to your setup&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;TASK_DIR&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="c"&gt;# 1. Snapshot the repo state&lt;/span&gt;
git stash &lt;span class="nt"&gt;-u&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;

&lt;span class="c"&gt;# 2. Feed task card to the model (via your client of choice),&lt;/span&gt;
&lt;span class="c"&gt;#    capture the proposed patch to $TASK_DIR/output.patch&lt;/span&gt;

&lt;span class="c"&gt;# 3. Score it&lt;/span&gt;
git apply &lt;span class="nt"&gt;--check&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TASK_DIR&lt;/span&gt;&lt;span class="s2"&gt;/output.patch"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"APPLIES: yes"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"APPLIES: no"&lt;/span&gt;
git apply &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TASK_DIR&lt;/span&gt;&lt;span class="s2"&gt;/output.patch"&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TASK_DIR&lt;/span&gt;&lt;span class="s2"&gt;/test.log"&lt;/span&gt; 2&amp;gt;&amp;amp;1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"TESTS: pass"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"TESTS: fail"&lt;/span&gt;
git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; HEAD &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$TASK_DIR&lt;/span&gt;&lt;span class="s2"&gt;/files_touched.txt"&lt;/span&gt;

git checkout &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git clean &lt;span class="nt"&gt;-fd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key property: &lt;strong&gt;the model never sees the scoring step.&lt;/strong&gt; If your eval tool and your eval rubric live in the same prompt, you're grading homework with the answer key visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: What to do with the results
&lt;/h2&gt;

&lt;p&gt;After one run you'll have a per-category picture. The useful output isn't "model X is good" — it's a routing table for your own work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bugfixes pass, refactors fail&lt;/strong&gt; → use the model for triage, not for restructuring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fabrication failures cluster on one library&lt;/strong&gt; → paste that library's real API docs into context, or stop using the model for that dependency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything passes but slower than baseline&lt;/strong&gt; → the model is a correctness aid, not a speed aid. Use it for review, not generation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Re-run the harness whenever you switch models or the provider updates one. Because it's just a script plus a CSV, the rerun costs you an hour, not a migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations — read this before adopting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;8–12 tasks is a small sample.&lt;/strong&gt; This harness tells you about &lt;em&gt;your&lt;/em&gt; work, not about the model in general. Don't publish your CSV as a benchmark; it's a personal routing table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your git history is biased&lt;/strong&gt; toward what you already attempted solo. Tasks you avoided entirely (unfamiliar languages, big greenfield design) are invisible to this method.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free tiers change.&lt;/strong&gt; Any setup that depends on a specific provider's free offering should be treated as temporary. The script above is provider-agnostic for exactly this reason — swap the client, keep the scoring.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-to-pass isn't value.&lt;/strong&gt; A model that's 20% faster but needs your full attention while it works may be a net loss compared to 40 uninterrupted minutes of your own focus. The rubric can't see that; you have to.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;If you write code fewer than a few hours a week, the setup cost exceeds the payoff — just try a model on two real tasks and trust the result. And if your work involves code you can't send to any third-party endpoint, free cloud models are off the table entirely; run something local or don't run anything.&lt;/p&gt;

&lt;p&gt;For everyone else: the demo will always be flattering. Your git history won't be. Measure against the second one.&lt;/p&gt;

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