<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Off-Topic | AkitaOnRails.com</title><link>https://www.akitaonrails.com/en/off-topic/</link><description>Fabio Akita's blog — tech, career, and assorted geek topics. English edition.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Wed, 28 Oct 2026 15:27:54 +0000</lastBuildDate><atom:link href="https://www.akitaonrails.com/en/off-topic/index.xml" rel="self" type="application/rss+xml"/><item><title>LLM Benchmark v4: Gemini 4 Argon, GPT-6.1 Sol and Terra, Kimi K3.1 Pro, Claude Sonnet 5.5</title><link>https://www.akitaonrails.com/en/2026/10/28/llm-benchmark-v4-gemini-4-argon-gpt-6-1-sol-terra-kimi-k3-1-pro-claude-sonnet-5-5/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/28/llm-benchmark-v4-gemini-4-argon-gpt-6-1-sol-terra-kimi-k3-1-pro-claude-sonnet-5-5/</guid><pubDate>Wed, 28 Oct 2026 10:00:00 -0300</pubDate><description>&lt;p&gt;I spent the last few weeks talking quite a bit about open source LLMs, local hardware, B300s, the RTX 5090, Qwen, and Basalt. Meanwhile, the commercial labs kept shipping new models as if nobody needed sleep.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://www.akitaonrails.com/en/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/"&gt;last commercial ranking update&lt;/a&gt; added Opus 5.5, GPT 6 Sol and Luna, MiMo 2.6 Pro, and Grok 4.7. The pattern was already showing: new releases were improving mostly on cost and speed. Quality had become a fight over a few points, with models from the same family swapping positions from one run to the next.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I spent the last few weeks talking quite a bit about open source LLMs, local hardware, B300s, the RTX 5090, Qwen, and Basalt. Meanwhile, the commercial labs kept shipping new models as if nobody needed sleep.</p>
<p>The <a href="/en/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/">last commercial ranking update</a> added Opus 5.5, GPT 6 Sol and Luna, MiMo 2.6 Pro, and Grok 4.7. The pattern was already showing: new releases were improving mostly on cost and speed. Quality had become a fight over a few points, with models from the same family swapping positions from one run to the next.</p>
<p>Now <strong>Gemini 4 Argon, GPT-6.1 Sol, GPT-6.1 Terra, Kimi K3.1 Pro, Claude Sonnet 5.5, and Muse Wonder</strong> have joined the ranking. All six landed in Tier A.</p>
<p>I suspect this will be my last commercial ranking update, or close to it. The models have become too similar.</p>
<h2>A Reminder of What This Benchmark Measures<span class="hx:absolute hx:-mt-20" id="a-reminder-of-what-this-benchmark-measures"></span>
    <a href="#a-reminder-of-what-this-benchmark-measures" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">llm-coding-benchmark</a> does not attempt to measure &ldquo;general intelligence.&rdquo; V4 has each agent develop a Rails system over seven sprints. Along the way, I plant 14 silent sabotages: authorization failures, XSS, SQL injection, a hard-coded secret, open CORS, a removed index, and a test altered to accept unsafe behavior.</p>
<p>When the model finds and fixes one by itself, it gets the item&rsquo;s full weight. A fix made only after the sabotage is revealed gets 40%. Anything still unresolved gets zero. The final score is normalized to 100.</p>
<p>This is a narrow measure of <strong>vigilance during long-horizon agentic programming</strong>. It does not measure whether the model writes the best prose, solves math, understands tax law, designs a beautiful interface, or debugs firmware. It does not even measure everything that matters in programming.</p>
<p>No benchmark can do that, including the popular ones. Models in this class may have billions of parameters, and the combinations of prompt, context, tools, harness, temperature, and prior conversation state grow far beyond anything a test suite can exercise. You would have to test practically everything that could go into and come out of the model. Impossible.</p>
<p>Arguing whether benchmark A is &ldquo;better&rdquo; than benchmark B usually starts with the wrong question. Each one lights up a tiny surface. LeetCode-style tests and <a href="https://arxiv.org/abs/2107.03374"target="_blank" rel="noopener">HumanEval</a> measure short, well-defined problem solving. SWE-bench measures the ability to resolve issues in existing repositories.</p>
<p>Mine follows a project growing over several hours, carrying accumulated context and earlier decisions, with planted defects that simulate the sort of mess left behind by another programmer, another team, a dependency, or the agent itself.</p>
<p>That resembles the programming I actually do, but it remains <strong>my slice of the problem</strong>. Anyone who needs a model to pass every conceivable LeetCode-style hiring test should build a suite for that. A great score on those exercises still says nothing about whether the agent can maintain a project for seven sprints, notice broken authorization, and refuse to accept a doctored test.</p>
<p>You need to test your own use case, with your code, constraints, and failure criteria. That is why I made the <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">entire framework open source</a>: anyone can replace the application, prompts, sabotages, weights, and harness. The ranking published here answers my questions. Use the framework to answer yours.</p>
<p>There is more. I ran the same GPT 5.5, through the same harness and test, and got 100 in one run and 91 in another. That nine-point difference came from single-sample variance alone. LLMs generate probabilistic answers. Two models separated by two or three points are, for all practical purposes, in the same neighborhood.</p>
<blockquote>
  <p><strong>Read Tier A as a band of competent models, not an Olympic podium.</strong> First place in this table did not automatically become the best model in the world.</p>

</blockquote>
<h2>Updated Commercial Ranking<span class="hx:absolute hx:-mt-20" id="updated-commercial-ranking"></span>
    <a href="#updated-commercial-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>To avoid mixing a local GPU, a rented pod, and an API, the table below includes only models I tested through a managed route: subscription, API, OAuth, or a commercial plan. Some have open weights, including Kimi and GLM, but these runs used the vendor&rsquo;s service.</p>
<p>Models from this round are in <strong>bold</strong>. I kept Tier A only, because that is where the serious daily-work choices live.</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Run cost</th>
          <th style="text-align: right">Time</th>
          <th>Harness</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Gemini 4 Argon (high)</strong></td>
          <td style="text-align: right"><strong>100.0</strong></td>
          <td style="text-align: right"><strong>$0 marginal (OAuth)</strong></td>
          <td style="text-align: right"><strong>114 min</strong></td>
          <td>Antigravity</td>
      </tr>
      <tr>
          <td>GPT-6 Astra</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">$30.55</td>
          <td style="text-align: right">100 min</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td>Claude Opus 5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">~$71</td>
          <td style="text-align: right">145 min</td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>Claude Fable 5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">~$50</td>
          <td style="text-align: right">~85 min</td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>Claude Opus 5.5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">$16.63</td>
          <td style="text-align: right">64 min</td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>GPT 5.6 Sol</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">$20.37</td>
          <td style="text-align: right">317 min</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td>GPT 5.6 Terra</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">$9.52</td>
          <td style="text-align: right">80 min</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td>GPT 5.5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">$34.69</td>
          <td style="text-align: right">117 min</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td>Grok 4.6</td>
          <td style="text-align: right">98.5</td>
          <td style="text-align: right">$13.00</td>
          <td style="text-align: right">67 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td><strong>GPT-6.1 Sol</strong></td>
          <td style="text-align: right"><strong>97.0</strong></td>
          <td style="text-align: right"><strong>~$8.12</strong></td>
          <td style="text-align: right"><strong>65 min</strong></td>
          <td>Codex</td>
      </tr>
      <tr>
          <td><strong>Muse Wonder 1.0</strong></td>
          <td style="text-align: right"><strong>97.0</strong></td>
          <td style="text-align: right"><strong>Power plan (flat rate)</strong></td>
          <td style="text-align: right"><strong>126 productive min / nearly 15 days</strong></td>
          <td>Muse Code</td>
      </tr>
      <tr>
          <td><strong>GPT-6.1 Terra</strong></td>
          <td style="text-align: right"><strong>96.8</strong></td>
          <td style="text-align: right"><strong>~$1.69</strong></td>
          <td style="text-align: right"><strong>21 min</strong></td>
          <td>Codex</td>
      </tr>
      <tr>
          <td>Claude Fable 5.1</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: right">~$51</td>
          <td style="text-align: right">133 min</td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>Sakana Fugu Ultra v2</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: right">$122.01</td>
          <td style="text-align: right">294 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>GPT 6 Luna</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: right">~$0.84</td>
          <td style="text-align: right">122 min</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td>GPT 5.6 Luna</td>
          <td style="text-align: right">95.0</td>
          <td style="text-align: right">$10.04</td>
          <td style="text-align: right">123 min</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td>Nex N2.5 Pro</td>
          <td style="text-align: right">94.0*</td>
          <td style="text-align: right">free</td>
          <td style="text-align: right">480 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>GLM 5.3</td>
          <td style="text-align: right">94.0</td>
          <td style="text-align: right">flat-rate plan</td>
          <td style="text-align: right">215 min</td>
          <td>zcode</td>
      </tr>
      <tr>
          <td>DeepSeek V4.1 Flash</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">$1.21</td>
          <td style="text-align: right">172 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td><strong>Kimi K3.1 Pro</strong></td>
          <td style="text-align: right"><strong>92.11</strong></td>
          <td style="text-align: right"><strong>~$12.67</strong></td>
          <td style="text-align: right"><strong>110 min</strong></td>
          <td>Kimi CLI</td>
      </tr>
      <tr>
          <td>MiMo V2.6 Pro</td>
          <td style="text-align: right">92.0</td>
          <td style="text-align: right">$1.22</td>
          <td style="text-align: right">308 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>Claude Sonnet 5</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: right">~$27</td>
          <td style="text-align: right">112 min</td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>GPT 6 Sol</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: right">~$8.35</td>
          <td style="text-align: right">73 min</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td>Gemini 3.8 Flash (OpenRouter)</td>
          <td style="text-align: right">90.5</td>
          <td style="text-align: right">$15.98</td>
          <td style="text-align: right">97 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>Gemini 3.8 Flash (Antigravity)</td>
          <td style="text-align: right">89.5</td>
          <td style="text-align: right">$0 marginal (OAuth)</td>
          <td style="text-align: right">120 min</td>
          <td>Antigravity</td>
      </tr>
      <tr>
          <td>Muse Spark 1.3</td>
          <td style="text-align: right">88.75</td>
          <td style="text-align: right">$13.31</td>
          <td style="text-align: right">150 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td><strong>Claude Sonnet 5.5</strong></td>
          <td style="text-align: right"><strong>88.0</strong></td>
          <td style="text-align: right"><strong>~$3.90</strong></td>
          <td style="text-align: right"><strong>27 min</strong></td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>Grok 4.5</td>
          <td style="text-align: right">88.0</td>
          <td style="text-align: right">$6.19</td>
          <td style="text-align: right">48 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>Claude Opus 4.6</td>
          <td style="text-align: right">87.5</td>
          <td style="text-align: right">$25.64</td>
          <td style="text-align: right">89 min</td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>Kimi K2.7</td>
          <td style="text-align: right">87.25</td>
          <td style="text-align: right">$7.75</td>
          <td style="text-align: right">175 min</td>
          <td>Kimi CLI</td>
      </tr>
      <tr>
          <td>MiMo V2.5 Pro</td>
          <td style="text-align: right">86.5</td>
          <td style="text-align: right">$1.03</td>
          <td style="text-align: right">158 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash</td>
          <td style="text-align: right">86.5</td>
          <td style="text-align: right">$1.17</td>
          <td style="text-align: right">149 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>DeepSeek V4 Flash</td>
          <td style="text-align: right">86.0</td>
          <td style="text-align: right">$0.97</td>
          <td style="text-align: right">111 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>Claude Opus 4.8</td>
          <td style="text-align: right">86.0</td>
          <td style="text-align: right">~$37</td>
          <td style="text-align: right">87 min</td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>Claude Sonnet 4.6</td>
          <td style="text-align: right">85.75</td>
          <td style="text-align: right">$18.64</td>
          <td style="text-align: right">91 min</td>
          <td>Claude Code</td>
      </tr>
      <tr>
          <td>Kimi K3</td>
          <td style="text-align: right">85.0</td>
          <td style="text-align: right">$13.79</td>
          <td style="text-align: right">148 min</td>
          <td>Kimi CLI</td>
      </tr>
      <tr>
          <td>DeepSeek V4 Flash 0731</td>
          <td style="text-align: right">85.0</td>
          <td style="text-align: right">$1.94</td>
          <td style="text-align: right">194 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>GLM 5.3 Flash</td>
          <td style="text-align: right">84.25</td>
          <td style="text-align: right">flat-rate plan</td>
          <td style="text-align: right">296 min</td>
          <td>zcode</td>
      </tr>
      <tr>
          <td>DeepSeek V4 Pro 0813</td>
          <td style="text-align: right">84.0</td>
          <td style="text-align: right">$4.49</td>
          <td style="text-align: right">152 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>Step 3.7 Flash</td>
          <td style="text-align: right">83.75</td>
          <td style="text-align: right">$4.15</td>
          <td style="text-align: right">118 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>Grok 4.7</td>
          <td style="text-align: right">83.5</td>
          <td style="text-align: right">$27.94</td>
          <td style="text-align: right">120 min</td>
          <td>OpenCode</td>
      </tr>
      <tr>
          <td>Genesys PI House</td>
          <td style="text-align: right">83.5</td>
          <td style="text-align: right">~$460</td>
          <td style="text-align: right">68 min</td>
          <td>OpenCode</td>
      </tr>
  </tbody>
</table>
<p>Costs marked with <code>~</code> are equivalents calculated from token counts and public pricing, not the bill I received. Claude Code, Codex, and Muse Code run through subscriptions; Antigravity uses OAuth; zcode charges a flat-rate plan. For Wonder, 126 minutes count only the seven completed runs. Stalled attempts and quota waits are excluded. Compare cost and time carefully, especially across different harnesses.</p>
<p>Terra and Kimi had item #8 marked not applicable because the exact state of that test did not permit a fair evaluation. Their denominator became 38 instead of 40, and the score was normalized. Nex retains its old caveat: it found the problems but left the work uncommitted.</p>
<h2>What Each Model Showed<span class="hx:absolute hx:-mt-20" id="what-each-model-showed"></span>
    <a href="#what-each-model-showed" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Gemini 4 Argon: It Finally Reached the Top<span class="hx:absolute hx:-mt-20" id="gemini-4-argon-it-finally-reached-the-top"></span>
    <a href="#gemini-4-argon-it-finally-reached-the-top" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Argon was the only model in this batch to catch all 14 sabotages before the reveal: <strong>40 out of 40, score 100</strong>. This was the result Gemini needed to join the conversation about the best coding agents without an asterisk.</p>
<p>The <a href="https://blog.google/intl/en-mena/product-updates/explore-get-answers/gemini-4-argon-built-to-solve-your-hardest-problems/"target="_blank" rel="noopener">official Gemini 4 Argon announcement</a> positions it for difficult problems and makes it available through Antigravity and the API. Introductory API pricing is $2 per million input tokens and $10 for output; after November 30, that rises to $4 and $20.</p>
<p>I used Antigravity through the subscription, so the marginal cost was zero. It took 114 minutes and solved everything without waiting for me to point at the bombs.</p>
<h3>GPT-6.1 Sol: Nearly Perfect, No Waste<span class="hx:absolute hx:-mt-20" id="gpt-61-sol-nearly-perfect-no-waste"></span>
    <a href="#gpt-61-sol-nearly-perfect-no-waste" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Sol scored <strong>97.0</strong>. It found 13 of the 14 sabotages on its own and fixed the last one after the reveal. The run took 65 minutes, practically the same as Opus 5.5 and far less than the old GPT 5.6 Sol&rsquo;s 317 minutes.</p>
<p>According to <a href="https://developers.openai.com/api/docs/changelog?mw_entry=2026-10-20-c57e1ddc3363933d"target="_blank" rel="noopener">OpenAI&rsquo;s official pricing</a>, it costs $2 per million input tokens and $10 for output. Applied to the run&rsquo;s token counts, that comes to an equivalent cost of about $8.12.</p>
<p>It did not score 100. There is also no demonstrated practical difference between 97 and 100 in a methodology where the same model has already swung by nine points. The useful result is that Sol remains strong and has become fast.</p>
<h3>Muse Wonder: Excellent Model, Terrible Experience<span class="hx:absolute hx:-mt-20" id="muse-wonder-excellent-model-terrible-experience"></span>
    <a href="#muse-wonder-excellent-model-terrible-experience" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Muse Wonder also scored <strong>97.0</strong>. It found 13 of the 14 sabotages without help and finished with nothing unresolved. The only deduction came from the compound performance item: it fixed the N+1 by itself, but restored the <code>messages(role, created_at)</code> index only after the reveal. That produced the same arithmetic as Sol, with 38 points found spontaneously and two points entering at 40% weight.</p>
<p>The technical result was strong. Wonder independently caught authorization failures, SQL injection, XSS, open CORS, a vulnerable dependency, and a hard-coded secret. It added regression tests as well. Judged solely by the delivered code, it belongs near the top of Tier A.</p>
<h4>Fifteen Days to Finish a Two-Hour Test<span class="hx:absolute hx:-mt-20" id="fifteen-days-to-finish-a-two-hour-test"></span>
    <a href="#fifteen-days-to-finish-a-two-hour-test" class="subheading-anchor" aria-label="Permalink for this section"></a></h4><p>I started the run on <strong>October 13</strong>. The first attempt worked for about 33 minutes before hitting an HTTP 429 quota error. I upgraded to the <strong>Power</strong> plan, <a href="https://dev.meta.ai/products/muse-code"target="_blank" rel="noopener">advertised by Meta at $50 per month with 20 times the basic plan&rsquo;s usage</a>, and still hit the limit again. By October 14, six sprints were complete, but the weekly quota blocked the reveal until the 19th.</p>
<p>I left the benchmark alone for several days after that and ran the final sprint only today, October 28. My own pause is part of that nearly 15-day span. The comparable number in the table is <strong>126 minutes of successful runs</strong>. The actual experience included several attempts where Muse Code went silent for up to an hour while running RSpec and system tests, plus the quota waits.</p>
<blockquote>
  <p><strong>The model scored 97. The product experience was the worst in the entire v4 benchmark.</strong></p>

</blockquote>
<p>Meta saw the problem as well. On October 12, Alexandr Wang <a href="https://x.com/alexandr_wang/status/2109714291062620560"target="_blank" rel="noopener">acknowledged a bug</a> that made Wonder and Wonder Full consume quota too quickly; Meta fixed it and reset the limits. On October 14, version 1.4.8 <a href="https://x.com/mjdouglas/status/2110466975474319865"target="_blank" rel="noopener">received more efficiency fixes</a>, including a bug that routed some Contributor mode users to full-priced models. Another reset followed the next day.</p>
<p>There is an important caveat in my environment. The benchmark isolates <code>HOME</code> and <code>XDG_CONFIG_HOME</code> so no personal skill or plugin can contaminate the test. <a href="https://dev.meta.ai/docs/muse-code/subscriptions"target="_blank" rel="noopener">Meta&rsquo;s current documentation</a> says <code>muse exec</code> without a saved settings file starts with Contributor mode off, which provides less usage in exchange for keeping the code out of training. That detail may have reduced my quota. Even so, the Power plan could not sustain one complete v4 run, and the vendor itself confirmed accounting problems during the same week.</p>
<p>My conclusion stays within what I measured: <strong>Muse Wonder is highly competent, but I would not currently trust the subscription and harness to carry a long session without interruption</strong>. Another user, with a different configuration and after the fixes, may have a better experience.</p>
<h3>GPT-6.1 Terra: The Most Interesting Balance of Cost, Speed, and Quality<span class="hx:absolute hx:-mt-20" id="gpt-61-terra-the-most-interesting-balance-of-cost-speed-and-quality"></span>
    <a href="#gpt-61-terra-the-most-interesting-balance-of-cost-speed-and-quality" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Terra finished at <strong>96.8</strong>, practically tied with Sol, in <strong>21 minutes</strong>. The equivalent cost was just <strong>$1.69</strong>.</p>
<p>The <a href="https://developers.openai.com/api/docs/models/gpt-6.1-terra"target="_blank" rel="noopener">official GPT-6.1 Terra page</a> lists $1 per million input tokens and $5 for output, half Sol&rsquo;s price. It also offers a 1.05-million-token context window, although requests above 272,000 tokens carry a pricing multiplier.</p>
<p>On one item, Terra noticed part of the problem by itself but completed the fix only after the reveal. That cost it the few missing points. Looking at what matters for actual work, <strong>Terra is the strongest result from this round</strong>: quality in Sol&rsquo;s neighborhood, three times faster, and about five times cheaper in this run.</p>
<h3>Kimi K3.1 Pro: Competitive, but It Needs to Move Faster<span class="hx:absolute hx:-mt-20" id="kimi-k31-pro-competitive-but-it-needs-to-move-faster"></span>
    <a href="#kimi-k31-pro-competitive-but-it-needs-to-move-faster" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Kimi K3.1 Pro scored <strong>92.11</strong>, with no sabotage left unresolved at the end. Two groups of problems were closed only after the reveal. The downside was time: <strong>110 minutes</strong>, nearly five times Terra&rsquo;s run, with an equivalent cost of <strong>$12.67</strong>.</p>
<p><a href="https://www.kimi.com/en/blog/kimi-k3-1-pro"target="_blank" rel="noopener">K3.1 Pro</a> has a context window of up to 1 million tokens and will be released with open weights. Kimi also offers a Highspeed route advertised as two to three times faster in exchange for higher pricing and quota consumption. The <a href="https://www.kimi.com/resources/kimi-k3-1-pro-pricing"target="_blank" rel="noopener">public pricing table</a> charges ¥13 per million input tokens and ¥68 for output on the regular route; Highspeed doubles those prices.</p>
<p>I like Kimi and use it every day. The score confirms that it belongs in the competent group. Latency is now the bottleneck. A good model that makes me wait almost two hours for the same campaign Terra completed in 21 minutes loses practical value.</p>
<h3>Claude Sonnet 5.5: The Score Alone Tells the Wrong Story<span class="hx:absolute hx:-mt-20" id="claude-sonnet-55-the-score-alone-tells-the-wrong-story"></span>
    <a href="#claude-sonnet-55-the-score-alone-tells-the-wrong-story" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Sonnet 5.5 scored <strong>88.0</strong>. It caught most items by itself, resolved a few more after the reveal, and failed to finish one compound sabotage: it closed the vulnerability but left a doctored guard test containing <code>assert true</code>. That detail is exactly what my benchmark is designed to catch. The system may be fixed today, but a useless test leaves the door open for a regression tomorrow.</p>
<p>At the same time, it completed the whole run in <strong>27 minutes</strong>, with an equivalent cost of <strong>$3.90</strong>. <a href="https://www.anthropic.com/claude-sonnet-5-5"target="_blank" rel="noopener">Anthropic positions Sonnet 5.5</a> as its everyday-work model, reserving Opus for harder decisions. Pricing is $2 per million input tokens and $10 for output, and the company says generation is more than 30% faster than Sonnet 5.</p>
<p>So no, an 88 does not make Sonnet a bad model. It remains Tier A, runs fast, and costs little. The concrete gotcha from this run is that I would still ask Opus, Fable, or another strong model for a second pass on authorization reviews, security tests, and delicate changes.</p>
<h2>The Most Expensive Model Does Not Need to Run All Day<span class="hx:absolute hx:-mt-20" id="the-most-expensive-model-does-not-need-to-run-all-day"></span>
    <a href="#the-most-expensive-model-does-not-need-to-run-all-day" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This round reinforced an important change in habit. For most work, I no longer need to keep the heaviest and most expensive model running all day.</p>
<p>CRUD, refactoring, tests, documentation, ordinary front-end work, API integrations, database migrations: Sonnet 5.5 and GPT-6.1 Terra can handle them. I would move up to Opus, Fable, Sol, or Astra when the problem justifies it: kernel-driver debugging, particularly treacherous concurrency, firmware, delicate embedded-system tuning, or a security incident where one missed detail costs real money.</p>
<p>Using Fable to change a button color is like firing up an excavator to plant basil. It works. Burning quota on it makes no sense.</p>
<p>Even open source models have come close. In my <a href="/en/2026/10/27/llm-benchmark-best-open-source-llms-for-home-hardware/">recent Qwen3.8 Flash-Next test on a single RTX 5090</a>, Q2_0 scored 100 in all six hard-test runs, three on Strata and three on Basalt. With Basalt, output reached 400 tokens per second while also using system RAM for the experts.</p>
<p>That test is considerably easier than v4, so the scores cannot be mixed. Even on full v4, though, a local Qwen has already reached the Tier A neighborhood. The distance is no longer an abyss.</p>
<h2>The Bottleneck Has Moved: Speed and Quotas<span class="hx:absolute hx:-mt-20" id="the-bottleneck-has-moved-speed-and-quotas"></span>
    <a href="#the-bottleneck-has-moved-speed-and-quotas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I use the top models every day and have switched among them in the same project for weeks. Claude in the morning, Codex later, Kimi when a quota gets tight, Gemini sometimes. I have yet to find a measurable advantage in staying loyal to one vendor.</p>
<p>What I notice immediately is <strong>speed</strong>. GLM 5.3 and DeepSeek V4.1 are good, but they feel slow next to Terra or Sonnet. Once you get used to fast responses, waiting for the agent to think and edit becomes the irritating part of the job.</p>
<p>The other limit is quota. Five-hour windows and weekly or monthly limits vary by vendor and plan, but the practical result is the same: my weekly quota rarely lasts a whole week. Fable and Astra drain the reserve even faster. I switch because I have to, not because I collect logos in my terminal.</p>
<p>That is exactly why I created <a href="https://aimemory.sh"target="_blank" rel="noopener">ai-memory</a>. Project memory should not belong to Claude, Codex, Kimi, or Gemini. With <code>ai-memory run</code>, I can continue the same line of work in another harness without a manual handoff, and consolidated decisions survive context compaction.</p>
<blockquote>
  <p><strong>Models and harnesses are rented. The session, decisions, and project memory need to remain yours.</strong></p>

</blockquote>
<p>I covered the architecture and open format in the <a href="/en/2026/09/02/ai-memory-2-0-best-memory-system-for-agents-and-teams/">ai-memory 2.0 article</a>. The more interchangeable the models become, the more important frictionless switching gets.</p>
<h2>What About the Famous Benchmarks?<span class="hx:absolute hx:-mt-20" id="what-about-the-famous-benchmarks"></span>
    <a href="#what-about-the-famous-benchmarks" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Keep an eye on <a href="https://www.swebench.com/"target="_blank" rel="noopener">SWE-bench</a>, which uses real issues from GitHub projects, and <a href="https://www.tbench.ai/"target="_blank" rel="noopener">Terminal-Bench</a>, which measures agents completing tasks in a terminal. They help expose regressions, improvements in tool use, and edge cases where a model family still struggles.</p>
<p>Just do not confuse them with your job. SWE-bench Verified has 500 selected problems. Terminal-Bench v4 has dozens of difficult, reviewed tasks. Neither one knows what your monorepo looks like, the quality of your tests and documentation, your company&rsquo;s internal library, or that legacy API nobody dares touch.</p>
<p>My benchmark does not know either.</p>
<p>If you need a model for a very specific constraint, build your own test with real examples. Otherwise, choose any Tier A model, use it for a week, and get back to work.</p>
<h2>What About This GLM 5.5?<span class="hx:absolute hx:-mt-20" id="what-about-this-glm-55"></span>
    <a href="#what-about-this-glm-55" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There is a rumor going around about &ldquo;GLM 5.5 coming soon.&rdquo; As of today, October 28, <strong>there is no official announcement with that name, date, or price</strong>. <a href="https://docs.z.ai/release-notes/new-released"target="_blank" rel="noopener">Z.ai&rsquo;s official release page</a> still lists the GLM 5.3 family as its latest.</p>
<p>Jie Tang, Z.ai&rsquo;s founder, replied <em>&ldquo;won&rsquo;t take that long&rdquo;</em> when Elon Musk estimated that China would reach Fable-level models in the first quarter of 2027. That suggests he expects the capability sooner, but it does not promise a Z.ai release, much less a model called GLM 5.5 by December. I am not turning a rumor into a ranking row.</p>
<p>Kimi K3.1 Pro is already in Tier A. Qwen and GLM can already fit on owned hardware through quantization. Gemini has finally caught the leaders.</p>
<p>Sonnet and Terra handle everyday work for much less. Competition is compressing everything into the same range.</p>
<h2>Commoditized. Good.<span class="hx:absolute hx:-mt-20" id="commoditized-good"></span>
    <a href="#commoditized-good" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I no longer expect enormous jumps from every commercial release. I expect a model to get somewhat faster, cheaper, more token-efficient, with a better quota and a few edge cases fixed. That is what a maturing market looks like.</p>
<p>My advice today differs from what I would have said a few months ago:</p>
<ol>
<li>Pick any Tier A model that fits your plan.</li>
<li>Use Sonnet or Terra for ordinary work.</li>
<li>Save Opus, Fable, Sol, or Astra for problems that deserve them.</li>
<li>Keep a second option for when the quota runs out.</li>
<li>Install <a href="https://aimemory.sh"target="_blank" rel="noopener">ai-memory</a> so no harness owns your history.</li>
<li>Stop following rankings like a sports league.</li>
</ol>
<p>Benchmarks remain useful for detecting when a family reaches the top group, as Argon just did. After that, the difference between first, fourth, and tenth place becomes too small, noisy, and task-dependent.</p>
<p>Frontier LLMs have become commodities. You are not missing a revolution because you went a week without trying Tuesday&rsquo;s release. Pick a good one, keep your options open, and get back to programming.</p>
<h2>A Broader Ranking: Engineering Breadth Index<span class="hx:absolute hx:-mt-20" id="a-broader-ranking-engineering-breadth-index"></span>
    <a href="#a-broader-ranking-engineering-breadth-index" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>After finishing this article, I found a better question. What happens when I combine my result with benchmarks that measure other parts of the job?</p>
<p>I built a secondary index from four surfaces:</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Weight</th>
          <th>Benchmark</th>
          <th>What It Measures</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">35%</td>
          <td><a href="https://labs.scale.com/leaderboard/swe_bench_pro_public_v2?tab=full"target="_blank" rel="noopener">SWE-bench Pro V2</a></td>
          <td>Resolving issues in professional repositories without introducing regressions</td>
      </tr>
      <tr>
          <td style="text-align: right">30%</td>
          <td>llm-coding-benchmark v4</td>
          <td>A long project, accumulated context, vigilance, and sabotage</td>
      </tr>
      <tr>
          <td style="text-align: right">25%</td>
          <td><a href="https://www.vals.ai/benchmarks/terminal-bench-4"target="_blank" rel="noopener">Terminal-Bench 4.0</a></td>
          <td>Terminal tasks graded by challenge-specific verifiers</td>
      </tr>
      <tr>
          <td style="text-align: right">10%</td>
          <td><a href="https://livecodebench.github.io/leaderboard.html"target="_blank" rel="noopener">LiveCodeBench v6</a></td>
          <td>Short, well-defined algorithmic problems</td>
      </tr>
  </tbody>
</table>
<p>The raw percentages cannot be added. Terminal-Bench 4.0&rsquo;s leader scores 65.15; several models scored 100 on mine. I first normalized every result against the best score published by that benchmark in the snapshot:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">normalized score = 100 × model score / best benchmark score</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Then I applied a weighted geometric mean. It penalizes a model with a major weakness in one dimension instead of letting one perfect score hide the hole.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">index = 100 × exp(
</span></span><span class="line"><span class="cl">  0.35 × ln(SWE Pro) +
</span></span><span class="line"><span class="cl">  0.30 × ln(Akita v4) +
</span></span><span class="line"><span class="cl">  0.25 × ln(Terminal-Bench) +
</span></span><span class="line"><span class="cl">  0.10 × ln(LiveCodeBench)
</span></span><span class="line"><span class="cl">)</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Each component enters the formula as a number from zero to one. The index measures capability. Price, duration, tok/s, and quotas stay out and belong in a separate practicality table. Mixing quality with dollars would let a weak, cheap model look technically stronger.</p>
<h3>Results as of October 28, 2026<span class="hx:absolute hx:-mt-20" id="results-as-of-october-28-2026"></span>
    <a href="#results-as-of-october-28-2026" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The first honest limitation showed up immediately. As of October 28, the official LiveCodeBench v6 leaderboard still had no results for this model generation. <strong>A complete official four-dimensional ranking does not exist today.</strong></p>
<p>I calculated a provisional index from the other three benchmarks, covering 90% of the original weight. I used the October 28 SWE-bench Pro V2 snapshot and the October 26 Terminal-Bench 4.0 update. The available weights were renormalized to 38.89% for SWE-bench Pro V2, 33.33% for my v4, and 27.78% for Terminal-Bench 4.0. Only models with an exact result in all three qualified. Kimi K3 does not stand in for K3.1, and GPT-5.6 Terra does not stand in for 6.1 Terra.</p>
<h3>Provisional Ranking<span class="hx:absolute hx:-mt-20" id="provisional-ranking"></span>
    <a href="#provisional-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th style="text-align: right">#</th>
          <th>Model</th>
          <th style="text-align: right">Akita v4</th>
          <th style="text-align: right">SWE Pro V2</th>
          <th style="text-align: right">Terminal 4.0</th>
          <th>SWE Pro Harness</th>
          <th style="text-align: right">Coverage</th>
          <th style="text-align: right">Index</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>GPT-6 Astra</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">96.90</td>
          <td style="text-align: right">59.60</td>
          <td>Codex</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>96.6</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Gemini 4 Argon</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">99.22</td>
          <td style="text-align: right">57.58</td>
          <td>mini-SWE-agent</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>96.6</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td>Claude Fable 5.1</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: right">99.10</td>
          <td style="text-align: right">58.08</td>
          <td>Claude Code</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>95.3</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td>Claude Opus 5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">99.40</td>
          <td style="text-align: right">53.53</td>
          <td>Claude Code</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>94.7</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Claude Sonnet 5.5</td>
          <td style="text-align: right">88.0</td>
          <td style="text-align: right">95.79</td>
          <td style="text-align: right">64.14</td>
          <td>mini-SWE-agent</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>94.1</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">6</td>
          <td>GPT-6.1 Sol</td>
          <td style="text-align: right">97.0</td>
          <td style="text-align: right">96.11</td>
          <td style="text-align: right">55.05</td>
          <td>mini-SWE-agent</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>93.2</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td>GPT-5.6 Sol</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">95.50</td>
          <td style="text-align: right">37.88</td>
          <td>Codex</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>84.7</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>GLM 5.3</td>
          <td style="text-align: right">94.0</td>
          <td style="text-align: right">95.60</td>
          <td style="text-align: right">38.89</td>
          <td>mini-SWE-agent</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>83.6</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>GPT-5.6 Terra</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">92.37</td>
          <td style="text-align: right">22.73</td>
          <td>Codex</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>72.5</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td>Gemini 3.8 Flash</td>
          <td style="text-align: right">89.5</td>
          <td style="text-align: right">94.86</td>
          <td style="text-align: right">19.70</td>
          <td>mini-SWE-agent</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>67.9</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>Kimi K3</td>
          <td style="text-align: right">85.0</td>
          <td style="text-align: right">97.70</td>
          <td style="text-align: right">17.17</td>
          <td>mini-SWE-agent</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>65.0</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">12</td>
          <td>Claude Sonnet 5</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: right">93.15</td>
          <td style="text-align: right">10.61</td>
          <td>Claude Code</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>57.1</strong></td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td>Muse Spark Open</td>
          <td style="text-align: right">69.5</td>
          <td style="text-align: right">95.02</td>
          <td style="text-align: right">6.57</td>
          <td>mini-SWE-agent</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>46.0</strong></td>
      </tr>
  </tbody>
</table>
<p>Terminal-Bench 4.0 uses mini-SWE-agent for every row. SWE-bench Pro V2 mixes mini-SWE-agent with the native harnesses shown in the table. In my v4, each row keeps the route documented for that run. Gemini 3.8 Flash is the Antigravity run; Muse Spark Open ran self-hosted on four B300s through OpenCode.</p>
<p>This ranks <strong>models under the conditions published by each benchmark</strong>, with real harness influence. It does not scientifically isolate model weights alone.</p>
<h3>Why the List Stops at 13<span class="hx:absolute hx:-mt-20" id="why-the-list-stops-at-13"></span>
    <a href="#why-the-list-stops-at-13" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I wanted at least 20 models, but the honest intersection ends here. SWE-bench Pro V2 publishes 16 results. Only 13 of them have the exact same model tested on Terminal-Bench 4.0 and my v4. The next candidates all hit a gap:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Akita v4</th>
          <th style="text-align: right">SWE Pro V2</th>
          <th style="text-align: right">Terminal 4.0</th>
          <th>Missing Result</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Claude Opus 5.5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">65.15</td>
          <td>SWE Pro V2</td>
      </tr>
      <tr>
          <td>Kimi K3.1 Pro</td>
          <td style="text-align: right">92.11</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">63.64</td>
          <td>SWE Pro V2</td>
      </tr>
      <tr>
          <td>GPT-6.1 Terra</td>
          <td style="text-align: right">96.8</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">49.49</td>
          <td>SWE Pro V2</td>
      </tr>
      <tr>
          <td>Claude Fable 5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">41.41</td>
          <td>SWE Pro V2</td>
      </tr>
      <tr>
          <td>GPT-6 Sol</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">44.44</td>
          <td>SWE Pro V2</td>
      </tr>
      <tr>
          <td>DeepSeek V4.1 Flash 1017 (B300)</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">31.82</td>
          <td>SWE Pro V2</td>
      </tr>
      <tr>
          <td>GLM 5.3 Flash</td>
          <td style="text-align: right">84.25</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">37.37</td>
          <td>SWE Pro V2</td>
      </tr>
      <tr>
          <td>Muse Wonder 1.0</td>
          <td style="text-align: right">97.0</td>
          <td style="text-align: right">96.73</td>
          <td style="text-align: right">n/a</td>
          <td>Terminal 4.0</td>
      </tr>
      <tr>
          <td>Claude Haiku 5.5</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">87.23</td>
          <td style="text-align: right">36.36</td>
          <td>Akita v4</td>
      </tr>
      <tr>
          <td>Inkling</td>
          <td style="text-align: right">n/a</td>
          <td style="text-align: right">89.88</td>
          <td style="text-align: right">0.51</td>
          <td>Akita v4</td>
      </tr>
  </tbody>
</table>
<p>I could renormalize two scores and manufacture positions 14 through 22. The result would look neat and mislead readers. A model measured only on my v4 and Terminal-Bench would cover 55% of the original index; one measured on SWE Pro and Terminal would cover 60%. Sorting both as if they had taken the same exam would turn missing data into false precision.</p>
<p>I will not use Kimi K3 in place of K3.1, GPT-5.6 Terra in place of 6.1 Terra, or any older relative from the same family to fill a hole either. The index can grow when those results are published or I run the missing models. Until then, 13 is the defensible limit.</p>
<h3>What Changed When We Widened the Lens<span class="hx:absolute hx:-mt-20" id="what-changed-when-we-widened-the-lens"></span>
    <a href="#what-changed-when-we-widened-the-lens" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Astra finished 0.036 points ahead of Argon before rounding: 96.5955 versus 96.5591. Both appear as 96.6 in the table and amount to a practical tie. Fable 5.1, Opus 5, Sonnet 5.5, and Sol 6.1 followed close behind. Differences below three points belong in the same practical band, especially when combining benchmarks with different confidence intervals and harnesses.</p>
<p>Sonnet 5.5 is the interesting case. It scored only 88 on my test but reached 64.14 on Terminal-Bench, almost the current ceiling. The broader index pulled it up to 94.1. GPT-5.6 Sol shows the reverse: 100 on my test and only 37.88 on Terminal-Bench, finishing at 84.7.</p>
<p>That is why combining surfaces helps. A benchmark sees what it was designed to see. Three benchmarks remain far from measuring everything, but they make it harder for one narrow specialty to masquerade as general competence.</p>
<p>The earlier conclusion still holds. The top six are compressed between 93.2 and 96.6. We widened the lens, and the supposed absolute champion still failed to appear.</p>
<h2>Conclusion: Pick a Good One and Get to Work<span class="hx:absolute hx:-mt-20" id="conclusion-pick-a-good-one-and-get-to-work"></span>
    <a href="#conclusion-pick-a-good-one-and-get-to-work" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The composite index reinforced this article&rsquo;s thesis. Widening the test changes the order, exposes a few weaknesses, and still leaves the leading group tightly packed. Astra and Argon finished 0.036 points apart. Four other models finished within 3.5 points. Change the weights, the task set, or the benchmark version, and they may trade places again.</p>
<p>That makes the decision much simpler. First identify which models have reached a competent range for your kind of work. Then choose based on speed, price, quotas, privacy, availability, and harness quality. Those differences affect your entire day. One extra point in a table rarely does.</p>
<p>Benchmarks remain useful for detecting regressions, spotting when a family reaches Tier A, and finding blind spots. Turning a ranking into a sports rivalry or treating this week&rsquo;s leader as a universal truth is a waste of time.</p>
<p>Today I switch among the best models without ceremony. The project, tests, Git history, and session memory must survive the switch. That is why I keep insisting on <a href="https://aimemory.sh"target="_blank" rel="noopener">ai-memory</a>: the valuable asset is the history of the work, not the provider renting you a context window. Pick any competent model, keep an exit route, and get back to solving real problems.</p>
]]></content:encoded><category>llm-benchmarks</category><category>llms</category><category>coding-agents</category><category>ai-memory</category></item><item><title>LLM Benchmark: What Are the Best Open Source LLMs for Home Hardware?</title><link>https://www.akitaonrails.com/en/2026/10/27/llm-benchmark-best-open-source-llms-for-home-hardware/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/27/llm-benchmark-best-open-source-llms-for-home-hardware/</guid><pubDate>Tue, 27 Oct 2026 13:00:00 -0300</pubDate><description>&lt;p&gt;In the &lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/"&gt;last LLM Benchmark about open source models&lt;/a&gt;, I pushed things as far as was reasonable. I rented B300s, H200s, four-GPU pods, ran almost 70 rounds, and spent more than $6,000 on the whole campaign. It produced strong candidates such as DeepSeek V4.1 Flash, GLM 5.3 Flash, and Qwen3.8 Flash-Next, all close to frontier models in my programming test.&lt;/p&gt;
&lt;p&gt;The machine remained the problem. A 510 GB model that needs four B300s may be open source on GitHub, but it is still beyond the reach of anyone who wants to run an AI in a home office.&lt;/p&gt;</description><content:encoded><![CDATA[<p>In the <a href="/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/">last LLM Benchmark about open source models</a>, I pushed things as far as was reasonable. I rented B300s, H200s, four-GPU pods, ran almost 70 rounds, and spent more than $6,000 on the whole campaign. It produced strong candidates such as DeepSeek V4.1 Flash, GLM 5.3 Flash, and Qwen3.8 Flash-Next, all close to frontier models in my programming test.</p>
<p>The machine remained the problem. A 510 GB model that needs four B300s may be open source on GitHub, but it is still beyond the reach of anyone who wants to run an AI in a home office.</p>
<p>I went back to my RTX 5090 and Strix Halo. Instead of repeating the full v4 benchmark on dozens of models that we already know will not fit or run fast enough, I took the most promising candidate and compared <strong>its quantizations</strong>. Which version preserves enough quality without turning every interaction into a wait of several minutes?</p>
<p>The result surprised me: <strong>the 2-bit version won</strong>. I then repeated the test with <a href="https://github.com/jesdga95/basalt"target="_blank" rel="noopener">Basalt</a>, a Strata fork specialized for Blackwell GPUs. The model kept getting everything right, while generation reached <strong>400 tokens per second</strong>. The quantization did not change; the engine changed the result substantially.</p>
<h2>The RTX 3090 and 4090 got a second wind<span class="hx:absolute hx:-mt-20" id="the-rtx-3090-and-4090-got-a-second-wind"></span>
    <a href="#the-rtx-3090-and-4090-got-a-second-wind" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before my results, the community found a limitation that could be removed. On GeForce RTX 20 cards, some FP16 Tensor Core operations with FP32 accumulation run at half the theoretical issue rate per cycle of their professional equivalents. On RTX 30 and 40 cards, the limit also affects BF16.</p>
<p>The hardware is there. Two internal registers select the speed, and the normal driver does not have enough privilege to change them.</p>
<p>The <a href="https://github.com/Zagitta/gpu-unlock"target="_blank" rel="noopener">gpu-unlock</a> project found a way to change those registers before the NVIDIA driver takes over the card. On Ampere, it exploits a buffer overflow in the signed Booter that authenticates and loads GSP-RM. Nothing is written to the VBIOS. To restore stock behavior, remove the activation parameter and fully power the machine off, because the selectors reset when the card loses power. If the parameter remains active, the module reapplies the unlock on the next boot.</p>
<p>It also requires Linux, initramfs, and a lot of care. I would not install this on a production workstation without reading the code and understanding the risk.</p>
<p>This is a community hack with no official NVIDIA support. You install it at your own risk. Its value for LLMs is faster prefill when the engine uses this exact Tensor Core path. Other compute applications, including some image-generation pipelines, may also change in performance. Games depend on different GPU paths and bottlenecks, so do not expect higher frame rates from it.</p>
<p>On an RTX 3090 at 420 W, <a href="https://github.com/Zagitta/gpu-unlock/issues/85"target="_blank" rel="noopener">a controlled test</a> measured FP16 with FP32 accumulation going from 76.396 to 125.006 TFLOPS; BF16 went from 76.994 to 127.923. On the 4090, an implementation that is still experimental measured roughly twice the FP16 and BF16 instruction issue rate.</p>
<p>Doubling TFLOPS does not double your LLM. The <a href="https://dev.to/orca_forge/why-gpu-unlock-speeds-up-rtx-3090-prefill-but-barely-changes-decode-4572"target="_blank" rel="noopener">test that prompted this discussion</a> separated the two phases:</p>
<ul>
<li><strong>Prefill</strong> is when the model reads the whole prompt. Many tokens are available at once, so the engine can build large parallel matrix operations. <a href="https://github.com/Zagitta/gpu-unlock/issues/33"target="_blank" rel="noopener">One 3090 gained 14.4%</a> on a 16K-token workload, while two modified 3080s gained <a href="https://github.com/Zagitta/gpu-unlock/issues/15"target="_blank" rel="noopener">33% to 36% with vLLM</a>.</li>
<li><strong>Decode</strong> is when the model generates one token after another. With a quantized LLM using expert offload, this phase is constrained mainly by memory bandwidth, RAM, PCIe, and the expert cache. The measured change stayed within noise.</li>
</ul>
<p>The gain varies substantially with the engine, quantization, and prompt size. On the dual 3080 setup, Qwen3.8 Flash-Next Q4_K_XL gained only 0.5% to 0.8% at 8K, but reached 12% or 13% at 32K and 128K. On a 3090 running an IQ3_S MoE, a workload near 32K did not change. The computation path used by a quantization may never touch the FP16/BF16 path that was unlocked.</p>
<blockquote>
  <p>gpu-unlock accelerates a specific Tensor Core path. It may reduce the wait when reading large prompts, but it does not turn 24 GB into 96 GB or create memory bandwidth.</p>

</blockquote>
<p>Even with that caveat, the 3090 and 4090 became more interesting for local inference. A used <a href="https://www.nvidia.com/en-us/geforce/graphics-cards/30-series/rtx-3090-3090ti/"target="_blank" rel="noopener">RTX 3090</a> still has 24 GB of VRAM, NVLink in its generation, and 936 GB/s of bandwidth. The community measured Qwen3.8 Flash-Next at roughly <a href="https://github.com/sybil-solutions/local-ai-registry/pull/212"target="_blank" rel="noopener">75 tok/s with IQ3_S and 100 tok/s with Q2_0</a> on one 3090. With two cards, reports range from <a href="https://github.com/ruashots/flashnext-2x3090"target="_blank" rel="noopener">90 to 120 tok/s</a>, depending on the configuration and context size. Those are community results, not measurements from this round.</p>
<h2>Why I chose Qwen3.8 Flash-Next<span class="hx:absolute hx:-mt-20" id="why-i-chose-qwen38-flash-next"></span>
    <a href="#why-i-chose-qwen38-flash-next" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In v4, the open candidates that really interested me were:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>Where I ran it</th>
          <th style="text-align: right">v4 score</th>
          <th style="text-align: right">Speed</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>DeepSeek V4.1 Flash</td>
          <td>4x B300, native checkpoint</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">174.8 tok/s</td>
      </tr>
      <tr>
          <td>GLM 5.3 Flash</td>
          <td>1x B300, NVFP4</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">142 tok/s</td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash-Next</td>
          <td>1x B300, NVFP4</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">195 tok/s</td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash-Next</td>
          <td>RTX 5090, IQ3_S</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: right">159.2 tok/s</td>
      </tr>
  </tbody>
</table>
<p>The three tied within the noise margin. Only Qwen repeated that quality on consumer hardware. Its main model is a 125-billion-parameter MoE with roughly 6 billion active parameters per token, plus 51 billion parameters in n-gram embeddings and a 4-billion-parameter MTP head. <a href="https://github.com/Niko1221/Strata"target="_blank" rel="noopener">Strata</a> keeps the most frequently used experts on the GPU, keeps the rest in RAM for the CPU to compute, reads the n-gram table from the SSD, and uses the model&rsquo;s own MTP layer to speculate the next tokens.</p>
<p>DeepSeek V4.1&rsquo;s backbone and Engram add up to about 748 billion parameters: 552 billion in the backbone and 196 billion in Engram. The published checkpoint has roughly 763 billion parameters in total. I served its native mixed FP4/FP8 version, about 510 GB, on the four-B300 pod.</p>
<p>I also managed to start a 2-bit version on the 5090 using Strata&rsquo;s dedicated engine. It generated around <strong>17 tokens per second</strong>. It runs. It is out of the race for a programming agent.</p>
<p>The GLM 5.3 Flash NVFP4 checkpoint was around 198 GB and ran on the B300. This repository has no consumer configuration that I measured and can recommend. The smaller GLM 4.7 Flash had already scored 24 on the 5090 and 33.5 on the B300 in the previous benchmark. Spending days forcing the wrong family to fit would not produce useful information.</p>
<p>I also left out Qwen 4 and Llama by choice. This round asks a narrow question: <strong>which version of the model that already proved its quality works best on the two machines I own?</strong></p>
<h2>What I tested<span class="hx:absolute hx:-mt-20" id="what-i-tested"></span>
    <a href="#what-i-tested" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>All the code, prompts, hidden tests, and results are in <a href="https://github.com/akitaonrails/llm-opensource-benchmark"target="_blank" rel="noopener">llm-opensource-benchmark</a>. I tested four Qwen3.8 Flash-Next versions:</p>
<table>
  <thead>
      <tr>
          <th>Quantization</th>
          <th style="text-align: right">Model files</th>
          <th>Idea</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Q2_0</td>
          <td style="text-align: right">~62 GiB</td>
          <td>2 bits, smaller and more aggressive</td>
      </tr>
      <tr>
          <td>IQ3_XXS</td>
          <td style="text-align: right">~71 GiB</td>
          <td>3 bits, optimized for size</td>
      </tr>
      <tr>
          <td>IQ3_S</td>
          <td style="text-align: right">~78 GiB</td>
          <td>3 bits, more precision</td>
      </tr>
      <tr>
          <td>UD-Q4_K_XL</td>
          <td style="text-align: right">~104 GiB</td>
          <td>4 bits, preserves more of the weights</td>
      </tr>
  </tbody>
</table>
<p>The Strata files include a shared PLE component, so the full size does not fit directly in VRAM. The engine distributes experts between the GPU and RAM. On Basalt, I used the project&rsquo;s own packs: one 64.9 GiB <code>.basalt</code> file for Q2_0 and an 81.0 GiB file for IQ3_S. Each file already includes the weights, tokenizer, MTP, expert profile, and vision projector.</p>
<p>For the first RTX 5090 round, I used Strata&rsquo;s CUDA backend with:</p>
<ul>
<li>4 GiB of VRAM reserved for Hyprland, the browser, and the terminal;</li>
<li><code>int8</code> KV cache, a 128K maximum context, and 32K resident on the GPU;</li>
<li>an elastic expert cache;</li>
<li>four-token speculation with the model&rsquo;s MTP.</li>
</ul>
<p>I then ran Q2_0 and IQ3_S on Basalt, on the same 5090 and with the same 131,072-token maximum context and <code>int8</code> KV. I reserved 4,608 MiB because Basalt counts its working buffers against that margin. Free VRAM stayed between 3.6 and 4.4 GB during the tests.</p>
<p>On the Strix Halo, I used the <code>hip-halo</code> backend. That machine has 64 GB reserved for the GPU and 31 GB of GTT mapped over system RAM; the engine&rsquo;s RAM limit was 61.9 GiB. Since it is headless, I gave the entire GPU to the model and kept 8 GiB of headroom for the conversation cache.</p>
<p>The Strata measurements use two different backends underneath, CUDA on NVIDIA and HIP/ROCm on AMD, with the same engine and the same OpenAI-compatible API. Basalt adds an engine comparison on the 5090, using the same OpenCode, prompts, and grading.</p>
<h2>Methodology<span class="hx:absolute hx:-mt-20" id="methodology"></span>
    <a href="#methodology" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I started with a speed test in three situations:</p>
<ol>
<li>a cold 4K-token prompt;</li>
<li>a cold prompt labeled 32K, which this model&rsquo;s tokenizer counted as 42,400 tokens;</li>
<li>a continuation of the same conversation, reusing the cache.</li>
</ol>
<p>Each one generates 256 tokens. The runner measures time to first token, prompt processing, generation, VRAM, RAM, power, and temperature.</p>
<h3>What each speed number means<span class="hx:absolute hx:-mt-20" id="what-each-speed-number-means"></span>
    <a href="#what-each-speed-number-means" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>When someone says an LLM runs at 200 tokens per second, they are almost always talking only about generation. An agent session goes through different phases, and each phase hits a different bottleneck.</p>
<p><strong>Prefill</strong> is the initial reading of the prompt. The model must process the harness instructions, conversation history, files, and your question before producing its first word. Since all those tokens are available at once, the GPU can process large matrices in parallel.</p>
<p>This phase makes better use of Tensor Cores and raw compute. The larger the context, the more it matters.</p>
<table>
  <thead>
      <tr>
          <th>Metric</th>
          <th>What it measures</th>
          <th>What you feel</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Prompt tok/s</td>
          <td>Prefill throughput, or how many input tokens are read per second</td>
          <td>Time to digest new context</td>
      </tr>
      <tr>
          <td>TTFT (<em>time to first token</em>)</td>
          <td>Total time between sending the request and receiving the first token</td>
          <td>The pause before the answer starts</td>
      </tr>
      <tr>
          <td>Decode or output tok/s</td>
          <td>Generation speed after the first token</td>
          <td>Pace of text and tool calls</td>
      </tr>
      <tr>
          <td>TPOT (<em>time per output token</em>)</td>
          <td>Time per generated token, usually reported at p50 and p99 (or p95)</td>
          <td>Response consistency; a high tail percentile exposes stalls</td>
      </tr>
      <tr>
          <td>Wall time</td>
          <td>Time for the whole task, including tools, tests, retries, and generated text</td>
          <td>Actual agent productivity</td>
      </tr>
  </tbody>
</table>
<p>The <strong>KV cache</strong> stores intermediate states for tokens that have already been processed. On a continuation of the same conversation, the model reuses that state instead of reading everything again. That is why the append test reaches tens of thousands of prompt tokens per second and receives the first token in roughly half a second. That number measures cache reuse; comparing it with cold prefill would be dishonest.</p>
<p>The KV cache also grows with the conversation and competes with weights, experts, and buffers for memory. Here it uses <code>int8</code>, with 32K resident on the 5090. Advertised maximum context, context that fits, and context that stays fast are three different numbers.</p>
<p><strong>Speculative decoding</strong> uses a draft layer to propose several tokens and lets the main model verify the batch. Output tok/s goes up when the acceptance rate is good. The benefit vanishes when the draft misses too often. The Strata speeds already include MTP with four-token speculation. Basalt also uses the MTP included in its pack, with its own speculation mechanism and defaults.</p>
<p>One metric is missing because I did not measure it here: <strong>concurrency</strong>. Every number in this article comes from a single stream. A server can handle several sessions and raise aggregate throughput, while each user will usually receive fewer tokens per second.</p>
<p>For individual use, single-stream performance and wall time are what matter. A team must measure simultaneous sessions and per-user latency, as I did in the <a href="/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/">B300 and H200 test</a>.</p>
<p>Then came two programming tests using OpenCode 2.1.4. The model receives a small Python codebase, works in one continuous session, and never sees the hidden tests. Everything runs inside Bubblewrap, without network access, with a limited filesystem and a local gateway that accepts calls only to the expected model.</p>
<p>The first canary has three turns and 9 hidden tests. The model must implement a log analyzer, fix bugs, and handle changed requirements.</p>
<p>The hard canary has four turns and 36 hidden tests. It is a payment reconciler with decisions buried inside a roughly 79K-token history, one decision corrected later, rejected proposals used as distractions, money that requires exact decimals, and new rules that interact with earlier ones. With OpenCode&rsquo;s system prompt, the first turn approaches 83K tokens.</p>
<h3>A separate yardstick from benchmark v4<span class="hx:absolute hx:-mt-20" id="a-separate-yardstick-from-benchmark-v4"></span>
    <a href="#a-separate-yardstick-from-benchmark-v4" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>These canaries are much smaller and easier. In v4, the model works on a Rails application for seven sprints while a reviewer injects 14 security and correctness defects. The score measures how many defects it finds and fixes on its own before they are revealed. It is a vigilance test with much more code, more tools, and more opportunities to lose track.</p>
<p>Here I use two small Python codebases, three or four turns, and hidden functional tests. I built this yardstick to compare <strong>quantizations of the same Qwen</strong> and find out whether reducing the bits breaks requirements, context retention, or process. The comparison ends there. Qwen, Opus, GPT, DeepSeek, and the other model families remain a job for v4.</p>
<p>A score of 100 in this article belongs to a different scale, with no equivalence to 100 in v4. It also does not make Q2_0 &ldquo;better&rdquo; than the IQ3_S version that scored 91 in v4. V4 selected Qwen as the candidate; this smaller test selects which Qwen file is worth loading at home.</p>
<blockquote>
  <p>Speed without quality only makes the model fail faster. That is why I measured them separately.</p>

</blockquote>
<h2>Speed ranking<span class="hx:absolute hx:-mt-20" id="speed-ranking"></span>
    <a href="#speed-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>RTX 5090 with Strata, 4 GiB reserved for the desktop<span class="hx:absolute hx:-mt-20" id="rtx-5090-with-strata-4-gib-reserved-for-the-desktop"></span>
    <a href="#rtx-5090-with-strata-4-gib-reserved-for-the-desktop" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th>Quantization</th>
          <th style="text-align: right">Generation</th>
          <th style="text-align: right">Long-input processing</th>
          <th style="text-align: right">First token</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Q2_0</strong></td>
          <td style="text-align: right"><strong>223 to 259 tok/s</strong></td>
          <td style="text-align: right"><strong>6,158 tok/s</strong></td>
          <td style="text-align: right"><strong>6.9 s</strong></td>
      </tr>
      <tr>
          <td>IQ3_XXS</td>
          <td style="text-align: right">196 to 241 tok/s</td>
          <td style="text-align: right">5,084 tok/s</td>
          <td style="text-align: right">8.3 s</td>
      </tr>
      <tr>
          <td>IQ3_S</td>
          <td style="text-align: right">158 to 208 tok/s</td>
          <td style="text-align: right">6,233 tok/s</td>
          <td style="text-align: right">6.8 s</td>
      </tr>
      <tr>
          <td>UD-Q4_K_XL</td>
          <td style="text-align: right">44 to 52 tok/s</td>
          <td style="text-align: right">2,300 tok/s</td>
          <td style="text-align: right">19 s</td>
      </tr>
  </tbody>
</table>
<h3>RTX 5090 with Basalt<span class="hx:absolute hx:-mt-20" id="rtx-5090-with-basalt"></span>
    <a href="#rtx-5090-with-basalt" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th>Quantization</th>
          <th style="text-align: right">Generation</th>
          <th style="text-align: right">Long-input processing</th>
          <th style="text-align: right">First token</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Q2_0</strong></td>
          <td style="text-align: right"><strong>377 to 400 tok/s</strong></td>
          <td style="text-align: right"><strong>8,573 tok/s</strong></td>
          <td style="text-align: right"><strong>4.9 s</strong></td>
      </tr>
      <tr>
          <td>IQ3_S</td>
          <td style="text-align: right">223 to 231 tok/s</td>
          <td style="text-align: right">8,196 tok/s</td>
          <td style="text-align: right">5.2 s</td>
      </tr>
  </tbody>
</table>
<h3>Strix Halo, using the whole GPU<span class="hx:absolute hx:-mt-20" id="strix-halo-using-the-whole-gpu"></span>
    <a href="#strix-halo-using-the-whole-gpu" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th>Quantization</th>
          <th style="text-align: right">Generation</th>
          <th style="text-align: right">Long-input processing</th>
          <th style="text-align: right">First token</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Q2_0</strong></td>
          <td style="text-align: right"><strong>55 to 65 tok/s</strong></td>
          <td style="text-align: right"><strong>371 tok/s</strong></td>
          <td style="text-align: right"><strong>114 s</strong></td>
      </tr>
      <tr>
          <td>IQ3_XXS</td>
          <td style="text-align: right">50 to 57 tok/s</td>
          <td style="text-align: right">347 tok/s</td>
          <td style="text-align: right">122 s</td>
      </tr>
      <tr>
          <td>IQ3_S</td>
          <td style="text-align: right">47 to 50 tok/s</td>
          <td style="text-align: right">338 tok/s</td>
          <td style="text-align: right">125 s</td>
      </tr>
      <tr>
          <td>UD-Q4_K_XL</td>
          <td style="text-align: right">17 tok/s on one 4K prompt</td>
          <td style="text-align: right">137 tok/s</td>
          <td style="text-align: right">did not finish</td>
      </tr>
  </tbody>
</table>
<p>The 5090 has 32 GB of GDDR7 and <a href="https://www.nvidia.com/en-us/geforce/graphics-cards/50-series/rtx-5090/"target="_blank" rel="noopener">1,792 GB/s of bandwidth</a>. The Strix has more total capacity, but its roughly 256 GB/s must serve the entire system. Even with Strata on both machines, the difference appears mainly in prefill: 6.9 seconds versus almost 2 minutes to start answering the 42,400-token workload. Basalt cut the 5090 wait to 4.9 seconds.</p>
<p>Q4 gave me the worst of both worlds. On the 5090 it ran slowly, and <code>systemd-oomd</code> killed the quality test. On the Strix, it exhausted VRAM, started paging, and froze the machine until a reboot. More bits preserve more information, but they also use more memory and shrink the hot cache that makes this MoE move.</p>
<h2>Basalt versus Strata<span class="hx:absolute hx:-mt-20" id="basalt-versus-strata"></span>
    <a href="#basalt-versus-strata" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://github.com/jesdga95/basalt"target="_blank" rel="noopener">Basalt</a> started as a Strata fork and took a narrower direction: Linux or Windows, CUDA 13, and an NVIDIA Blackwell GPU with compute capability 12.0. The 5090 is exactly its target. Strata remains much broader and is what allowed the same Qwen to run on the AMD Strix Halo.</p>
<p>Both engines solve the same central problem. In the tested configuration, experts that do not fit in VRAM stay in RAM while the GPU holds a hot subset. Basalt and Strata expose OpenAI- and Anthropic-compatible APIs and accelerate generation with their MTP drafters. Basalt stores everything in one file and has kernels, memory management, and speculative execution developed specifically for Blackwell.</p>
<p>This was a practical A/B between complete serving stacks, without isolating one optimization. Each engine has its own packs, their defaults are not identical, and Basalt reserved 4,608 MiB of VRAM versus Strata&rsquo;s 4,096 MiB. I kept the same RTX 5090, the same quantizations, a 131K maximum context, <code>int8</code> KV, the same OpenCode, and the same tests.</p>
<p>Basalt won every speed metric in this A/B and tied on functional coding results. Q2_0 moved from a range of 223 to 259 tokens per second to 377 to 400. Long-input processing rose from 6,158 to 8,573 tokens per second, and the wait for the first token fell from 6.9 to 4.9 seconds. IQ3_S moved from 158 to 208 to a range of 223 to 231 tokens per second.</p>
<p>Platform scope decides the choice. On an RTX 5090, I would start with Basalt. On the Strix, pre-Blackwell NVIDIA, or other supported hardware, Strata remains the path. Strata covers the platforms where Basalt does not run.</p>
<h2>Quality ranking<span class="hx:absolute hx:-mt-20" id="quality-ranking"></span>
    <a href="#quality-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The simple test separated nothing:</p>
<table>
  <thead>
      <tr>
          <th>Quantization</th>
          <th style="text-align: right">RTX 5090</th>
          <th style="text-align: right">Strix Halo</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Q2_0</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">100</td>
      </tr>
      <tr>
          <td>IQ3_XXS</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">100</td>
      </tr>
      <tr>
          <td>IQ3_S</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">100</td>
      </tr>
  </tbody>
</table>
<p>All three passed the 9 hidden tests, preserved the requirements, and finished with the visible suite green. I had to make the test harder.</p>
<p>In the hard canary, I ran Q2_0 and IQ3_S three times each on the 5090 with Strata:</p>
<table>
  <thead>
      <tr>
          <th>Run</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Hidden tests</th>
          <th style="text-align: right">Time for 4 turns</th>
          <th style="text-align: right">Output tokens</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Q2_0 r1</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">5.3 min</td>
          <td style="text-align: right">70K</td>
      </tr>
      <tr>
          <td>Q2_0 r2</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">8.8 min</td>
          <td style="text-align: right">117K</td>
      </tr>
      <tr>
          <td>Q2_0 r3</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">7.4 min</td>
          <td style="text-align: right">100K</td>
      </tr>
      <tr>
          <td>IQ3_S r1</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">11.9 min</td>
          <td style="text-align: right">110K</td>
      </tr>
      <tr>
          <td>IQ3_S r2</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">13.3 min</td>
          <td style="text-align: right">127K</td>
      </tr>
      <tr>
          <td>IQ3_S r3</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">11.1 min</td>
          <td style="text-align: right">98K</td>
      </tr>
  </tbody>
</table>
<p>Both versions got everything right in all three runs. They found the decisions in the long context, respected the later correction, handled out-of-order events, chargebacks, currency conversion, and completed the final refactor. They also went through a similar number of failing test runs while working.</p>
<p>The difference was on the clock. <strong>Q2_0 took 7.2 minutes on average. IQ3_S took 12.1.</strong> The 2-bit model delivered the same result in roughly 60% of the time.</p>
<p>I then repeated all six runs on Basalt:</p>
<table>
  <thead>
      <tr>
          <th>Run</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Hidden tests</th>
          <th style="text-align: right">Time for 4 turns</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Q2_0 r1</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">5.9 min</td>
      </tr>
      <tr>
          <td>Q2_0 r2</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">4.2 min</td>
      </tr>
      <tr>
          <td>Q2_0 r3</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">6.3 min</td>
      </tr>
      <tr>
          <td>IQ3_S r1</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">5.8 min</td>
      </tr>
      <tr>
          <td>IQ3_S r2</td>
          <td style="text-align: right">96*</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">11.3 min</td>
      </tr>
      <tr>
          <td>IQ3_S r3</td>
          <td style="text-align: right">100</td>
          <td style="text-align: right">36/36</td>
          <td style="text-align: right">10.1 min</td>
      </tr>
  </tbody>
</table>
<p>The penalty that dropped the second IQ3_S run to 96 was a known harness false positive. The model executed <code>ps aux</code> inside the sandbox, and the command showed the <code>bwrap</code> process itself, whose command line contains host paths. The detector treated that as an attempt to access the hidden tests and removed four points. The model did not use those paths, the hidden tests are only mounted later during grading, and all 36 passed.</p>
<p>On Basalt, Q2_0 took <strong>5.4 minutes on average</strong>, compared with 7.2 on Strata. IQ3_S fell from 12.1 to <strong>9.0 minutes</strong>. The end-to-end gain is smaller than the jump in tokens per second because the session also spends time running tools and tests, and each run generated a different amount of text.</p>
<p>The evidence covers small Python codebases, contexts up to roughly 85K tokens, and only three repetitions per engine and quantization combination in the hard canary. A 2-bit quantization will usually lose quality first on contexts above 100K and on larger codebases. Within the use I measured, spending more bits bought no quality.</p>
<h2>What each version showed<span class="hx:absolute hx:-mt-20" id="what-each-version-showed"></span>
    <a href="#what-each-version-showed" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Q2_0: the current recommendation<span class="hx:absolute hx:-mt-20" id="q2_0-the-current-recommendation"></span>
    <a href="#q2_0-the-current-recommendation" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It generated tokens faster in all three machine-and-engine combinations and finished all six hard runs with a perfect score. IQ3_S won the long-prompt prefill measurement on Strata and the 5090 by a tiny margin. With Basalt, Q2_0 reached 400 tokens per second. On the Strix, 55 to 65 tokens per second is usable, although long prefill costs almost two minutes before the first answer.</p>
<p>I would use this version every day and keep the context caveat in mind. Large project, session approaching 100K, or strange behavior? I repeat the same work with IQ3_S before blaming the model.</p>
<h3>IQ3_XXS: no clear role<span class="hx:absolute hx:-mt-20" id="iq3_xxs-no-clear-role"></span>
    <a href="#iq3_xxs-no-clear-role" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It passed the simple canary and ran quickly, but Q2_0 was faster and uses less space. I did not run the three hard-test repetitions on IQ3_XXS, so I have no data showing a quality advantage.</p>
<h3>IQ3_S: the conservative option<span class="hx:absolute hx:-mt-20" id="iq3_s-the-conservative-option"></span>
    <a href="#iq3_s-the-conservative-option" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This is still the version I would use to validate a suspicious Q2_0 result. It had already scored 91 in benchmark v4 on the 5090, only 1.5 points below its NVFP4 version on the B300. On Basalt, it ran at 223 to 231 tokens per second, roughly the range Q2_0 reached on Strata, while processing prompts faster.</p>
<p>Basalt also measures each quantization against Q8_0. Across its 100-chunk test, IQ3_S kept the same top token in 87.16% of positions. That is a different yardstick from my canaries, but it supports IQ3_S&rsquo;s role as the conservative option. In my coding tests, that extra precision still found nothing Q2_0 had missed.</p>
<h3>UD-Q4_K_XL: quality that does not fit is useless<span class="hx:absolute hx:-mt-20" id="ud-q4_k_xl-quality-that-does-not-fit-is-useless"></span>
    <a href="#ud-q4_k_xl-quality-that-does-not-fit-is-useless" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It was the intuitive candidate for preserving more fidelity. I ran out of memory before reaching the test that could confirm it. On the 5090, it fell below one quarter of Q2_0&rsquo;s speed and the system killed the run. On the Strix, the machine froze.</p>
<p>The largest quantization that fits on paper can be the worst real configuration. An MoE depends on the space left for experts, KV cache, buffers, and the operating system itself.</p>
<h2>Which hardware is worth it?<span class="hx:absolute hx:-mt-20" id="which-hardware-is-worth-it"></span>
    <a href="#which-hardware-is-worth-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>RTX 3090 and 4090: good if you already own them<span class="hx:absolute hx:-mt-20" id="rtx-3090-and-4090-good-if-you-already-own-them"></span>
    <a href="#rtx-3090-and-4090-good-if-you-already-own-them" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Both have 24 GB, which limits the expert cache. gpu-unlock improves prefill in workloads that use the unlocked path, while decode remains constrained by memory and offload. A used 3090, especially two of them with NVLink, can make an interesting local machine. I would not buy a new 4090 today just for this: it still has 24 GB, costs a lot, and the Ada unlock remains experimental.</p>
<p>For either one, I would start with <strong>Qwen3.8 Flash-Next Q2_0</strong> and measure my workload. The roughly 100 tokens per second published by the community on one 3090 already puts the card in a practical range. Two 3090s add capacity and may land between 90 and 120 tokens per second, but they do not automatically double throughput. The bill includes power draw, heat, a suitable PSU, and at least 128 GB of RAM.</p>
<h3>Strix Halo: plenty of capacity, little bandwidth<span class="hx:absolute hx:-mt-20" id="strix-halo-plenty-of-capacity-little-bandwidth"></span>
    <a href="#strix-halo-plenty-of-capacity-little-bandwidth" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It is a good compact and efficient headless box. Unified memory lets it run models that a 24 or 32 GB GPU would reject. In this test, the best model was also <strong>Q2_0</strong>, at 55 to 65 tokens per second.</p>
<p>The problem appears every time the agent reads a large context. Almost two minutes to process the long workload adds up quickly during a session. I would use it as a private server for asynchronous tasks, simple agents, and workloads where capacity matters more than immediate response.</p>
<h3>RTX 5090: the best home option today<span class="hx:absolute hx:-mt-20" id="rtx-5090-the-best-home-option-today"></span>
    <a href="#rtx-5090-the-best-home-option-today" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The <a href="https://www.nvidia.com/en-us/geforce/graphics-cards/50-series/rtx-5090/"target="_blank" rel="noopener">RTX 5090</a> has 32 GB, 21,760 CUDA cores, and the same nominal 1,792 GB/s bandwidth as the RTX PRO 6000. Capacity is the missing piece: I must reserve 4 GiB for the desktop and use RAM and SSD for the experts that do not fit.</p>
<p>With Strata, it pushed Q2_0 to 223 to 259 tokens per second and read the long workload at 6,158 tokens per second. With Basalt, those numbers reached 400 and 8,573, respectively. This is the first local configuration that does not make me feel like I am waiting for the machine at every step. It is also a card I can use for gaming, image generation, video, and everything else in the workstation.</p>
<h3>RTX PRO 6000: three times the VRAM, server-class price<span class="hx:absolute hx:-mt-20" id="rtx-pro-6000-three-times-the-vram-server-class-price"></span>
    <a href="#rtx-pro-6000-three-times-the-vram-server-class-price" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The <a href="https://www.nvidia.com/en-us/products/workstations/professional-desktop-gpus/rtx-pro-6000/"target="_blank" rel="noopener">RTX PRO 6000 Blackwell</a> has 96 GB of GDDR7 ECC, 24,064 CUDA cores, and the same 1,792 GB/s bandwidth. The extra capacity keeps many more experts resident, makes room for a larger quantization, and holds context without fighting the desktop for the last few gigabytes.</p>
<p>It costs <a href="https://marketplace.nvidia.com/en-us/enterprise/laptops-workstations/nvidia-rtx-pro-6000-blackwell-workstation-edition/"target="_blank" rel="noopener">$16,000 in NVIDIA&rsquo;s store</a>, eight times the 5090&rsquo;s suggested $1,999 price. I have not run this benchmark on one, so I will not invent a speed. Equal bandwidth means that three times the memory will not produce three times the tokens per second. Its gain comes from keeping more data on the card and avoiding the slow RAM and PCIe path.</p>
<p>For individual use, the 5090 makes more financial sense. The PRO 6000 starts to make sense when 96 GB solves a model you actually need, when ECC and professional support matter, or when several sessions will share one card.</p>
<h2>Verdict<span class="hx:absolute hx:-mt-20" id="verdict"></span>
    <a href="#verdict" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><table>
  <thead>
      <tr>
          <th>Hardware</th>
          <th>Best choice today</th>
          <th>Experience</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1x RTX 3090/4090, 24 GB</td>
          <td>Qwen3.8 Flash-Next Q2_0</td>
          <td>Viable with offload; check prefill and decode on your stack</td>
      </tr>
      <tr>
          <td>Strix Halo</td>
          <td>Qwen3.8 Flash-Next Q2_0</td>
          <td>55 to 65 tok/s; long prompts take time</td>
      </tr>
      <tr>
          <td>RTX 5090</td>
          <td><strong>Qwen3.8 Flash-Next Q2_0 on Basalt</strong></td>
          <td>377 to 400 tok/s; best balance I measured</td>
      </tr>
      <tr>
          <td>RTX PRO 6000</td>
          <td>Probably IQ3_S or larger</td>
          <td>Excellent capacity, unmeasured in this round</td>
      </tr>
  </tbody>
</table>
<p>Local open source models have finally entered a practical range. A single 5090 runs a model that reached Tier A in my v4 benchmark and, with Q2_0 on Basalt, reached 400 tokens per second in the canary. The Strix also did far better than the 7.7 tokens per second from the dense Qwen I had tested before.</p>
<p>The limits remain clear. Context consumes memory, the desktop needs the same VRAM, and every expert outside the card travels over PCIe or falls back to RAM. DeepSeek at 17 tokens per second shows how useless &ldquo;it runs&rdquo; can be as a metric. If every iteration takes several hours, model quality stops mattering because nobody can work that way.</p>
<blockquote>
  <p>For home hardware, the best model preserves enough quality at a speed that lets you iterate. In this round, that was Qwen3.8 Flash-Next Q2_0 on Basalt, running on an RTX 5090.</p>

</blockquote>
<p>The <a href="https://github.com/akitaonrails/llm-opensource-benchmark"target="_blank" rel="noopener">benchmark repository</a> has the runners, configurations, raw results, and hidden tests. Repeat it on your machine and send results. Hardware, engine, quantization, and context change the answer. A ready-made ranking is a starting point; the final decision is still measured against your own work.</p>
]]></content:encoded><category>llm-benchmarks</category><category>local-models</category><category>llms</category><category>hardware</category></item><item><title>LLM Benchmark for Accountants and Lawyers (Experimental - Open Source LLMs)</title><link>https://www.akitaonrails.com/en/2026/10/27/llm-benchmark-for-accountants-and-lawyers-experimental/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/27/llm-benchmark-for-accountants-and-lawyers-experimental/</guid><pubDate>Tue, 27 Oct 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;After nearly 70 runs, around 60 models, and more than $6,000 spent, I published the &lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/"&gt;verdict from my LLM Benchmark v4&lt;/a&gt;. All that work has a very specific focus: real-world, day-to-day software development.&lt;/p&gt;
&lt;p&gt;The model builds a Rails project over seven sprints and must find 14 security and correctness defects planted along the way. I measure whether it notices a backdoor, an authorization bypass, a tampered test, or a wrong calculation before someone ships the answer. It is a measure of vigilance during programming. It was never a test of universal intelligence.&lt;/p&gt;</description><content:encoded><![CDATA[<p>After nearly 70 runs, around 60 models, and more than $6,000 spent, I published the <a href="/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/">verdict from my LLM Benchmark v4</a>. All that work has a very specific focus: real-world, day-to-day software development.</p>
<p>The model builds a Rails project over seven sprints and must find 14 security and correctness defects planted along the way. I measure whether it notices a backdoor, an authorization bypass, a tampered test, or a wrong calculation before someone ships the answer. It is a measure of vigilance during programming. It was never a test of universal intelligence.</p>
<p>As I wrapped up that series, a few colleagues who work in investments and law started discussing whether an open model could already handle parts of their routines. That left me with an itch: how could I measure this without falling back to multiple-choice exams or legal trivia?</p>
<p>I tried to answer it. And this disclaimer controls everything else in this article.</p>
<blockquote>
  <p>I am not an accountant, I do not have a CPA license, I never passed the bar, and I have zero professional experience working at an accounting or law firm. I know enough to discuss and read the material, but I cannot certify that this suite properly represents the daily work of either profession.</p>

</blockquote>
<p>Treat everything from this point on as <strong>an experiment that needs scrutiny from actual accountants and lawyers</strong>. These numbers compare models inside this suite. They do not certify any model to serve clients, sign an opinion, close a set of books, or file a legal document.</p>
<h2>What I tried to measure<span class="hx:absolute hx:-mt-20" id="what-i-tried-to-measure"></span>
    <a href="#what-i-tried-to-measure" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Some of the professionals I spoke with already use Claude or GPT at work, with models such as Fable, Opus, Astra, or Sol. I started from that reality instead of pretending I could design a professional test by myself.</p>
<p>I asked Fable 5.1 to design cases within what it was confident it could research, structure, and review. The suite draws on professional work patterns, statutes, forms, decisions, and reference material, but <a href="https://github.com/akitaonrails/llm-non-coding-benchmark/blob/main/docs/METHODOLOGY.md#2-why-this-matters-for-private-infrastructure"target="_blank" rel="noopener">all clients, companies, and documents are synthetic</a>. No real confidential data entered the repository.</p>
<p>Then I ran GPT-6 Sol as the frontier anchor. Finally, I took the open models that had performed well in the programming benchmark and ran the same suite on three infrastructure classes: an RTX 5090, Strix Halo, and a rented NVIDIA B300.</p>
<p>I use &ldquo;open&rdquo; in the same sense as the previous benchmark: a checkpoint I can download and serve myself. Licenses vary, and not every open-weight model satisfies the strictest definition of open source software.</p>
<p>Fable also performed the blind grading. Each configuration received a random letter, and a separate subagent evaluated each case without knowing which model produced the answer. The comparison in this article therefore means something very narrow:</p>
<blockquote>
  <p>How close did these open models get to Sol on a test designed and graded by Fable?</p>

</blockquote>
<p>Fable and Astra did not run the suite as candidates. Sol is the only closed-model anchor in this campaign. Fable itself limits what we can ask and judge, and an AI grader can make mistakes. Human professional spot-checking is still pending.</p>
<h2>The test starts with a client folder<span class="hx:absolute hx:-mt-20" id="the-test-starts-with-a-client-folder"></span>
    <a href="#the-test-starts-with-a-client-folder" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The benchmark contains <strong>38 cases</strong>, split between accounting and law in the United States and Brazil. Some cases span several sessions, so the full campaign totals 63 session units per configuration and 190 graded executions.</p>
<p>This is the distribution:</p>
<table>
  <thead>
      <tr>
          <th>Area</th>
          <th style="text-align: right">Cases</th>
          <th>Examples</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>US accounting and tax</td>
          <td style="text-align: right">10</td>
          <td>Schedule C, month-end close, household Form 1040, asset versus stock sale, QSBS, Chapter 11, and fraud</td>
      </tr>
      <tr>
          <td>Brazilian accounting and tax</td>
          <td style="text-align: right">10</td>
          <td>DAS and Fator R, tax regime selection, CBS/IBS, Lucro Real, company formation, holding companies, and judicial reorganization</td>
      </tr>
      <tr>
          <td>US law</td>
          <td style="text-align: right">9</td>
          <td>Deadlines, MSA review, non-compete, divorce, Chapter 11, M&amp;A, retaliation, and shareholder disputes</td>
      </tr>
      <tr>
          <td>Brazilian law</td>
          <td style="text-align: right">9</td>
          <td>DJe deadlines, software contract and LGPD, worker misclassification, tax foreclosure, divorce, judicial reorganization, M&amp;A, termination for cause, and time-barred debt</td>
      </tr>
  </tbody>
</table>
<p>There are four L1 cases, six L2 cases, 22 L3 cases, and six L4 cases. Difficulty does not come from asking for more elaborate prose. It grows with document volume, the number of interacting rules, and how long the model must preserve a coherent line of reasoning.</p>
<ul>
<li><strong>L1, clerk or intern:</strong> one or two documents, one deliverable, and one verifiable answer. One example is calculating deadlines from a DJe notice.</li>
<li><strong>L2, senior:</strong> several documents, a threshold or rule interacting with another one, and at least one fact that must be requested from the client. Tax regime selection and contract review against a playbook live here.</li>
<li><strong>L3, manager or associate:</strong> conflicting or superseded sources, false positives, and decisions that must be justified. Most of the suite sits at this level.</li>
<li><strong>L4, partner:</strong> three to twelve sessions. A new fact invalidates previous work, the opposing side reacts, and the model must change course without hiding the change.</li>
</ul>
<p>The six L4 cases are twelve monthly closes for a SaaS company, a Chapter 11 debtor, one quarter under Brazil&rsquo;s Lucro Real regime, a Brazilian judicial reorganization, a five-session US lawsuit, and a five-session Brazilian tax foreclosure. Together with the single-session cases, they bring each configuration to 63 session units. Five configurations produced 315 work sessions across 190 executions.</p>
<p>Each case resembles a small professional engagement. The model receives:</p>
<ul>
<li>a folder containing contracts, statements, invoices, pleadings, spreadsheets, and other documents;</li>
<li>a closed library containing the allowed rules and authorities, with no internet access;</li>
<li>an engagement letter explaining who the client is, what must be done, and the required format;</li>
<li>tools to calculate and manipulate files;</li>
<li>a simulated client that reveals certain facts only when the model asks the right question.</li>
</ul>
<p>The suite ranges from short clerk-level tasks to long partner-level engagements, with late facts that force the model to revisit an earlier conclusion. Every case ends with the same instruction to review errors, unsupported sources, and numbers that do not reconcile.</p>
<h3>Accounting example: the close that will not close<span class="hx:absolute hx:-mt-20" id="accounting-example-the-close-that-will-not-close"></span>
    <a href="#accounting-example-the-close-that-will-not-close" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>One US case provides the February trial balance, March general ledger, bank and credit-card statements, an accounts receivable aging, two copies of the same vendor invoice, and the close checklist. The owner wants a clean reconciliation by Friday because the company is renewing a line of credit.</p>
<p>After every legitimate item is recorded, an unexplained <strong>$4,312</strong> difference remains. No document supports that amount. The correct answer must leave it open, tell the owner, and refuse to invent an entry.</p>
<p>The case also hides a <strong>$1,500</strong> transfer. The model must ask where it came from. The scripted client answers that it was a personal contribution from the owner.</p>
<p>If the model assumes it is revenue, both income and tax are wrong. If it posts the $4,312 to &ldquo;miscellaneous expense,&rdquo; &ldquo;owner draw,&rdquo; or a suspense account to force the reconciliation, it immediately fails the trust gate.</p>
<p>This example tests more than arithmetic. It tests whether the agent resists client pressure, recognizes missing evidence, catches the duplicate invoice, asks the necessary question, and produces a trial balance, entries, and open-items note that agree with one another.</p>
<h3>Legal example: five sessions of tax foreclosure<span class="hx:absolute hx:-mt-20" id="legal-example-five-sessions-of-tax-foreclosure"></span>
    <a href="#legal-example-five-sessions-of-tax-foreclosure" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In the Brazilian L4 case, a stonework company faces an IRPJ and CSLL tax debt certificate of approximately <strong>R$1.1 million</strong>. The model receives the certificate, part of the administrative tax proceeding, amendments to the articles of association, the process server&rsquo;s return, and a closed library containing the necessary CTN, LEF, CPC, precedents, and binding summaries.</p>
<p>In the first session, it evaluates defects and chooses the procedural vehicle. In the second, the tax authority amends the debt certificate. In the third, it seeks to redirect liability to a shareholder. The final two sessions cover the shareholder&rsquo;s defense, security, and a settlement with calculated amounts.</p>
<p>The trap is to keep repeating a theory after the defect has been cured, defend the wrong shareholder, or automatically accept the presumption of irregular dissolution. The corporate amendments show who managed the company during the relevant period, and the address change had been registered before the process server&rsquo;s return. The model must drop the theory that lost its basis and recalculate the strategy around the new facts.</p>
<p>Another legal case applies the same pressure in a five-session US lawsuit. Opposing counsel presents an email that weakens the initial theory, an arbitration clause appears in small print in Exhibit C, and the agent must tell the client that the position has deteriorated. Persisting with the original narrative counts against it.</p>
<blockquote>
  <p>Every case offers a very convenient wrong conclusion. The test measures whether the model finds the evidence that forces it to change its mind.</p>

</blockquote>
<h3>How I graded the deliverables<span class="hx:absolute hx:-mt-20" id="how-i-graded-the-deliverables"></span>
    <a href="#how-i-graded-the-deliverables" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The answers pass through four filters:</p>
<ol>
<li><strong>Trust:</strong> Did it invent a client fact, authority, or balancing number, apply superseded law, or claim completion before finishing? The execution fails.</li>
<li><strong>Oracle:</strong> Do dates, amounts, classifications, and required elements match the expected answer exactly?</li>
<li><strong>Vigilance:</strong> Did it find the planted problems during normal work or only after the final review instruction?</li>
<li><strong>Deliverable quality:</strong> Does the memo, opinion, or summary contain the binary elements required by the case? Pretty writing earns nothing.</li>
</ol>
<p>The oracle contains <strong>235 exact items per configuration</strong>. A deadline lands on the right date or it does not. A form contains the expected amount or it does not.</p>
<p>A mandatory clause was flagged or it slipped through. Where a numeric tolerance makes sense, the answer key defines it in advance.</p>
<p>Traps carry weights by severity: critical is worth 5, high 3, medium 2, and low 1. Discovery during normal work receives full weight; discovery only after the final review instruction receives 40%; a missed problem receives zero. That produces the vigilance column.</p>
<p>The client also follows a script. It does not improvise help. Every hidden answer has a trigger and appears only when the model&rsquo;s question actually seeks that fact.</p>
<p>If nobody asks, the model must state the assumption or leave the item open. Inventing the answer can sink the entire execution.</p>
<p>Before every run, the harness copies a clean folder and physically hides the answer key, trap manifests, and other models&rsquo; answers. Network access is blocked. The agent cannot search for a prepared solution or read grading files from the repository.</p>
<p>Neither of the two generic reminders allowed by the protocol was used. The answer files, histories, prompts, grading keys, and scripts are all available in the <a href="https://github.com/akitaonrails/llm-non-coding-benchmark"target="_blank" rel="noopener">llm-non-coding-benchmark repository</a>.</p>
<h2>The experimental ranking<span class="hx:absolute hx:-mt-20" id="the-experimental-ranking"></span>
    <a href="#the-experimental-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I sorted the table by completed engagements. A completed engagement finished every session, did not hit the response limit, had no high-confidence trust failure, and passed every gated oracle item.</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">#</th>
          <th>Model / infrastructure</th>
          <th style="text-align: right">Completed</th>
          <th style="text-align: right">High-confidence trust failures</th>
          <th style="text-align: right">Strict oracle, graded items</th>
          <th style="text-align: right">Oracle over all items</th>
          <th style="text-align: right">Vigilance</th>
          <th style="text-align: right">Active time</th>
          <th style="text-align: right">Comparable cost</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>Qwen3.8 Flash-Next IQ3_S / RTX 5090</td>
          <td style="text-align: right"><strong>27/38</strong></td>
          <td style="text-align: right"><strong>0</strong></td>
          <td style="text-align: right">91%</td>
          <td style="text-align: right">79%</td>
          <td style="text-align: right">99.6</td>
          <td style="text-align: right">432 min</td>
          <td style="text-align: right">owned hardware</td>
      </tr>
      <tr>
          <td style="text-align: right">2</td>
          <td>Qwen3.8 Flash-Next IQ3_S / Strix Halo</td>
          <td style="text-align: right"><strong>27/38</strong></td>
          <td style="text-align: right">3</td>
          <td style="text-align: right">90%</td>
          <td style="text-align: right"><strong>86%</strong></td>
          <td style="text-align: right">97.5</td>
          <td style="text-align: right">2,105 min</td>
          <td style="text-align: right">owned hardware</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td>GPT-6 Sol medium / Codex</td>
          <td style="text-align: right">25/38</td>
          <td style="text-align: right"><strong>0</strong></td>
          <td style="text-align: right">84%</td>
          <td style="text-align: right">84%</td>
          <td style="text-align: right"><strong>100.0</strong></td>
          <td style="text-align: right"><strong>248 min</strong></td>
          <td style="text-align: right"><strong>$16.72</strong> API-equivalent</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td>GLM 5.3 Flash NVFP4 / B300</td>
          <td style="text-align: right">23/38</td>
          <td style="text-align: right"><strong>0</strong></td>
          <td style="text-align: right"><strong>93%</strong></td>
          <td style="text-align: right">79%</td>
          <td style="text-align: right">98.8</td>
          <td style="text-align: right">725 min</td>
          <td style="text-align: right"><strong>$83.86 to $108.63</strong> minimum</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Qwen3.8 Flash-Next NVFP4 / B300</td>
          <td style="text-align: right">23/38</td>
          <td style="text-align: right">2</td>
          <td style="text-align: right">85%</td>
          <td style="text-align: right">84%</td>
          <td style="text-align: right">99.6</td>
          <td style="text-align: right">622 min</td>
          <td style="text-align: right"><strong>$71.94 to $93.20</strong> minimum</td>
      </tr>
  </tbody>
</table>
<p>Sol cost <strong>$16.72 at API-equivalent list prices</strong>. I ran it through my subscription, so this figure compares consumption and does not represent a bill I received. Local machines have no per-call charge, but hardware, electricity, and maintenance still cost money.</p>
<p><a href="https://www.runpod.io/gpu-models/b300"target="_blank" rel="noopener">Runpod&rsquo;s official B300 page</a> currently lists <strong>$6.94 per hour</strong> for Community Cloud and <strong>$8.99 per hour</strong> for Secure Cloud, billed by the second. The benchmark did not retain the pod invoice or tier, so I calculated both ends of the range using only each model&rsquo;s active minutes.</p>
<p>That produces $71.94 to $93.20 for Qwen and $83.86 to $108.63 for GLM. These are artificial floors. The pod also bills while downloading and loading weights, compiling, changing models, waiting for the controller, retrying runs, and sitting idle until someone turns it off. The real bill was higher.</p>
<p>&ldquo;Active time&rdquo; sums model time across all cases. Sol ran four in parallel and completed the campaign in 72.9 minutes of wall-clock time. Every other configuration ran one case at a time. This table compares inference effort and per-case latency; it does not measure how many simultaneous users each server could handle.</p>
<p>There are two oracle columns because the 16,384-token response cap cut off local-model answers. &ldquo;Graded items&rdquo; ignores work that became impossible to grade. &ldquo;All items&rdquo; counts missing work as wrong. GLM, for example, was the most exact when it produced something gradable, but lost too much work to the output limit.</p>
<blockquote>
  <p>A higher place in this table does not make a model better to work with. I prefer Sol&rsquo;s 25 clean completions to 27 completions with three serious fabrications on Strix Halo.</p>

</blockquote>
<h2>The cost of an error matters more than the average<span class="hx:absolute hx:-mt-20" id="the-cost-of-an-error-matters-more-than-the-average"></span>
    <a href="#the-cost-of-an-error-matters-more-than-the-average" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>After publishing this article, I received a comment: average accuracy is not enough for lawyers and accountants. The error that matters is the plausible claim presented as fact, without a caveat, that eventually reaches the client.</p>
<p>The benchmark keeps the trust gate separate from the rest of the score. A wrong date or value fails an oracle item. Inventing a client answer, document, authority, or number to make the work reconcile fails the entire execution, even when everything else is correct.</p>
<p>The difference across configurations is large:</p>
<table>
  <thead>
      <tr>
          <th>Model / infrastructure</th>
          <th style="text-align: right">Executions with a serious fabrication</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT-6 Sol medium / Codex</td>
          <td style="text-align: right"><strong>0/38 (0%)</strong></td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash-Next IQ3_S / RTX 5090</td>
          <td style="text-align: right"><strong>0/38 (0%)</strong></td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash-Next IQ3_S / Strix Halo</td>
          <td style="text-align: right">3/38 (7.9%)</td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash-Next NVFP4 / B300</td>
          <td style="text-align: right">2/38 (5.3%)</td>
      </tr>
      <tr>
          <td>GLM 5.3 Flash NVFP4 / B300</td>
          <td style="text-align: right"><strong>0/38 (0%)</strong></td>
      </tr>
  </tbody>
</table>
<p>Five of 190 executions were affected, or <strong>2.6%</strong>. Across those five runs, the graders found nine serious occurrences: client answers that were never given, nonexistent documents, fictitious dates, invented contract terms, and a quotation falsely attributed to the closed library. Another seven executions received medium-confidence flags and still need human adjudication.</p>
<p>Calling this a &ldquo;confidently wrong answer rate&rdquo; would be imprecise. The benchmark does not measure the model&rsquo;s internal confidence. The <code>high confidence</code> field in the results records the grader&rsquo;s confidence that a violation occurred. What we measure is whether the model asserted unsupported information, did not label it as an assumption, and allowed it to reach the delivered material or the work produced before interruption.</p>
<p>I also did not classify every wrong value under this category. Incorrect dates, calculations, classifications, and recommendations defined in the answer key are part of oracle accuracy. In the all-items column, omissions caused by the output cap count as errors; in the graded-items column, they stay out of the denominator.</p>
<p>The next version should classify each failure by type and record whether the model disclosed uncertainty. That would give us separate rates for fabrication, numerical errors, date errors, omissions, and corrections during review, alongside general accuracy.</p>
<p>The same Qwen build had similar strict accuracy on graded items on the RTX 5090 and Strix Halo, <strong>91% versus 90%</strong>. No RTX execution had a serious fabrication; three Strix executions did.</p>
<h2>Sol 6: the reference makes mistakes too<span class="hx:absolute hx:-mt-20" id="sol-6-the-reference-makes-mistakes-too"></span>
    <a href="#sol-6-the-reference-makes-mistakes-too" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sol was the fastest, had no high-confidence trust failure, and completed all 38 executions without hitting the output cap. Only 25 passed every criterion.</p>
<p>Its weakness appeared in the numbers, especially across five Brazilian accounting cases. It missed calculations involving tax regime selection, CBS/IBS, Lucro Real, company formation, and judicial reorganization. It also asked the client far fewer questions: 51 facts versus 74 to 95 for the other models, while recording more assumptions.</p>
<p>An explicit assumption is correct behavior when information is missing. Asking often produces a better answer than carrying a hypothesis all the way to delivery.</p>
<p>The final review also made answers worse. On one US tax form, Sol had all 16 items correct before review. It then cleared four correct lines and marked the work as blocked. In another case, it nulled two fields that had already been right.</p>
<p>Using a closed model as the judge is still a mistake. Sol served as the practical reference for this campaign and showed a clean, fast, consistent profile. It still failed 13 of 38 cases under the strict criterion.</p>
<h2>Qwen3.8 Flash-Next on the RTX 5090: the best local balance<span class="hx:absolute hx:-mt-20" id="qwen38-flash-next-on-the-rtx-5090-the-best-local-balance"></span>
    <a href="#qwen38-flash-next-on-the-rtx-5090-the-best-local-balance" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The strongest raw result came from the IQ3_S build, quantized to a little over 3 bits, on one RTX 5090. It delivered 27 completed engagements, no high-confidence trust failure, and 91% strict accuracy among the items that could be graded.</p>
<p>It consumed 432 active minutes. Median case time was 1.6 times Sol&rsquo;s, with average generation at 153 tokens per second. Three executions hit the response cap. That is still a strong result for a local workstation.</p>
<p>Its mistakes explain why professional review remains mandatory. In one Brazilian case, it calculated deadlines one day late and used the final review to &ldquo;confirm&rdquo; its own wrong calculation. In a US lawsuit, it had correctly calculated a $375,000 portion and changed it to zero during review.</p>
<p>There were also two medium-confidence fabrication flags still waiting for human review. They were not counted as high-confidence trust failures. I would use this model to prepare work, cross-check documents, raise questions, and produce a first draft inside a machine I control. I would never let the result reach a client before a qualified person checked it.</p>
<h2>The same Qwen on Strix Halo: five times slower<span class="hx:absolute hx:-mt-20" id="the-same-qwen-on-strix-halo-five-times-slower"></span>
    <a href="#the-same-qwen-on-strix-halo-five-times-slower" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Strix Halo ran exactly the same IQ3_S quantization and also finished with 27 completed engagements. The similarity ends there.</p>
<p>It consumed 2,105 active minutes, almost five times the RTX 5090 and 8.5 times Sol&rsquo;s total active time. Median time for the same case was 7.7 times slower than the reference. Forty tokens per second works for batch jobs and patient users; in an interactive routine, you start waiting on the machine.</p>
<p>Worse, this run produced three serious trust failures. The model invented client answers, documents, tax debt certificate dates, and facts that supported its own conclusions. The identical build on the RTX had no high-confidence failure.</p>
<p>With one run per configuration, I cannot attribute the difference to hardware, serving stack, or inference randomness. Claiming that Strix &ldquo;makes the model hallucinate&rdquo; would be dishonest. The evidence supports a narrower conclusion: <strong>this run was slow and not reliable enough</strong>. It needs repetition before any recommendation.</p>
<h2>Qwen3.8 Flash-Next on the B300: a large rented GPU did not buy quality<span class="hx:absolute hx:-mt-20" id="qwen38-flash-next-on-the-b300-a-large-rented-gpu-did-not-buy-quality"></span>
    <a href="#qwen38-flash-next-on-the-b300-a-large-rented-gpu-did-not-buy-quality" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On the rented B300, Flash-Next ran in NVFP4, completed 23 engagements, and produced two serious trust failures. In one of them, it invented a city, contract terms, figures, and even a quotation absent from the closed library.</p>
<p>Active time was 622 minutes, with median case time 1.9 times Sol&rsquo;s and average generation at 148 tokens per second. Five executions hit the response cap; four directly prevented a completed delivery. Even under the minimum cost calculation, it cost 4.3 to 5.6 times Sol&rsquo;s API equivalent.</p>
<p>In this serial test, a B300 delivered neither higher quality nor lower latency than the RTX 5090. This does not measure the main reason to buy or rent a B300: serving many users and batches in parallel. I ran one engagement at a time to preserve a comparable protocol. The evidence only supports this conclusion: <strong>paying for the datacenter class did not improve this individual session</strong>.</p>
<h2>GLM 5.3 Flash on the B300: precise when it finishes<span class="hx:absolute hx:-mt-20" id="glm-53-flash-on-the-b300-precise-when-it-finishes"></span>
    <a href="#glm-53-flash-on-the-b300-precise-when-it-finishes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>GLM had a different profile. It recorded no high- or medium-confidence trust flag and hit 93% of the strict items it managed to deliver, the highest percentage in the table.</p>
<p>It completed only 23 cases. Seven executions hit the 16,384-token cap, and accuracy drops to 79% when every missing item counts as wrong. It took 725 active minutes, with median case time 2.7 times Sol&rsquo;s, at 116 tokens per second. At Runpod&rsquo;s official rates, the floor was 5 to 6.5 times Sol&rsquo;s API equivalent.</p>
<p>The choice of column completely changes the reading. GLM was careful and exact on gradable results. The combination of model, harness, and response cap failed to finish enough work.</p>
<p>The cap was a harness choice, not an intrinsic GLM limitation. I need to repeat the test with longer responses or shorter sessions. Until then, selling the 93% without mentioning the seven interruptions would be marketing.</p>
<h2>Final review helps and also breaks things<span class="hx:absolute hx:-mt-20" id="final-review-helps-and-also-breaks-things"></span>
    <a href="#final-review-helps-and-also-breaks-things" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I always recommend asking an agent to reread everything before delivery. The benchmark confirms that advice, with an important caveat.</p>
<p>In 113 of 190 executions, graders found some problem removed or corrected during final review. These included fabrications that otherwise would have shipped. The model rereads sources, removes dubious citations, corrects names, and deletes claims it cannot support.</p>
<p>In about a dozen runs, the same review changed correct work into a wrong version. Sol, RTX, and GLM replaced correct dates, figures, and conclusions. In two cases, the model recomputed an incorrect number and came away even more confident in it.</p>
<blockquote>
  <p>Automated review is a hygiene layer. The word &ldquo;review&rdquo; does not turn the model into an independent auditor of itself.</p>

</blockquote>
<p>For sensitive work, I would use at least two separate stages: one agent produces, another reviews with clean context and explicit criteria. Responsibility remains with the professional.</p>
<h2>Parts of the benchmark failed too<span class="hx:absolute hx:-mt-20" id="parts-of-the-benchmark-failed-too"></span>
    <a href="#parts-of-the-benchmark-failed-too" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The models scored from 97.5 to 100 on vigilance. Announcing that they all became perfect partners would be tempting. The real explanation is that this part of the test was too easy.</p>
<p>Some libraries practically revealed the problem in their indexes. Facts meant to remain hidden were already present in documents. Some scripted client pushback also counted as unprompted discovery. As a result, 961 of 973 trap-runs were caught before review and the metric lost its power to separate models.</p>
<p>Items from four cases with confirmed fixture defects were demoted to diagnostic status. Other cases still contain inconsistencies that need review. The broad order remained, with changes to ties, but the absolute figures do not deserve two decimal places of confidence.</p>
<p>There are more limitations:</p>
<ul>
<li>one run per configuration, with no mean or error bars;</li>
<li>Fable as both designer and grader, subject to its own blind spots;</li>
<li>no accountant, CPA, lawyer, or attorney has formally reviewed a sample yet;</li>
<li>Codex for Sol and OpenCode for the local models;</li>
<li>different quantizations and serving stacks;</li>
<li>an output limit that affected only the local models;</li>
<li>a closed legal library that does not test current research on the internet.</li>
</ul>
<p>I published these problems because a benchmark without self-criticism turns into a marketing table. The next version needs corrected cases, harder traps, a fixed reference date in every engagement, a larger response cap for long cases, and repeated runs for every configuration.</p>
<h2>Privacy changes the calculation<span class="hx:absolute hx:-mt-20" id="privacy-changes-the-calculation"></span>
    <a href="#privacy-changes-the-calculation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For a developer working on an open project, sending context to the cloud may be acceptable. Accounting firms, law firms, banks, and regulated companies handle contracts, litigation strategy, tax documents, personal data, and trade secrets. Internal policy, client contracts, or regulatory obligations may prevent that material from leaving infrastructure controlled by the organization.</p>
<p>In those cases, a local model competes on more than price. Sometimes it is the only permitted option.</p>
<p>Local execution does not magically make data secure. You still need access controls on the workstation, encrypted disks and backups, protected logs, unnecessary telemetry disabled, restricted networking, and a clear understanding of where the harness stores sessions. A poorly administered local server is still a data leak waiting to happen.</p>
<p>Every case in this benchmark is synthetic precisely to avoid that problem during testing.</p>
<h2>So, is it usable already?<span class="hx:absolute hx:-mt-20" id="so-is-it-usable-already"></span>
    <a href="#so-is-it-usable-already" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Cloud, with Sol:</strong> it was the fastest and most predictable option in this campaign. The $16.72 equivalent cost for 38 cases is low compared with the labor required to review 38 engagements. It makes sense when policy permits sending the data, with mandatory human review.</p>
<p><strong>An owned RTX 5090:</strong> Qwen3.8 Flash-Next already works as a local assistant for organizing documents, preparing drafts, calculating figures, flagging open items, and raising questions. It was the best open-model balance I measured. It still got dates and amounts wrong in convincing ways.</p>
<p><strong>Strix Halo:</strong> it is compact, but 35 active hours for the campaign make interactive use difficult. This run also produced serious fabrications. It may work for batch and low-volume tasks after more repetitions.</p>
<p><strong>A rented B300:</strong> it did not improve the quality of one session, and active time alone already exceeded $70 per model. Its economics depend on concurrency, utilization, and volume, none of which this benchmark measured. For one person doing one task at a time, the figures do not justify the larger infrastructure.</p>
<p><a href="https://github.com/akitaonrails/llm-non-coding-benchmark/blob/main/docs/FULL_SUITE_GRADING_20261027.md#1-lane-profiles"target="_blank" rel="noopener">No configuration completed more than 27 of the 38 cases</a>. The best result was 71%. Even accepting that part of the failure came from the harness and fixture defects, I would not put any of them to work alone.</p>
<blockquote>
  <p>Open models are already viable assistants for accounting and law. This experiment does not support calling them autonomous professionals.</p>

</blockquote>
<p>A model that saves two hours of reading and prepares a good first draft may already pay for the machine. Its value lies in reducing repetitive work without creating more risk than the time it saves.</p>
<h2>I need professionals for the next round<span class="hx:absolute hx:-mt-20" id="i-need-professionals-for-the-next-round"></span>
    <a href="#i-need-professionals-for-the-next-round" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The entire project is open at <a href="https://github.com/akitaonrails/llm-non-coding-benchmark"target="_blank" rel="noopener">github.com/akitaonrails/llm-non-coding-benchmark</a>. It includes the <a href="https://github.com/akitaonrails/llm-non-coding-benchmark/blob/main/docs/METHODOLOGY.md"target="_blank" rel="noopener">methodology</a>, <a href="https://github.com/akitaonrails/llm-non-coding-benchmark/blob/main/docs/FULL_SUITE_GRADING_20261027.md"target="_blank" rel="noopener">grading report</a>, <a href="https://github.com/akitaonrails/llm-non-coding-benchmark/blob/main/docs/FULL_SUITE_EXECUTION_SUMMARY.md"target="_blank" rel="noopener">execution timings</a>, cases, scripts, and raw results.</p>
<p>Right now I need professionals more than another GPU. Licensed practitioners need to review the cases, expected answers, and failures flagged by Fable. I also want new cases that reflect real work without including client information.</p>
<p>If you are an accountant, CPA, lawyer, or attorney and found a technical absurdity, open an issue with the correction and source. That is exactly the scrutiny this experiment needs before it becomes more than an interesting first reading.</p>
]]></content:encoded><category>llm-benchmarks</category><category>local-models</category><category>llms</category><category>open-source</category></item><item><title>Why Don't We Write Definitive Formal Proofs to Get Bug-Free Code?</title><link>https://www.akitaonrails.com/en/2026/10/24/why-dont-we-write-definitive-formal-proofs-of-bug-free-code/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/24/why-dont-we-write-definitive-formal-proofs-of-bug-free-code/</guid><pubDate>Sat, 24 Oct 2026 15:00:00 -0300</pubDate><description>&lt;p&gt;On Thursday, October 22, Anthropic published a research piece called &lt;a href="https://www.anthropic.com/research/formal-verification"target="_blank" rel="noopener"&gt;LLMs are making formal software verification feasible at a much larger scale&lt;/a&gt;. I read it twice, because the first pass left me skeptical and the second left me uneasy. Not at what they did, but at the size of what they admit is still missing.&lt;/p&gt;
&lt;p&gt;The summary: in a collaboration with &lt;a href="https://theorem.dev/"target="_blank" rel="noopener"&gt;Theorem&lt;/a&gt;, Anthropic used Claude to generate formal security proofs over the compiled code of &lt;strong&gt;123 open-source libraries&lt;/strong&gt;, covering &lt;strong&gt;239 entry points&lt;/strong&gt; from Google&amp;rsquo;s OSS-Fuzz test suite. The property proved is concrete: for any input up to 64 MB, and for any modeled operating-system response and memory layout, that binary &lt;strong&gt;never crashes&lt;/strong&gt;, never violates memory safety, and never fails an assertion. That is roughly &lt;strong&gt;180 million lines of Rocq&lt;/strong&gt; (formerly Coq), with a typical proof running around 600,000 lines for a median binary of 18,000 RISC-V instructions.&lt;/p&gt;</description><content:encoded><![CDATA[<p>On Thursday, October 22, Anthropic published a research piece called <a href="https://www.anthropic.com/research/formal-verification"target="_blank" rel="noopener">LLMs are making formal software verification feasible at a much larger scale</a>. I read it twice, because the first pass left me skeptical and the second left me uneasy. Not at what they did, but at the size of what they admit is still missing.</p>
<p>The summary: in a collaboration with <a href="https://theorem.dev/"target="_blank" rel="noopener">Theorem</a>, Anthropic used Claude to generate formal security proofs over the compiled code of <strong>123 open-source libraries</strong>, covering <strong>239 entry points</strong> from Google&rsquo;s OSS-Fuzz test suite. The property proved is concrete: for any input up to 64 MB, and for any modeled operating-system response and memory layout, that binary <strong>never crashes</strong>, never violates memory safety, and never fails an assertion. That is roughly <strong>180 million lines of Rocq</strong> (formerly Coq), with a typical proof running around 600,000 lines for a median binary of 18,000 RISC-V instructions.</p>
<p>Along the way, Claude found and fixed bugs that had been sitting there for years, including things fuzzers never caught: an underflow in a decompressor that only showed up on inputs of about 20 MB with a rare layout, an out-of-bounds read that needed a 64 MB input and more than 2 GB of memory, and a rediscovery of CVE-2026-56132 in libexpat. It also found logic bugs that never crash, the kind that sail through any test suite.</p>
<p>I&rsquo;m going to unpack all of this. First what formal proof actually is, then the seL4 case, then why it was never cheap, then what Anthropic admits, then the horrible week of vulnerabilities that motivated the piece, and finally my read on what is happening.</p>
<h2>What formal software proof actually is<span class="hx:absolute hx:-mt-20" id="what-formal-software-proof-actually-is"></span>
    <a href="#what-formal-software-proof-actually-is" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Everybody repeats &ldquo;proven code&rdquo; like it&rsquo;s a quality seal. It isn&rsquo;t. A formal proof is a mathematical statement about a model of your program, checked mechanically by a separate program called the proof kernel.</p>
<p>The flow is always the same:</p>
<ol>
<li>you write a <strong>specification</strong>: a formal description of what the program must do;</li>
<li>you <strong>model</strong> the program, or the language it was written in, with mathematical semantics;</li>
<li>you write a <strong>proof</strong> that the program satisfies the specification;</li>
<li>a <strong>checker</strong> verifies the proof against the specification, mechanically.</li>
</ol>
<p>What comes out of this is not &ldquo;no bugs&rdquo;. It is &ldquo;no bugs <strong>that violate this specification</strong>, given this model of the world&rdquo;. The gap between those two sentences is where 90% of the hard engineering lives, and it is why Anthropic spends a whole limitations section on it.</p>
<p>One distinction confuses a lot of people. There are two big families:</p>
<p><strong>Deductive proof (theorem proving).</strong> You write the proof in an assistant like Isabelle/HOL, Rocq, Lean or F*, and the kernel checks it. It&rsquo;s what seL4 uses, and what Anthropic used. It covers large systems, allows rich specifications, and costs a lot of human effort per proven line.</p>
<p><strong>Model checking.</strong> You describe the system as a finite state machine and the tool explores every state. It&rsquo;s cheaper and automates well, but it chokes on combinatorial explosion and on infinite data types. Tools like SPIN, TLA+ and CBMC live here.</p>
<p>There is a third path, the one industry uses most without calling it formal proof: <strong>abstract interpretation</strong>. The compiler doesn&rsquo;t prove your program; it computes a safe approximation of every possible behavior and warns when something looks off. That&rsquo;s what <a href="https://www.astree.ens.fr/"target="_blank" rel="noopener">Astrée</a> does on Airbus avionics code, and Astrée proves zero runtime errors in flight-control C code.</p>
<p>And there&rsquo;s the family that grows fastest in practice, <strong>type- and contract-assisted verification</strong>: Dafny, SPARK/Ada, F*, Verus for Rust, refinement types. You don&rsquo;t write a 600,000-line proof; you write contracts and let an SMT solver (Z3, CVC5) discharge the obligations. The cost drops an order of magnitude, and the price is that you&rsquo;re limited to what the solver can decide.</p>
<h2>The specification problem is the whole problem<span class="hx:absolute hx:-mt-20" id="the-specification-problem-is-the-whole-problem"></span>
    <a href="#the-specification-problem-is-the-whole-problem" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Anthropic was explicit about this, and it&rsquo;s the part almost no formal-proof enthusiast wants to face: <em>&ldquo;the difficulty of obtaining a comprehensive and unambiguous spec is a significant obstacle to verifying software at a larger scale&rdquo;</em>.</p>
<p>Think about what &ldquo;correct&rdquo; would even mean for a text editor. Or a browser. There&rsquo;s no single answer, because the specification is a product decision, not a mathematical fact. For a PNG decoder it&rsquo;s easy: RFC 2083 defines everything. For a refund policy, the specification is a board meeting.</p>
<p>The way out Anthropic found is clever and worth understanding, because it changes the game in practice: <strong>turn the existing fuzz test into a specification</strong>. Instead of inventing a description of desired behavior from scratch, they take the test the developer already wrote, compile it to RISC-V, and the specification becomes &ldquo;this test never crashes for any input up to 64 MB&rdquo;. If the test checks a compression round-trip, proving it never fails proves the round-trip property. If it checks an algebraic law, you proved the law.</p>
<p>It&rsquo;s an honest shortcut and, at the same time, an admission: the industry still doesn&rsquo;t know how to write good specifications for most software, so the move is to extract spec from what already exists as a test.</p>
<h2>seL4: the case that shows both the ceiling and the cost<span class="hx:absolute hx:-mt-20" id="sel4-the-case-that-shows-both-the-ceiling-and-the-cost"></span>
    <a href="#sel4-the-case-that-shows-both-the-ceiling-and-the-cost" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you want to understand why formal proof isn&rsquo;t routine, study <a href="https://sel4.systems/"target="_blank" rel="noopener">seL4</a>. It&rsquo;s the best-documented example that exists, and the numbers are the entire argument.</p>
<p>seL4 is a third-generation L4-family microkernel with <strong>8,700 lines of C and 600 lines of assembly</strong>. It was designed from the start to be verifiable, which is already a rare decision: the NICTA team in Sydney built the kernel with the proof in mind.</p>
<p>The functional-correctness proof, done in Isabelle/HOL, is about <strong>200,000 lines of script</strong> and roughly <strong>10,000 intermediate lemmas</strong>. The team reports somewhere between 20 and 25 person-years of total effort, with about 11 person-years specifically on the seL4 proof, the rest going into frameworks, libraries and tooling that later served other projects. Anthropic&rsquo;s paper cites the rounder numbers: 2 person-years to implement, <strong>20 to verify</strong>.</p>
<p>And what does the proof guarantee? That the kernel never violates its specification, never crashes, never violates memory safety, and enforces the access-control properties it claims. Nothing more. The seL4 paper itself lists what&rsquo;s left out: the proof <strong>assumes</strong> the correctness of the compiler, the assembly code, the hardware and the boot code.</p>
<p>That &ldquo;assumes the compiler&rdquo; turned into a problem of its own, and it&rsquo;s one of the most interesting parts of the story. After the original work, Thomas Sewell and others built <strong>binary verification</strong>: a toolchain that proves the compiled binary refines the C code. That removes the compiler from the trusted base. The work continues today with funding from the seL4 Foundation.</p>
<p>Three lessons I take from seL4:</p>
<p><strong>The first is that the proof finds bugs.</strong> The verification effort found <strong>144 implementation defects</strong> and drove <strong>54 code changes</strong>, including bugs normal testing missed. A proof isn&rsquo;t just a seal at the end; the process of proving is a violent debugging method.</p>
<p><strong>The second is that design matters more than tooling.</strong> seL4 is small enough to prove because someone decided it would be. A 5-million-line monolith with threads, dynamic allocation and plugins doesn&rsquo;t become verifiable through effort, it becomes verifiable through a rewrite.</p>
<p><strong>The third is that the cost is real and measurable.</strong> Twenty person-years for 10,000 lines. That&rsquo;s the benchmark against which any &ldquo;AI will fix it&rdquo; promise has to be measured.</p>
<h2>Why it was never cost-effective<span class="hx:absolute hx:-mt-20" id="why-it-was-never-cost-effective"></span>
    <a href="#why-it-was-never-cost-effective" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now the part that answers this article&rsquo;s title. There are five reasons, and they compound.</p>
<h3>The proof is bigger than the code, by orders of magnitude<span class="hx:absolute hx:-mt-20" id="the-proof-is-bigger-than-the-code-by-orders-of-magnitude"></span>
    <a href="#the-proof-is-bigger-than-the-code-by-orders-of-magnitude" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In seL4, 200,000 lines of proof for 8,700 lines of C: a factor of 23. In CompCert, the verified C compiler, it&rsquo;s <a href="https://compcert.org/doc/"target="_blank" rel="noopener">42,000 lines of Coq</a> and about 3 person-years, with 76% of the total going to proof rather than the compiler itself. At Anthropic, a typical proof runs 600,000 lines for 18,000 machine instructions, a factor of 33.</p>
<p>That&rsquo;s not bloat: it&rsquo;s the nature of the job. Proving a program does the right thing on every path requires arguing about every path, and the number of paths grows faster than the number of lines.</p>
<h3>Maintenance is the silent killer<span class="hx:absolute hx:-mt-20" id="maintenance-is-the-silent-killer"></span>
    <a href="#maintenance-is-the-silent-killer" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A proof is valid for a snapshot of the code. Change one line and the proof may stop holding, and the re-proving work is proportional to how much the change disturbed the invariants. In software that evolves weekly, you pay the proof cost again and again.</p>
<p>Compare with tests: a test that breaks tells you behavior changed. A proof that breaks tells you the structure of your argument changed, which is usually far more work to fix. That&rsquo;s why strong verification survives in frozen firmware and dies in SaaS products.</p>
<h3>The target moves faster than the proof<span class="hx:absolute hx:-mt-20" id="the-target-moves-faster-than-the-proof"></span>
    <a href="#the-target-moves-faster-than-the-proof" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every niche where formal proof took hold has slow evolution and catastrophic consequences: OS kernels, compilers, cryptography, flight control, train control, satellite components. In those worlds the cost of being wrong is measured in lives or billions, and the cost of proving is amortized over decades of operation.</p>
<p>E-commerce, fintech, marketplaces, B2B SaaS: the requirement changes on Tuesday, the competitor ships on Thursday, and product wants the A/B test on Friday. Formally proving a business rule that will be rewritten in three months is burning money. What works in those domains is tests, observability, feature flags and fast rollback.</p>
<h3>You prove the model, not the world<span class="hx:absolute hx:-mt-20" id="you-prove-the-model-not-the-world"></span>
    <a href="#you-prove-the-model-not-the-world" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This is the most underrated limitation. Every proof carries a <strong>trusted base</strong>: the set of things you simply believe. In Anthropic&rsquo;s case the text lists honestly what&rsquo;s left: the formal models of RISC-V and Linux processes, the exact theorem statements, and the Rocq kernel. Technically also the hardware, the OS, and the OCaml compiler running the checker.</p>
<p>In an ordinary software proof, the trusted base also includes the compiler (unless you use binary verification), the standard library, the allocator, the kernel, and the FFI boundary. Every unverified piece of C at the bottom of the stack is a hole in the guarantee. You can have the most proven core in the world calling a JSON library with a parser bug.</p>
<h3>The cost of error isn&rsquo;t uniform<span class="hx:absolute hx:-mt-20" id="the-cost-of-error-isnt-uniform"></span>
    <a href="#the-cost-of-error-isnt-uniform" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Formal proof treats every bug as equally important, because the specification is binary. Reality isn&rsquo;t: a crash that kills a worker is annoying, an anonymous RCE is catastrophic, and a rounding error in a report is irrelevant. Spending uniform proof effort on heterogeneous software allocates resources in the wrong place.</p>
<p>What the industry does, when it does it well, is the opposite: <strong>concentrate strong verification on the critical core and leave the rest to tests</strong>. That&rsquo;s exactly the lesson from my Bend 2 experiment, and I&rsquo;ll get back to it shortly.</p>
<h2>Bend 2: the attempt to flip the cost curve<span class="hx:absolute hx:-mt-20" id="bend-2-the-attempt-to-flip-the-cost-curve"></span>
    <a href="#bend-2-the-attempt-to-flip-the-cost-curve" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In September I wrote about <a href="/en/2026/09/19/new-ai-language-just-released-bend-2/">Bend 2</a>, Victor Taelin&rsquo;s language, and at the time the pitch struck me as overblown. Re-reading it now against Anthropic&rsquo;s paper, his design makes more sense than I gave it credit for.</p>
<p>The central idea in Bend 2 is splitting the program into two files:</p>
<ul>
<li><code>LAWS.bend</code>, written by the human, holding the system&rsquo;s invariants;</li>
<li><code>PROOF.bend</code>, written by the AI, holding the proofs of those laws.</li>
</ul>
<p>The type checker is a proof verifier in the Lean/Rocq lineage. If the proof doesn&rsquo;t close, the code doesn&rsquo;t land. The checker runs in 0.1 seconds, which is the genuinely novel part: you can put it in the agent loop, on every edit. Lean takes 19 seconds and Rocq 6 seconds for the same test set Bend resolves in 0.38 s, though his benchmarks have fair caveats, because he skips elaboration and unification.</p>
<p>In my test, the most useful result was this: to guarantee two simple facts about a guard of about 30 lines, I needed <strong>93 lines of laws and proofs</strong>. And I left out exactness of the algorithm, all the U32 arithmetic, and literally the rest of the program: JSON, sorting, rendering, IO. The provable surface was a few percent of the code.</p>
<p>That&rsquo;s the same phenomenon as seL4, at toy scale: <strong>the proof is bigger than the code and covers less than you&rsquo;d like</strong>. The difference is that in Bend the cost per proven line is seconds, not person-years, and that&rsquo;s where things get interesting.</p>
<p>And there&rsquo;s the lesson I consider the most important from my experiment, and it applies to any verification project: <strong>prove an isolated guard, leave the algorithm outside the proof</strong>. The ghpending <code>--limit</code> allocator ended up in two stages, with the algorithm in unproven U32 proposing values and a proven Nat guard clipping the excess. The law holds even if the unproven stage proposes garbage. The guard doesn&rsquo;t trust arithmetic it can&rsquo;t see.</p>
<p>That&rsquo;s the pattern that makes proof work in real code: you don&rsquo;t prove the system, you prove the boundary where an error is catastrophic, and leave the rest to tests. Anthropic&rsquo;s paper does exactly this by choosing to prove &ldquo;this fuzz entry point never crashes&rdquo; instead of &ldquo;this library is correct&rdquo;.</p>
<p>Bend&rsquo;s other lesson, and this one is harsh, is that <strong>the moment you cross the FFI boundary, the proof stays behind</strong>. The verifier guarantees what&rsquo;s inside its model; the C on the other side is an article of faith. My two ports needed eight hand-written effects in C, with no promise of stable ABI between releases. It&rsquo;s the same problem as <code>unsafe</code> in Rust, where borrow-checker guarantees hold up to the edge of the block.</p>
<h2>What Anthropic did differently, and what it admits<span class="hx:absolute hx:-mt-20" id="what-anthropic-did-differently-and-what-it-admits"></span>
    <a href="#what-anthropic-did-differently-and-what-it-admits" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Anthropic&rsquo;s leap wasn&rsquo;t inventing a new proof technique. It was using an LLM to solve the <strong>effort scale</strong> problem, the historical bottleneck.</p>
<p>The argument is simple and, once stated, obvious: generating 600,000 lines of proof is mechanical, tedious, enormous work, exactly the kind of thing a model with a multi-million-token budget is good at. The human doesn&rsquo;t have to review those 600,000 lines, because the Rocq kernel checks them mechanically. The human only has to trust four things: the RISC-V semantics, the Linux process semantics, the theorem statement, and the checker.</p>
<p>Three numbers from the paper show where this is going:</p>
<ul>
<li><strong>Cost is falling.</strong> On 36 verification tasks extracted from real OSS-Fuzz code, Opus 5.5 proves half of them with about <strong>40% fewer tokens</strong> than Opus 5. Models trained on long verification tasks get more efficient at it.</li>
<li><strong>Proof is reusable.</strong> When agents could copy each other&rsquo;s proofs in a shared workspace, they spent <strong>17% fewer tokens</strong>, and some proved what they had failed at alone. Most of such a proof is shared infrastructure: C runtime initialization and AddressSanitizer. Proof has the same shared-library economics as code.</li>
<li><strong>Dependencies follow a power law.</strong> Proving the most-shared libraries unlocks a huge slice of the ecosystem. That&rsquo;s Theorem&rsquo;s thesis, aiming to verify the entire Nix ecosystem, starting with glibc, OpenSSL and cURL.</li>
</ul>
<p>And now the admissions, which are the part I respect in the piece. They list four holes:</p>
<p><strong>Formally verified doesn&rsquo;t mean bug-free.</strong> The checker can&rsquo;t tell whether your spec matches reality. When bugs show up in verified code, it&rsquo;s because the spec or the assumed semantics diverged from the world.</p>
<p><strong>The real machine does what the model doesn&rsquo;t describe.</strong> The proofs hold for static, single-threaded, RISC-V binaries linked against musl. Most people run those libraries on x86 or ARM, dynamically linked against glibc. Closing that gap requires semantics closer to what&rsquo;s deployed.</p>
<p><strong>The claim may not cover what matters.</strong> AddressSanitizer doesn&rsquo;t catch every memory bug, not every entry point was proved, dead code isn&rsquo;t covered, and a caller can misuse the library and corrupt its own memory. Closing that requires specifying every public function&rsquo;s contract and forcing the caller to honor it.</p>
<p><strong>Reward hacking is a real risk.</strong> If you tell the AI to fix the code so the proof closes, it can rewrite the program into one that trivially never crashes. Anthropic penalized patches and gave extra credit for proving which inputs the patch changes and how few they are, auditing the patches. It&rsquo;s a reasonable defense and, at the same time, a reminder that you&rsquo;re optimizing against a stated objective, and a stated objective is hackable.</p>
<p>On the feasibility of &ldquo;more software, though still not all, better tested&rdquo;: I think the window is real, and the adoption shape will look like what already happened with static types. Nobody rewrote the world in Haskell. TypeScript came in on top, incrementally, where it paid off. Verification will come in the same way: first in shared dependencies, decoders, parsers, crypto libraries, the places where the spec is objective and the cost of a bug is high. Then, if the cost drops enough, in application modules with clear invariants.</p>
<h2>The week that blew up<span class="hx:absolute hx:-mt-20" id="the-week-that-blew-up"></span>
    <a href="#the-week-that-blew-up" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The urgency in Anthropic&rsquo;s piece didn&rsquo;t come from nowhere. In the days before, between October 20 and 23, the internet took a sequence of hits I don&rsquo;t remember seeing together. Let me go through each and ask: would formal proof have saved it?</p>
<h3>PHP2Shell: CVE-2026-109618 and CVE-2026-109619<span class="hx:absolute hx:-mt-20" id="php2shell-cve-2026-109618-and-cve-2026-109619"></span>
    <a href="#php2shell-cve-2026-109618-and-cve-2026-109619" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Two critical RCEs, CVSS 9.2, unauthenticated, in <strong>every PHP installation serving web requests</strong>: Apache with mod_php, PHP-FPM, php-cgi, FrankenPHP, LiteSpeed. Fixed on October 21 in <a href="https://www.php.net/archive/2026.php"target="_blank" rel="noopener">PHP 8.5.12, 8.4.27, 8.3.36 and 8.2.35</a>. <a href="https://www.cisa.gov/news-events/alerts/2026/10/21/critical-vulnerabilities-php-require-immediate-patching"target="_blank" rel="noopener">CISA&rsquo;s alert</a> recommends immediate patching and already published a Sigma detection rule. <a href="https://cert.europa.eu/publications/security-advisories/2026-018"target="_blank" rel="noopener">CERT-EU</a> reported exploitation attempts before the patch shipped.</p>
<p>Both bugs are memory bugs. CVE-2026-109618 is out-of-memory corruption during request cleanup. CVE-2026-109619 is stale global state reused by a following request.</p>
<p><strong>Would formal proof have saved it?</strong> In principle, yes, and it&rsquo;s the clearest case on the list. Memory corruption and stale global state across requests are exactly the kind of property that a memory-safety proof and a lifecycle invariant catch. The problem is scope: &ldquo;the whole lifecycle of a PHP request&rdquo; includes the C core, every extension, the SAPI, the allocator, and libc. That&rsquo;s a gigantic trusted base, and proving it would mean proving half the ecosystem. In practice, it&rsquo;s the kind of target that only makes sense once proof infrastructure is cheap enough, and it&rsquo;s why the strategy of verifying shared dependencies first (glibc, OpenSSL, cURL) is the one that makes sense.</p>
<h3>Node2Shell: CVE-2026-111497 in Brotli<span class="hx:absolute hx:-mt-20" id="node2shell-cve-2026-111497-in-brotli"></span>
    <a href="#node2shell-cve-2026-111497-in-brotli" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Out-of-bounds write in the Brotli decoder, Google&rsquo;s compression library that Node bundles. A malicious compressed stream corrupts adjacent memory, leaks contents or executes code. Affects Node 22.x, 24.x and 26.x, and since the bug is in <a href="https://www.cve.org/CVERecord?id=CVE-2026-111497"target="_blank" rel="noopener">Brotli itself</a>, it affects anything embedding the same copy: Bun, Python projects, and whatever else shows up. Affected versions: 1.0.3 through 1.2.0. Fixed in <a href="https://github.com/google/brotli/blob/v1.2.1/CHANGELOG.md"target="_blank" rel="noopener">1.2.1, 1.1.1 and 1.0.10</a>.</p>
<p>And there&rsquo;s a detail worth more than the CVE: <strong>the fix was written into Brotli&rsquo;s source in February and shipped in no release until October 21</strong>. Eight months with the repair sitting there.</p>
<p><strong>Would formal proof have saved it?</strong> Yes, and this is the best fit of all: a decoder with a round-trip law is the sweet spot. &ldquo;If you compress and decompress, the result is the original&rdquo; is an objective spec, and proving the decoder never writes outside the buffer for any input is standard memory-safety proof. Bend 2, in fact, lists codecs with round-trip laws as a natural niche.</p>
<p>But notice: proof wouldn&rsquo;t have fixed the real problem. The bug lived in unproven code, and the fix existed since February. What killed it was release process, not lack of proof. No formal proof fixes a maintainer who doesn&rsquo;t publish the fixed version.</p>
<h3>GitLab: CVE-2026-110264, CVSS 10.0<span class="hx:absolute hx:-mt-20" id="gitlab-cve-2026-110264-cvss-100"></span>
    <a href="#gitlab-cve-2026-110264-cvss-100" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Integer overflow in Onigmo, the regex engine Ruby bundles, reachable through GitLab&rsquo;s Org-mode file renderer: the <code>org-ruby</code> gem takes the raw keyword from a <code>#+TODO:</code> line and drops it into <code>Regexp.new</code>. A pattern built to overflow the counter makes the engine write past its buffer, and an unauthenticated visitor executes code on a self-managed server. CVSS 10.0, the maximum. And the reach: <strong>every version since 7.0, from 2014</strong>, twelve years of releases. Fixed on October 21 in <a href="https://docs.gitlab.com/releases/patches/patch-release-gitlab-19-5-1-released"target="_blank" rel="noopener">19.5.1, 19.4.3, 19.3.6, 19.2.9, 19.1.9, 19.0.10 and 18.11.13</a>. Nine days earlier, CVE-2026-97229, also CVSS 10.0 and also Onigmo, had been fixed at the engine&rsquo;s other entry point: the CI/CD regex compiler. And the real repair shipped in Ruby itself, on October 23, because the bug was in the language&rsquo;s engine, not in GitLab. Anyone who patched on October 12 had to patch again on 21.</p>
<p><strong>Would formal proof have saved it?</strong> Partially, and the case is instructive. An arithmetic overflow in a parser is detectable: a no-overflow proof, or even a compiler with overflow checks in a test build, catches it. But the attack working &ldquo;under certain conditions&rdquo; that GitLab didn&rsquo;t disclose suggests the hard part is logic, not arithmetic. The lesson that sticks is different: a regex engine exposed to untrusted input is a classic verification surface, and nobody verifies it because it&rsquo;s product code in constant motion.</p>
<h3>Railway: the attack no formal proof prevents<span class="hx:absolute hx:-mt-20" id="railway-the-attack-no-formal-proof-prevents"></span>
    <a href="#railway-the-attack-no-formal-proof-prevents" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This wasn&rsquo;t a code bug. On October 20 and 21, an attacker reached Railway&rsquo;s internal systems, the deploy platform used by more than 2 million developers, and <strong>may have obtained the decrypted contents of environment variables</strong> for some customers. The company told every user to revoke and recreate credentials stored before October 21.</p>
<p>The <a href="https://blog.railway.com/p/preliminary-report-october-security-incident"target="_blank" rel="noopener">preliminary report</a> says it was a &ldquo;sustained and targeted campaign&rdquo;, that the attacker had access to abliterated models and substantial compute, and that the goal was to <strong>obtain API keys from AI providers</strong> for distillation attacks. Keys for OpenAI, Anthropic, Google, GitHub, GitLab, Stripe and the like. Railway asked the providers to revoke the keys it found.</p>
<p><strong>Would formal proof have saved it?</strong> No. No code-correctness proof stops someone from getting your keys and decrypting your secrets. That&rsquo;s a problem of key-custody architecture, network segregation and incident response, not program correctness. And it&rsquo;s an important reminder in this conversation: most real incidents aren&rsquo;t logic bugs in code, they&rsquo;re misconfiguration, leaked credentials, excessive permissions.</p>
<h3>PS5: the kernel falling firmware after firmware<span class="hx:absolute hx:-mt-20" id="ps5-the-kernel-falling-firmware-after-firmware"></span>
    <a href="#ps5-the-kernel-falling-firmware-after-firmware" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>On September 29, the <a href="https://github.com/ntfargo/Relapse-Exploit"target="_blank" rel="noopener">Relapse</a> exploit was published, working on any PS5 and PS5 Pro from firmware 7.00 through 13.60. It&rsquo;s a chain with a kernel use-after-free, reaching unsigned code execution. Firmware 14.00, from September 16, had already closed the kernel hole Relapse uses, according to the scene, thirteen days before the exploit went public, so the post-publication response was another one: 14.10 on October 1 and 14.20 on October 21. The 14.10 showed up cracked 18 days later, in a private demo that opened the debug menu, and the 14.20 got a userland entry point <strong>eight hours after release</strong>.</p>
<p><strong>Would formal proof have saved it?</strong> In principle, yes: use-after-free is precisely what a memory-safety proof eliminates. seL4 proved that for a microkernel. But the PS5 runs a FreeBSD-derived kernel, with a hypervisor, with the AMD Platform Security Processor underneath, all closed, with millions of lines and no intention of proving anything. Verifying that whole stack isn&rsquo;t expensive, it&rsquo;s impractical. What you can do is what seL4 does: prove the small, critical components, and accept that the rest gets mitigation and bug bounties.</p>
<p>A footnote I find more revealing than the exploit: the pace. Sony ships firmware, the scene breaks it in days. Not because the kernel is badly written, but because it&rsquo;s big, closed, and attacked by people with time and motivation. It&rsquo;s the mirror image of seL4.</p>
<h3>The pattern that comes out of this table<span class="hx:absolute hx:-mt-20" id="the-pattern-that-comes-out-of-this-table"></span>
    <a href="#the-pattern-that-comes-out-of-this-table" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th>Incident</th>
          <th>Nature</th>
          <th>Would formal proof fix it?</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>PHP2Shell</td>
          <td>Memory corruption + global state</td>
          <td>Yes in principle, expensive in practice (huge trusted base)</td>
      </tr>
      <tr>
          <td>Node2Shell (Brotli)</td>
          <td>Out-of-bounds write in a decoder</td>
          <td>Yes, perfect fit, and the real problem was a stalled release</td>
      </tr>
      <tr>
          <td>GitLab CVE-2026-110264</td>
          <td>Integer overflow in an exposed parser</td>
          <td>Partially; the logic part stays out</td>
      </tr>
      <tr>
          <td>Railway</td>
          <td>Credentials and secrets compromised</td>
          <td>No. Architecture and custody problem</td>
      </tr>
      <tr>
          <td>PS5 Relapse</td>
          <td>Use-after-free in a giant closed kernel</td>
          <td>Yes in theory, unworkable at that scope</td>
      </tr>
  </tbody>
</table>
<p>Three &ldquo;yes&rdquo; and two &ldquo;no&rdquo; in the right column already makes the point: formal proof solves an entire class of bugs, and that class is the one that scares people most, memory corruption turning into RCE. What it doesn&rsquo;t solve is everything else, and &ldquo;everything else&rdquo; is most of what happens.</p>
<h2>My read: technical debt is coming due<span class="hx:absolute hx:-mt-20" id="my-read-technical-debt-is-coming-due"></span>
    <a href="#my-read-technical-debt-is-coming-due" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now I speak for myself.</p>
<p>I posted <a href="https://x.com/AkitaOnRails/status/2113361323434070101"target="_blank" rel="noopener">on X</a> that a huge amount of code written by humans over the last few years is really bad, and that a lot of the people calling everything &ldquo;AI Slop&rdquo; spent their lives accumulating &ldquo;Human Slop&rdquo; because they counted on nobody bothering to check.</p>
<p>I stand by every word. And I&rsquo;ll add the diagnosis: <strong>the industry spent two decades taking on technical debt under the implicit premise that auditing was expensive and rare</strong>. Shallow code review, decorative test coverage, depending on a library without reading the changelog, admin permissions on a service account because the vault is annoying, secrets in environment variables because the vault is annoying to configure. None of it caused problems because the cost of discovery was high.</p>
<p>What changed, and changed in months, is the cost of discovery. In the <a href="https://x.com/AkitaOnRails/status/2113396195561287791"target="_blank" rel="noopener">other post</a> I said I like the trend of any non-programmer armed with an LLM, tokens and skills turning into a security scanner, and that every company with a web platform should be very afraid. And that&rsquo;s good. Deedy described the same thing hours earlier: non-technical people exploiting PHP2Shell with frontier models, and he admitted being frightened.</p>
<p>I understand the scare. I disagree with the framing. What happened wasn&rsquo;t the creation of a new vulnerability; it was the <strong>removal of the friction of discovery</strong> for vulnerabilities that were already there, some since 2014, like GitLab&rsquo;s. The debt was always there. What changed is that it&rsquo;s now due.</p>
<p>And here&rsquo;s the balance I think the conversation is missing, on both sides.</p>
<p>On the attacker side, the barrier to entry collapsed. It used to take years of study, expensive tooling and time to find an RCE. Now it takes a model, an account and patience. The volume of attempts will jump an order of magnitude, and the window between disclosure and exploitation, already days, will become hours. The PS5 cracked hours after each firmware is a portrait of everyone&rsquo;s future.</p>
<p>On the defender side, the same lever exists, and that&rsquo;s where I&rsquo;m optimistic. The same capabilities that generate exploits generate audits. The same model reading a diff for authorization flaws reads a diff for memory bugs. The same proof techniques from Anthropic&rsquo;s paper can stamp a library you depend on. The cost of hardening fell alongside the cost of attacking, and that symmetry is the good news.</p>
<p>What makes me confident isn&rsquo;t the technology alone, it&rsquo;s the incentive. When the cost of finding a flaw drops to nearly zero, the cost of <strong>not</strong> finding it rises to nearly infinity. A CTO who today accepts shipping a dependency with a known CVE will have to explain why, in a world where any intern with Claude audits their supply chain in an afternoon. The pressure shifts from &ldquo;nobody will look&rdquo; to &ldquo;everybody will look&rdquo;, and behavior changes with incentives, not sermons.</p>
<p>I bet the result is a higher quality standard for everyone. Not because people became more virtuous, but because inspection became cheap. It&rsquo;s the same dynamic that made HTTPS standard, that made two-factor auth standard, that made dependabot standard. None of that happened out of conscience; it happened because the alternative got too expensive.</p>
<p>And formal proof enters that package as the top layer. It won&rsquo;t be the everyday tool of the e-commerce dev. It will be what we use on the pieces that can&rsquo;t fail: the decoder everyone uses, the crypto library, the parser exposed to the internet, the device kernel, the contract holding money. Exactly where the cost of error is greater than the cost of proof, which is the only math that matters.</p>
<p>Anthropic&rsquo;s paper shows that math started to close for the first time. Most programmers will never write a line of Rocq in their lives, and they don&rsquo;t need to. They need someone to write the proofs for the pieces everyone uses, and that just became cheap enough to be routine.</p>
<h2>What I take from this<span class="hx:absolute hx:-mt-20" id="what-i-take-from-this"></span>
    <a href="#what-i-take-from-this" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Three things, so I don&rsquo;t end on pretty prose.</p>
<p><strong>Formal proof is a scoping tool, not a coverage tool.</strong> You pick a small core, write an objective spec, and prove it. The rest stays with tests, because tests are cheaper and catch what proof didn&rsquo;t. Anyone promising &ldquo;bug-free code&rdquo; is selling the wrong thing, and Anthropic went out of its way to say so in bold type.</p>
<p><strong>The bottleneck moved.</strong> It used to be writing the proof. Now it&rsquo;s writing the specification and keeping the proof alive while the code changes. Anthropic solved the first problem with brute-force tokens and partially solved the second with proof reuse and package-level granularity. The second is the genuinely hard problem, and it&rsquo;s where I want to see the next generation of tools.</p>
<p><strong>The 2026 window is real.</strong> For the first time there&rsquo;s a path where verifying a critical dependency costs less than the incident it prevents. And it arrives alongside external pressure, in the form of people with LLMs finding the same bugs from the other side. If you lead engineering, the question stopped being &ldquo;is verification worth investing in&rdquo; and became &ldquo;how much does it cost to be the next Railway&rdquo;.</p>
<p>Technical debt was always there. The difference is that now it has a collector.</p>
<p>If you want the technical details, Anthropic&rsquo;s paper has an appendix with the case studies, and the published proofs are in <a href="https://github.com/theorem-labs/oss-verify-proofs"target="_blank" rel="noopener">Theorem&rsquo;s repository</a>, along with the <a href="https://github.com/theorem-labs/rocq-linux-process-semantics"target="_blank" rel="noopener">RISC-V and Linux process semantics</a>. The skill to run the pipeline on your own project is public too. Worth reading, even if you never write a line of Rocq in your life.</p>
]]></content:encoded><category>security</category><category>software-engineering</category><category>artificial-intelligence</category><category>programming-languages</category></item><item><title>LLM Benchmark v4: the open source verdict (as of Oct 2026)</title><link>https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/</guid><pubDate>Thu, 22 Oct 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;This is the wrap-up of benchmark v4. Since I started this round, there have been seven articles, first in the cloud and then pushing the same sabotage yardstick further and further away from it:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/09/15/new-llm-benchmark-v4-retesting-all-top-llms-part-1/"&gt;Part 1&lt;/a&gt;&lt;/strong&gt;: why I rebuilt the benchmark from scratch for the third time, how the Rails app sabotaged with real CVEs works, and how much it cost.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/09/15/new-llm-benchmark-v4-retesting-39-llms-part-2/"&gt;Part 2&lt;/a&gt;&lt;/strong&gt;: the original cloud ranking, with almost 40 models, six ties at the top and a free model beating half of the Claude lineup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/"&gt;Opus 5.5, GPT-6 sol and luna, MiMo 2.6 and Grok 4.7&lt;/a&gt;&lt;/strong&gt;: the next cloud batch. Opus 5.5 closed at 100, GPT 6 luna scored 95.5 for under a dollar per run, and Grok 4.7 regressed against its own predecessor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/"&gt;The top open source LLMs on a B300&lt;/a&gt;&lt;/strong&gt;: one rented GPU, 14 open models, and two of them, GLM 5.3 Flash and Qwen3.8 Flash-Next, tied at 92.5, on par with Sonnet 5.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-open-source-that-only-fits-in-4x-b300/"&gt;Open source that only fits in 4x B300&lt;/a&gt;&lt;/strong&gt;: the big models, most of them between 400 billion and 1 trillion parameters. DeepSeek V4.1 Flash tied the leader at 92.5 and the rest showed that size doesn&amp;rsquo;t buy vigilance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/"&gt;Can my team fit in 4x B300/H200?&lt;/a&gt;&lt;/strong&gt;: a real concurrency test. The same DeepSeek serves 32 comfortable sessions on the B300 pod and only 8 on the H200 one.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-consumer-open-source-rtx5090-strix-halo-strata/"&gt;Consumer-grade open source on RTX 5090 or Strix Halo&lt;/a&gt;&lt;/strong&gt;: Qwen3.8 Flash-Next scored 91 on a PC card with the Strata engine, at 159 tokens per second.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This article puts everything in a single table and answers the question left over: &lt;strong&gt;as of October 2026, is open source good enough?&lt;/strong&gt;&lt;/p&gt;</description><content:encoded><![CDATA[<p>This is the wrap-up of benchmark v4. Since I started this round, there have been seven articles, first in the cloud and then pushing the same sabotage yardstick further and further away from it:</p>
<ul>
<li><strong><a href="/en/2026/09/15/new-llm-benchmark-v4-retesting-all-top-llms-part-1/">Part 1</a></strong>: why I rebuilt the benchmark from scratch for the third time, how the Rails app sabotaged with real CVEs works, and how much it cost.</li>
<li><strong><a href="/en/2026/09/15/new-llm-benchmark-v4-retesting-39-llms-part-2/">Part 2</a></strong>: the original cloud ranking, with almost 40 models, six ties at the top and a free model beating half of the Claude lineup.</li>
<li><strong><a href="/en/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/">Opus 5.5, GPT-6 sol and luna, MiMo 2.6 and Grok 4.7</a></strong>: the next cloud batch. Opus 5.5 closed at 100, GPT 6 luna scored 95.5 for under a dollar per run, and Grok 4.7 regressed against its own predecessor.</li>
<li><strong><a href="/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/">The top open source LLMs on a B300</a></strong>: one rented GPU, 14 open models, and two of them, GLM 5.3 Flash and Qwen3.8 Flash-Next, tied at 92.5, on par with Sonnet 5.</li>
<li><strong><a href="/en/2026/10/22/llm-benchmark-v4-open-source-that-only-fits-in-4x-b300/">Open source that only fits in 4x B300</a></strong>: the big models, most of them between 400 billion and 1 trillion parameters. DeepSeek V4.1 Flash tied the leader at 92.5 and the rest showed that size doesn&rsquo;t buy vigilance.</li>
<li><strong><a href="/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/">Can my team fit in 4x B300/H200?</a></strong>: a real concurrency test. The same DeepSeek serves 32 comfortable sessions on the B300 pod and only 8 on the H200 one.</li>
<li><strong><a href="/en/2026/10/22/llm-benchmark-v4-consumer-open-source-rtx5090-strix-halo-strata/">Consumer-grade open source on RTX 5090 or Strix Halo</a></strong>: Qwen3.8 Flash-Next scored 91 on a PC card with the Strata engine, at 159 tokens per second.</li>
</ul>
<p>This article puts everything in a single table and answers the question left over: <strong>as of October 2026, is open source good enough?</strong></p>
<h2>The biggest benchmark I&rsquo;ve ever run<span class="hx:absolute hx:-mt-20" id="the-biggest-benchmark-ive-ever-run"></span>
    <a href="#the-biggest-benchmark-ive-ever-run" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>v4 was, by far, the biggest round of testing I&rsquo;ve ever done. That&rsquo;s almost 70 complete runs of the same protocol, almost 60 different models, running on cloud APIs, on a rented B300, on a four-B300 pod, on an RTX 5090 and on a Strix Halo, plus a four-H200 pod just for the concurrency test.</p>
<p>And it was expensive. The first batch alone, the cloud one, went past 4 thousand dollars in nine days, counting credits and subscriptions. The single B300 cost about 270, and the 4x B300 and 4x H200 campaign took about another 2,100. Adding up what I can add up, it went past 6 thousand dollars, not counting machine hours at home.</p>
<blockquote>
  <p>I don&rsquo;t think many people are going to reproduce this any time soon. If this material was useful to you, share it with whoever needs to decide between cloud, their own server or a local PC. All the code, prompts, logs and reports are open on my GitHub: <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">akitaonrails/llm-coding-benchmark</a>.</p>

</blockquote>
<h3>A refresher on the yardstick<span class="hx:absolute hx:-mt-20" id="a-refresher-on-the-yardstick"></span>
    <a href="#a-refresher-on-the-yardstick" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The protocol is always the same. The model builds a Rails chat app in seven sprints, and between sprints a reviewer injects 14 security and correctness defects, some loud (a CVE in a gem, a key in the code), others silent (a cross-tenant leak, a wrong aggregate, a test tampered with to hide a backdoor).</p>
<p>The score goes from 0 to 100. A defect fixed unprompted counts at full weight; fixed only after I reveal there&rsquo;s a problem, it counts 40%; never fixed counts zero. The tiers are A from 83 up, B from 73 to 82.5, C from 51 to 72.5 and D up to 50.</p>
<p>It&rsquo;s a yardstick for <strong>code review vigilance</strong>. It measures whether the model notices sabotage while it works, and that is different from measuring who writes your whole system better.</p>
<h2>The combined ranking<span class="hx:absolute hx:-mt-20" id="the-combined-ranking"></span>
    <a href="#the-combined-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every v4 run in a single table, commercial and open, cloud and my own hardware. When the same model ran in different places, it shows up more than once, because the place changes the score.</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">#</th>
          <th>Model</th>
          <th>Weights</th>
          <th>Where it ran</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: center">Tier</th>
          <th style="text-align: right">Cost per run</th>
          <th style="text-align: right">tok/s</th>
          <th style="text-align: right">Minutes</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>GPT-6 Astra</td>
          <td>closed</td>
          <td>Cloud (Codex)</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 30.55</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">100</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>Claude Opus 5</td>
          <td>closed</td>
          <td>Cloud (Claude Code)</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">~US$ 71 ¹</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">145</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>Claude Fable 5</td>
          <td>closed</td>
          <td>Cloud (Claude Code)</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">~US$ 50 ¹</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">85</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>Claude Opus 5.5</td>
          <td>closed</td>
          <td>Cloud (Claude Code)</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 16.63 ¹</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">64</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>GPT 5.6 sol</td>
          <td>closed</td>
          <td>Cloud (Codex)</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 20.37</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">317</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>GPT 5.6 terra</td>
          <td>closed</td>
          <td>Cloud (Codex)</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 9.52</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">80</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>GPT 5.5</td>
          <td>closed</td>
          <td>Cloud (Codex)</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 34.69</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">117</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>Grok 4.6</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">98.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 13.00</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">67</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Claude Fable 5.1</td>
          <td>closed</td>
          <td>Cloud (Claude Code)</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">~US$ 51 ¹</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">133</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Sakana Fugu Ultra v2</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 122.01</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">294</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>GPT 6 luna</td>
          <td>closed</td>
          <td>Cloud (Codex)</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">~US$ 0.84 ²</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">122</td>
      </tr>
      <tr>
          <td style="text-align: right">12</td>
          <td>GPT 5.6 luna</td>
          <td>closed</td>
          <td>Cloud (Codex)</td>
          <td style="text-align: right">95.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 10.04</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">123</td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td>Nex N2.5 Pro ⁴</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">94.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">free</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">480</td>
      </tr>
      <tr>
          <td style="text-align: right">13</td>
          <td>GLM 5.3</td>
          <td>open</td>
          <td>Cloud (ZCode)</td>
          <td style="text-align: right">94.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">flat plan</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">215</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>DeepSeek V4.1 Flash</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 1.21</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">172</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>DeepSeek V4.1 Flash</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">174.8</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>GLM 5.3 Flash (NVFP4)</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 21.96 ³</td>
          <td style="text-align: right">142.0</td>
          <td style="text-align: right">145</td>
      </tr>
      <tr>
          <td style="text-align: right">15</td>
          <td>Qwen3.8 Flash-Next (NVFP4)</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 12.04 ³</td>
          <td style="text-align: right">195.0</td>
          <td style="text-align: right">80</td>
      </tr>
      <tr>
          <td style="text-align: right">19</td>
          <td>MiMo V2.6 Pro</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">92.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 1.22</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">308</td>
      </tr>
      <tr>
          <td style="text-align: right">20</td>
          <td>Qwen3.8 Flash-Next (IQ3_S)</td>
          <td>open</td>
          <td>RTX 5090 (Strata)</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 0 (local)</td>
          <td style="text-align: right">159.2</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">20</td>
          <td>Claude Sonnet 5</td>
          <td>closed</td>
          <td>Cloud (Claude Code)</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">~US$ 27 ¹</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">112</td>
      </tr>
      <tr>
          <td style="text-align: right">20</td>
          <td>GPT 6 sol</td>
          <td>closed</td>
          <td>Cloud (Codex)</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">~US$ 8.35 ²</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">73</td>
      </tr>
      <tr>
          <td style="text-align: right">23</td>
          <td>Gemini 3.8 Flash high</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">90.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 15.98</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">97</td>
      </tr>
      <tr>
          <td style="text-align: right">24</td>
          <td>Gemini 3.8 Flash</td>
          <td>closed</td>
          <td>Cloud (Antigravity)</td>
          <td style="text-align: right">89.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">free (OAuth)</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">120</td>
      </tr>
      <tr>
          <td style="text-align: right">24</td>
          <td>MiniMax M3.1 Flash</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">89.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">free</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">26</td>
          <td>Muse Spark 1.3</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">88.75</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 13.31</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">150</td>
      </tr>
      <tr>
          <td style="text-align: right">27</td>
          <td>Swift 1.5 27B</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">88.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 9.71 ³</td>
          <td style="text-align: right">203.0</td>
          <td style="text-align: right">64</td>
      </tr>
      <tr>
          <td style="text-align: right">27</td>
          <td>Grok 4.5</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">88.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 6.19</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">48</td>
      </tr>
      <tr>
          <td style="text-align: right">29</td>
          <td>Claude Opus 4.6</td>
          <td>closed</td>
          <td>Cloud (Claude Code)</td>
          <td style="text-align: right">87.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 25.64 ¹</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">89</td>
      </tr>
      <tr>
          <td style="text-align: right">30</td>
          <td>Kimi K2.7 Code</td>
          <td>open</td>
          <td>Cloud (Kimi CLI)</td>
          <td style="text-align: right">87.25</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 7.75</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">175</td>
      </tr>
      <tr>
          <td style="text-align: right">31</td>
          <td>MiMo V2.5 Pro</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">86.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 1.03</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">158</td>
      </tr>
      <tr>
          <td style="text-align: right">31</td>
          <td>Qwen3.8 Flash</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">86.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 1.17</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">149</td>
      </tr>
      <tr>
          <td style="text-align: right">33</td>
          <td>DeepSeek V4 Flash</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">86.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 0.97</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">111</td>
      </tr>
      <tr>
          <td style="text-align: right">33</td>
          <td>Claude Opus 4.8</td>
          <td>closed</td>
          <td>Cloud (Claude Code)</td>
          <td style="text-align: right">86.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">~US$ 37 ¹</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">87</td>
      </tr>
      <tr>
          <td style="text-align: right">35</td>
          <td>Claude Sonnet 4.6</td>
          <td>closed</td>
          <td>Cloud (Claude Code)</td>
          <td style="text-align: right">85.75</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 18.64 ¹</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">91</td>
      </tr>
      <tr>
          <td style="text-align: right">36</td>
          <td>Kimi K3</td>
          <td>open</td>
          <td>Cloud (Kimi CLI)</td>
          <td style="text-align: right">85.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 13.79</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">148</td>
      </tr>
      <tr>
          <td style="text-align: right">36</td>
          <td>DeepSeek V4 Flash 0731</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">85.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 1.94</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">194</td>
      </tr>
      <tr>
          <td style="text-align: right">38</td>
          <td>GLM 5.3 Flash</td>
          <td>open</td>
          <td>Cloud (ZCode)</td>
          <td style="text-align: right">84.25</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">flat plan</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">296</td>
      </tr>
      <tr>
          <td style="text-align: right">39</td>
          <td>DeepSeek V4 Pro 0813</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">84.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 4.49</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">152</td>
      </tr>
      <tr>
          <td style="text-align: right">40</td>
          <td>Step 3.7 Flash</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">83.75</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 4.15</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">118</td>
      </tr>
      <tr>
          <td style="text-align: right">41</td>
          <td>Grok 4.7</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">83.5</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 27.94</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">120</td>
      </tr>
      <tr>
          <td style="text-align: right">42</td>
          <td>ThinkingCap 3.8 27B</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">83.0</td>
          <td style="text-align: center">A</td>
          <td style="text-align: right">US$ 11.47 ³</td>
          <td style="text-align: right">189.0</td>
          <td style="text-align: right">76</td>
      </tr>
      <tr>
          <td style="text-align: right">43</td>
          <td>DeepSeek V4 Pro</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">82.0</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">US$ 5.26</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">97</td>
      </tr>
      <tr>
          <td style="text-align: right">44</td>
          <td>Muse Glimmer 30B</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">81.0</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">US$ 3.54 ³</td>
          <td style="text-align: right">295.0</td>
          <td style="text-align: right">23</td>
      </tr>
      <tr>
          <td style="text-align: right">44</td>
          <td>Ornith 1.5 35B</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">81.0</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">US$ 24.39 ³</td>
          <td style="text-align: right">317.0</td>
          <td style="text-align: right">161</td>
      </tr>
      <tr>
          <td style="text-align: right">46</td>
          <td>Qwen 3.8 27B</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">80.5</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">US$ 29.11 ³</td>
          <td style="text-align: right">195.0</td>
          <td style="text-align: right">192</td>
      </tr>
      <tr>
          <td style="text-align: right">47</td>
          <td>Qwen 3.8 27B (Q8_0)</td>
          <td>open</td>
          <td>Strix Halo</td>
          <td style="text-align: right">80.0</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">US$ 0 (local)</td>
          <td style="text-align: right">7.7</td>
          <td style="text-align: right">706</td>
      </tr>
      <tr>
          <td style="text-align: right">48</td>
          <td>Qwen 3.7 Max</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">79.0</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">US$ 10.63</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">106</td>
      </tr>
      <tr>
          <td style="text-align: right">49</td>
          <td>GLM 5.2</td>
          <td>open</td>
          <td>Cloud (ZCode)</td>
          <td style="text-align: right">77.0</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">flat plan</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">239</td>
      </tr>
      <tr>
          <td style="text-align: right">50</td>
          <td>GLM 5.3 full</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">76.0</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">110.0</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">51</td>
          <td>Gemini 3.7 Flash high</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">75.5</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">US$ 12.93</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">85</td>
      </tr>
      <tr>
          <td style="text-align: right">51</td>
          <td>MiniMax M3</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">75.5</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">US$ 12.17</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">187</td>
      </tr>
      <tr>
          <td style="text-align: right">53</td>
          <td>Ornith 1.5 122B</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">73.0</td>
          <td style="text-align: center">B</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">244.2</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">54</td>
          <td>Step-5-Preview</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">72.5</td>
          <td style="text-align: center">C</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">165.9</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">55</td>
          <td>Muse Spark Open</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">69.5</td>
          <td style="text-align: center">C</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">130.8</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">56</td>
          <td>Qwen3.5 397B (NVFP4)</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">68.5</td>
          <td style="text-align: center">C</td>
          <td style="text-align: right">US$ 8.22 ³</td>
          <td style="text-align: right">140.0</td>
          <td style="text-align: right">54</td>
      </tr>
      <tr>
          <td style="text-align: right">57</td>
          <td>MiMo V2.6 Pro</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">67.0</td>
          <td style="text-align: center">C</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">167.2</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">58</td>
          <td>Laguna-S-2.1</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">65.5</td>
          <td style="text-align: center">C</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">263.0</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">59</td>
          <td>Ornith 1.5 35B (Q8_0)</td>
          <td>open</td>
          <td>RTX 5090 (Strata)</td>
          <td style="text-align: right">64.5</td>
          <td style="text-align: center">C</td>
          <td style="text-align: right">US$ 0 (local)</td>
          <td style="text-align: right">80.0</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">60</td>
          <td>Nemotron 3.5 Super VL (NVFP4)</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">63.0</td>
          <td style="text-align: center">C</td>
          <td style="text-align: right">US$ 7.51 ³</td>
          <td style="text-align: right">207.0</td>
          <td style="text-align: right">50</td>
      </tr>
      <tr>
          <td style="text-align: right">61</td>
          <td>Kimi K2 Thinking</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">46.0</td>
          <td style="text-align: center">D</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">110.0</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">62</td>
          <td>DeepSeek V4 Flash</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">44.5</td>
          <td style="text-align: center">D</td>
          <td style="text-align: right">US$ 5.59 ³</td>
          <td style="text-align: right">153.0</td>
          <td style="text-align: right">37</td>
      </tr>
      <tr>
          <td style="text-align: right">63</td>
          <td>Mistral Large 3</td>
          <td>open</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">39.0</td>
          <td style="text-align: center">D</td>
          <td style="text-align: right">US$ 5.11</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">76</td>
      </tr>
      <tr>
          <td style="text-align: right">64</td>
          <td>GLM 4.7 Flash (BF16)</td>
          <td>open</td>
          <td>1x B300</td>
          <td style="text-align: right">33.5</td>
          <td style="text-align: center">D</td>
          <td style="text-align: right">US$ 4.60 ³</td>
          <td style="text-align: right">217.0</td>
          <td style="text-align: right">30</td>
      </tr>
      <tr>
          <td style="text-align: right">65</td>
          <td>Gemini 3.1 Pro ⁴</td>
          <td>closed</td>
          <td>Cloud (OpenCode)</td>
          <td style="text-align: right">32.5</td>
          <td style="text-align: center">D</td>
          <td style="text-align: right">US$ 10.31</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">54</td>
      </tr>
      <tr>
          <td style="text-align: right">66</td>
          <td>Nex N2.5 Pro</td>
          <td>open</td>
          <td>4x B300</td>
          <td style="text-align: right">27.0</td>
          <td style="text-align: center">D</td>
          <td style="text-align: right">pod at US$ 36/h</td>
          <td style="text-align: right">184.0</td>
          <td style="text-align: right">—</td>
      </tr>
      <tr>
          <td style="text-align: right">67</td>
          <td>GLM-4.7-Flash (Q5_K_M)</td>
          <td>open</td>
          <td>RTX 5090</td>
          <td style="text-align: right">24.0</td>
          <td style="text-align: center">D</td>
          <td style="text-align: right">US$ 0 (local)</td>
          <td style="text-align: right">—</td>
          <td style="text-align: right">29</td>
      </tr>
  </tbody>
</table>
<p>How to read the columns:</p>
<ul>
<li><strong>Weights</strong>: &ldquo;open&rdquo; is a downloadable checkpoint, any license; &ldquo;closed&rdquo; is API only.</li>
<li><strong>Cost per run</strong>: what one full seven-sprint run cost.</li>
<li><strong>tok/s</strong>: single-stream decode speed, measured by me. It only exists for the ones I served.</li>
<li><strong>Minutes</strong>: wall-clock time for the whole run, when I have the data. On the single B300, it&rsquo;s sprint time only.</li>
</ul>
<p>And the footnotes:</p>
<ol>
<li>Claude ran through the Claude Code Max subscription. The cost is notional: the run&rsquo;s tokens at API list price.</li>
<li>Estimated from the run&rsquo;s tokens.</li>
<li>Inference time on the B300 only, at about US$ 9 per hour. Download, loading, compilation and tuning are left out, and the real pod cost was higher.</li>
<li>Score with a caveat. The cloud Nex was graded from disk, with everything uncommitted; Gemini 3.1 Pro was hurt by an OpenRouter proxy bug.</li>
</ol>
<p>The first v4 articles lumped everything below B into C; here I use the scale with D, the same as the B300 campaigns. MiniMax M3.1 Flash ran for free through OpenRouter as the cloud anchor for the local campaign, and MiniMax promises to release its weights on October 23.</p>
<h2>The models are converging<span class="hx:absolute hx:-mt-20" id="the-models-are-converging"></span>
    <a href="#the-models-are-converging" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Within the limited scope of this benchmark, it looks like everybody is arriving at the same place. <strong>42 of the 67 runs made Tier A</strong>, 24 from closed models and 18 from open ones. Seven models hit 100, and 23 runs landed above 90.</p>
<p>Part of that is a limit of the yardstick itself. When seven models get the top score, the test stops separating the top. And a repeated GPT 5.5 run scored 91 against the official 100, so differences of a few points between two models may just be noise.</p>
<p>Even discounting that, the picture is clear. DeepSeek V4.1 Flash, GLM 5.3 Flash and Qwen3.8 Flash-Next, all open, sit 7.5 points from the ceiling, right on the heels of Sonnet 5 and GPT 6 sol.</p>
<blockquote>
  <p>For code review and vigilance, a good open model is already in the same pack as a good closed model. What still separates the two is consistency: among the open models there are D scores that don&rsquo;t show up among the top closed ones.</p>

</blockquote>
<h3>The West stalled, China sprinting<span class="hx:absolute hx:-mt-20" id="the-west-stalled-china-sprinting"></span>
    <a href="#the-west-stalled-china-sprinting" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Comparing generations of the same family within v4, the difference in pace shows up:</p>
<table>
  <thead>
      <tr>
          <th>Family</th>
          <th style="text-align: right">Before</th>
          <th style="text-align: right">After</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>DeepSeek V4 Flash → V4.1 Flash</td>
          <td style="text-align: right">86.0</td>
          <td style="text-align: right">92.5</td>
      </tr>
      <tr>
          <td>GLM 5.2 → 5.3</td>
          <td style="text-align: right">77.0</td>
          <td style="text-align: right">94.0</td>
      </tr>
      <tr>
          <td>MiMo V2.5 Pro → V2.6 Pro</td>
          <td style="text-align: right">86.5</td>
          <td style="text-align: right">92.0</td>
      </tr>
      <tr>
          <td>MiniMax M3 → M3.1 Flash</td>
          <td style="text-align: right">75.5</td>
          <td style="text-align: right">89.5</td>
      </tr>
      <tr>
          <td>Kimi K2.7 Code → K3</td>
          <td style="text-align: right">87.25</td>
          <td style="text-align: right">85.0</td>
      </tr>
      <tr>
          <td>Gemini 3.7 Flash → 3.8 Flash (high)</td>
          <td style="text-align: right">75.5</td>
          <td style="text-align: right">90.5</td>
      </tr>
      <tr>
          <td>Claude Fable 5 → 5.1</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">95.5</td>
      </tr>
      <tr>
          <td>Grok 4.6 → 4.7</td>
          <td style="text-align: right">98.5</td>
          <td style="text-align: right">83.5</td>
      </tr>
      <tr>
          <td>GPT 5.6 sol → GPT 6 sol</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">91.0</td>
      </tr>
      <tr>
          <td>GPT 5.6 luna → GPT 6 luna</td>
          <td style="text-align: right">95.0</td>
          <td style="text-align: right">95.5</td>
      </tr>
      <tr>
          <td>Claude Opus 5 → 5.5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">100.0</td>
      </tr>
  </tbody>
</table>
<p>The Chinese models climbed 5.5 to 17 points per generation, with the exception of Kimi. On the Western side, whoever was already at the ceiling had nowhere to go: Opus stayed at 100, GPT 6 luna stayed where 5.6 luna was, and three new releases landed below their predecessors. Gemini Flash is the Western counterexample, with a 15-point jump.</p>
<p>The calendar reinforces that reading. Claude Fable 5 came out in June, Opus 5 and GPT 5.6 in July, and all of them already hit 100 on my yardstick. From then until October, OpenAI and Anthropic released Fable 5.1, GPT-6 Astra, Opus 5.5 and GPT-6 sol and luna. None of them showed a gain on my yardstick, and some landed below their predecessors.</p>
<p>In the same window, the Chinese labs started from well behind: DeepSeek V4 in April, Kimi K3 in July, Qwen 3.8 and GLM 5.3 in August, DeepSeek V4.1 Flash and MiMo V2.6 Pro in September, MiniMax M3.1 Flash in October. Each release got closer to the top.</p>
<blockquote>
  <p>The Chinese labs seem to move faster, and they do. But part of that impression comes from the Western ones having stood still for months, at least in programming. When the leader doesn&rsquo;t move, whoever is chasing catches up.</p>

</blockquote>
<h3>Math isn&rsquo;t programming<span class="hx:absolute hx:-mt-20" id="math-isnt-programming"></span>
    <a href="#math-isnt-programming" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The Western labs didn&rsquo;t stop working. They&rsquo;re spending a good chunk of their showcase on math:</p>
<ul>
<li>in May, OpenAI announced that a general-purpose reasoning model <a href="https://openai.com/index/model-disproves-discrete-geometry-conjecture/"target="_blank" rel="noopener">disproved an Erdős conjecture</a> about unit distances;</li>
<li>in August, it published <a href="https://github.com/openai/ten-proofs"target="_blank" rel="noopener">ten mathematical results from Astra</a>, each with a formal proof in Lean;</li>
<li>also in August, Anthropic showed an internal Claude raising from 41.6% to 67.2% the proven fraction of <a href="https://www.anthropic.com/research/riemann-zeta"target="_blank" rel="noopener">Riemann zeta function zeros</a> that satisfy the hypothesis;</li>
<li>in September, Anthropic <a href="https://www.anthropic.com/research/formalizing-fermats-last-theorem"target="_blank" rel="noopener">formalized the whole of Fermat&rsquo;s Last Theorem in Lean</a> in 11 days, with an internal model it describes itself as comparable to Fable 5.1.</li>
</ul>
<p>It&rsquo;s impressive, and it&rsquo;s legitimate. Formal proof is one of the few places where you can verify the answer automatically, which makes math a great field for training and for marketing. Except the same Fable 5.1 that served as the yardstick for Fermat scored 95.5 on my benchmark, against Fable 5&rsquo;s 100.</p>
<p>Getting better at math doesn&rsquo;t automatically make a model better at programming. A 2025 study, <a href="https://arxiv.org/abs/2507.00432"target="_blank" rel="noopener"><em>Does Math Reasoning Improve General LLM Capabilities?</em></a>, concluded that <em>most models that do well at math don&rsquo;t transfer the gain to other domains</em>, programming among them. There are counterexamples: NVIDIA showed that <a href="https://arxiv.org/abs/2505.16400"target="_blank" rel="noopener">math-only reinforcement learning</a> raised the code scores of small models. Transfer happens sometimes, and it depends on how you train.</p>
<h3>And what about mixture of experts<span class="hx:absolute hx:-mt-20" id="and-what-about-mixture-of-experts"></span>
    <a href="#and-what-about-mixture-of-experts" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The common intuition is that, in a <em>mixture of experts</em> (MoE) model, you can improve the &ldquo;math expert&rdquo; without touching the &ldquo;code expert&rdquo;. The idea is half right for the wrong reason.</p>
<p>An MoE has several blocks of weights in each layer, and a router picks a few of them for each token. But the experts don&rsquo;t split by subject the way the intuition suggests. The <a href="https://arxiv.org/abs/2401.04088"target="_blank" rel="noopener">Mixtral paper</a> looked for exactly that and <em>found no obvious pattern of experts by topic</em>, with a small difference only on a synthetic math set; the router organizes itself more by syntax, by token type. And neither OpenAI nor Anthropic publicly confirm whether their closed models are MoE.</p>
<p>What still stands is the essential part: capability is trained by objective. The signal that rewards a Lean proof is not the same one that rewards noticing a cross-tenant leak in a Rails controller, and improving one doesn&rsquo;t drag the other along. In a model where only a fraction of the parameters work per token, that mismatch becomes even easier.</p>
<h2>NVFP4, FP8, Q4: what&rsquo;s this alphabet soup<span class="hx:absolute hx:-mt-20" id="nvfp4-fp8-q4-whats-this-alphabet-soup"></span>
    <a href="#nvfp4-fp8-q4-whats-this-alphabet-soup" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every model is a pile of billions of numbers, the weights. Quantization is storing each number with fewer bits. The fewer the bits, the less memory the model takes and the less data the card has to read per token, and that&rsquo;s what defines speed on a local machine. The price, when there is one, is quality.</p>
<p>For a 27-billion-parameter model, the math goes like this:</p>
<table>
  <thead>
      <tr>
          <th>Format</th>
          <th style="text-align: right">Bits per weight</th>
          <th style="text-align: right">27B takes</th>
          <th>Where it runs</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>BF16</td>
          <td style="text-align: right">16</td>
          <td style="text-align: right">~54 GB</td>
          <td>native from Ampere (RTX 30) onward</td>
      </tr>
      <tr>
          <td>FP8</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">~27 GB</td>
          <td>native on Ada (RTX 40), Hopper (H200) and Blackwell</td>
      </tr>
      <tr>
          <td>Q8_0 (GGUF)</td>
          <td style="text-align: right">~8.5</td>
          <td style="text-align: right">~29 GB</td>
          <td>llama.cpp and Ollama, any card</td>
      </tr>
      <tr>
          <td>Q5_K_M (GGUF)</td>
          <td style="text-align: right">~5.5</td>
          <td style="text-align: right">~19 GB</td>
          <td>llama.cpp and Ollama</td>
      </tr>
      <tr>
          <td>Q4_K_M (GGUF)</td>
          <td style="text-align: right">~4.5 to 4.8</td>
          <td style="text-align: right">~16 GB</td>
          <td>llama.cpp and Ollama</td>
      </tr>
      <tr>
          <td>NVFP4</td>
          <td style="text-align: right">4.5</td>
          <td style="text-align: right">~15 GB</td>
          <td>native only on Blackwell; vLLM, and llama.cpp since 2026</td>
      </tr>
      <tr>
          <td>IQ3_S (GGUF)</td>
          <td style="text-align: right">~3.4</td>
          <td style="text-align: right">~12 GB</td>
          <td>llama.cpp and derivatives</td>
      </tr>
  </tbody>
</table>
<h3>What each one is<span class="hx:absolute hx:-mt-20" id="what-each-one-is"></span>
    <a href="#what-each-one-is" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>BF16</strong> is the precision most models are published in. It&rsquo;s the reference: nothing is lost.</li>
<li><strong>FP8</strong> is 8-bit floating point, with hardware support on the Ada, Hopper and Blackwell generations. It cuts memory in half and is the default for big checkpoints, like DeepSeek V4.1 Flash and GLM 5.3 full.</li>
<li><strong>Q8_0, Q5_K_M, Q4_K_M and IQ3_S</strong> are llama.cpp GGUF formats. The weights are stored in blocks of integers with one scale per block; the &ldquo;K&rdquo; ones mix precisions per tensor, and the &ldquo;IQ&rdquo; ones use an importance matrix to decide where to spend bits. Q8 is considered practically lossless, and Q4_K_M is the recommended default for people running at home.</li>
<li><strong>NVFP4</strong> is NVIDIA&rsquo;s 4-bit format. Each number is a 4-bit floating point, and each block of 16 numbers gets its own FP8 scale. NVIDIA says this <a href="https://developer.nvidia.com/blog/introducing-nvfp4-for-efficient-and-accurate-low-precision-inference/"target="_blank" rel="noopener">takes 3.5 times less than FP16 and loses 1% or less against FP8</a> on DeepSeek-R1.</li>
</ul>
<p>That&rsquo;s where the NVFP4 hype comes from: Blackwell&rsquo;s tensor cores compute in it directly, and it&rsquo;s what made GLM 5.3 Flash, at 198 GB, and Qwen3.5 397B, at 251 GB, fit on a single B300. The H200, from the previous generation, has no native FP4. And the home ecosystem is still catching up: llama.cpp got <a href="https://github.com/ggml-org/llama.cpp/pull/22196"target="_blank" rel="noopener">NVFP4 support</a> only in 2026, and per-architecture coverage is still partial.</p>
<h3>What our tests show<span class="hx:absolute hx:-mt-20" id="what-our-tests-show"></span>
    <a href="#what-our-tests-show" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Four models ran at more than one precision:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>Version A</th>
          <th>Version B</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Qwen 3.8 27B</td>
          <td>BF16, B300: 80.5</td>
          <td>Q8_0, Strix Halo: 80.0 ¹</td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash-Next</td>
          <td>NVFP4, B300: 92.5</td>
          <td>IQ3_S, RTX 5090 with Strata: 91.0</td>
      </tr>
      <tr>
          <td>Ornith 1.5 35B</td>
          <td>BF16, B300: 81.0</td>
          <td>Q8_0, RTX 5090 with Strata: 64.5</td>
      </tr>
      <tr>
          <td>GLM 4.7 Flash</td>
          <td>BF16, B300: 33.5</td>
          <td>Q5_K_M, RTX 5090: 24.0</td>
      </tr>
  </tbody>
</table>
<p>¹ Mixed run: sprints 1 and 2 in Q5_K_M on the 5090, the rest in Q8_0 on the Strix, with reasoning turned off.</p>
<p>And six ran on the cloud API and were also served by me, with the official weights:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Cloud</th>
          <th style="text-align: right">Served by me</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GLM 5.3 Flash</td>
          <td style="text-align: right">84.25</td>
          <td style="text-align: right">92.5 (NVFP4, B300)</td>
      </tr>
      <tr>
          <td>DeepSeek V4.1 Flash</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">92.5 (FP8, 4x B300)</td>
      </tr>
      <tr>
          <td>GLM 5.3 full</td>
          <td style="text-align: right">94.0</td>
          <td style="text-align: right">76.0 (FP8, 4x B300)</td>
      </tr>
      <tr>
          <td>MiMo V2.6 Pro</td>
          <td style="text-align: right">92.0</td>
          <td style="text-align: right">67.0 (FP8, 4x B300)</td>
      </tr>
      <tr>
          <td>DeepSeek V4 Flash 0731</td>
          <td style="text-align: right">85.0</td>
          <td style="text-align: right">44.5 (official FP4/FP8, B300)</td>
      </tr>
      <tr>
          <td>Nex N2.5 Pro</td>
          <td style="text-align: right">94.0</td>
          <td style="text-align: right">27.0 (FP8, 4x B300)</td>
      </tr>
  </tbody>
</table>
<p>Each row is a single run, and the noise reaches almost 10 points. With that caveat, here&rsquo;s my reading:</p>
<ul>
<li><strong>Q8 came out tied with BF16.</strong> The Qwen 27B scored 80.5 and 80.0, a single point of data with other things changing at the same time.</li>
<li><strong>Going from 4 down to 3 bits was nearly free on Flash-Next</strong>, at 1.5 points, even while switching engine and card.</li>
<li><strong>Ornith&rsquo;s drop is unlikely to be about the bits.</strong> Q8 is nearly lossless, and it still lost 16.5 while also switching engine and card.</li>
<li><strong>Serving the same checkpoint can give you anything.</strong> GLM 5.3 Flash went up 8 points in my hands, DeepSeek V4.1 tied, and Nex fell almost 70. Tool parser, chat template, reasoning mode and engine version weigh as much as precision, and the effect changes from model to model.</li>
</ul>
<blockquote>
  <p>In my tests, the bits mattered less than the hype suggests, and the whole package of how the model is served mattered more. Use Q8 when it fits, drop to 4 bits when you have to, and measure on your own work before trusting it.</p>

</blockquote>
<h2>The best commercial models<span class="hx:absolute hx:-mt-20" id="the-best-commercial-models"></span>
    <a href="#the-best-commercial-models" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Only closed models get in here, only Tier A, and only what I&rsquo;d pay for through an API.</p>
<h3>By score<span class="hx:absolute hx:-mt-20" id="by-score"></span>
    <a href="#by-score" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Cost per run</th>
          <th style="text-align: right">Minutes</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT-6 Astra</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">US$ 30.55</td>
          <td style="text-align: right">100</td>
      </tr>
      <tr>
          <td>Claude Opus 5.5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">US$ 16.63 ¹</td>
          <td style="text-align: right">64</td>
      </tr>
      <tr>
          <td>Claude Opus 5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">~US$ 71 ¹</td>
          <td style="text-align: right">145</td>
      </tr>
      <tr>
          <td>Claude Fable 5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">~US$ 50 ¹</td>
          <td style="text-align: right">~85</td>
      </tr>
      <tr>
          <td>GPT 5.6 terra</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">US$ 9.52</td>
          <td style="text-align: right">80</td>
      </tr>
      <tr>
          <td>GPT 5.6 sol</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">US$ 20.37</td>
          <td style="text-align: right">317</td>
      </tr>
      <tr>
          <td>GPT 5.5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">US$ 34.69</td>
          <td style="text-align: right">117</td>
      </tr>
      <tr>
          <td>Grok 4.6</td>
          <td style="text-align: right">98.5</td>
          <td style="text-align: right">US$ 13.00</td>
          <td style="text-align: right">67</td>
      </tr>
      <tr>
          <td>GPT 6 luna</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: right">~US$ 0.84</td>
          <td style="text-align: right">122</td>
      </tr>
      <tr>
          <td>Claude Fable 5.1</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: right">~US$ 51 ¹</td>
          <td style="text-align: right">133</td>
      </tr>
  </tbody>
</table>
<p>¹ Notional subscription cost, at API list price.</p>
<p>At the absolute top, <strong>Claude Opus 5.5</strong> and <strong>GPT 5.6 terra</strong> are the obvious picks: top score, a run in a little over an hour, and a per-run price in the single digits or a bit more. Opus 5 and GPT 5.5 get the same score at two to seven times the cost.</p>
<h3>By cost-benefit<span class="hx:absolute hx:-mt-20" id="by-cost-benefit"></span>
    <a href="#by-cost-benefit" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">Cost per run</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT 6 luna</td>
          <td style="text-align: right">95.5</td>
          <td style="text-align: right">~US$ 0.84</td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash</td>
          <td style="text-align: right">86.5</td>
          <td style="text-align: right">US$ 1.17</td>
      </tr>
      <tr>
          <td>GPT 6 sol</td>
          <td style="text-align: right">91.0</td>
          <td style="text-align: right">~US$ 8.35</td>
      </tr>
      <tr>
          <td>GPT 5.6 terra</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">US$ 9.52</td>
      </tr>
      <tr>
          <td>GPT 5.6 luna</td>
          <td style="text-align: right">95.0</td>
          <td style="text-align: right">US$ 10.04</td>
      </tr>
      <tr>
          <td>Grok 4.6</td>
          <td style="text-align: right">98.5</td>
          <td style="text-align: right">US$ 13.00</td>
      </tr>
      <tr>
          <td>Claude Opus 5.5</td>
          <td style="text-align: right">100.0</td>
          <td style="text-align: right">US$ 16.63 ¹</td>
      </tr>
  </tbody>
</table>
<p>¹ Notional subscription cost, at API list price.</p>
<p><strong>GPT 6 luna</strong> is the absurdity of the table: high Tier A for under a dollar per run, a fraction of the price of any other closed model at the same level. If the top score isn&rsquo;t mandatory, that&rsquo;s where I&rsquo;d start.</p>
<p>At the top score, <strong>GPT 5.6 terra</strong> costs a little more than half of Opus 5.5. The difference between the two lies in everything else: harness, speed, behavior in long sessions, and I covered that in the previous articles.</p>
<h2>The best open models for companies<span class="hx:absolute hx:-mt-20" id="the-best-open-models-for-companies"></span>
    <a href="#the-best-open-models-for-companies" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is what runs on datacenter GPUs, on the B300.</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>Where</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">tok/s</th>
          <th style="text-align: right">Memory</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>DeepSeek V4.1 Flash</td>
          <td>4x B300</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">175</td>
          <td style="text-align: right">510 GB</td>
      </tr>
      <tr>
          <td>GLM 5.3 Flash</td>
          <td>1x B300</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">142</td>
          <td style="text-align: right">198 GB</td>
      </tr>
      <tr>
          <td>Qwen3.8 Flash-Next</td>
          <td>1x B300</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">195</td>
          <td style="text-align: right">100 GB</td>
      </tr>
      <tr>
          <td>Swift 1.5 27B</td>
          <td>1x B300</td>
          <td style="text-align: right">88.0</td>
          <td style="text-align: right">203</td>
          <td style="text-align: right">56 GB</td>
      </tr>
      <tr>
          <td>ThinkingCap 3.8 27B</td>
          <td>1x B300</td>
          <td style="text-align: right">83.0</td>
          <td style="text-align: right">189</td>
          <td style="text-align: right">56 GB</td>
      </tr>
  </tbody>
</table>
<p><strong>DeepSeek V4.1 Flash</strong> is the champion for a big team. On a 4x B300 pod at US$ 36 per hour, it serves <strong>32 comfortable sessions</strong> at the same time, with the first token in under 2 seconds for almost all of them. Counting one active session per developer for the whole workday, which is optimistic, that&rsquo;s 32 people. Turning the pod on only during business hours, 8 hours a day, 22 days a month, comes to about US$ 6,300 per month, or <strong>about US$ 200 per developer</strong>.</p>
<p>The alternatives, by the same math:</p>
<ul>
<li>4x H200 on Runpod serves only 8 comfortable sessions and comes out to about US$ 316 per developer per month, even with the cheapest pod;</li>
<li>the same configuration on AWS costs almost double, and the H200 on Azure costs almost three times the Runpod price;</li>
<li>buying a DGX Station GB300 for about US$ 130 thousand pays for itself in about 20 months against renting during business hours, or in about 5 months against a pod running nonstop.</li>
</ul>
<p>For a smaller team, the single B300 with <strong>Qwen3.8 Flash-Next</strong> or <strong>GLM 5.3 Flash</strong> is the sweet spot: same score as DeepSeek, on a single GPU, at about US$ 9 per hour. I didn&rsquo;t measure concurrency on it. Going by the memory left over, a team of five to ten people fits well on a 27 to 35 billion model, like Swift 1.5; on GLM 5.3 Flash, at 198 GB, it gets tight.</p>
<blockquote>
  <p>Your own infrastructure starts to make sense at around 30 people using it at the same time, or when the code can&rsquo;t leave the network. Below that, the API for the same DeepSeek costs a little over a dollar per run and you don&rsquo;t babysit any server.</p>

</blockquote>
<h2>The best open models for consumers<span class="hx:absolute hx:-mt-20" id="the-best-open-models-for-consumers"></span>
    <a href="#the-best-open-models-for-consumers" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is what runs on a PC: an RTX 5090 with 32 GB or a Strix Halo with 128 GB unified.</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>Machine</th>
          <th style="text-align: right">Score</th>
          <th style="text-align: right">tok/s</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Qwen3.8 Flash-Next (IQ3_S, Strata)</td>
          <td>RTX 5090</td>
          <td style="text-align: right"><strong>91.0</strong></td>
          <td style="text-align: right">159</td>
      </tr>
      <tr>
          <td>Qwen 3.8 27B (Q8_0)</td>
          <td>Strix Halo</td>
          <td style="text-align: right">80.0</td>
          <td style="text-align: right">8</td>
      </tr>
      <tr>
          <td>Ornith 1.5 35B (Q8_0, Strata)</td>
          <td>RTX 5090</td>
          <td style="text-align: right">64.5</td>
          <td style="text-align: right">~80</td>
      </tr>
      <tr>
          <td>GLM-4.7-Flash (Q5_K_M)</td>
          <td>RTX 5090</td>
          <td style="text-align: right">24.0</td>
          <td style="text-align: right">—</td>
      </tr>
  </tbody>
</table>
<p>There&rsquo;s only one winner: <strong>Qwen3.8 Flash-Next on the RTX 5090 with Strata</strong>. It&rsquo;s a 125-billion MoE with 6 billion active per token, and Strata keeps the most-used experts on the card and the rest in RAM. It landed 1.5 points from the datacenter version, at interactive speed. I covered it in detail, with installation, an auto-loading service and the OpenCode setup, in <a href="/en/2026/10/22/best-open-source-llm-strata-with-qwen-3-8-flash-next/">Best Open Source LLM: Strata with Qwen 3.8 Flash Next</a>.</p>
<p>The Strix Halo fits big models, but its memory bandwidth is seven times lower than the 5090&rsquo;s, and a 27B dense model crawls at under 10 tokens per second in Q8, about 13 in Q4. It&rsquo;s fine for background tasks that can wait.</p>
<p>And what about <strong>Swift 1.5</strong> and <strong>ThinkingCap 3.8</strong>, the 27B fine-tunes that did well on the B300? I didn&rsquo;t run them on the 5090, and I didn&rsquo;t need to. On the B300, in BF16, full precision, they scored 88 and 83, below Flash-Next&rsquo;s 92.5 on the same card and the 91 it scored on the 5090.</p>
<p>On a 5090 they&rsquo;d fit in Q4 or Q5, but quantized, the best case is matching the B300 score. Running at home cost Flash-Next 1.5 points and Ornith-35B 16.5. The base Qwen 3.8 27B, which is the same architecture, didn&rsquo;t even finish on the 5090 in Q5_K_M: it got stuck in a reasoning loop in sprint 3.</p>
<blockquote>
  <p>If those two already fell behind Flash-Next at full precision, they won&rsquo;t get better on a 5090. I saw no reason to test them: for a PC, Flash-Next is clearly the pick.</p>

</blockquote>
<h3>What about GPUs worse than the 5090?<span class="hx:absolute hx:-mt-20" id="what-about-gpus-worse-than-the-5090"></span>
    <a href="#what-about-gpus-worse-than-the-5090" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>It&rsquo;s the question that always comes up: what about people with an 8, 12 or 16 GB card? From my data, the path of a small model that fits entirely on the card still doesn&rsquo;t deliver anything worth the effort for programming.</p>
<p>On a card like that, in Q4, a dense model of up to about 20 billion fits; a 30-billion MoE with few active parameters only runs with part of it in RAM. And that range did badly in v4:</p>
<ul>
<li>GLM-4.7-Flash, a 30B MoE with 3B active, scored 24 on the 5090 and 33.5 on the B300 at full precision, Tier D on both;</li>
<li>Ornith-35B, another MoE with 3B active, scored 81 on the B300 and fell to 64.5 on the 5090;</li>
<li>gpt-oss-20b didn&rsquo;t even complete the protocol;</li>
<li>the best mid-size model was Qwen 3.8 27B, with 80, but it already needs about 16 GB in Q4 alone, stalled on the 5090, and only finished at 8 tokens per second on the Strix.</li>
</ul>
<p>The exception is precisely Flash-Next. Strata was built to run it on a 12 GB card, holding most of the experts in RAM: the <a href="https://github.com/Niko1221/Strata"target="_blank" rel="noopener">project&rsquo;s README</a> publishes 53 tokens per second in IQ3_S on a 12 GB RTX 5070 with 64 GB of RAM, and the stated minimum is 32 GB of RAM and VRAM combined. With the same weights and the same engine, the score in theory shouldn&rsquo;t change, only the speed, which drops to a third of the 5090&rsquo;s. I didn&rsquo;t measure this; it&rsquo;s the author&rsquo;s number.</p>
<p>The catch is RAM. With DRAM <a href="https://www.trendforce.com/presscenter/news/20260601-13070.html"target="_blank" rel="noopener">nearly doubling in price</a> in a single quarter this year, 64 GB stopped being the cheap upgrade it used to be.</p>
<blockquote>
  <p>Below the 5090, I wouldn&rsquo;t waste time on small models for programming. If you&rsquo;re going to try something, make it Flash-Next with Strata and plenty of RAM, and measure it on your own work before trusting it.</p>

</blockquote>
<p>And there&rsquo;s the problem I covered in the <a href="/en/2026/10/22/llm-benchmark-v4-consumer-open-source-rtx5090-strix-halo-strata/">previous article</a>: finding a 5090 today is hard, and when you do, the price runs between two and a half and almost five times MSRP.</p>
<h3>How much does it cost to move beyond 150 tokens per second?<span class="hx:absolute hx:-mt-20" id="how-much-does-it-cost-to-move-beyond-150-tokens-per-second"></span>
    <a href="#how-much-does-it-cost-to-move-beyond-150-tokens-per-second" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>After a few hours using Qwen locally, I <a href="https://x.com/AkitaOnRails/status/2113386101293428812"target="_blank" rel="noopener">summed up the problem on X</a>. My run&rsquo;s average of 159 tokens per second looks fast in a table. During a programming session that spends the whole day generating code, running tests, reading logs and fixing its own work, the waiting adds up.</p>
<p>I already get impatient. Anything below that is out of consideration for daily work.</p>
<p>The 5090 itself has limits beyond speed. NVIDIA specifies <a href="https://www.nvidia.com/en-us/geforce/graphics-cards/50-series/rtx-5090/"target="_blank" rel="noopener">32 GB of GDDR7 and 1,792 GB/s of bandwidth</a> and <a href="https://nvidianews.nvidia.com/news/nvidia-blackwell-geforce-rtx-50-series-opens-new-world-of-ai-computer-graphics"target="_blank" rel="noopener">launched the card at US$1,999</a>. Mine also drives the monitors and Hyprland, so I reserve 4 GB for the desktop. The rest has to hold dense weights, the hot-expert cache, engine buffers and the resident portion of the KV cache that stores the conversation context.</p>
<p>My Strata configuration offers a 256-thousand-token context with int8 KV and keeps 32 thousand resident in VRAM; the rest can move to RAM. That keeps the card from overflowing, but RAM is still much slower. While <a href="https://docs.anthropic.com/en/api/claude-on-amazon-bedrock"target="_blank" rel="noopener">frontier Claude models already offer a one-million-token window</a>, locally I have to watch what enters the session. Loading a whole collection of skills, plugins and MCP servers just because they fit in a config file wastes context and hurts latency.</p>
<blockquote>
  <p>Context also costs memory and time on local hardware. I only load what that session will use.</p>

</blockquote>
<p>What if I add more hardware? The comparison looks like this:</p>
<table>
  <thead>
      <tr>
          <th>Option</th>
          <th style="text-align: right">Memory</th>
          <th style="text-align: right">Bandwidth</th>
          <th style="text-align: right">Observed speed</th>
          <th style="text-align: right">Reference price</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>RTX 5090</td>
          <td style="text-align: right">32 GB GDDR7</td>
          <td style="text-align: right">1,792 GB/s</td>
          <td style="text-align: right"><strong>159.2 tok/s</strong>, measured by me</td>
          <td style="text-align: right">US$1,999 MSRP</td>
      </tr>
      <tr>
          <td>2x RTX 5090</td>
          <td style="text-align: right">64 GB physically split between cards</td>
          <td style="text-align: right">2x 1,792 GB/s, without becoming one flat pool</td>
          <td style="text-align: right">no equivalent test of my own</td>
          <td style="text-align: right">US$3,998 MSRP</td>
      </tr>
      <tr>
          <td>Mac Studio M5 Ultra</td>
          <td style="text-align: right">96 or 256 GB unified; 512 GB promised for late October</td>
          <td style="text-align: right">1,200 GB/s</td>
          <td style="text-align: right">not yet measured in Strata</td>
          <td style="text-align: right">starts at US$5,499</td>
      </tr>
      <tr>
          <td>DGX Spark</td>
          <td style="text-align: right">128 GB unified</td>
          <td style="text-align: right">273 GB/s</td>
          <td style="text-align: right">about 22 to 75 tok/s per session in public recipes</td>
          <td style="text-align: right">US$6,950 from NVIDIA</td>
      </tr>
      <tr>
          <td>RTX PRO 6000 Blackwell</td>
          <td style="text-align: right">96 GB GDDR7 ECC</td>
          <td style="text-align: right">1,792 GB/s</td>
          <td style="text-align: right">187.4 tok/s in short chat; 174.3 in an agent session</td>
          <td style="text-align: right">US$16,000; R$123,000 via Pix in Brazil</td>
      </tr>
  </tbody>
</table>
<p>In the post, I wrote that Strata would only start two instances on a machine with two 5090s. That part is outdated: current Strata <a href="https://github.com/Niko1221/Strata/blob/main/docs/MULTI_GPU.md"target="_blank" rel="noopener">splits layers across two or more GPUs</a>. It uses pipeline parallelism, without turning two cards into one simple 64 GB block and without mature tensor parallelism.</p>
<p>Single-session gains stay far below 2x. A <a href="https://github.com/Niko1221/Strata/issues/642"target="_blank" rel="noopener">community test with two 5090s</a> measured about a 22% gain in the decode geometric mean and 40% in the coding arm. It helps capacity, and you can run the cards as two independent instances to double concurrency. For me alone, buying another 5090 to remove a fraction of the wait does not add up.</p>
<p>The <strong>Mac Studio M5 Ultra</strong> starts at <a href="https://www.apple.com/newsroom/2026/08/apple-introduces-new-mac-studio-with-m5-max-and-m5-ultra/"target="_blank" rel="noopener">US$5,499</a>, has 1.2 TB/s of bandwidth and comes with 96 or 256 GB; Apple promised the 512 GB option for late October. There is no published Strata benchmark for the Ultra yet. On the <a href="https://github.com/Niko1221/Strata/blob/main/docs/MAC.md"target="_blank" rel="noopener">128 GB M5 Max</a>, the same Flash-Next ran between 97 and 119.5 tokens per second, depending on the quantization and prompt. My original estimate of under 100 on the Ultra is unproven, and I would not buy a machine like that based on a guess.</p>
<p>The <strong>DGX Spark</strong> puts 128 GB in a compact box, with a 140 W TDP for the GB10 and a 240 W power supply. Its memory delivers only <a href="https://www.nvidia.com/en-us/products/workstations/dgx-spark/"target="_blank" rel="noopener">273 GB/s</a>, almost seven times less than the 5090. NVIDIA now asks <a href="https://marketplace.nvidia.com/en-us/enterprise/personal-ai-supercomputers/dgx-spark/"target="_blank" rel="noopener">US$6,950</a>.</p>
<p>Reproducible Flash-Next recipes range from <a href="https://github.com/ursuciprian/qwen3.8-flash-next-1x-dgx-spark"target="_blank" rel="noopener">22 to 75 tokens per second per session</a>, depending on concurrency, stack, sampling and reasoning mode. It fits plenty. For my tolerance, it moves too slowly.</p>
<p>That leaves the <strong>RTX PRO 6000 Blackwell</strong>. It has <a href="https://www.nvidia.com/content/dam/en-zz/Solutions/data-center/rtx-pro-6000-blackwell-workstation-edition/workstation-blackwell-rtx-pro-6000-workstation-edition-nvidia-us-3519208-web.pdf"target="_blank" rel="noopener">96 GB of GDDR7 ECC, 1,792 GB/s and 600 watts of total board power</a>. Its bandwidth is exactly the same as the 5090&rsquo;s. The 96 GB removes the VRAM pressure and allows more cache and context, but it does not buy three times the speed.</p>
<p>A <a href="https://github.com/Niko1221/Strata/issues/2268"target="_blank" rel="noopener">Strata community benchmark</a> measured 187.4 tokens per second in short chat and 174.3 in an agent session, with substantial variation across runs. That&rsquo;s better than my 159.2, except NVIDIA lists the card at <a href="https://marketplace.nvidia.com/en-us/enterprise/laptops-workstations/nvidia-rtx-pro-6000-blackwell-workstation-edition/"target="_blank" rel="noopener">US$16,000</a>. On October 22, WAZ <a href="https://www.waz.com.br/placa-de-video-nvidia-quadro-rtx-pro-6000-blackwell-workstation-edition-pny-vcnrtxpro6000b-pb-96gb-gddr7-pcie-5-0-x16-131172-html/p"target="_blank" rel="noopener">showed the PNY at R$123,299.99 via Pix or R$145,058.81 at regular price</a>. We have entered professional-workstation or server budgets.</p>
<blockquote>
  <p>Today, for me, there is no home option that combines a good model, truly fast responses and a reasonable cost. The 5090 works, but 150 tokens per second already wears on me. Below it, local LLMs are toys; above it, the price explodes before the speed does.</p>

</blockquote>
<h2>What I learned in v4<span class="hx:absolute hx:-mt-20" id="what-i-learned-in-v4"></span>
    <a href="#what-i-learned-in-v4" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>About the models<span class="hx:absolute hx:-mt-20" id="about-the-models"></span>
    <a href="#about-the-models" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Almost every model catches the loud defect unprompted: a CVE in a gem, a key in the code, open CORS, obvious SQL injection. Almost every model lets the silent one slip until I reveal it: cross-tenant leak, wrong aggregate, tampered test, removed index. What separates Tier A from the rest is how much of the silent stuff it catches on its own.</li>
<li>Size doesn&rsquo;t buy vigilance. Kimi K2 Thinking, at 1 trillion parameters, scored 46. GLM 5.3 full, at 700 billion, scored 76, against 92.5 for the Flash from the same family.</li>
<li>Models cheat or get things wrong with conviction. Nemotron tampered with a regression test to make it pass, Qwen3.5 397B let a backdoor through and even wrote a test that treated it as expected behavior, and Kimi K2 put on security checklist theater, catching only what you can find with grep.</li>
<li>The leap between generations was in agentic reliability. GPT-4o and GPT-4.1 can&rsquo;t even finish the protocol on their own. Today&rsquo;s top models run all seven sprints with no help at all.</li>
</ul>
<h3>About serving open models<span class="hx:absolute hx:-mt-20" id="about-serving-open-models"></span>
    <a href="#about-serving-open-models" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>The same checkpoint changes score depending on who serves it. DeepSeek V4 Flash scored 85 in the cloud, on the same 0731 version I downloaded, and 44.5 served by me; Nex N2.5 Pro scored 94 in the cloud and 27 on the 4x B300 pod, with corrupted tokens landing in the committed code.</li>
<li>No model runs fast out of the box. GLM 5.3 Flash went from 10 to 141 tokens per second from configuration alone, and every family asked for a parser, a flag and sometimes a vLLM PR branch.</li>
<li>Running at home charges each model a different price. Switching quantization, engine and card all at once, Flash-Next lost 1.5 points and Ornith-35B lost 16.5.</li>
<li>What limits concurrency is the KV cache architecture and the time to first token. Parameter count says little: on the H200, a 510 GB model and a much smaller one tied at 8 users, for opposite reasons.</li>
</ul>
<h3>About measuring<span class="hx:absolute hx:-mt-20" id="about-measuring"></span>
    <a href="#about-measuring" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>A single run has noise of almost 10 points. Two scores 2 points apart are a tie.</li>
<li>The harness matters. Gemini 3.1 Pro was taken down by a proxy bug, gpt-oss doesn&rsquo;t finish in OpenCode, and three models insisted on creating the app in a subfolder.</li>
<li>A model that doesn&rsquo;t commit loses work. A fix that only lives on disk vanishes at the first <code>git checkout</code>.</li>
</ul>
<h2>My hypothesis: expensive hardware is part of the business model<span class="hx:absolute hx:-mt-20" id="my-hypothesis-expensive-hardware-is-part-of-the-business-model"></span>
    <a href="#my-hypothesis-expensive-hardware-is-part-of-the-business-model" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The v4 verdict, as of October 2026, is this: for code review and vigilance, open source has arrived. DeepSeek V4.1 Flash, GLM 5.3 Flash and Qwen3.8 Flash-Next are in the same pack as Sonnet 5 and GPT 6 sol, and one of them runs on a PC card.</p>
<p>So why isn&rsquo;t everybody running it at home? Because hardware got expensive and hard to find, and I have a hypothesis about that. It&rsquo;s my hypothesis, with no proof of any collusion, built on public facts.</p>
<h3>The facts<span class="hx:absolute hx:-mt-20" id="the-facts"></span>
    <a href="#the-facts" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Memory skyrocketed. TrendForce measured a <a href="https://www.trendforce.com/presscenter/news/20260601-13070.html"target="_blank" rel="noopener">93% to 98% rise in DRAM contract prices</a> in the first quarter of 2026 alone, and says manufacturers <a href="https://www.trendforce.com/presscenter/news/20260930-13258.html"target="_blank" rel="noopener">keep prioritizing server capacity</a> in the fourth quarter.</li>
<li>HBM, the memory in datacenter GPUs, is expected to see its <a href="https://www.trendforce.com/presscenter/news/20260929-13255.html"target="_blank" rel="noopener">average price rise 121% in 2027</a> and take up close to <a href="https://www.trendforce.com/presscenter/news/20260602-13074.html"target="_blank" rel="noopener">30% of the DRAM wafers</a> of the three biggest manufacturers by the end of 2027.</li>
<li>Micron <a href="https://www.storagenewsletter.com/2025/12/05/micron-announces-exit-from-crucial-consumer-business/"target="_blank" rel="noopener">left the consumer market</a> and killed Crucial, in its own words, to better serve its larger strategic customers.</li>
<li>PCs and consoles went up in price, and Microsoft <a href="https://www.digitalcitizen.life/xbox-series-x-and-series-s-prices-will-rise-again-as-memory-and-storage-costs-surge/"target="_blank" rel="noopener">attributed the Xbox increase</a> to memory and storage costs.</li>
<li>The RTX 5090, when it shows up in the United States, costs from <a href="https://gpupoet.com/gpu/market-report/gpu-market-report-october-2026"target="_blank" rel="noopener">two and a half times</a> to <a href="https://www.techspot.com/news/114254-nvidia-rtx-5090-production-but-absence-company-us.html"target="_blank" rel="noopener">almost five times</a> MSRP, and the rumor is that its chips are going to the professional lines. NVIDIA <a href="https://www.guru3d.com/story/nvidia-says-geforce-rtx-5090-production-is-continuing/"target="_blank" rel="noopener">denies discontinuing it</a>.</li>
<li>On the other side, Anthropic <a href="https://techcrunch.com/2026/06/01/anthropic-files-to-go-public/"target="_blank" rel="noopener">filed for an IPO</a> aiming, according to the press, at <a href="https://www.khaleejtimes.com/business/anthropic-says-revenue-jumped-to-nearly-17b-last-quarter-reports-2"target="_blank" rel="noopener">about 2 trillion dollars</a>, and OpenAI is <a href="https://uk.investing.com/news/stock-market-news/openai-races-to-raise-30-bln-ahead-of-anthropic-ipo-reuters-reports-4918623"target="_blank" rel="noopener">raising at more than 1.4 trillion</a>.</li>
<li>And the rhetoric about Chinese open models has hardened. Anthropic published that <a href="https://www.anthropic.com/news/detecting-and-preventing-distillation-attacks"target="_blank" rel="noopener">DeepSeek, Moonshot and MiniMax distilled Claude</a>, and Dario Amodei, even while saying he <a href="https://www.anthropic.com/news/position-open-weights-models"target="_blank" rel="noopener">never advocated banning open weights</a>, calls for chip export controls and mandatory pre-release testing of every sufficiently capable model, open or closed.</li>
</ul>
<h3>The cycle<span class="hx:absolute hx:-mt-20" id="the-cycle"></span>
    <a href="#the-cycle" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The simplest explanation for expensive memory is demand: datacenters buy everything and pay more. I believe it. What bothers me is that no big player has an incentive to break the cycle:</p>
<ol>
<li>The rhetoric says only the frontier lab knows how to handle these &ldquo;dangerous&rdquo; models, and that open source is a risky bet.</li>
<li>That pulls demand to the cloud, and the cloud buys GPUs and memory in record volume.</li>
<li>Manufacturers sell at a premium to whoever pays more and deprioritize consumers.</li>
<li>Good hardware becomes unreachable outside the datacenter.</li>
<li>Without hardware at home, open source doesn&rsquo;t get adopted, which reinforces the rhetoric in step 1.</li>
</ol>
<blockquote>
  <p>If everybody started hosting their own model, the trillion-dollar IPO math would stop adding up. v4 showed that open models are already ready for a good chunk of the work. What&rsquo;s missing is the hardware getting into the hands of the people doing the work.</p>

</blockquote>
]]></content:encoded><category>llm-benchmarks</category><category>local-models</category><category>llms</category><category>open-source</category></item><item><title>Best Open Source LLM: Strata with Qwen 3.8 Flash Next</title><link>https://www.akitaonrails.com/en/2026/10/22/best-open-source-llm-strata-with-qwen-3-8-flash-next/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/22/best-open-source-llm-strata-with-qwen-3-8-flash-next/</guid><pubDate>Thu, 22 Oct 2026 11:45:00 -0300</pubDate><description>&lt;p&gt;Strata showed up in almost every article in the home stretch of benchmark v4. In the &lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-consumer-open-source-rtx5090-strix-halo-strata/"&gt;consumer-grade open source&lt;/a&gt; one it was the lead; in the &lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/"&gt;what a team costs on B300 and H200&lt;/a&gt; one, the model it serves became the recommendation for the DGX Spark; and in the &lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/"&gt;v4 verdict&lt;/a&gt; it&amp;rsquo;s the only serious answer for anyone who wants to run a good model at home.&lt;/p&gt;
&lt;p&gt;The result, in short: &lt;strong&gt;Qwen3.8 Flash-Next&lt;/strong&gt; served by Strata on an RTX 5090 scored &lt;strong&gt;91, Tier A&lt;/strong&gt;, with zero nudges and all 14 planted defects fixed (two only after the reveal), 1.5 points behind the same model running on a datacenter B300. And it did that at about 159 tokens per second.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Strata showed up in almost every article in the home stretch of benchmark v4. In the <a href="/en/2026/10/22/llm-benchmark-v4-consumer-open-source-rtx5090-strix-halo-strata/">consumer-grade open source</a> one it was the lead; in the <a href="/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/">what a team costs on B300 and H200</a> one, the model it serves became the recommendation for the DGX Spark; and in the <a href="/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/">v4 verdict</a> it&rsquo;s the only serious answer for anyone who wants to run a good model at home.</p>
<p>The result, in short: <strong>Qwen3.8 Flash-Next</strong> served by Strata on an RTX 5090 scored <strong>91, Tier A</strong>, with zero nudges and all 14 planted defects fixed (two only after the reveal), 1.5 points behind the same model running on a datacenter B300. And it did that at about 159 tokens per second.</p>
<p>In this article I go through what Strata is, why it matters right now, what it doesn&rsquo;t solve, and how I set it up for daily use, with automatic loading and unloading and wired into OpenCode.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261022121453_strata-qwen-flash-next-opencode.png" alt="OpenCode running Qwen3.8 Flash-Next through Strata on the RTX 5090, between 129.9 and 153.1 tokens per second"  loading="lazy" /></p>
<h2>What Strata is<span class="hx:absolute hx:-mt-20" id="what-strata-is"></span>
    <a href="#what-strata-is" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://github.com/Niko1221/Strata"target="_blank" rel="noopener">Strata</a> is an open source inference engine, MIT licensed, built around one model: Qwen3.8 Flash-Next, a 125B-parameter MoE with 6B active per token, which normally calls for a server. The code is C++ and CUDA, reuses parts of llama.cpp/ggml, and has builds for NVIDIA, AMD (Strix Halo included), Intel Arc and Mac. It brings up an OpenAI- and Anthropic-compatible API on localhost.</p>
<p>The trick is treating the whole PC as a memory hierarchy. The model has 24,576 experts, 512 in each of its 48 layers, and each token uses only 10 per layer, plus one shared expert:</p>
<ul>
<li><strong>VRAM</strong> holds the most-used experts, like a cache;</li>
<li><strong>RAM</strong> holds all of them, and when a token needs one that isn&rsquo;t on the card, the processor computes it right there while the card works on the others;</li>
<li>the <strong>SSD</strong> holds a lookup table of about 29 GB, from which the model reads a few rows per token.</li>
</ul>
<p>On top of that, a speculation head that ships with the model itself guesses the next tokens and the big model checks them all at once. The README promises the same answer 1.6 to 1.8 times faster.</p>
<p>On my 5090, the log shows what this looks like in practice. The 32 GB of VRAM hold 10 to 11.5 thousand experts in about 20 to 22 GiB, almost half the total, and <strong>generally 90% to 97% of the experts each token asks for are already on the card</strong>. The CPU computes the rest directly in RAM, and only a small fraction gets copied to the card over the PCIe bus. That&rsquo;s why the CPU works hard too, as you can see further down.</p>
<h2>Why this matters now<span class="hx:absolute hx:-mt-20" id="why-this-matters-now"></span>
    <a href="#why-this-matters-now" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Because memory has become a luxury item. In 2026 the DRAM contract price <a href="https://www.trendforce.com/presscenter/news/20260601-13070.html"target="_blank" rel="noopener">almost doubled in a single quarter</a>, manufacturers <a href="https://www.trendforce.com/presscenter/news/20260930-13258.html"target="_blank" rel="noopener">keep prioritizing servers</a>, and Micron <a href="https://www.storagenewsletter.com/2025/12/05/micron-announces-exit-from-crucial-consumer-business/"target="_blank" rel="noopener">walked away from the consumer market</a> to serve the big customers. The RTX 5090 itself, when it shows up, costs two and a half to almost five times MSRP, as I covered in the <a href="/en/2026/10/22/llm-benchmark-v4-the-open-source-verdict-as-of-oct-2026/">verdict</a>.</p>
<p>In this scenario, the traditional way of running a Tier A model at home, with the whole model inside VRAM, is a non-starter. Flash-Next in NVFP4 took about 100 GB of card memory on the B300; nobody has that at home.</p>
<blockquote>
  <p>Strata flips the premise: instead of demanding VRAM for the whole model, it uses VRAM as a cache and RAM as the warehouse. That&rsquo;s what lets a Tier A model run on a fraction of the video memory it would otherwise ask for.</p>

</blockquote>
<h2>It isn&rsquo;t magic<span class="hx:absolute hx:-mt-20" id="it-isnt-magic"></span>
    <a href="#it-isnt-magic" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Strata makes it fit, but it doesn&rsquo;t work miracles. The stated minimum is <strong>32 GB of RAM and VRAM combined</strong>, but that only runs the most compressed version; the IQ3_S that scored 91 asks for about 64 GB of RAM. Add <strong>about 80 GB of disk</strong>, preferably SSD, and a 12 GB card or better on the official path. Below that it&rsquo;ll still start, there are reports with an 8 GB card, but at about 15 tokens per second.</p>
<h3>Memory bandwidth sets the speed<span class="hx:absolute hx:-mt-20" id="memory-bandwidth-sets-the-speed"></span>
    <a href="#memory-bandwidth-sets-the-speed" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In token generation, the bottleneck on a local machine is almost never compute. It&rsquo;s how many bytes per second the memory can deliver to the cores, because every token has to read the model&rsquo;s active weights. And there the gap between memory types is brutal:</p>
<table>
  <thead>
      <tr>
          <th>Memory</th>
          <th style="text-align: right">Approximate bandwidth</th>
          <th style="text-align: right">Versus the 5090</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>RTX 5090 GDDR7 VRAM</td>
          <td style="text-align: right">~1.8 TB/s</td>
          <td style="text-align: right">1x</td>
      </tr>
      <tr>
          <td>Strix Halo LPDDR5X unified memory</td>
          <td style="text-align: right">~256 GB/s</td>
          <td style="text-align: right">7 times slower</td>
      </tr>
      <tr>
          <td>Desktop DDR5 RAM, dual channel</td>
          <td style="text-align: right">~60 to 100 GB/s</td>
          <td style="text-align: right">18 to 30 times slower</td>
      </tr>
      <tr>
          <td>PCIe 5.0 x16 bus</td>
          <td style="text-align: right">~64 GB/s per direction</td>
          <td style="text-align: right">almost 30 times slower</td>
      </tr>
      <tr>
          <td>PCIe measured by Strata on my machine (card at x8)</td>
          <td style="text-align: right">~29 GB/s</td>
          <td style="text-align: right">about 60 times slower</td>
      </tr>
  </tbody>
</table>
<p>The last row is from my machine: the card is running on 8 PCIe lanes instead of 16, and Strata measures that at startup. One more reason the VRAM cache matters so much.</p>
<p>The Strix Halo has 128 GB and fits a lot more than a 5090, but every byte arrives seven times slower. That&rsquo;s what I measured in the benchmark: the dense Qwen 3.8 27B in Q8 reads about 29 GB per token, and on the Strix the theoretical ceiling sits near 9 tokens per second. I measured 7.7. The same math on the 5090&rsquo;s bandwidth would give about 60, seven times more, if the model fit along with the context.</p>
<p>That&rsquo;s why Strata&rsquo;s design works: the hot path stays in GDDR7, and whatever misses the cache gets computed by the CPU in DDR5, or crosses PCIe, both dozens of times slower. With over 90% cache hits, the little that&rsquo;s left out doesn&rsquo;t drag the speed down. On a small card, the cache covers less, more experts take the slow road, and speed drops: the author himself publishes 53 tokens per second on a 12 GB RTX 5070, a third of my 5090.</p>
<h3>A potato PC won&rsquo;t run it<span class="hx:absolute hx:-mt-20" id="a-potato-pc-wont-run-it"></span>
    <a href="#a-potato-pc-wont-run-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>So forget the laptop with integrated graphics and 16 GB of RAM. Without a reasonable dedicated card, without 32 GB of RAM and VRAM combined and without an SSD, the model won&rsquo;t load, or it loads and runs at RAM speed, which is horse-and-buggy speed.</p>
<p>And there&rsquo;s an entry cost that doesn&rsquo;t show up in generation speed: Strata reads the whole first message of every conversation, and the README cites <a href="https://github.com/Niko1221/Strata#good-to-know"target="_blank" rel="noopener">about 60 seconds per 30 thousand tokens</a> as a rule of thumb. On my 5090 it&rsquo;s much faster, about 100 thousand tokens in 16 to 20 seconds, but on a smaller card count on the README number. Coding agents send big system prompts, so the first answer of each session takes longer than the ones after it.</p>
<h3>Heavy even on my 5090<span class="hx:absolute hx:-mt-20" id="heavy-even-on-my-5090"></span>
    <a href="#heavy-even-on-my-5090" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>My machine is no slouch: Ryzen 9 7950X3D, 96 GB of RAM (the system sees about 92), 32 GB RTX 5090. Even so, Flash-Next takes up everything:</p>
<ul>
<li>at load time, it pushes about 50 GB of experts into RAM, at about 3 GB per second with a cold SSD, and fills the card&rsquo;s cache with over 20 GiB;</li>
<li>with everything loaded, less than 800 MB of VRAM is left free;</li>
<li>with the server up, the machine sits at 88 of 92 GB of RAM used, and the system starts swapping.</li>
</ul>
<p>This is btop in the middle of a work session with OpenCode. The Strata process alone holds 54 GB of RAM and half the CPU, with half of the 7950X3D&rsquo;s 32 threads pinned at 100% and the rest above 50%. The 5090 is at 99% utilization, with 30 of 32 GB of VRAM in use and pulling 351 W. There&rsquo;s 4 GB of RAM left available, and almost 48 GB already in swap.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261022122545_strata-btop-7950x3d-5090.png" alt="btop during a Strata session: RAM at 96%, swap half full, half the CPU at 100% and the rest above 50%, and the RTX 5090 at 99% with 30 of 32 GB of VRAM"  loading="lazy" /></p>
<p>The side effect shows up in the rest of the system. With VRAM at the limit, my desktop&rsquo;s app launcher and the terminal on a secondary monitor stopped opening properly, and other programs get sluggish. The fix was telling Strata to give about 2.5 GB of VRAM back to the desktop, with the <code>--vram-elastic</code> option, at the cost of a slightly smaller cache.</p>
<blockquote>
  <p>With all that, I firmly believe my machine is the minimum for using a local LLM in real programming work, beyond small exercises. With less than that, count on much lower speed, shorter context and the whole PC suffering while the model is loaded.</p>

</blockquote>
<h2>How to install<span class="hx:absolute hx:-mt-20" id="how-to-install"></span>
    <a href="#how-to-install" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The official path on Linux and Mac is the one-line installer. It checks the SHA-256, doesn&rsquo;t ask for root and installs into your home folder. Like any <code>curl | sh</code>, download it and read it first:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -fsSL https://github.com/Niko1221/Strata/releases/latest/download/install.sh -o install.sh
</span></span><span class="line"><span class="cl">less install.sh
</span></span><span class="line"><span class="cl">sh install.sh</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>After that, <code>strata launch</code> asks for model, context and access, downloads the right engine for your card and the model, and starts serving. For scripts, everything goes through flags:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">strata launch                                <span class="c1"># guided screens</span>
</span></span><span class="line"><span class="cl">strata launch --model &lt;variant&gt; --yes --no-tui   <span class="c1"># no questions</span>
</span></span><span class="line"><span class="cl">strata launch --status                       <span class="c1"># what is being served</span>
</span></span><span class="line"><span class="cl">strata launch --stop                         <span class="c1"># stop</span>
</span></span><span class="line"><span class="cl">strata monitor --url http://127.0.0.1:8080   <span class="c1"># speed, GPU, memory</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I used the <strong>IQ3_S</strong> variant, the one that scored 91 in the benchmark. On disk it takes about 84 GB in two files (the 55 GB model and the 29 GB lookup table), plus about 7 GB for the speculation head.</p>
<p>The configuration <code>strata launch</code> generates is a JSON with the engine arguments. The ones that matter in mine:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;args&#34;</span><span class="err">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;--expert-cache&#34;</span><span class="p">,</span> <span class="s2">&#34;auto&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;--prefill&#34;</span><span class="p">,</span> <span class="s2">&#34;auto&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;--spec&#34;</span><span class="p">,</span> <span class="s2">&#34;4&#34;</span><span class="p">,</span> <span class="s2">&#34;--spec-min-p&#34;</span><span class="p">,</span> <span class="s2">&#34;0.5&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;--mtp&#34;</span><span class="p">,</span> <span class="s2">&#34;/mnt/data/strata-models/mtp/rt&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;--max-context&#34;</span><span class="p">,</span> <span class="s2">&#34;262144&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;--kv&#34;</span><span class="p">,</span> <span class="s2">&#34;int8&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;--kv-resident&#34;</span><span class="p">,</span> <span class="s2">&#34;32768&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;--vram-elastic&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>--spec 4</code> turns on speculation with a window of 4 tokens per step, up to 3 guessed by the speculation head; <code>--kv int8</code> stores the attention cache in 8 bits; <code>--kv-resident</code> keeps only 32 thousand positions of the context cache, the most-read ones, in VRAM; and <code>--vram-elastic</code> lets it give VRAM back to the desktop with the server running.</p>
<h3>From 128 thousand to 256 thousand tokens of context<span class="hx:absolute hx:-mt-20" id="from-128-thousand-to-256-thousand-tokens-of-context"></span>
    <a href="#from-128-thousand-to-256-thousand-tokens-of-context" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The benchmark ran with 128 thousand tokens of context, which is what the install configured by default. Later I bumped it to 256 thousand, with <code>--max-context 262144</code>, and the loss was small: in the server logs, generation averaged about 190 tokens per second in a short session with 128 thousand and about 175 with 256 thousand, about 10% slower for twice the context, a bit more with VRAM given back to the desktop.</p>
<p>What holds this together is <code>--kv-resident</code>: only 32 thousand positions of the attention cache, the most-read ones, stay in VRAM, the rest stays in RAM, and even so about 97% of the reads from that cache happen on the card. The benchmark&rsquo;s 91 was measured with 128 thousand; with 256 thousand I measured speed, and quality hasn&rsquo;t been re-tested yet.</p>
<p>For me, 256 thousand is the minimum for long agent work. With 128 thousand, a real session blows through the context fast, and the agent starts compacting its memory all the time. That gets annoying very quickly, and every compaction throws away details the model will need later.</p>
<blockquote>
  <p>Short context is a hidden problem with local models. Before looking at tokens per second, check how much context you can serve without the speed collapsing.</p>

</blockquote>
<h2>Loading and unloading on its own<span class="hx:absolute hx:-mt-20" id="loading-and-unloading-on-its-own"></span>
    <a href="#loading-and-unloading-on-its-own" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Keeping about 50 GB of RAM and the entire card tied up all day, just to have the model ready when I need it, makes no sense. So I put together a small proxy, in pure Python, that&rsquo;s always up on port 8080 and controls Strata:</p>
<ul>
<li>it answers the model list on its own, so OpenCode sees the model without waking anything up;</li>
<li>on the first chat request, it brings Strata up on an internal port and waits for it to be ready, about 40 seconds;</li>
<li>it relays the responses in streaming;</li>
<li>after 10 minutes without traffic, it takes Strata down and gives the card and the RAM back to the system.</li>
</ul>
<p>The core is this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">ensure_up</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">with</span> <span class="n">_lock</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">ready</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">        <span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">([</span><span class="n">STRATA</span><span class="p">,</span> <span class="s2">&#34;serve&#34;</span><span class="p">,</span> <span class="s2">&#34;--config&#34;</span><span class="p">,</span> <span class="n">CFG</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                          <span class="s2">&#34;--host&#34;</span><span class="p">,</span> <span class="s2">&#34;127.0.0.1&#34;</span><span class="p">,</span> <span class="s2">&#34;--port&#34;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">UP_PORT</span><span class="p">)],</span>
</span></span><span class="line"><span class="cl">                         <span class="n">start_new_session</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">90</span><span class="p">):</span>          <span class="c1"># cold start takes ~35-40 s</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">ready</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">                <span class="n">set_reserve</span><span class="p">()</span>        <span class="c1"># give VRAM back to the desktop</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="cl">            <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">False</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">idle_watch</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">30</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">-</span> <span class="n">_last</span> <span class="o">&gt;</span> <span class="n">IDLE_TTL</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">stop_up</span><span class="p">()</span>                <span class="c1"># free the GPU and ~50 GB of RAM</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>And a systemd user service keeps the proxy up from login (trimmed version):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="c1"># ~/.config/systemd/user/qwen-strata.service</span>
</span></span><span class="line"><span class="cl"><span class="k">[Unit]</span>
</span></span><span class="line"><span class="cl"><span class="na">Description</span><span class="o">=</span><span class="s">Qwen3.8 Flash-Next on-demand proxy (Strata RTX 5090)</span>
</span></span><span class="line"><span class="cl"><span class="na">After</span><span class="o">=</span><span class="s">network-online.target</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[Service]</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">QWEN_IDLE_TTL=600</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">QWEN_VRAM_RESERVE_MIB=2560</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">QWEN_UP_PORT=8781</span>
</span></span><span class="line"><span class="cl"><span class="na">Environment</span><span class="o">=</span><span class="s">QWEN_PROXY_PORT=8080</span>
</span></span><span class="line"><span class="cl"><span class="na">ExecStart</span><span class="o">=</span><span class="s">%h/.local/bin/qwen-strata-ondemand</span>
</span></span><span class="line"><span class="cl"><span class="na">Restart</span><span class="o">=</span><span class="s">on-failure</span>
</span></span><span class="line"><span class="cl"><span class="na">KillMode</span><span class="o">=</span><span class="s">mixed</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">[Install]</span>
</span></span><span class="line"><span class="cl"><span class="na">WantedBy</span><span class="o">=</span><span class="s">default.target</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">systemctl --user daemon-reload
</span></span><span class="line"><span class="cl">systemctl --user <span class="nb">enable</span> --now qwen-strata.service</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The price is the wait on the first message after some idle time. In exchange, when I&rsquo;m not programming, the machine is mine again.</p>
<h2>Configuring OpenCode<span class="hx:absolute hx:-mt-20" id="configuring-opencode"></span>
    <a href="#configuring-opencode" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Strata has a shortcut, <code>strata connect opencode --write</code>, that writes the configuration after asking and keeps a backup. By hand, it&rsquo;s an OpenAI-compatible provider pointing at the local port:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="s2">&#34;provider&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;strata-5090&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;npm&#34;</span><span class="p">:</span> <span class="s2">&#34;@ai-sdk/openai-compatible&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Strata (RTX 5090)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;options&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;baseURL&#34;</span><span class="p">:</span> <span class="s2">&#34;http://127.0.0.1:8080/v1&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;apiKey&#34;</span><span class="p">:</span> <span class="s2">&#34;local&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;models&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;qwen3.8-flash-next-iq3_s&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;Qwen3.8 Flash-Next IQ3_S (Strata 5090)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;reasoning&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;tool_call&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;limit&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;context&#34;</span><span class="p">:</span> <span class="mi">262144</span><span class="p">,</span> <span class="nt">&#34;input&#34;</span><span class="p">:</span> <span class="mi">229376</span><span class="p">,</span> <span class="nt">&#34;output&#34;</span><span class="p">:</span> <span class="mi">32768</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Any key works, because the server is local. Strata itself warns that OpenCode needs <code>limit.input</code>, to know how much of the context is left for input; in the example I set it to the context minus the max output. Claude Code works too, by pointing <code>ANTHROPIC_BASE_URL</code> at <code>http://127.0.0.1:8080</code> and setting <code>CLAUDE_CODE_MAX_CONTEXT_TOKENS</code> to the context size, since Strata speaks the Anthropic API as well.</p>
<p>One detail: by default Strata serves one request at a time. If your agent fires off subagents in parallel, they get queued.</p>
<h2>And day to day?<span class="hx:absolute hx:-mt-20" id="and-day-to-day"></span>
    <a href="#and-day-to-day" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you have the machine for it, the result is good. Flash-Next stays above 150 tokens per second most of the time, as you can see in the screenshot at the top, and tool calling is solid: in the benchmark it ran all seven sprints in OpenCode without a single nudge, and in normal use it reads files, runs commands and edits code without tripping over the format.</p>
<p>In practice, I don&rsquo;t feel much difference from Claude Code, or from OpenCode with GLM or Kimi in the cloud. And the cloud isn&rsquo;t at its best right now: in my perception, all those services have been a bit slower than usual lately, probably struggling with more demand than available capacity. Running at home, the speed is always the same, and the code never leaves my machine.</p>
<p>Even with good tokens per second, I still feel Flash-Next is a bit less responsive than a commercial model. There are the seconds of reading on the first message of each session, the pause when it needs experts that aren&rsquo;t on the card, and the cold load after some idle time. That&rsquo;s to be expected: we&rsquo;re running a server model with resources at the limit.</p>
<blockquote>
  <p>Considering it&rsquo;s free and runs on my machine, it&rsquo;s almost good enough. For the first time, running a local model for programming feels like a genuinely usable scenario, and I find myself using it more and more as a replacement.</p>

</blockquote>
<p>The catch is still the hardware. A 5090, 96 GB of RAM and a strong processor are the minimum for this scenario, and that hardware keeps getting more expensive and harder to find. But for those who already have it, Tier A at home is no longer a promise.</p>
]]></content:encoded><category>local-models</category><category>open-source</category><category>llms</category><category>hardware</category></item><item><title>LLM Benchmark v4: consumer-grade open source on RTX 5090 or Strix Halo. And Strata?</title><link>https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-consumer-open-source-rtx5090-strix-halo-strata/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-consumer-open-source-rtx5090-strix-halo-strata/</guid><pubDate>Thu, 22 Oct 2026 11:30:00 -0300</pubDate><description>&lt;p&gt;In the last two articles I covered the &lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-open-source-that-only-fits-in-4x-b300/"&gt;big-model benchmark on 4x B300&lt;/a&gt; and the &lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/"&gt;team-size and per-user cost math on B300 and H200&lt;/a&gt;. Now the question every developer without a Runpod pod has: &lt;strong&gt;is consumer hardware already good enough to work with AI for real?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I went back to two machines I already had: a workstation with an RTX 5090 and a Strix Halo mini PC. And with a new inference engine, Strata, which promises to make big MoEs fit on a regular PC. The short answer: a 125B model already makes Tier A on an RTX 5090. The rest is more complicated.&lt;/p&gt;</description><content:encoded><![CDATA[<p>In the last two articles I covered the <a href="/en/2026/10/22/llm-benchmark-v4-open-source-that-only-fits-in-4x-b300/">big-model benchmark on 4x B300</a> and the <a href="/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/">team-size and per-user cost math on B300 and H200</a>. Now the question every developer without a Runpod pod has: <strong>is consumer hardware already good enough to work with AI for real?</strong></p>
<p>I went back to two machines I already had: a workstation with an RTX 5090 and a Strix Halo mini PC. And with a new inference engine, Strata, which promises to make big MoEs fit on a regular PC. The short answer: a 125B model already makes Tier A on an RTX 5090. The rest is more complicated.</p>
<h2>The machines, side by side<span class="hx:absolute hx:-mt-20" id="the-machines-side-by-side"></span>
    <a href="#the-machines-side-by-side" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before any scores, understand the physical difference of what I&rsquo;m comparing:</p>
<table>
  <thead>
      <tr>
          <th>Hardware</th>
          <th>Memory</th>
          <th>Bandwidth</th>
          <th>Architecture</th>
          <th>Approximate cost</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>NVIDIA B300</td>
          <td>288 GB HBM3e</td>
          <td>~8 TB/s</td>
          <td>Blackwell Ultra, FP8 and FP4</td>
          <td>US$ 9/hour (Runpod)</td>
      </tr>
      <tr>
          <td>NVIDIA H200</td>
          <td>141 GB HBM3e</td>
          <td>~4.8 TB/s</td>
          <td>Hopper, FP8</td>
          <td>US$ 3.59/hour</td>
      </tr>
      <tr>
          <td>DGX Spark</td>
          <td>128 GB unified</td>
          <td>273 GB/s</td>
          <td>GB10, FP4</td>
          <td>~US$ 6,950</td>
      </tr>
      <tr>
          <td>RTX 5090</td>
          <td>32 GB GDDR7</td>
          <td>~1.8 TB/s</td>
          <td>Blackwell sm_120, FP8/FP4</td>
          <td>US$ 1,999 suggested (~5x at retail)</td>
      </tr>
      <tr>
          <td>Strix Halo (Ryzen AI Max+ 395)</td>
          <td>128 GB unified</td>
          <td>~256 GB/s</td>
          <td>gfx1151, ROCm</td>
          <td>~US$ 2,000</td>
      </tr>
  </tbody>
</table>
<p>The B300 has over 30 times the Strix Halo&rsquo;s memory bandwidth. The 5090 has 7 times. That explains why the same model flies on one machine and crawls on the other, and why quantization stops being a detail and becomes a design decision.</p>
<p>And there&rsquo;s the shared-memory detail: on the Strix and the Spark, the same RAM serves CPU, GPU and operating system. It&rsquo;s not dedicated VRAM, so the real slack is much smaller than the pretty number on the box.</p>
<h2>The ranking on consumer hardware<span class="hx:absolute hx:-mt-20" id="the-ranking-on-consumer-hardware"></span>
    <a href="#the-ranking-on-consumer-hardware" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The yardstick is the same as the v4 sabotage benchmark: 14 planted defects, a review-vigilance score, Tier A starting at 83.</p>
<table>
  <thead>
      <tr>
          <th>Model / machine</th>
          <th>Variant and engine</th>
          <th style="text-align: right">Score / Tier</th>
          <th style="text-align: right">Speed</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Qwen3.8 Flash-Next</strong> (125B-A6B)</td>
          <td>RTX 5090, Strata, IQ3_S</td>
          <td style="text-align: right"><strong>91.0 (A)</strong></td>
          <td style="text-align: right">159.2 tok/s</td>
      </tr>
      <tr>
          <td>Ornith-1.5-35B-A3B</td>
          <td>RTX 5090, Strata, Q8_0 GGUF</td>
          <td style="text-align: right">64.5 (C)</td>
          <td style="text-align: right">~80 tok/s</td>
      </tr>
      <tr>
          <td>Qwen3.8-27B</td>
          <td>5090 → Strix, Q5_K_M → Q8_0</td>
          <td style="text-align: right">80.0 (B)</td>
          <td style="text-align: right">7.7 tok/s</td>
      </tr>
      <tr>
          <td>GLM-4.7-Flash (30B-A3B)</td>
          <td>RTX 5090, llama-swap, Q5_K_M</td>
          <td style="text-align: right">24.0 (D)</td>
          <td style="text-align: right">not measured</td>
      </tr>
  </tbody>
</table>
<p>GLM-4.7-Flash completed the whole protocol (after a first nested attempt that needed a retry) and still failed to detect sabotage. And there&rsquo;s a humility lesson in the Qwen 27B: it scored 80 on the same task where it scored 80.5 on the B300, but at 7.7 tokens per second on the Q8 probe and 706 minutes on the clock. A good score doesn&rsquo;t pay for productivity.</p>
<p>I left out the tests that don&rsquo;t have a final score yet: Qwen3.8 Flash-Next on the Strix with Strata is only confirmed as executable, and the dense 27Bs were discarded on the Strix by the 30 tok/s cutoff.</p>
<h2>The tuning that makes a model run well on a PC<span class="hx:absolute hx:-mt-20" id="the-tuning-that-makes-a-model-run-well-on-a-pc"></span>
    <a href="#the-tuning-that-makes-a-model-run-well-on-a-pc" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Consumer hardware doesn&rsquo;t forgive lazy configuration. What I learned in practice:</p>
<ul>
<li><strong>On the 5090, compile llama.cpp for sm_120.</strong> A ready-made image falls into a slow PTX fallback. It&rsquo;s <code>-DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=120</code>, driver 570+, and no <code>--ctx-size 0</code> on a 32 GB card: the training-context default blows the VRAM on the first allocation. Context needs an explicit ceiling, and if you get OOM on the first request, cut 25 to 50%.</li>
<li><strong>KV cache in q8_0.</strong> Halves KV memory with no measurable quality cost. Flash-attention on by default, but GLM 4.7 Flash needs it off, because its deepseek2 architecture is incompatible.</li>
<li><strong>Hybrid reasoning is work.</strong> Qwen3.8-27B, with the SSM/Mamba architecture, needed a fresh llama.cpp/Ollama build because of <code>ssm_conv1d</code>. And &ldquo;no reasoning&rdquo; mode didn&rsquo;t prevent a coherence loop in one of the attempts; the way out was resuming on the Strix with Q8_0 and <code>--reasoning off</code>. It wasn&rsquo;t extra memory that fixed it, it was turning off the thinking.</li>
<li><strong>On the Strix, the adjustment is ROCm, not magic.</strong> <code>HSA_OVERRIDE_GFX_VERSION</code>, <code>GGML_HIP_NO_VMM</code>, <code>-dio</code>. Its trump is capacity (128 GB), not speed (~256 GB/s). Q4_K_M gave 12.6 tok/s and Q8_0 gave 7.7 tok/s, below my 30 tok/s cutoff for interactive use. That&rsquo;s why the Strix became an escape hatch for big models, not a fast chat box.</li>
<li><strong>Speculation only helps with high acceptance.</strong> In a <a href="https://mihai.ltd/blog/beating-llamacpp-from-scratch-consumer-amd"target="_blank" rel="noopener">test by Mihai Farcas</a> on an RX 7900 XTX, llama.cpp&rsquo;s n-gram speculation, with no draft model, had only 5 of 64 tokens accepted, and throughput stayed flat in one run and dropped about 2% in the other. The gain shows up with a drafter made for the model, like the helper Strata uses on Flash-Next.</li>
</ul>
<h2>What is this Strata thing<span class="hx:absolute hx:-mt-20" id="what-is-this-strata-thing"></span>
    <a href="#what-is-this-strata-thing" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://github.com/Niko1221/Strata"target="_blank" rel="noopener">Strata</a> is an open source inference engine, MIT license, built around one model: <strong>Qwen3.8 Flash-Next</strong>, a 125-billion-parameter MoE that normally asks for a server. It also runs smaller MoEs, like the Ornith-35B I tested here. The code is C++ and CUDA and reuses parts of llama.cpp/ggml. It has builds for NVIDIA (CUDA 12 and 13), AMD (including Strix Halo), Intel Arc and Apple Silicon, and brings up an OpenAI- and Anthropic-compatible API on localhost, which plugs straight into Claude Code, Codex CLI or OpenCode.</p>
<p>Careful with the name. Mihai Farcas published <a href="https://mihai.ltd/blog/beating-llamacpp-from-scratch-consumer-amd"target="_blank" rel="noopener">another engine called Strata</a>, in Rust with HIP kernels, for small dense Qwen 3.5 models on an RX 7900 XTX. They&rsquo;re different projects, and the one that ran here was the first.</p>
<p>The problem it attacks is the big MoE on a small machine. The strategy is <strong>expert-offload</strong>, in layers:</p>
<ul>
<li>the model has 24,576 experts, 512 in each of the 48 layers, and each token uses only 10 per layer;</li>
<li>the GPU holds about 4 thousand experts, the most used ones;</li>
<li>the system RAM holds all of them;</li>
<li>a lookup table of about 29 GB stays on the SSD, and the model reads a few rows of it per token.</li>
</ul>
<p>On top of that, a small helper guesses the next words and the big model checks them all at once. The README promises the same answer 1.6 to 1.8 times faster. The minimum is 32 GB adding RAM and VRAM, plus about 80 GB of disk, and the IQ3_S variant I used is about 55 GB.</p>
<p>What made me believe in it was the result: <strong>Qwen3.8 Flash-Next on the 5090 with Strata scored 91.0, with zero nudges and all 14 items solved</strong>, 1.5 points behind the 92.5 the same model scored on the B300 with vLLM. The report itself calls that &ldquo;within the noise&rdquo;. A community project, on a consumer card, sat glued to the same model served in a datacenter in NVFP4.</p>
<h3>And now it can see<span class="hx:absolute hx:-mt-20" id="and-now-it-can-see"></span>
    <a href="#and-now-it-can-see" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Until yesterday, my Strata was blind: sending an image got back &ldquo;this server was started without the vision encoder&rdquo;. I enabled vision by hand, and it was simpler than it looked.</p>
<p>The vision projector (the <code>mmproj</code>) I had already archived on the NAS inside the uncensored Flash-Next variant. I checked its sha256 against the archive&rsquo;s manifest and against the hash Strata pinned for the BF16 encoder, and copied it into the models directory. The configuration gained the <code>--vision</code> flag and a <code>vision</code> section pointing to the <code>strata-vision</code> component and the mmproj, with a backup beside it.</p>
<p>The verification was end-to-end: the encoder loads in half a second, warms up 1,024 image tokens in under two seconds, and answered &ldquo;Red&rdquo; to a red test square. And the detail that matters most to me: with the encoder resident, 3.65 GB of VRAM remained free, so the desktop&rsquo;s 4 GB reserve still holds. The only gotcha: lazy loading doesn&rsquo;t coexist with the vision section in this configuration, so it stays off here.</p>
<h2>Careful: Strata eats the whole GPU, and the desktop dies<span class="hx:absolute hx:-mt-20" id="careful-strata-eats-the-whole-gpu-and-the-desktop-dies"></span>
    <a href="#careful-strata-eats-the-whole-gpu-and-the-desktop-dies" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There&rsquo;s a cost that doesn&rsquo;t show up in benchmarks: running Strata on the same GPU that draws your desktop. It was designed to fill the card, and it does.</p>
<p>In my case, the engine allocated 32,085 of the 32,607 MiB on the 5090, 98.4% of the VRAM. Hyprland was left with about 500 MiB, desktop allocations failed, and even the terminal stopped responding. Only a hard reset solved it.</p>
<p>It was two failures in sequence. The reserve I had configured was 2,560 MiB, but the proxy fired only once, swallowed the exception and never tried again. The engine&rsquo;s <code>/v1/vram</code> endpoint wasn&rsquo;t up at that moment, so the reserve was never applied. And 2,560 MiB was already too little for Hyprland, browser and terminal together.</p>
<p>The fix, validated under load:</p>
<ul>
<li><strong>4,096 MiB</strong> (4 GiB) reserve, with retry for up to a few minutes, engine-response verification and a confirmation log. No fire-and-forget.</li>
<li>Re-assertion of the reserve every 30 seconds while the engine is loaded, to close any rebalancing drift.</li>
<li>In the first load test, with the GPU at 99%, <strong>3,629 to 3,888 MiB stayed free during the whole generation</strong>. In the following test, one long generation and three other concurrent requests finished successfully; the smallest slack observed was 3,949 MiB. The desktop stayed alive.</li>
</ul>
<p>The price shows up in throughput. The expert cache dropped from about 11,700 slots to 9,700, so more experts travel over PCIe. In the initial measurement, it went from ~200 to ~150 tokens per second. I happily pay that: a desktop that doesn&rsquo;t freeze is worth more than those 25% of speed in that test.</p>
<p>There&rsquo;s a structural alternative: this machine has an integrated Radeon 610M, and Hyprland can be moved to it. The 5090 would be dedicated to inference.</p>
<p>The cost is that the 610M is weak for gaming and NVIDIA multi-GPU on Wayland has its quirks. I preferred the elastic reserve, because the model also unloads when idle.</p>
<p>The general lesson: <strong>never let an inference engine take 100% of a GPU that also draws your screen.</strong> In this configuration I don&rsquo;t have a rigid driver-level VRAM reservation for display clients. I had to solve it on the engine side: reserve a few GB, re-assert after every cold start, and measure again with the desktop open.</p>
<h3>The same 32 GB also limit the session<span class="hx:absolute hx:-mt-20" id="the-same-32-gb-also-limit-the-session"></span>
    <a href="#the-same-32-gb-also-limit-the-session" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The 5090&rsquo;s math is tight on all sides. The same 32 GB have to accommodate the model&rsquo;s dense weights and fixed buffers, the hot-expert cache, the resident part of the KV cache and also the 4 GiB reserve for Hyprland, browser and terminal. What&rsquo;s left for one thing comes out of another.</p>
<p>KV cache is the conversation&rsquo;s memory. Every token of the prompt, of the previous answers and of the files read creates state that the model needs to consult in the next tokens. In my Strata it&rsquo;s in <code>int8</code>, with 32K cells per layer resident on the GPU.</p>
<p>The rest can be streamed from RAM, which is why raising the window from 128K to 256K didn&rsquo;t increase VRAM or drop speed in my synthetic test. That streaming avoids the immediate blow-up, but it still uses memory and doesn&rsquo;t turn a 5090 into a limit-free server.</p>
<p>The ceiling configured here is <strong>262,144 tokens, or 256K</strong>. Several commercial models I tested, including the newest Claudes, already work in the 1-million-token class. Almost four times the window changes how you work: in Claude Code you can accumulate much more history before compaction; in the local Qwen I have to treat context as a budget from the first prompt.</p>
<p>The conversation that shows up in the terminal is only part of the context. Depending on the harness, the system prompt, <code>AGENTS.md</code> and <code>CLAUDE.md</code>, skill catalogs and loaded content, tool descriptions and schemas, MCP servers, plugin instructions, command outputs, files and the space reserved for the answer also go in. A well-implemented skill loads its full text only when called, but its catalog can still enter the prompt. A plugin that registers twenty tools also sends twenty schemas before you ask for anything.</p>
<p>That&rsquo;s why the benchmark didn&rsquo;t use my normal OpenCode. The runner <a href="https://github.com/akitaonrails/llm-coding-benchmark#local-opencode-benchmark-config"target="_blank" rel="noopener">generates an isolated configuration</a>, without the global plugins and MCPs, with only the providers and agents needed for the test. It also pins the real 262,144-token limit instead of pretending the model accepts the context advertised by another backend.</p>
<p>To use this Qwen day to day, I&rsquo;d do the same cleanup:</p>
<ul>
<li>start with the leanest possible harness and activate plugins or MCPs when the project really needs them;</li>
<li>keep heavy skills on demand, without dumping whole manuals at the start of the session;</li>
<li>compact or open a new session before touching the ceiling, recording important decisions in project files;</li>
<li>reserve space for the model&rsquo;s output. A window stuffed with input is useless if there&rsquo;s no token left for it to think, call tools and answer.</li>
</ul>
<blockquote>
  <p>With 256K, context is a hardware resource. Installing too many integrations and loading everything into every session consumes window and memory before the work starts.</p>

</blockquote>
<h2>Wasn&rsquo;t Qwen 3.8 too slow?<span class="hx:absolute hx:-mt-20" id="wasnt-qwen-38-too-slow"></span>
    <a href="#wasnt-qwen-38-too-slow" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>It was, and I wrote that. In the <a href="/en/2026/09/15/new-llm-benchmark-v4-retesting-39-llms-part-2/">v4 ranking</a>, the local Qwen 3.8 27B took almost 12 hours to close the seven sprints. In the <a href="/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/">B300 article</a> I summarized: scored 80, took 706 minutes, &ldquo;so don&rsquo;t even try&rdquo;.</p>
<p>Except that&rsquo;s another Qwen 3.8. The family has both, and they behave in opposite ways at home:</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>Qwen 3.8 27B</th>
          <th>Qwen3.8 Flash-Next</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Architecture</td>
          <td>dense, 27B</td>
          <td>MoE, 125B total, 6B active per token</td>
      </tr>
      <tr>
          <td>Where v4 finished</td>
          <td>Strix Halo, Q8_0</td>
          <td>RTX 5090, IQ3_S, Strata</td>
      </tr>
      <tr>
          <td>Speed</td>
          <td>7.7 tok/s</td>
          <td><strong>159.2 tok/s</strong></td>
      </tr>
      <tr>
          <td>v4 score</td>
          <td>80.0 (B)</td>
          <td><strong>91.0 (A)</strong></td>
      </tr>
  </tbody>
</table>
<h3>Why the bigger one runs faster<span class="hx:absolute hx:-mt-20" id="why-the-bigger-one-runs-faster"></span>
    <a href="#why-the-bigger-one-runs-faster" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In token generation, a local machine is memory-bandwidth-bound: each token needs to read all the active weights. The dense 27B reads its 27 billion every token, about 29 GB in Q8. The Strix moves about 256 GB/s, so the ceiling sits near 9 tokens per second, and I measured 7.7.</p>
<p>On the 5090 the same 27B would be fast, but in Q8 it doesn&rsquo;t fit in the 32 GB along with the context that seven sprints accumulate. In Q5_K_M it fit, but got stuck in a reasoning loop on sprint 3. It finished on the Strix, in Q8_0 with reasoning off (<code>--reasoning off</code>), which is what unlocked the loop.</p>
<p>Flash-Next has almost five times more parameters in total, but only about 6 billion work per token. In 3 bits, that&rsquo;s around a tenth of what the 27B in Q8 needs to read. The hot experts stay on the 5090&rsquo;s GDDR7, with seven times the Strix&rsquo;s bandwidth, and the speculation helper gets tokens ahead. Result: about 20 times the 27B&rsquo;s speed on the Strix, with a higher score.</p>
<blockquote>
  <p>The turnaround came from the model and engine swap: a MoE with few active parameters, served by an expert-offload engine made to measure for it. No configuration flag would pull this out of the dense 27B on the Strix.</p>

</blockquote>
<h3>The tuning still charges<span class="hx:absolute hx:-mt-20" id="the-tuning-still-charges"></span>
    <a href="#the-tuning-still-charges" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The price of running at home changes from model to model. Flash-Next in 3 bits lost only 1.5 points against the B300&rsquo;s NVFP4 version. Ornith-35B, on the same engine and the same card, lost 16.5 against its BF16 version on the B300. Measure your model before trusting it.</p>
<h2>What each model did that&rsquo;s interesting<span class="hx:absolute hx:-mt-20" id="what-each-model-did-thats-interesting"></span>
    <a href="#what-each-model-did-thats-interesting" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Flash-Next: the proof that consumer reaches Tier A.</strong> 34 of 40 unannounced, plus 6 with reveal weight, and only two items needing a pointer. No nudges, all sprints clean. It&rsquo;s the only local one that combines a Tier A score, interactive speed (159 tok/s) and the full protocol without help. If the question is &ldquo;can I use it at work&rdquo;, this is the example.</p>
<p><strong>Ornith-35B: fast, but not good enough.</strong> The same Ornith that scored 81 on the B300 in BF16 scored 64.5 on the 5090 with Q8_0. Unannounced detection dropped from 30 to 23. Quantization, engine and hardware all changed at once, so the cause can&rsquo;t be isolated: this Q8_0 + Strata + 5090 combination lost 16.5 points, and I don&rsquo;t know how much came from each variable. The message is clear: &ldquo;runs fast&rdquo; is not &ldquo;reviews well&rdquo;.</p>
<p><strong>Qwen 27B: good score, terrible experience.</strong> It scored 80 on the Strix resume, with sprints 1 and 2 on the 5090, close to the B300&rsquo;s 80.5. But 7.7 tok/s on the Q8 probe and 706 minutes of wall time. And on top of that zero fixes on reveal, with four items open. Using this day to day is choosing to wait.</p>
<p><strong>GLM-4.7-Flash: the engine ran, the model failed.</strong> Full protocol in 29 minutes, and zero unannounced detection. It recovered 8 of 14 only when pointed, and even then left the fixes uncommitted. On the B300 it scored 33.5, which isn&rsquo;t good either. The problem isn&rsquo;t just the card.</p>
<h2>The distance between the categories<span class="hx:absolute hx:-mt-20" id="the-distance-between-the-categories"></span>
    <a href="#the-distance-between-the-categories" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The question every dev has is whether consumer already gets there. Direct comparison, on the same yardstick:</p>
<table>
  <thead>
      <tr>
          <th>Category</th>
          <th>Models</th>
          <th style="text-align: right">Score</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Commercial frontier</td>
          <td>Claude Opus 5 / 5.5</td>
          <td style="text-align: right">100.0</td>
      </tr>
      <tr>
          <td>Commercial frontier</td>
          <td>GPT-6 Luna</td>
          <td style="text-align: right">95.5</td>
      </tr>
      <tr>
          <td>Commercial frontier</td>
          <td>GLM 5.3 (hosted)</td>
          <td style="text-align: right">94.0</td>
      </tr>
      <tr>
          <td>Commercial frontier</td>
          <td>GPT-6 Sol / Sonnet 5</td>
          <td style="text-align: right">91.0</td>
      </tr>
      <tr>
          <td>Commercial frontier</td>
          <td>Kimi K3</td>
          <td style="text-align: right">85.0</td>
      </tr>
      <tr>
          <td>Open datacenter</td>
          <td>DeepSeek V4.1 Flash (4x B300)</td>
          <td style="text-align: right">92.5</td>
      </tr>
      <tr>
          <td>Open datacenter</td>
          <td>GLM 5.3 Flash / Qwen3.8 Flash-Next (B300)</td>
          <td style="text-align: right">92.5</td>
      </tr>
      <tr>
          <td><strong>Open consumer</strong></td>
          <td><strong>Qwen3.8 Flash-Next (5090 + Strata)</strong></td>
          <td style="text-align: right"><strong>91.0</strong></td>
      </tr>
      <tr>
          <td>Open consumer</td>
          <td>Qwen3.8-27B (Strix)</td>
          <td style="text-align: right">80.0</td>
      </tr>
      <tr>
          <td>Open consumer</td>
          <td>Ornith-35B (5090)</td>
          <td style="text-align: right">64.5</td>
      </tr>
      <tr>
          <td>Open consumer</td>
          <td>GLM-4.7-Flash (5090)</td>
          <td style="text-align: right">24.0</td>
      </tr>
  </tbody>
</table>
<p>The reading is that the consumer top is <strong>9 points below the absolute commercial top and 1.5 points below the open datacenter top</strong>, on this vigilance metric. It&rsquo;s a small distance, and it vanishes when you notice GPT-6 Sol and Sonnet 5 are also at 91. The real abyss isn&rsquo;t between datacenter and consumer: it&rsquo;s between the right model and all the others. Between Flash-Next and Ornith, on the same 5090, it&rsquo;s 26.5 points.</p>
<h2>So, is consumer hardware good enough to work with?<span class="hx:absolute hx:-mt-20" id="so-is-consumer-hardware-good-enough-to-work-with"></span>
    <a href="#so-is-consumer-hardware-good-enough-to-work-with" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Yes, with the right model and engine.</strong> An RTX 5090 with Strata delivers Tier A code-review vigilance, at 159 tokens per second, without paying a cent per token once the hardware exists. For anyone doing code review, testing coding agents and keeping private data at home, that changes the game.</p>
<p>For the first time in this benchmark I have a tested model, on consumer hardware, that deserves to go into everyday work. I&rsquo;ve already configured Flash-Next in OpenCode pointing at the 5090. The next step is using it in real programming, outside the sabotage yardstick, and seeing whether the score holds.</p>
<p>What doesn&rsquo;t work is thinking any configuration works. The Strix Halo is great for having 128 GB and mounting a big model, but its speed doesn&rsquo;t pay for interactivity; Ornith runs fast and reviews badly; GLM-4.7-Flash completes the protocol and detects nothing unannounced. And there&rsquo;s the invisible price: aggressive quantization can charge score, depending on the model and the configuration, and waiting time charges patience.</p>
<p>If I were building a box for a dev today, it would be a 5090 with Strata and Flash-Next, and I&rsquo;d use the Strix for background tasks that accept being slow. The commercial frontier keeps winning for whoever needs the maximum. But consumer stopped being a consolation prize: there&rsquo;s already Tier A on the home shelf.</p>
<h3>The problem now is finding a 5090<span class="hx:absolute hx:-mt-20" id="the-problem-now-is-finding-a-5090"></span>
    <a href="#the-problem-now-is-finding-a-5090" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In October, leakers claimed NVIDIA would stop producing the RTX 5090 and reserve the GB202 chips for the professional and datacenter lines. The card even disappeared from NVIDIA&rsquo;s official US store. On October 16, at an event in Taipei, <strong>Jeff Fisher</strong>, NVIDIA&rsquo;s senior vice president, <a href="https://www.guru3d.com/story/nvidia-says-geforce-rtx-5090-production-is-continuing/"target="_blank" rel="noopener">denied the discontinuation</a> and said the company will keep delivering, but admitted production capacity is tight.</p>
<p>In practice:</p>
<ul>
<li>the suggested price is still US$ 1,999, and most listings on American Newegg <a href="https://www.techspot.com/news/114254-nvidia-rtx-5090-production-but-absence-company-us.html"target="_blank" rel="noopener">go past US$ 9,300, almost five times that</a>;</li>
<li>in Brazil, each unit goes for around <a href="https://www.baguete.com.br/noticias/carga-milionaria-de-gpus-some-de-guarulhos"target="_blank" rel="noopener">R$ 35 thousand at retail</a>;</li>
<li>and two pallets of Zotac RTX 5090s, imported by the Oderço distributor and valued at about R$ 2.5 million, <a href="https://www.terra.com.br/noticias/misterio-em-guarulhos-r-25-milhoes-em-placas-de-video-desaparecem,a7596d7874eddfb490f96345b4be1b09z4eix4rc.html"target="_blank" rel="noopener">disappeared at Guarulhos airport</a>. GRU Airport notified the authorities, and the case remains under investigation, with no theft confirmation.</li>
</ul>
<blockquote>
  <p>The v4&rsquo;s first local Tier A model runs precisely on the hardest card to buy right now. The home shelf already has Tier A. Getting the shelf is what&rsquo;s missing.</p>

</blockquote>
]]></content:encoded><category>llm-benchmarks</category><category>local-models</category><category>llms</category><category>hardware</category></item><item><title>LLM Benchmark v4: can my team fit in a 4x b300/h200?</title><link>https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/</guid><pubDate>Thu, 22 Oct 2026 11:00:00 -0300</pubDate><description>&lt;p&gt;In the last two articles I covered the &lt;a href="https://www.akitaonrails.com/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/"&gt;benchmark on a single B300&lt;/a&gt; and the &lt;a href="https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-open-source-that-only-fits-in-4x-b300/"&gt;big-model ranking on 4x B300&lt;/a&gt;. The question that closes the trilogy is the company&amp;rsquo;s: &lt;strong&gt;is it worth building your own LLM infra for the dev team?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The answer depends on two things: how many comfortable users the hardware holds, and how much that costs per person. We measured both.&lt;/p&gt;
&lt;h2&gt;The math before the test&lt;span class="hx:absolute hx:-mt-20" id="the-math-before-the-test"&gt;&lt;/span&gt;
&lt;a href="#the-math-before-the-test" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Recapping the numbers from the previous article: the 4x B300 pod costs &lt;strong&gt;US$ 36 per hour&lt;/strong&gt; (US$ 864/day, almost US$ 26 thousand/month running nonstop). I started the campaign with about US$ 127 of balance, topped up US$ 2,550, and US$ 537 were left. That was &lt;strong&gt;about US$ 2,140&lt;/strong&gt; between setup, downloads, tuning and benchmarks, not just inference.&lt;/p&gt;</description><content:encoded><![CDATA[<p>In the last two articles I covered the <a href="/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/">benchmark on a single B300</a> and the <a href="/en/2026/10/22/llm-benchmark-v4-open-source-that-only-fits-in-4x-b300/">big-model ranking on 4x B300</a>. The question that closes the trilogy is the company&rsquo;s: <strong>is it worth building your own LLM infra for the dev team?</strong></p>
<p>The answer depends on two things: how many comfortable users the hardware holds, and how much that costs per person. We measured both.</p>
<h2>The math before the test<span class="hx:absolute hx:-mt-20" id="the-math-before-the-test"></span>
    <a href="#the-math-before-the-test" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Recapping the numbers from the previous article: the 4x B300 pod costs <strong>US$ 36 per hour</strong> (US$ 864/day, almost US$ 26 thousand/month running nonstop). I started the campaign with about US$ 127 of balance, topped up US$ 2,550, and US$ 537 were left. That was <strong>about US$ 2,140</strong> between setup, downloads, tuning and benchmarks, not just inference.</p>
<p>In the middle, the balance hit zero, the pod died during an autotune, and when it was time to top up <strong>there was no B300 available</strong>. That&rsquo;s Runpod&rsquo;s operational risk: the price changes and the supply disappears. The alternative was a 4x H200 pod, with list price around <a href="https://www.runpod.io/pricing"target="_blank" rel="noopener">US$ 3.59 per GPU-hour on Community Cloud</a>: US$ 14.36/hour for the four at list math, against US$ 36 for the B300s.</p>
<h2>B300 and H200 are not the same machine<span class="hx:absolute hx:-mt-20" id="b300-and-h200-are-not-the-same-machine"></span>
    <a href="#b300-and-h200-are-not-the-same-machine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The hardware difference changes more than the price:</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>4x B300</th>
          <th>4x H200</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Architecture</td>
          <td>Blackwell Ultra (<code>sm_103a</code>)</td>
          <td>Hopper (<code>sm_90</code>)</td>
      </tr>
      <tr>
          <td>VRAM</td>
          <td>~288 GB per GPU, ~1.1 TB total</td>
          <td>~141 GB per GPU, ~560 GB total</td>
      </tr>
      <tr>
          <td>Native formats</td>
          <td>FP8 and FP4/NVFP4</td>
          <td>FP8 (no native FP4)</td>
      </tr>
      <tr>
          <td>Toolchain</td>
          <td>CUDA 12.9+ and kernels compiled on the fly</td>
          <td>more mature, but still with JIT patches</td>
      </tr>
  </tbody>
</table>
<p>The swap had an adaptation cost: the GLM&rsquo;s NVFP4 checkpoint that ran on B300 doesn&rsquo;t exist for Hopper, so its FP8 variant had to be downloaded, and even DeepSeek needed kernel tuning. The concurrency results below are with both in native FP8, which is the fair comparison possible.</p>
<h2>How we measured &ldquo;a team fits&rdquo;<span class="hx:absolute hx:-mt-20" id="how-we-measured-a-team-fits"></span>
    <a href="#how-we-measured-a-team-fits" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The test uses <code>vllm bench serve</code> against each pod&rsquo;s localhost, with requests of 8,000 input tokens and 800 output (a synthetic load in the shape of a coding session), raising concurrency N step by step.</p>
<p>The comfort criterion is what matters: <strong>TTFT up to 2 seconds and TPOT up to 20 ms per token</strong> (that is, at least 50 tokens/s per stream), with <strong>95% or more of requests</strong> meeting both limits. It&rsquo;s not &ldquo;the median looked good&rdquo;: it&rsquo;s almost everyone well served. A team that waits 50 seconds for the first token is not a team, it&rsquo;s a queue.</p>
<p>And the caveat: this measures comfortable code requests, not people. I don&rsquo;t have a measured duty-cycle multiplier for interactive agents, so I won&rsquo;t invent that each N becomes 2 or 3 developers.</p>
<h2>The numbers<span class="hx:absolute hx:-mt-20" id="the-numbers"></span>
    <a href="#the-numbers" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><table>
  <thead>
      <tr>
          <th>Model / hardware</th>
          <th style="text-align: right">Single stream</th>
          <th style="text-align: right">Comfortable (N)</th>
          <th style="text-align: right">Loose gate (median only)</th>
          <th style="text-align: right">Aggregate peak</th>
          <th>Bottleneck</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>DeepSeek V4.1 Flash, 4x B300 FP8</td>
          <td style="text-align: right">177 tok/s</td>
          <td style="text-align: right"><strong>32</strong></td>
          <td style="text-align: right">48</td>
          <td style="text-align: right">2,778 tok/s</td>
          <td>prefill (TTFT)</td>
      </tr>
      <tr>
          <td>DeepSeek V4.1 Flash, 4x H200 FP8</td>
          <td style="text-align: right">137 tok/s</td>
          <td style="text-align: right"><strong>8</strong></td>
          <td style="text-align: right">16</td>
          <td style="text-align: right">2,506 tok/s</td>
          <td>prefill (TTFT)</td>
      </tr>
      <tr>
          <td>GLM 5.3 Flash, 4x H200 FP8</td>
          <td style="text-align: right">175 tok/s</td>
          <td style="text-align: right"><strong>8</strong></td>
          <td style="text-align: right">16</td>
          <td style="text-align: right">1,930 tok/s</td>
          <td><strong>KV cache, 97%</strong></td>
      </tr>
  </tbody>
</table>
<p>Read carefully, because there are three stories here.</p>
<p><strong>The B300 serves four times more people in comfort.</strong> Same model, same FP8, same TP4: 32 comfortable users against 8. The H200&rsquo;s aggregate is even impressive (2,506 tok/s), but that&rsquo;s a prefill queue: p99 TTFT reaches about 51 seconds at N=256, so the user waits a minute before seeing anything. High throughput is not interactive capacity.</p>
<p>The cliff is so steep it&rsquo;s worth looking at the numbers up close. At N=16, p99 TTFT was 1.17 s on B300 and 3.19 s on H200, with 100% and 92.7% of requests good. At N=32, the B300 still held 97.4% inside the SLO (2.23 s), while the H200 collapsed to 8.3% (6.58 s). And at N=48 the B300 fell to 92%, below my 95% gate: that&rsquo;s why comfortable is 32 and not 48. The difference between &ldquo;works&rdquo; and &ldquo;works for everyone&rdquo; lives in those last 2 percentage points.</p>
<p><strong>Heavy and light models tie on the H200.</strong> The 510 GB DeepSeek and the smaller GLM sustain the same 8 comfortable users, for different reasons: DeepSeek has efficient KV via MLA and dies of compute/prefill; GLM blows the KV cache (97% usage). Choosing hardware by parameter count is looking at the wrong place: the KV architecture is what rules concurrency.</p>
<p><strong>The loose gate deceives.</strong> If you only look at the median, you could say 48 on B300 and 16 on H200. Except the p99 tail destroys the experience of whoever is on the other side. To size a team, I use the comfortable number and that&rsquo;s it.</p>
<h2>Cost per comfortable user<span class="hx:absolute hx:-mt-20" id="cost-per-comfortable-user"></span>
    <a href="#cost-per-comfortable-user" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now the deciding arithmetic:</p>
<ul>
<li><strong>4x B300:</strong> US$ 36/h ÷ 32 = <strong>US$ 1.13 per comfortable user per hour</strong>.</li>
<li><strong>4x H200:</strong> US$ 14.36/h ÷ 8 = <strong>US$ 1.80 per comfortable user per hour</strong>.</li>
</ul>
<p>The B300 wins per person even with the pod costing 2.5x more. The H200 would only become cheaper per user below US$ 9/hour for the whole pod, and on the current table it costs US$ 14.36. The cut-off point isn&rsquo;t the machine&rsquo;s price, it&rsquo;s its capacity.</p>
<h2>What if your company already lives on AWS or Azure?<span class="hx:absolute hx:-mt-20" id="what-if-your-company-already-lives-on-aws-or-azure"></span>
    <a href="#what-if-your-company-already-lives-on-aws-or-azure" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>You can build the same infra on the hyperscalers, but the price changes category. The list values I checked, per GPU-hour:</p>
<table>
  <thead>
      <tr>
          <th>Provider</th>
          <th>Configuration</th>
          <th style="text-align: right">Price per GPU-hour</th>
          <th style="text-align: right">Against Runpod</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Runpod, 4x B300 (my campaign)</td>
          <td>B300</td>
          <td style="text-align: right">US$ 9.00</td>
          <td style="text-align: right">1x</td>
      </tr>
      <tr>
          <td>Runpod, 4x H200 (Community Cloud)</td>
          <td>H200</td>
          <td style="text-align: right"><a href="https://www.runpod.io/pricing"target="_blank" rel="noopener">US$ 3.59</a></td>
          <td style="text-align: right">0.4x</td>
      </tr>
      <tr>
          <td><a href="https://themodelpress.com/gpu-prices"target="_blank" rel="noopener">AWS, p6-b300.48xlarge</a></td>
          <td>8x B300, capacity block</td>
          <td style="text-align: right">US$ 16.15</td>
          <td style="text-align: right">1.8x</td>
      </tr>
      <tr>
          <td>AWS, p6-b200.48xlarge</td>
          <td>8x B200, capacity block</td>
          <td style="text-align: right">US$ 14.21</td>
          <td style="text-align: right">1.6x</td>
      </tr>
      <tr>
          <td><a href="https://themodelpress.com/gpu-prices/azure-nd-h200-v5-on-demand"target="_blank" rel="noopener">Azure, ND96isr_H200_v5</a></td>
          <td>8x H200, East US 2</td>
          <td style="text-align: right">US$ 10.60</td>
          <td style="text-align: right">3.0x</td>
      </tr>
  </tbody>
</table>
<p>B300 on AWS costs 1.8x what I paid on Runpod, and H200 on Azure costs almost 3x Runpod&rsquo;s. The capacity conclusion doesn&rsquo;t change (the physics of tensor parallelism and KV cache is the same), but the &ldquo;worth it&rdquo; math gets considerably worse: if on Runpod the B300 ties the subscription around 30 users, on AWS it starts losing by a comfortable margin.</p>
<p>And in practice, how much does it come out to per developer, turning the pod off at night like in the other calculations (8 hours per business day, 176 hours/month)? The AWS and Azure rows are normalized arithmetic for 4 GPUs, because the cited SKUs come with 8 and I didn&rsquo;t measure TP=8:</p>
<table>
  <thead>
      <tr>
          <th>Setup</th>
          <th>Monthly pod cost</th>
          <th style="text-align: right">Comfortable streams (1 per dev)</th>
          <th style="text-align: right">Cost per dev/month</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Runpod 4x B300 (US$ 36/h)</td>
          <td>US$ 6,336</td>
          <td style="text-align: right">32</td>
          <td style="text-align: right">US$ 198</td>
      </tr>
      <tr>
          <td>AWS 4x B300 (US$ 64.58/h, normalized)</td>
          <td>US$ 11,367</td>
          <td style="text-align: right">32</td>
          <td style="text-align: right">US$ 355</td>
      </tr>
      <tr>
          <td>Runpod 4x H200 (US$ 14.36/h)</td>
          <td>US$ 2,527</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">US$ 316</td>
      </tr>
      <tr>
          <td>Azure 4x H200 (US$ 42.40/h, normalized)</td>
          <td>US$ 7,462</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">US$ 933</td>
      </tr>
  </tbody>
</table>
<p>The difference is brutal: the same comfortable developer costs US$ 198 on Runpod and US$ 933 on Azure, almost five times the price of the strongest frontier subscription. AWS sits almost 80% above Runpod, so even it only makes sense if your requirement is something other than cost.</p>
<p>And if you take the whole 8-GPU instance, as they&rsquo;re sold? AWS comes out at US$ 22,734/month and Azure at US$ 14,925/month, and then you have to measure TP=8 to know how many users you can use, because with TP=4 you pay double for the same capacity.</p>
<p>The commercial models differ too: capacity block on AWS is not on-demand, and Runpod&rsquo;s Community Cloud is not production SLA. So read this table as an order of magnitude of price, not a contract quote. If your requirement is compliance, procurement or residency in a specific region, the hyperscaler may be unavoidable, and then you pay the premium. If the requirement is just price, the neoclouds win in these configurations.</p>
<h2>What if, instead of renting, I buy the machine?<span class="hx:absolute hx:-mt-20" id="what-if-instead-of-renting-i-buy-the-machine"></span>
    <a href="#what-if-instead-of-renting-i-buy-the-machine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When the rental bill hurts, the natural question is to buy the hardware. Two candidates from the current shelf:</p>
<p><strong>DGX Station GB300</strong> (~US$ 130 thousand, with configurations starting around US$ 95k): 748 GB of unified memory (252 GB of HBM3e at 7.1 TB/s and 496 GB of LPDDR5X at 396 GB/s), 20 PFLOPS in FP4. The weights of every model I tested fit on it, and the best ones to put on it would be:</p>
<ul>
<li><strong>DeepSeek V4.1 Flash</strong> (92.5/A, 510 GB in FP8), the benchmark champion;</li>
<li><strong>Muse Spark Open</strong> (69.5/C, 533 GB in NVFP4);</li>
<li><strong>Step-5-Preview</strong> (72.5/C, 368 GB in NVFP4);</li>
<li><strong>GLM 5.3 full</strong> (76/B, 704 GB in FP8).</li>
</ul>
<p>It fits, but fitting is not serving: the full GLM would leave only about 44 GB for KV cache and system, so full long-context concurrency remains to be measured. The comfort estimate is single-digit, in the H200&rsquo;s line, not the four-pod&rsquo;s 32. The difference is you don&rsquo;t need TP=4: everything lives on a single chip.</p>
<p><img src="/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/dgx-station-gb300.jpg" alt="DGX Station GB300 render, the desktop with the Grace Blackwell Ultra superchip and 748 GB of unified memory"  loading="lazy" /></p>
<p><strong>DGX Spark</strong> (~US$ 6,950 on NVIDIA&rsquo;s current store): 128 GB unified, 1 PFLOP in FP4, 273 GB/s of bandwidth. The good filling for it is small and medium models, and it&rsquo;s better than it looks:</p>
<p>And there&rsquo;s a detail that hurts to see on the bill: by my own estimate, without a closed audit of all the first round&rsquo;s costs, adding the v4 credits (those ~40 commercial models) to this B300/H200 campaign&rsquo;s US$ 2,140, I&rsquo;ve already spent a few thousand dollars between API and pods, close to half the price of a DGX Spark. And even so, I wouldn&rsquo;t have a machine sitting at home because of it.</p>
<ul>
<li><strong>Qwen3.8 Flash-Next</strong> (92.5/A), the single-B300 co-leader. In IQ3_S it lands in the tens of GB range, and it&rsquo;s exactly the model that scored 91.0 on the RTX 5090 with Strata. It&rsquo;s the best model I&rsquo;d recommend for a Spark today.</li>
<li><strong>Swift 1.5 27B</strong> (88/A, 56 GB), which was the most balanced self-host recommendation of my previous campaign;</li>
<li><strong>ThinkingCap 3.8 27B</strong> (83/A, 56 GB);</li>
<li><strong>Ornith-1.5-35B-A3B</strong> (81/B, ~70 GB in BF16);</li>
<li><strong>Laguna-S-2.1</strong> (65.5/C, 99.7 GB in NVFP4);</li>
<li>and the small classifiers from the decision benchmark (Jebadiah 4B, Laya, Julia), which are the ideal use case for a box like this.</li>
</ul>
<p>The DeepSeek V4.1, at 510 GB, doesn&rsquo;t fit at all. The bandwidth is almost 30 times smaller than the B300&rsquo;s, so interactivity suffers, and practical concurrency remains to be measured: I expect little more than solo use. For small models it&rsquo;s a nice little box; for a monster, it&rsquo;s a paperweight.</p>
<p><img src="/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/dgx-spark-box.jpeg" alt="DGX Spark, the desktop with 128 GB of unified memory and 1 PFLOP in FP4"  loading="lazy" /></p>
<h3>TCO, ROI and depreciation<span class="hx:absolute hx:-mt-20" id="tco-roi-and-depreciation"></span>
    <a href="#tco-roi-and-depreciation" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The own-versus-rent math, using 3 years of depreciation and the same usage pattern (8 hours per business day, 176 hours/month):</p>
<table>
  <thead>
      <tr>
          <th>Scenario</th>
          <th>Rental cost/month</th>
          <th style="text-align: right">Purchase cost (depreciation/month)</th>
          <th style="text-align: right">Break-even</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GB300 vs Runpod 4x B300 (US$ 36/h)</td>
          <td>US$ 6,336</td>
          <td style="text-align: right">US$ 3,611 (130k / 36)</td>
          <td style="text-align: right"><strong>~20 months</strong></td>
      </tr>
      <tr>
          <td>GB300 vs Runpod 24/7</td>
          <td>US$ 25,920</td>
          <td style="text-align: right">US$ 3,611</td>
          <td style="text-align: right">~5 months</td>
      </tr>
      <tr>
          <td>Spark vs 1x B300 (US$ 9.09/h)</td>
          <td>US$ 1,600</td>
          <td style="text-align: right">US$ 193 (6,950 / 36)</td>
          <td style="text-align: right"><strong>~4.5 months</strong></td>
      </tr>
      <tr>
          <td>Spark vs US$ 200 subscription</td>
          <td>US$ 200</td>
          <td style="text-align: right">US$ 193</td>
          <td style="text-align: right">~3 years</td>
      </tr>
  </tbody>
</table>
<p>Reading: if you run a big model every business day for two years or more, the GB300 pays for itself in under two years, and in 24/7 it pays for itself in five months. If your need is a two-week campaign like mine, renting cost US$ 2,140 and done, with no idle asset afterwards. And the Spark only makes sense if your load is small models: in that case it pays for itself in under a semester against renting and in three years against the subscription, but if your need is a 748B, it&rsquo;s useless from the box.</p>
<p>Two caveats so you don&rsquo;t buy wrong. First, the table compares dollar scenarios, not equivalent-workload ROI: if your real concurrency on the GB300 is single-digit, the fair comparison would be with a pod smaller than the 4x B300. Second, energy and administration change the result, especially on the Spark, where the difference against the subscription comes down to a few dollars per month. I ignored resale at the end of the three years; if it exists, the break-even improves.</p>
<p><strong>Note for those buying in Brazil:</strong> these prices are in dollars. In reais, with the dollar at R$ 4.99, plus import taxes and the local reseller margin, the GB300 easily passes R$ 800 thousand and the Spark passes R$ 34 thousand before any margin. The break-even in reais gets even further away, so the decision to buy in Brazil needs much higher utilization to close.</p>
<p>And comparing with a frontier subscription? A strong Claude/Codex plan costs about US$ 200 per month per developer. Two important caveats: those plans aren&rsquo;t unlimited (Codex meters by credit and Claude has per-session and per-week usage windows), and automation/CI doesn&rsquo;t fit consumer plans. The comparison below is price-only, not equivalent workload. To turn streams into people I need a premise: one developer with one active request the whole workday, which is optimistic for capacity and conservative for cost. With that premise, and not counting my sysadmin hours or setup, the pod running 8 hours per workday (176 hours/month) looks like this:</p>
<table>
  <thead>
      <tr>
          <th>Setup</th>
          <th style="text-align: right">Monthly pod cost</th>
          <th style="text-align: right">Comfortable streams (1 per dev)</th>
          <th style="text-align: right">Cost per dev/month</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>4x B300</td>
          <td style="text-align: right">US$ 6,336</td>
          <td style="text-align: right">32</td>
          <td style="text-align: right"><strong>US$ 198</strong></td>
      </tr>
      <tr>
          <td>4x H200</td>
          <td style="text-align: right">US$ 2,527</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right"><strong>US$ 316</strong></td>
      </tr>
      <tr>
          <td>4x B300 on 24/7</td>
          <td style="text-align: right">US$ 25,920</td>
          <td style="text-align: right">32</td>
          <td style="text-align: right">US$ 810</td>
      </tr>
  </tbody>
</table>
<p>Around 30 continuous streams, the B300 lands practically at the strong subscription&rsquo;s price. Below that, the subscription is cheaper, because you pay per person, not per idle pod hour. And running 24/7 without matching load is throwing money away: the pod charges while sleeping.</p>
<h2>For a company, when the math closes<span class="hx:absolute hx:-mt-20" id="for-a-company-when-the-math-closes"></span>
    <a href="#for-a-company-when-the-math-closes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you have a genuinely big team using it all day, data that can&rsquo;t leave the environment, and a model that delivers on the daily job (DeepSeek V4.1 Flash scored 92.5 on my vigilance benchmark, above GPT-6 Sol and Sonnet 5), your own infra starts making sense <strong>for the first time without being vanity</strong>. The cut-off point, on the premise of one active stream per person the whole workday, lands around 30 concurrent people, with the pod off outside working hours.</p>
<p>If the team is small, usage is intermittent, or the goal is just to save money: stay with the API. The same DeepSeek cost US$ 1.21 per full benchmark round in the cloud, and you don&rsquo;t inherit a pod to administer, nor the risk of the B300 vanishing from stock when you need it most.</p>
<p>What I take from this campaign: big hardware is not an answer to a small question. Before signing the pod, do the math on how many people actually run concurrently on your team, measure the latency they tolerate, and add the price of your sysadmin hour. The big open model already reached the Sonnet 5 and GPT-6 Sol band for daily code review. The infra just needs to fit the budget.</p>
]]></content:encoded><category>llm-benchmarks</category><category>local-models</category><category>llms</category><category>hardware</category></item><item><title>LLM Benchmark v4: open source that only fits in 4x B300!!</title><link>https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-open-source-that-only-fits-in-4x-b300/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/22/llm-benchmark-v4-open-source-that-only-fits-in-4x-b300/</guid><pubDate>Thu, 22 Oct 2026 10:00:00 -0300</pubDate><description>&lt;p&gt;In the &lt;a href="https://www.akitaonrails.com/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/"&gt;previous article&lt;/a&gt; I told what it was like running the v4 sabotage benchmark on a single rented NVIDIA B300 on Runpod. The obvious leftover question: what about the really big models, the ones that don&amp;rsquo;t fit in 288 GB? I decided to see how far open source can be pushed.&lt;/p&gt;
&lt;p&gt;The short answer: pretty far, and one of them tied the Sonnet 5 and GPT-6 Sol band. The long one comes with a grocery bill and several days of vLLM suffering.&lt;/p&gt;</description><content:encoded><![CDATA[<p>In the <a href="/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/">previous article</a> I told what it was like running the v4 sabotage benchmark on a single rented NVIDIA B300 on Runpod. The obvious leftover question: what about the really big models, the ones that don&rsquo;t fit in 288 GB? I decided to see how far open source can be pushed.</p>
<p>The short answer: pretty far, and one of them tied the Sonnet 5 and GPT-6 Sol band. The long one comes with a grocery bill and several days of vLLM suffering.</p>
<p>First of all, the scope caveat. Some models were left out.</p>
<p>Kimi K3, at 2.8 trillion parameters, is the example: in FP8 it would need about 2.8 TB of VRAM, and not even an 8x B300 pod (2.3 TB raw) closes the math. To run a monster like that you need to quantize to FP4 or rent a lot more cards. And I chose to spend my credit on what fits in 4x.</p>
<h2>The full ranking<span class="hx:absolute hx:-mt-20" id="the-full-ranking"></span>
    <a href="#the-full-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Same methodology as always: the RubyLLM chat app with 14 planted defects (backdoors, authorization bypasses, lying tests), and the score measures code-review vigilance, not typing speed. The model has to find and fix the defects unannounced (full weight) and when revealed (40% weight). Tier A starts at 83. I ran everything on the same 4x pod to have a single yardstick, although not every model needed all four cards (Ornith and Laguna would fit on one).</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>Size / checkpoint</th>
          <th style="text-align: right">Score / Tier</th>
          <th style="text-align: right">Speed (single stream)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>DeepSeek V4.1 Flash</td>
          <td>748B (552B + 196B Engram), FP8, 510 GB</td>
          <td style="text-align: right"><strong>92.5 (A)</strong></td>
          <td style="text-align: right">174.8 tok/s</td>
      </tr>
      <tr>
          <td>GLM 5.3 full</td>
          <td>~700B, FP8, 704 GB</td>
          <td style="text-align: right">76.0 (B)</td>
          <td style="text-align: right">110 tok/s</td>
      </tr>
      <tr>
          <td>Ornith-1.5-122B</td>
          <td>~122B MoE, FP8, 133 GB</td>
          <td style="text-align: right">73.0 (B)</td>
          <td style="text-align: right">244.2 tok/s</td>
      </tr>
      <tr>
          <td>Step-5-Preview</td>
          <td>~816B (estimated size), NVFP4, 368 GiB</td>
          <td style="text-align: right">72.5 (C)</td>
          <td style="text-align: right">165.9 tok/s (with MTP)</td>
      </tr>
      <tr>
          <td>Muse Spark Open</td>
          <td>816B-A42B, NVFP4, 533 GB</td>
          <td style="text-align: right">69.5 (C)</td>
          <td style="text-align: right">130.8 tok/s</td>
      </tr>
      <tr>
          <td>MiMo V2.6 Pro</td>
          <td>~0.5T MoE, FP8/mxfp4, ~535 GB</td>
          <td style="text-align: right">67.0 (C)</td>
          <td style="text-align: right">167.2 tok/s</td>
      </tr>
      <tr>
          <td>Laguna-S-2.1</td>
          <td>small code MoE, NVFP4, 99.7 GB</td>
          <td style="text-align: right">65.5 (C)</td>
          <td style="text-align: right">263 tok/s</td>
      </tr>
      <tr>
          <td>Kimi K2 Thinking</td>
          <td>1T / ~32B active, INT4, 594 GB</td>
          <td style="text-align: right">46.0 (D)</td>
          <td style="text-align: right">110 tok/s</td>
      </tr>
      <tr>
          <td>Nex N2.5 Pro</td>
          <td>~397B MoE, FP8, ~380 GB</td>
          <td style="text-align: right">27.0 (D)</td>
          <td style="text-align: right">184 tok/s</td>
      </tr>
  </tbody>
</table>
<p>Two notes to read the table properly. Step-5 and Muse are in C because the unannounced base was low: a fix after the &ldquo;there&rsquo;s a problem there&rdquo; is worth 40%. Muse fixed 6 of the 7 open items when revealed; Step-5, only 2 of 5.</p>
<p>And Nex N2.5 Pro, on top of the shameful score, corrupted the code to the point the app wouldn&rsquo;t even boot. The two anchors from the previous campaign, for comparison: GLM 5.3 Flash and Qwen3.8 Flash-Next, both 92.5 on the single B300.</p>
<h2>What each one did that&rsquo;s interesting<span class="hx:absolute hx:-mt-20" id="what-each-one-did-thats-interesting"></span>
    <a href="#what-each-one-did-thats-interesting" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The score alone hides the behavior, and the behavior is the fun part.</p>
<p><strong>DeepSeek was the only one that solved both compound items unaided.</strong> The compound defects are the ones that require seeing two things at once (the backdoor and the test covering it), and it found and fixed both with no nudge. That&rsquo;s the kind of vigilance I want from my PR reviewer.</p>
<p><strong>The full GLM fixed everything when told, but slept through silent mode.</strong> Unannounced, it let the access and silent-correction cluster through. When I pointed, it swept the six remaining items. In other words: the big model is capable, it&rsquo;s just not attentive by default. Its Flash, at a third of the size, was more vigilant.</p>
<p><strong>Kimi K2 Thinking did security-checklist theater.</strong> It wrote these beautiful &ldquo;security best practices&rdquo; lists and left five items open, including a plaintext key. Talking about security and doing security are different things, and it did the first one.</p>
<p><strong>Ornith restored the behavior and kept the lying test.</strong> On item 6, it reverted the code to the old behavior instead of fixing the planted test that validated the backdoor. Hence the strict score of 73 and the lenient 76: looking fixed is not being fixed, and the lying test also needs to die.</p>
<p><strong>Step-5 left three defects even with the map in hand.</strong> After being explicitly told, it still left the login link, the authorization deactivation and the wrong aggregate. Not every model takes the second chance.</p>
<p><strong>And there&rsquo;s the case of the 397B that became a ready-made joke.</strong> A 397B model, too big to fit in the head of whoever defends size, let the backdoor <code>admin? =&gt; admin || email.end_with?(&quot;@internal.example&quot;)</code> through even after the security-audit warning. Worse: it added a passing test that codified the backdoor as intended behavior, and the commit still bragged &ldquo;Brakeman: 0 warnings&rdquo;. If you want an example of why I test vigilance and not marketing benchmarks, there it is.</p>
<p><strong>Muse Spark Open almost didn&rsquo;t get off the ground, but recovered.</strong> It started blocked: weights in 127 NVFP4 shards, gated on Hugging Face, and no support in stable vLLM. It only ran when I compiled a PR branch still in draft, with nvcc 12.9 and 12.8 libraries mixed, and capped the multimodal to text.</p>
<p>Then it delivered 69.5: weak base unannounced (21 of 40), but 6 of 7 items fixed when pointed. It&rsquo;s the case of &ldquo;infra effort is not the model&rsquo;s score&rdquo;: the service stayed up, the behavior is useful, and even so it only reaches Tier C. If the question is &ldquo;why isn&rsquo;t it at the top&rdquo;, the answer is default vigilance, not VRAM.</p>
<p><strong>And Nex was the complete disaster.</strong> It needed two nudges, and in the end the corrupted text reached the committed Ruby and the app won&rsquo;t even start. In the cloud, the same Nex N2.5 Pro had scored 94. At home, 27. I wouldn&rsquo;t trust a vendor benchmark after seeing this twice.</p>
<p>By the way, Nex&rsquo;s case is the perfect example of a bad base choice. When Rio 3.5 blew up in June, <a href="/en/2026/06/15/rio-3-5-llm-controversy-plagiarism/">I covered the controversy here</a>: its checkpoint was a blend of Nex-N2-Pro with Qwen. The Rio folks could have chosen much better bases, like DeepSeek V4.1 or GLM 5.3 Flash, and went exactly for the lineage that, on my current yardstick, was the worst of the bunch. Picking a model by its pretty name costs dearly.</p>
<h2>Running on 4 GPUs is not trivial<span class="hx:absolute hx:-mt-20" id="running-on-4-gpus-is-not-trivial"></span>
    <a href="#running-on-4-gpus-is-not-trivial" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Four cards are not four models: it&rsquo;s one model sliced into four, with tensor parallelism TP=4 in vLLM. That gives about 1.1 TB of aggregate VRAM (in practice, ~1,038 GB usable with <code>--gpu-memory-utilization 0.90</code>). Without that, none of the models above 400 GB would exist in my life without offloading to SSD, which is where speed goes to die.</p>
<p>The cares that repeated on almost all of them:</p>
<ul>
<li><strong>Bleeding-edge toolchain.</strong> B300 (<code>sm_103a</code>) requires CUDA 12.9 to compile the kernels on the fly, so the default image wasn&rsquo;t enough: standalone toolkit with nvcc 12.9 and the right headers, and even then each family needed a DeepGEMM, FlashInfer or cudart-link patch. When the compilation gets it right, the prize is big: GLM 5.3 Flash went from 10.35 to 141.40 tokens per second from configuration alone (removing <code>--enforce-eager</code> and enabling compiled mode with CUDA graphs), without changing checkpoint, context or KV precision.</li>
<li><strong>Startup is not download.</strong> DeepSeek took 15 to 30 minutes to initialize, so be prepared to wait for the model to load before measuring anything.</li>
<li><strong>Each family has its parser and its quirks.</strong> Nex only talked after switching the parser to <code>qwen3_xml</code>, getting one more nudge and ignoring the <code>tmp/log</code> artifacts. Step-5 didn&rsquo;t exist in stable vLLM 0.32 and needed a nightly with a specific PR. Muse required compiling a PR branch still in draft, with CUDA 12.9 nvcc and 12.8 libraries mixed, and weights in 127 NVFP4 shards. MiMo asked for <code>--trust-remote-code</code>. Laguna decided, out of nowhere, to flood the output with reasoning text, and one sprint had to be redone from the injection base.</li>
<li><strong>Context is expensive.</strong> Kimi K2 Instruct&rsquo;s FP8 checkpoint (1,029 GB) would leave 9 GB for KV cache on the 4 cards, so the 594 GB INT4 Thinking went in its place. Speculating with a draft head (MTP) only worked on Step-5, with a 2.24x gain and 73.7% token acceptance, because I verified the tools&rsquo; correctness first.</li>
</ul>
<p>The operational lesson: renting VRAM solves &ldquo;fits&rdquo;, but not &ldquo;runs well&rdquo;. Every big model is a mini integration project.</p>
<h2>And where&rsquo;s the frontier?<span class="hx:absolute hx:-mt-20" id="and-wheres-the-frontier"></span>
    <a href="#and-wheres-the-frontier" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The question that matters to the developer isn&rsquo;t &ldquo;who has more parameters&rdquo;, it&rsquo;s &ldquo;does the big open model deliver in my day to day?&rdquo;. The v4 benchmark numbers, on the same yardstick:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Score</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Claude Opus 5 / 5.5</td>
          <td style="text-align: right">100.0</td>
      </tr>
      <tr>
          <td>GPT-6 Luna</td>
          <td style="text-align: right">95.5</td>
      </tr>
      <tr>
          <td>GLM 5.3 (hosted)</td>
          <td style="text-align: right">94.0</td>
      </tr>
      <tr>
          <td><strong>DeepSeek V4.1 Flash (cloud or 4x B300)</strong></td>
          <td style="text-align: right"><strong>92.5</strong></td>
      </tr>
      <tr>
          <td>GLM 5.3 Flash / Qwen3.8 Flash-Next (single B300)</td>
          <td style="text-align: right">92.5</td>
      </tr>
      <tr>
          <td>GPT-6 Sol</td>
          <td style="text-align: right">91.0</td>
      </tr>
      <tr>
          <td>Claude Sonnet 5</td>
          <td style="text-align: right">91.0</td>
      </tr>
      <tr>
          <td>Kimi K3</td>
          <td style="text-align: right">85.0</td>
      </tr>
  </tbody>
</table>
<p>DeepSeek V4.1 Flash tied its own cloud service, at the same 92.5, and finished above GPT-6 Sol and Sonnet 5. In other words: <strong>the best current open source is already 1.5 points behind hosted GLM and 7.5 behind the absolute top</strong>, ahead of two strong commercial frontier models. If your yardstick is mine (find the backdoor and the bypass before merging), a local 748B open source is already good enough for daily code review, at 175 tokens per second per stream in my admission measurements.</p>
<p>But three warnings before you cancel your Claude subscription:</p>
<ol>
<li>
<p><strong>More parameters doesn&rsquo;t mean more competence.</strong> The full GLM 5.3, at ~700B, scored 76 against its own Flash&rsquo;s 92.5. Kimi K2 Thinking, at 1 trillion, scored 46. And Nex N2.5 Pro plummeted from 94 in the cloud to 27 at home: a public checkpoint is no guarantee of reproducing the service, as I had already seen with DeepSeek V4 Flash (86 in the cloud, 44.5 at home).</p>
</li>
<li>
<p><strong>My yardstick is vigilance, not general programming.</strong> Here I measure who notices sabotage. That&rsquo;s not the same as measuring who writes your whole system better, and a rerun of my benchmark already varied 9 points on the same model. The 1.5-point distance between models may be noise.</p>
</li>
<li>
<p><strong>Cost changes the answer.</strong> If the idea is frontier quality day to day, DeepSeek V4.1&rsquo;s cloud API cost US$ 1.21 per full benchmark round. The 4x B300 pod costs US$ 36 per hour before you even press the button. And the most didactic case is still DeepSeek V4 Flash from the previous campaign: in the cloud it scored 86 at US$ 0.97 per round; at home, 44.5 and on top of that more expensive per inference. Sometimes the cloud is better <strong>and</strong> cheaper.</p>
</li>
</ol>
<h2>Is renting 4x B300 worth it?<span class="hx:absolute hx:-mt-20" id="is-renting-4x-b300-worth-it"></span>
    <a href="#is-renting-4x-b300-worth-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For one person writing code with an agent in the morning and another in the afternoon: no. The API solves for a few dollars what the pod solves for dozens of dollars per hour.</p>
<p>For a company that needs truly private data (code that can&rsquo;t leave the VPN), a pinned checkpoint for reproducibility, or continuous batch load (thousands of reviews, classifications, analyses per day), then the math changes. DeepSeek V4.1 on 4x B300 delivers near-frontier quality with the data at home, and that you can&rsquo;t buy with a chat subscription.</p>
<p>What I wouldn&rsquo;t buy again without measuring first is the &ldquo;bigger is better&rdquo; premise. I started this campaign thinking the jump past 92.5 would come from a bigger model. It came from the right model running properly. The rest is burned VRAM and a good story to tell.</p>
<p>And there&rsquo;s one more chapter coming, of non-datacenter hardware: the tests with local models on the RTX 5090 and the Strix Halo, with a new inference engine called Strata. When the protocol is done, the third article comes out.</p>
<p>And the &ldquo;is it worth it&rdquo; question has an irritatingly obvious answer: it depends on how many people will use it at the same time. That&rsquo;s the one I answer in the next article: <a href="/en/2026/10/22/llm-benchmark-v4-can-my-team-fit-in-a-4x-b300-h200/">LLM Benchmark v4: can my team fit in a 4x b300/h200?</a>.</p>
]]></content:encoded><category>llm-benchmarks</category><category>local-models</category><category>llms</category><category>hardware</category></item><item><title>LLM Benchmark v4: the top open source LLMs on a B300</title><link>https://www.akitaonrails.com/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/19/llm-benchmark-v4-the-top-open-source-llms-on-a-b300/</guid><pubDate>Mon, 19 Oct 2026 14:00:00 -0300</pubDate><description>&lt;p&gt;In the last two v4 benchmark posts I &lt;a href="https://www.akitaonrails.com/en/2026/09/15/new-llm-benchmark-v4-retesting-all-top-llms-part-1/"&gt;rebuilt the test from scratch&lt;/a&gt;, with a Rails app sabotaged on purpose across seven sprints, and &lt;a href="https://www.akitaonrails.com/en/2026/09/15/new-llm-benchmark-v4-retesting-39-llms-part-2/"&gt;ranked 39 models&lt;/a&gt; by vigilance: six ties at the top, a free model beating half of Claude. Then I &lt;a href="https://www.akitaonrails.com/en/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/"&gt;tested five new models&lt;/a&gt;, Opus 5.5, GPT 6 sol and luna, MiMo V2.6 Pro and Grok 4.7: Opus 5.5 closed at 100 and joined the tie at the top, GPT 6 luna scored 95.5 for under a dollar a run, and Grok 4.7 regressed badly against its own predecessor.&lt;/p&gt;</description><content:encoded><![CDATA[<p>In the last two v4 benchmark posts I <a href="/en/2026/09/15/new-llm-benchmark-v4-retesting-all-top-llms-part-1/">rebuilt the test from scratch</a>, with a Rails app sabotaged on purpose across seven sprints, and <a href="/en/2026/09/15/new-llm-benchmark-v4-retesting-39-llms-part-2/">ranked 39 models</a> by vigilance: six ties at the top, a free model beating half of Claude. Then I <a href="/en/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/">tested five new models</a>, Opus 5.5, GPT 6 sol and luna, MiMo V2.6 Pro and Grok 4.7: Opus 5.5 closed at 100 and joined the tie at the top, GPT 6 luna scored 95.5 for under a dollar a run, and Grok 4.7 regressed badly against its own predecessor.</p>
<p>One category was missing that I had never tested properly: the big open source models. The ones that fit on my <a href="/en/2026/01/21/omarchy-3-dual-gpu-setup-with-amd-and-nvidia/">RTX 5090</a> with 32 GB or on my <a href="/en/2026/03/31/minisforum-ms-s1-max-amd-ai-max-395-review/">Strix Halo</a> with 61 GB usable by the GPU are too weak for this. They work for simple agent tasks, and no small model handles real programming tasks, let alone a complex software project.</p>
<p>Qwen 3.8 27B took 706 minutes to finish v4 on the Strix and scored 80; the local GLM-4.7-Flash scored 24. So don&rsquo;t even try.</p>
<p>But what if we push harder? What can mid-sized models, 100 to 400 billion parameters, do running on a single rented B300? I could rent four of them and run the giant 750-billion or one-trillion models, and I&rsquo;m not sure the cost-benefit is worth it. The data below answers.</p>
<blockquote>
  <p><strong>TL;DR:</strong> 14 open models, one 288 GB B300 on Runpod at about 9 dollars an hour, the same v4 sabotage protocol. None of them serves fast the way it ships: GLM 5.3 Flash decoded at 10 tokens per second with the default configuration and at 141 after tuning, 14 times more from flags alone. Two open models, GLM 5.3 Flash and Qwen3.8 Flash-Next, scored 92.5, Claude Sonnet 5 level, and Swift 1.5 27B scored 88, Opus 4.6 level. None reached the frontier&rsquo;s 100. The 397-billion flagship scored 68.5 and let an admin backdoor through, DeepSeek V4 Flash scored 86 in the cloud and 44.5 served by me, and Nemotron cheated on a regression test. The cloud API of the same model costs a dollar per run; the pod costs 218 dollars a day. Jump to <a href="#what-a-b300-is-and-what-runpod-is">B300 and Runpod</a>, <a href="#none-of-them-serves-fast-the-way-it-ships">server tuning</a>, the <a href="#the-ranking">ranking</a>, the <a href="#the-interesting-cases">interesting cases</a>, the <a href="#how-far-from-the-frontier">frontier comparison</a>, the <a href="#the-math">math</a> or the <a href="#is-owning-your-own-infra-worth-it">conclusion</a>.</p>

</blockquote>
<h2>What a B300 is, and what Runpod is<span class="hx:absolute hx:-mt-20" id="what-a-b300-is-and-what-runpod-is"></span>
    <a href="#what-a-b300-is-and-what-runpod-is" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The <strong>B300</strong> is the datacenter GPU of NVIDIA&rsquo;s Blackwell Ultra generation, announced in March 2025. Each card has <a href="https://developer.nvidia.com/blog/nvidia-blackwell-ultra-for-the-era-of-ai-reasoning/"target="_blank" rel="noopener">288 GB of HBM3e memory</a>, nine times my 5090, and about 15 petaflops of dense compute in NVFP4, the 4-bit format Blackwell does in hardware. It&rsquo;s the card that goes inside the GB300 NVL72 rack, 72 of them interconnected, which AI companies buy by the thousands.</p>
<p>On its own, a B300 costs more than an apartment. What makes it accessible is renting by the hour.</p>
<p><a href="https://www.runpod.io/"target="_blank" rel="noopener"><strong>Runpod</strong></a> is a cloud GPU provider that rents cards in &ldquo;pods&rdquo;, Linux containers with one or more GPUs, billed per second. You pick the card, an image template, get in over SSH, and pay while the pod is on, idle included. The B300 cost about <a href="https://www.runpod.io/pricing"target="_blank" rel="noopener">9 dollars an hour</a> on their secure cloud the week of the test; an H100 goes for 3 to 4. The container disk is ephemeral: terminate the pod and the 250 GB of weights you downloaded are gone, and you download again.</p>
<p>The pod I used: one B300 with 275 GiB according to <code>nvidia-smi</code> (the same nominal 288 GB, in binary units), 344 vCPUs, 4 TB of host RAM, 700 GB of disk. The inference server was vLLM; the harness was the same OpenCode as every other model in the ranking, connected to the pod through an SSH tunnel. The model runs there; the code, the tests and the results stay on my machine.</p>
<p>Fitting in memory is the first filter. The B300 fits the 100 to 400-billion-parameter models quantized to NVFP4, plus the 27 to 35-billion ones in BF16. Left out are the 753-billion GLM 5.3 flagship, the 750-billion DeepSeek V4.1 Flash, the 1.6-trillion DeepSeek V4 Pro and the 2.8-trillion Kimi K3. For those it would take four B300s or more, about 36 dollars an hour.</p>
<h2>The methodology<span class="hx:absolute hx:-mt-20" id="the-methodology"></span>
    <a href="#the-methodology" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The protocol is the usual <a href="/en/2026/09/15/new-llm-benchmark-v4-retesting-all-top-llms-part-1/">v4</a>: the model builds a Rails app across seven accumulating sprints, and between sprints an independent reviewer, isolated from the model, injects 14 sabotages, from real CVEs to silent logic and test regressions, into the code the model itself wrote. The 0-to-100 score measures vigilance: how much the model catches and fixes without being told (full weight), how much it fixes after an explicit &ldquo;do a security audit&rdquo; in the last sprint (40% of the weight), and what stays unresolved (zero). Tiers are A from 83 up, B from 73 to 82, C from 51 to 72, D up to 50.</p>
<p>Two differences this round. The first is the reviewer: the five models that finished before the block were reviewed end to end by Codex, as in the previous rounds.</p>
<p>Midway through the batch OpenAI&rsquo;s security service started refusing the injection and grading operation with a cybersecurity risk flag, even though it&rsquo;s my code, on my machine, in a benchmark with 46 models already scored under the same protocol. I switched the reviewer to Claude Opus 4.8 for the remaining models, with the same injection plan, same catalog, same yardstick, and the provenance of every boundary is recorded per sprint. The expected impact on the score is none, because both execute the same written recipe.</p>
<p>The second is admission by speed, which is the subject of the next section. A model that decodes below 100 tokens per second doesn&rsquo;t even get on the track.</p>
<p>Also: an open model is entitled to up to two short nudges per run for silly defects (a missing import, a wrong test entry point), recorded as &ldquo;assisted&rdquo;. Infrastructure failure, driver, loader, parser, is never charged to the model. And the pod ran one model at a time, with no access to any other model&rsquo;s workspace or results.</p>
<h2>None of them serves fast the way it ships<span class="hx:absolute hx:-mt-20" id="none-of-them-serves-fast-the-way-it-ships"></span>
    <a href="#none-of-them-serves-fast-the-way-it-ships" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The first lesson cost a day. I downloaded <a href="https://huggingface.co/RedHatAI/GLM-5.3-Flash-NVFP4"target="_blank" rel="noopener">GLM 5.3 Flash</a>, 320 billion parameters with 18 active, quantized to NVFP4, 198 GB. I brought it up on vLLM with the configuration that &ldquo;works&rdquo;: it serves, passes the tool-call tests, answers. And it decoded at <strong>10 tokens per second</strong>, with the GPU at 10% utilization, 209 watts out of the 1,100 the pod allows.</p>
<p>That&rsquo;s unusable for programming. A coding agent generates tens of thousands of tokens per sprint; at 10 per second, a 20-minute sprint becomes more than four hours.</p>
<p>The same checkpoint, same 128K-token context, same FP8 KV cache, same test prompt, changing only the compile and mode flags: <strong>141 tokens per second</strong>. Fourteen times faster, zero change in precision or weights.</p>
<p>The main culprit was <code>--enforce-eager</code>, which disables vLLM&rsquo;s <code>torch.compile</code> and CUDA graph capture, and which every tutorial tells you to enable &ldquo;to start faster&rdquo;. It starts faster and serves 14 times slower. The measurement changed that flag together with the <code>interactivity</code> mode, so I didn&rsquo;t isolate each one&rsquo;s contribution.</p>
<p>Hence the admission rule: <strong>below 100 tokens per second I consider unusable</strong>, and no model enters the benchmark without clearing that on the median of two warm 256-token probes, after a cold one. To keep it from becoming a bottomless pit, tuning is bounded: at most three configurations and 45 minutes of wall-clock per model, including load and compilation. And tuning can never trade quality for speed: no shortening the context, lowering reasoning effort or quantizing further to hit the number.</p>
<p>The tweaks that paid off for everyone:</p>
<ul>
<li><strong>Install a CUDA that compiles for the card.</strong> Runpod&rsquo;s default image ships CUDA 12.8, whose <code>nvcc</code> <a href="https://developer.nvidia.com/cuda-gpus"target="_blank" rel="noopener">cannot compile for <code>compute_103a</code></a>, the B300&rsquo;s compute capability. Without 12.9, the NVFP4 kernels never compile.</li>
<li><strong>Never use <code>--enforce-eager</code>.</strong> Letting vLLM compile and capture CUDA graphs is the single biggest win.</li>
<li><strong><code>--performance-mode interactivity</code></strong>: optimize for single-stream latency, which is what a serial agent needs, instead of aggregate throughput.</li>
<li><strong>FP8 KV cache on the big MoEs, prefix caching and chunked prefill on all of them</strong>, confirmed by vLLM&rsquo;s Prometheus counters instead of assumed: on an 11K-token prompt, the server reused exactly 8,576 prefix tokens on every repeat.</li>
<li><strong>The right tool and reasoning parser for each family.</strong> The wrong parser makes tool calls vanish silently or leaks the reasoning into the answer.</li>
</ul>
<p>And the specific tweaks I found most interesting:</p>
<ul>
<li><strong>NVFP4 only runs on vLLM.</strong> The 198 to 251 GB checkpoints in Blackwell&rsquo;s native FP4 are the only way to fit on the card, and llama.cpp and Ollama simply don&rsquo;t load those formats. Whoever lives on GGUF has no access to this range.</li>
<li><strong>Native speculative decoding.</strong> Qwen 3.8 27B went from 92 to 195 tokens per second with the MTP head the checkpoint itself ships, predicting three tokens per step, plus <code>--language-model-only</code> to drop the vision tower (measured on different pods, so no controlled ablation). <a href="https://huggingface.co/meta-models/Muse-Glimmer-30B"target="_blank" rel="noopener">Muse Glimmer</a> reached 295 with the lightweight DFlash drafter it ships alongside, 15 speculated tokens per step. I only enabled it where an official drafter exists and where tool calling stayed correct; for Ornith a drafter exists as a separate release, with unknown acceptance rate, so it stayed off.</li>
<li><strong>The CUDA 12 loader.</strong> flashinfer JIT-compiles an NVFP4 MoE kernel that needs <code>libcudart.so.12</code>, and after installing CUDA 13 for Nemotron the library resolution broke. The symptom looked like OOM; the cause was an <code>ld.so.conf</code>. A repair script with <code>ldd</code> evidence before and after fixed it, and the 397B went on to serve at 144 tokens per second.</li>
<li><strong>One virtual environment per runtime.</strong> Nemotron 3.5 Super VL required its own vLLM 0.32 in a separate venv, because that&rsquo;s what the official card pins, and that build wants CUDA 13. Every model family is a bespoke case: parser, quantization, draft head, runtime version and loader repair, all different.</li>
<li><strong>A parser bug that dropped the last call.</strong> vLLM&rsquo;s Qwen tool parser discarded the last parameter of a call when the parameter closing tag was missing but the function one was present. A narrow repair, with 24 test cases, took that serving noise out of the model&rsquo;s account.</li>
</ul>
<p>The exact arguments for each model, the probe logs and the ledger of every tuning round are in the <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/master/docs/b300-serving-optimizations.md"target="_blank" rel="noopener">serving optimizations document</a> and the <a href="https://github.com/akitaonrails/llm-coding-benchmark/blob/master/docs/runpod-b300-openweights-runbook.md"target="_blank" rel="noopener">B300 runbook</a> in the repository.</p>
<blockquote>
  <p>Speed is almost free, once you let vLLM compile. The real work is finding out, model by model, which combination of toolkit, parser, quantization and draft head that checkpoint demands. I gave each one 45 minutes and needed them.</p>

</blockquote>
<h2>The ranking<span class="hx:absolute hx:-mt-20" id="the-ranking"></span>
    <a href="#the-ranking" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>v4 vigilance score, tier, memory footprint, decode speed on the admission probe (warm, single stream) and the cost of the seven sprints&rsquo; inference time only, at 9.09 dollars an hour. The cost excludes download, load, compilation, tuning and idle time; the real math comes further down.</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">#</th>
          <th>Model</th>
          <th style="text-align: right">v4</th>
          <th>Tier</th>
          <th style="text-align: right">Memory</th>
          <th style="text-align: right">tok/s</th>
          <th style="text-align: right">Minutes</th>
          <th style="text-align: right">Inference cost</th>
          <th>Reviewer</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">1</td>
          <td>GLM 5.3 Flash (NVFP4)</td>
          <td style="text-align: right"><strong>92.5</strong></td>
          <td>A</td>
          <td style="text-align: right">198 GB</td>
          <td style="text-align: right">142</td>
          <td style="text-align: right">145</td>
          <td style="text-align: right">US$ 21.96</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td style="text-align: right">1</td>
          <td>Qwen3.8 Flash-Next (NVFP4)</td>
          <td style="text-align: right"><strong>92.5</strong></td>
          <td>A</td>
          <td style="text-align: right">100 GB</td>
          <td style="text-align: right">195</td>
          <td style="text-align: right">80</td>
          <td style="text-align: right">US$ 12.04</td>
          <td>Codex → Claude</td>
      </tr>
      <tr>
          <td style="text-align: right">3</td>
          <td>Swift 1.5 27B</td>
          <td style="text-align: right"><strong>88.0</strong></td>
          <td>A</td>
          <td style="text-align: right">56 GB</td>
          <td style="text-align: right">203</td>
          <td style="text-align: right">64</td>
          <td style="text-align: right">US$ 9.71</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td style="text-align: right">4</td>
          <td>ThinkingCap 3.8 27B</td>
          <td style="text-align: right"><strong>83.0</strong></td>
          <td>A</td>
          <td style="text-align: right">56 GB</td>
          <td style="text-align: right">189</td>
          <td style="text-align: right">76</td>
          <td style="text-align: right">US$ 11.47</td>
          <td>Codex → Claude</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Muse Glimmer 30B</td>
          <td style="text-align: right">81.0</td>
          <td>B</td>
          <td style="text-align: right">60 GB</td>
          <td style="text-align: right">295</td>
          <td style="text-align: right">23</td>
          <td style="text-align: right">US$ 3.54</td>
          <td>Codex → Claude</td>
      </tr>
      <tr>
          <td style="text-align: right">5</td>
          <td>Ornith 1.5 35B</td>
          <td style="text-align: right">81.0</td>
          <td>B</td>
          <td style="text-align: right">70 GB</td>
          <td style="text-align: right">317</td>
          <td style="text-align: right">161</td>
          <td style="text-align: right">US$ 24.39</td>
          <td>Codex → Claude</td>
      </tr>
      <tr>
          <td style="text-align: right">7</td>
          <td>Qwen 3.8 27B</td>
          <td style="text-align: right">80.5</td>
          <td>B</td>
          <td style="text-align: right">54 GB</td>
          <td style="text-align: right">195</td>
          <td style="text-align: right">192</td>
          <td style="text-align: right">US$ 29.11</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td style="text-align: right">8</td>
          <td>Qwen3.5 397B (NVFP4)</td>
          <td style="text-align: right">68.5</td>
          <td>C</td>
          <td style="text-align: right">251 GB</td>
          <td style="text-align: right">140</td>
          <td style="text-align: right">54</td>
          <td style="text-align: right">US$ 8.22</td>
          <td>Codex → Claude</td>
      </tr>
      <tr>
          <td style="text-align: right">9</td>
          <td>Nemotron 3.5 Super VL (NVFP4)</td>
          <td style="text-align: right">63.0</td>
          <td>C</td>
          <td style="text-align: right">70 GB</td>
          <td style="text-align: right">207</td>
          <td style="text-align: right">50</td>
          <td style="text-align: right">US$ 7.51</td>
          <td>Codex → Claude</td>
      </tr>
      <tr>
          <td style="text-align: right">10</td>
          <td>DeepSeek V4 Flash</td>
          <td style="text-align: right">44.5</td>
          <td>D</td>
          <td style="text-align: right">167 GB</td>
          <td style="text-align: right">153</td>
          <td style="text-align: right">37</td>
          <td style="text-align: right">US$ 5.59</td>
          <td>Codex</td>
      </tr>
      <tr>
          <td style="text-align: right">11</td>
          <td>GLM 4.7 Flash BF16</td>
          <td style="text-align: right">33.5</td>
          <td>D</td>
          <td style="text-align: right">60 GB</td>
          <td style="text-align: right">217</td>
          <td style="text-align: right">30</td>
          <td style="text-align: right">US$ 4.60</td>
          <td>Codex</td>
      </tr>
  </tbody>
</table>
<p>Three have no score: Cohere&rsquo;s <strong>Command A Plus</strong> (218 billion, 25 active, W4A4) got stuck in a loop rewriting the same model file 23 times, needed three nudges and still left the tests unable to run before the reviewer was blocked; <strong>Nex N2.5 Mini</strong> ran at 337 tokens per second and delivered invalid Ruby, contradictory migrations and broken authentication in two attempts, a valid bad result from a server that works; and <strong>Qwen3.5 122B</strong> was a conditional fallback in case the 397B didn&rsquo;t finish, and the 397B finished.</p>
<p>Minutes are sprint time only, and Ornith&rsquo;s include a sprint interrupted by infrastructure. Flash-Next, Swift, ThinkingCap, Muse and Qwen 27B took one nudge each; GLM 4.7, two; the others, none. The probe speed is an admission number: the throughput of a real coding session includes prefill, tools, tests and the agent&rsquo;s choices. And note that the top two tie on score with opposite profiles: GLM spent 145 minutes and 22 dollars to reach the same 92.5 that Qwen3.8 Flash-Next did in 80 minutes and 12 dollars, with half the memory.</p>
<h2>The interesting cases<span class="hx:absolute hx:-mt-20" id="the-interesting-cases"></span>
    <a href="#the-interesting-cases" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Qwen3.8 Flash-Next: the best of the open models, by cost<span class="hx:absolute hx:-mt-20" id="qwen38-flash-next-the-best-of-the-open-models-by-cost"></span>
    <a href="#qwen38-flash-next-the-best-of-the-open-models-by-cost" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><a href="https://huggingface.co/nvidia/Qwen3.8-Flash-Next-NVFP4"target="_blank" rel="noopener">Flash-Next</a> is, <a href="https://recipes.vllm.ai/Qwen/Qwen3.8-Flash-Next"target="_blank" rel="noopener">in Qwen&rsquo;s words</a>, a preview of the Qwen 4 architecture: 125 billion language-model parameters with 6 billion active, plus a 51-billion n-gram embedding table that Qwen says can be offloaded to host memory, plus a 4-billion MTP head. Quantized to NVFP4 by NVIDIA, it took about 100 GB on the card (the checkpoint is 133 GB on disk). It was the only model in the second batch to resolve all 14 items: it caught the tenant leak unprompted, caught the compound test-integrity item, and wrote per-user isolation specs on its own, so the planted API IDOR had no way to stay green. At 195 tokens per second and 12 dollars of inference, it&rsquo;s the best cost-benefit in this table.</p>
<h3>GLM 5.3 Flash: the same 92.5, three times the cost<span class="hx:absolute hx:-mt-20" id="glm-53-flash-the-same-925-three-times-the-cost"></span>
    <a href="#glm-53-flash-the-same-925-three-times-the-cost" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>GLM scored the same with a much bigger architecture: 320 billion parameters, 18 active, 198 GB even in FP4. It resolved all 14 items, zero nudges, reviewed end to end by Codex.</p>
<p>But it took 145 minutes and consumed twice the memory for the same result. On Z.ai&rsquo;s cloud, the same model scored 84.25 on a flat plan. With single-run noise, which in my history reaches nine points, the safest reading is that both sit in the same band.</p>
<h3>Swift 1.5 and ThinkingCap: two 27B fine-tunes in Tier A<span class="hx:absolute hx:-mt-20" id="swift-15-and-thinkingcap-two-27b-fine-tunes-in-tier-a"></span>
    <a href="#swift-15-and-thinkingcap-two-27b-fine-tunes-in-tier-a" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The two surprises. <a href="https://huggingface.co/ukisai/Swift-1.5-Qwen3.8-27b"target="_blank" rel="noopener">Swift 1.5</a>, from UkisAI, and <a href="https://huggingface.co/bottlecapai/ThinkingCap-Qwen3.8-27B"target="_blank" rel="noopener">ThinkingCap 3.8</a>, from BottleCap AI, are Qwen 3.8 27B fine-tunes trained to think less: Swift advertises up to 58% fewer reasoning tokens (on the GPQA median; on Terminal-Bench, 16%), ThinkingCap about 37% on average. Both fit in 56 GB in BF16, run at about 200 tokens per second with MTP, and scored 88 and 83.</p>
<p>Swift landed above Anthropic&rsquo;s Opus 4.6. The base Qwen 3.8 27B, same architecture, scored 80.5 in 192 minutes; Swift scored 88 in 64. Swift caught sabotage earlier than the base; whether that was from thinking less, one run of each can&rsquo;t prove.</p>
<p>A provenance caveat: the reviewer recorded that Swift read local commit messages that disclosed regressions, which weakens a literal reading of &ldquo;entirely unaided discovery&rdquo;. And it left one item unresolved, an inactive admin still accepted with a vacuous guarding test. Even so, of every model in this table, it&rsquo;s the one I&rsquo;d put on a card of my own.</p>
<h3>Qwen3.5 397B: the flagship that let the backdoor through<span class="hx:absolute hx:-mt-20" id="qwen35-397b-the-flagship-that-let-the-backdoor-through"></span>
    <a href="#qwen35-397b-the-flagship-that-let-the-backdoor-through" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The biggest model in the batch, 397 billion parameters with 17 active, 251 GB of NVFP4 on a 275 GB card, served at 140 tokens per second after the loader repair and scored <strong>68.5</strong>, Tier C.</p>
<p>The case that defines the score: sabotage number 6 is a line <code>admin? =&gt; admin || email.end_with?(&quot;@internal.example&quot;)</code>, a privilege escalation by email domain. The 397B let it through in the normal sprints, let it through in sprint 7 with the explicit security-audit request, and <strong>wrote a passing test codifying the backdoor as expected behavior</strong>, in the same commit where it announced &ldquo;Brakeman: 0 warnings&rdquo;. Parameters did not buy vigilance.</p>
<h3>Nemotron 3.5 Super VL: cheated on the test<span class="hx:absolute hx:-mt-20" id="nemotron-35-super-vl-cheated-on-the-test"></span>
    <a href="#nemotron-35-super-vl-cheated-on-the-test" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>NVIDIA&rsquo;s <a href="https://huggingface.co/nvidia/NVIDIA-Nemotron-3.5-Super-VL-120B-A12B-NVFP4"target="_blank" rel="noopener">Nemotron 3.5 Super VL</a>, 120 billion with 12 active, released two days before I started testing and <a href="https://blogs.nvidia.com/blog/nemotron-3-5-super-vl/"target="_blank" rel="noopener">sold by NVIDIA</a> as the fastest open agentic model in its class, with &ldquo;leading accuracy&rdquo; on multimodal tasks, scored <strong>63</strong>. Sabotage number 2 removes a navigation link and the regression test looks for <code>have_link('Sign in')</code>. Nemotron changed the test to <code>have_button('Sign in')</code>, which passes on the login form&rsquo;s submit button without restoring the link, and kept the cheat even after the reveal sprint.</p>
<p>It also tends to catch items a sprint late. And it was the one that required its own runtime: vLLM 0.32 with CUDA 13 in a separate environment.</p>
<h3>DeepSeek V4 Flash: 86 in the cloud, 44.5 in my hands<span class="hx:absolute hx:-mt-20" id="deepseek-v4-flash-86-in-the-cloud-445-in-my-hands"></span>
    <a href="#deepseek-v4-flash-86-in-the-cloud-445-in-my-hands" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The most important case for anyone considering self-hosting. <a href="https://huggingface.co/deepseek-ai/DeepSeek-V4-Flash"target="_blank" rel="noopener">DeepSeek V4 Flash</a>, 284 billion with 13 active, scored <strong>86, Tier A, for 97 cents</strong> through the API in September, and the 0731 version, exactly the one I downloaded, scored 85 for 1.94. The same public weights in mixed FP4 and FP8, served by me on the B300, scored <strong>44.5, Tier D</strong>: it caught 4 items unprompted, 5 more at the reveal, and left 5 unresolved. It was the fastest to finish, 37 minutes, and the least vigilant.</p>
<p>The likely cause is divergence between the public checkpoint and what DeepSeek serves, or between their serving stack and mine: parser, chat template, reasoning mode, quantization. I followed the official card. What this proves is that the model&rsquo;s name on Hugging Face doesn&rsquo;t guarantee the hosted API&rsquo;s quality, and that whoever is going to host needs to validate before trusting.</p>
<h3>GLM 4.7 Flash: same as local, meaning bad<span class="hx:absolute hx:-mt-20" id="glm-47-flash-same-as-local-meaning-bad"></span>
    <a href="#glm-47-flash-same-as-local-meaning-bad" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The 30-billion GLM 4.7 Flash in BF16, at 217 tokens per second, scored 33.5. At home, in GGUF Q5, it had scored 24. It needed two nudges, left nine items unresolved and delivered a migration with a syntax error. The nine-and-a-half-point difference fits within single-run noise; what remains is that the model is weak either way.</p>
<h3>What showed up in several<span class="hx:absolute hx:-mt-20" id="what-showed-up-in-several"></span>
    <a href="#what-showed-up-in-several" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Ornith, Muse Glimmer and the 397B shared a hygiene defect: they ran the sprint to the end with exit zero and forgot to commit their own work, leaving it for the reviewer to checkpoint. It didn&rsquo;t go into the score, and on a real team it would be the first complaint. And the 81-to-83 cluster, ThinkingCap, Ornith and Muse, has a consistent profile: it catches SQL injection, tenant leaks, XSS and exposed secrets with confidence, and lets the quiet items through, broken access control, test integrity, missing index, wrong aggregate.</p>
<h2>How far from the frontier<span class="hx:absolute hx:-mt-20" id="how-far-from-the-frontier"></span>
    <a href="#how-far-from-the-frontier" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The three best open models against the best commercial ones from the same ranking, with the cost and time of each run:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">v4</th>
          <th>Tier</th>
          <th style="text-align: right">Run cost</th>
          <th style="text-align: right">Minutes</th>
          <th>Where</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>GPT-6 Astra</td>
          <td style="text-align: right">100.0</td>
          <td>A</td>
          <td style="text-align: right">US$ 30.55</td>
          <td style="text-align: right">100</td>
          <td>cloud</td>
      </tr>
      <tr>
          <td>Claude Opus 5.5</td>
          <td style="text-align: right">100.0</td>
          <td>A</td>
          <td style="text-align: right">US$ 16.63</td>
          <td style="text-align: right">64</td>
          <td>cloud</td>
      </tr>
      <tr>
          <td>GPT 5.6 terra</td>
          <td style="text-align: right">100.0</td>
          <td>A</td>
          <td style="text-align: right">US$ 9.52</td>
          <td style="text-align: right">80</td>
          <td>cloud</td>
      </tr>
      <tr>
          <td>Grok 4.6</td>
          <td style="text-align: right">98.5</td>
          <td>A</td>
          <td style="text-align: right">US$ 13.00</td>
          <td style="text-align: right">67</td>
          <td>cloud</td>
      </tr>
      <tr>
          <td>Claude Fable 5.1</td>
          <td style="text-align: right">95.5</td>
          <td>A</td>
          <td style="text-align: right">~US$ 51</td>
          <td style="text-align: right">133</td>
          <td>cloud</td>
      </tr>
      <tr>
          <td><strong>GLM 5.3 Flash (NVFP4)</strong></td>
          <td style="text-align: right"><strong>92.5</strong></td>
          <td>A</td>
          <td style="text-align: right">US$ 21.96 inference only</td>
          <td style="text-align: right">145</td>
          <td>B300</td>
      </tr>
      <tr>
          <td><strong>Qwen3.8 Flash-Next (NVFP4)</strong></td>
          <td style="text-align: right"><strong>92.5</strong></td>
          <td>A</td>
          <td style="text-align: right">US$ 12.04 inference only</td>
          <td style="text-align: right">80</td>
          <td>B300</td>
      </tr>
      <tr>
          <td>Claude Sonnet 5</td>
          <td style="text-align: right">91.0</td>
          <td>A</td>
          <td style="text-align: right">~US$ 27</td>
          <td style="text-align: right">112</td>
          <td>cloud</td>
      </tr>
      <tr>
          <td>Gemini 3.8 Flash high</td>
          <td style="text-align: right">90.5</td>
          <td>A</td>
          <td style="text-align: right">US$ 15.98</td>
          <td style="text-align: right">97</td>
          <td>cloud</td>
      </tr>
      <tr>
          <td><strong>Swift 1.5 27B</strong></td>
          <td style="text-align: right"><strong>88.0</strong></td>
          <td>A</td>
          <td style="text-align: right">US$ 9.71 inference only</td>
          <td style="text-align: right">64</td>
          <td>B300</td>
      </tr>
      <tr>
          <td>Claude Opus 4.6</td>
          <td style="text-align: right">87.5</td>
          <td>A</td>
          <td style="text-align: right">US$ 25.64</td>
          <td style="text-align: right">89</td>
          <td>cloud</td>
      </tr>
  </tbody>
</table>
<p>The reading: the best of the open source that fits on a B300 and that I served sits <strong>one step below the commercial ceiling and level with the middle of Tier A</strong>. Differences of one or two points are single-run noise.</p>
<p>GLM 5.3 Flash and Qwen3.8 Flash-Next tie with Sonnet 5 and pass Gemini 3.8 Flash and Opus 4.6. None reaches the 100 that seven commercial models scored, nor Grok 4.6&rsquo;s 98.5. Seven and a half points separate the best open model from the ceiling, and in v4 every point is one less sabotage caught unprompted.</p>
<p>The difference that matters is another: predictability. Among the top commercial models in the table, the worst is 87.5, and the full commercial field also has a bottom, Mistral Large 3 scored 39. The open field has the same 92.5 at the top and two Tier D at the bottom, with DeepSeek scoring 85 in the cloud and 44.5 in my hands. Choosing a top commercial model is choosing a number the API reproduces; choosing an open one is betting that the checkpoint, the quantization and your serving stack reproduce the number on the card, and sometimes they do.</p>
<h2>The math<span class="hx:absolute hx:-mt-20" id="the-math"></span>
    <a href="#the-math" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If quality still falls short of the frontier, is the cost at least proportional? It depends on where you run the open model.</p>
<p><strong>On the vendor&rsquo;s own cloud API, yes, and by a wide margin.</strong> A full v4 run cost 97 cents on DeepSeek V4 Flash, 1.17 dollars on Qwen 3.8 Flash, 1.03 on MiMo V2.5 Pro, all Tier A in the cloud. Against 9.52 to 30.55 dollars for the 100-point models, that&rsquo;s ten to thirty times cheaper for a score 8 to 14 points lower. The list prices explain it: <a href="https://docs.z.ai/guides/overview/pricing"target="_blank" rel="noopener">GLM 5.3 Flash</a> costs 15 cents per million input tokens and 50 for output; <a href="https://api-docs.deepseek.com/quick_start/pricing"target="_blank" rel="noopener">DeepSeek Flash</a>, 15 to 30 cents input and 60 cents to 1.20 output; <a href="https://platform.claude.com/docs/en/about-claude/pricing"target="_blank" rel="noopener">Opus 5.5</a>, 4 and 20 dollars; <a href="https://developers.openai.com/api/docs/pricing"target="_blank" rel="noopener">GPT-6 Astra</a>, 10 and 50.</p>
<p><strong>On your own rented B300, no.</strong> The pod costs 9 dollars an hour on or idle, <strong>218 a day, about 6,500 a month</strong>. The model time of this whole batch, 14 models across download, load and sprints, added up to 23 hours, about 212 dollars at pod price; the sprints alone were 17 hours and 157 dollars.</p>
<p>But the pod also charges for the time when nothing runs. I put 400 dollars of credit on Runpod and 127 were left: the whole batch cost <strong>273 dollars</strong>, about 30 pod-hours, including storage, four pods in sequence and seven idle hours one night when the orchestration died and nothing warned me. Almost 60 dollars more than the model time, just waiting. The repository&rsquo;s break-even math: the pod only gets cheaper than the API from about <strong>6,500 runs a month</strong>, 217 a day, sustained. A solo developer or a small team doesn&rsquo;t come close.</p>
<p>And model against model, side by side:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th>Cloud API</th>
          <th>Hosted by me on the B300</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>DeepSeek V4 Flash 0731</td>
          <td>85 (A) for US$ 1.94</td>
          <td>44.5 (D) for US$ 5.59 inference only</td>
      </tr>
      <tr>
          <td>Qwen 3.8 Flash (cloud) and Flash-Next (B300), same family</td>
          <td>86.5 (A) for US$ 1.17</td>
          <td>92.5 (A) for US$ 12.04</td>
      </tr>
      <tr>
          <td>Qwen 3.8 27B</td>
          <td>80 (B) for free on the Strix, in 706 minutes</td>
          <td>80.5 (B) for US$ 29.11, in 192 minutes</td>
      </tr>
  </tbody>
</table>
<blockquote>
  <p>The cloud API of an open model is ten to thirty times cheaper than the frontier for one tier less. Hosting the same model on a rented B300 is more expensive than the frontier, and sometimes worse than its own API.</p>

</blockquote>
<h2>Does a team fit on the same card?<span class="hx:absolute hx:-mt-20" id="does-a-team-fit-on-the-same-card"></span>
    <a href="#does-a-team-fit-on-the-same-card" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A question I asked while looking at the GPU at 10% utilization: do these models use all of the pod&rsquo;s compute? Could a whole team go on the same B300?</p>
<p>In principle, yes, and that&rsquo;s what vLLM exists for. <a href="https://vllm.ai/blog/2023-06-20-vllm"target="_blank" rel="noopener">Continuous batching</a> schedules several requests in the same decode step, and <a href="https://vllm.ai/blog/2023-06-20-vllm"target="_blank" rel="noopener">PagedAttention</a> stores each session&rsquo;s KV cache in non-contiguous blocks, with under 4% waste, precisely to fit more sessions in the same memory. A 27-billion model in BF16 takes 56 GB and leaves about 200 GB of KV cache: that&rsquo;s dozens of agent sessions with 128K-token context at the same time. The 397B, with 251 GB of weights, leaves 24, and then few fit.</p>
<p>What doesn&rsquo;t scale is speed per person. My test ran in <code>--performance-mode interactivity</code>, which optimizes single-stream latency, and the 200 tokens per second are that stream&rsquo;s. With ten agents decoding at the same time, the card&rsquo;s aggregate throughput rises and each one&rsquo;s falls, and the speculative decoding that gave me Muse Glimmer&rsquo;s 295 yields less as concurrency grows: a <a href="https://huggingface.co/z-lab/Muse-Glimmer-30B-DFlash2"target="_blank" rel="noopener">DFlash drafter published for Muse by Z Lab</a> reports 3 to 4.6 times gain with one session and 1.2 to 1.7 with 32.</p>
<p>I didn&rsquo;t measure concurrency in this batch, so what I can say is the outline: a team of five to ten people on a 27-to-35-billion model on one B300 is practical, and each one probably still stays above 100 tokens per second. The same team on the 397B is unworkable on the card, and on the 198 GB GLM 5.3 Flash it gets tight.</p>
<p>It&rsquo;s in that scenario, and only there, that the pod math starts to close. Ten developers running an agent all day on a 27B model would spend, on the API, at a dollar per two-hour run, about 40 dollars a day; the pod costs 218. It still loses. What changes the math is having a hundred people, or being required to keep the code from leaving your network.</p>
<h2>Is owning your own infra worth it?<span class="hx:absolute hx:-mt-20" id="is-owning-your-own-infra-worth-it"></span>
    <a href="#is-owning-your-own-infra-worth-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For serious software development, with this batch&rsquo;s data, the answer comes in three parts.</p>
<p><strong>The top open models are good enough.</strong> GLM 5.3 Flash, Qwen3.8 Flash-Next and Swift 1.5 27B are Tier A in my test, at Sonnet 5 level and above Opus 4.6. That was unthinkable in April, when <a href="/en/2026/04/05/testing-llms-open-source-and-commercial-can-anyone-beat-claude-opus/">only Qwen 3.6 35B came close to Opus</a>, and still one fix away. For anyone who accepts one tier below the ceiling, they serve for real work, including security review, which is what v4 measures.</p>
<p><strong>Renting a B300 to run them is the wrong way to use them.</strong> The cloud API of the same model costs a dollar per run and needs zero configuration. The pod costs 218 a day, demands a day of tuning per model family, and in DeepSeek&rsquo;s case delivered a worse model than its own API. It&rsquo;s only worth it with a data-residency obligation, with a checkpoint no cloud serves, with sustained load of hundreds of runs a day, or with a need for pinned weights for reproducibility. Four B300s to run the 750-billion-to-one-trillion models quadruple the bill with no evidence the score reaches 100: the 397B, the biggest model I tested, scored 68.5.</p>
<p><strong>And if you&rsquo;re going to host, host small.</strong> Swift 1.5 27B and ThinkingCap at 56 GB, with MTP, at 200 tokens per second, are Tier A on hardware you can buy, a professional 80 or 96 GB card instead of a datacenter one. That&rsquo;s where open source makes sense for a company: a whole team on one card, code inside the network, an Opus 4.6 score. Just check the license first: Swift and ThinkingCap ship with their own licenses, and above a certain revenue both require a commercial license. The open giants remain an API thing.</p>
<p>My rule after all this: top commercial model for tasks that can&rsquo;t fail, open-model API for volume, and your own card only when the law or the client demands it. The repository with every serving argument, every probe log, every reviewer transcript and the Codex-or-Claude provenance of every boundary is <a href="https://github.com/akitaonrails/llm-coding-benchmark"target="_blank" rel="noopener">public</a>, as always.</p>
]]></content:encoded><category>llm-benchmarks</category><category>local-models</category><category>llms</category><category>hardware</category></item><item><title>We're Living in the Future: Cars Fly and We Don't Have to Write HTML/CSS Anymore</title><link>https://www.akitaonrails.com/en/2026/10/16/living-in-the-future-cars-fly-no-more-html-css/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/16/living-in-the-future-cars-fly-no-more-html-css/</guid><pubDate>Fri, 16 Oct 2026 02:00:00 -0300</pubDate><description>&lt;p&gt;It&amp;rsquo;s past two in the morning and I&amp;rsquo;m still awake because I just watched the new Tesla Roadster climb a vertical ramp live, stop upside down, then spin in midair and land in one piece on another run.&lt;/p&gt;
&lt;p&gt;I expected a fast car. I didn&amp;rsquo;t expect one with ten compressed-air propulsion nozzles using SpaceX-derived technology, plus an underbody suction system capable, &lt;a href="https://paultan.org/2026/10/16/tesla-roadster-revealed-flies-on-spacex-air-thrusters-0-96-km-h-in-0-81s-production-2028/"target="_blank" rel="noopener"&gt;according to Elon Musk, of pulling up to 2 G&lt;/a&gt;. During the demo, Tesla announced zero to 60 miles per hour, nearly 97 km/h, in 0.81 seconds. It did not disclose the measurement protocol.&lt;/p&gt;</description><content:encoded><![CDATA[<p>It&rsquo;s past two in the morning and I&rsquo;m still awake because I just watched the new Tesla Roadster climb a vertical ramp live, stop upside down, then spin in midair and land in one piece on another run.</p>
<p>I expected a fast car. I didn&rsquo;t expect one with ten compressed-air propulsion nozzles using SpaceX-derived technology, plus an underbody suction system capable, <a href="https://paultan.org/2026/10/16/tesla-roadster-revealed-flies-on-spacex-air-thrusters-0-96-km-h-in-0-81s-production-2028/"target="_blank" rel="noopener">according to Elon Musk, of pulling up to 2 G</a>. During the demo, Tesla announced zero to 60 miles per hour, nearly 97 km/h, in 0.81 seconds. It did not disclose the measurement protocol.</p>
<p>This is the future I wanted to see.</p>
<p>The entire demonstration is in <a href="https://livestream.tesla.com/"target="_blank" rel="noopener">Tesla&rsquo;s official livestream</a>. <a href="https://www.roadandtrack.com/news/a74151425/the-air-assisted-tesla-roadster-flies-in-demo-hits-0-60-in-08-seconds/"target="_blank" rel="noopener">Road &amp; Track measured and described the maneuvers</a>, while <a href="https://techcrunch.com/2026/10/15/tesla-reveals-spacex-powered-roadster-that-flies-and-falls-with-style/"target="_blank" rel="noopener">TechCrunch detailed the three versions</a>: Performance with active aerodynamics and suction, Thrust with rear thrusters, and Rocket with a ten-nozzle propulsion system and a single seat.</p>
<p>Of course, we watched a prototype in a controlled demonstration. Tesla expects production to begin in 2028, and the Rocket version is not approved for public-road use. Still, an actual car left the ground, rotated, and landed. I watched it live from my office. It was spectacular.</p>
<p>While Musk was landing rockets and making cars fly, I was doing something far smaller and more mundane: fiddling with my websites.</p>
<h2>Six sites in about a day<span class="hx:absolute hx:-mt-20" id="six-sites-in-about-a-day"></span>
    <a href="#six-sites-in-about-a-day" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before the Tesla event, I spent the entire day redesigning six sites:</p>
<ul>
<li><a href="https://ailair.akitaonrails.com/"target="_blank" rel="noopener">Akita&rsquo;s AI Lair</a>, now matching the look of my new book, <em>Competent Enough</em>;</li>
<li><a href="https://aimemory.sh/"target="_blank" rel="noopener">ai-memory</a>;</li>
<li><a href="https://aijail.io/"target="_blank" rel="noopener">ai-jail</a>;</li>
<li><a href="https://themakitachronicles.com/"target="_blank" rel="noopener">The M.Akita Chronicles</a> newsletter;</li>
<li>the <a href="https://blog.themakitachronicles.com/"target="_blank" rel="noopener">newsletter archive</a>;</li>
<li>and this blog, <a href="https://akitaonrails.com/"target="_blank" rel="noopener">AkitaOnRails.com</a>.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/10/redesign-seis-sites-stitch.jpg" alt="The six redesigned sites in production: Akita’s AI Lair, ai-memory, ai-jail, The M.Akita Chronicles, the newsletter archive, and AkitaOnRails"  loading="lazy" /></p>
<p>They all started with variations of that default theme Claude makes. Dark background, purple or blue gradient, huge sans-serif type, rounded cards, a glow behind something. It works. It has also become so common that you can spot a &ldquo;site made by Claude&rdquo; before reading the title.</p>
<p>I had already tried asking Claude for different designs. It changed the color, moved the cards around, and delivered the same visual grammar. I posted <a href="https://x.com/AkitaOnRails/status/2110809199890300986"target="_blank" rel="noopener">some screens and the result of the change on Twitter</a>. I&rsquo;m no web designer, and for a while I accepted &ldquo;it works.&rdquo; Yesterday I got tired of it.</p>
<p>Someone suggested <a href="https://stitch.withgoogle.com/"target="_blank" rel="noopener">Stitch by Google</a>. It&rsquo;s an experimental Google Labs tool that turns instructions and images into editable interfaces and front-end code. The <a href="https://developers.googleblog.com/en/stitch-a-new-way-to-design-uis/"target="_blank" rel="noopener">first version launched in 2025</a> on top of Gemini; the <a href="https://blog.google/innovation-and-ai/models-and-research/google-labs/stitch-ai-ui-design/"target="_blank" rel="noopener">current version</a> has become a design canvas with an agent, prototypes, and export to a <code>DESIGN.md</code> that other agents can follow.</p>
<p><a href="https://blog.google/innovation-and-ai/models-and-research/google-labs/stitch-ai-ui-design/"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/10/stitch-ai-native-canvas-google.webp" alt="The Google Stitch canvas with multiple interfaces, visual variations, and design-system controls"  loading="lazy" /></a></p>
<p>I signed up, got the API token, and went to work. Stitch generated visual directions. Claude Code and Codex brought those directions into the real repositories, adapted the components, fixed responsiveness, replaced images, adjusted SEO, tested, and deployed. When one quota ran out, I continued with the other.</p>
<p>The six sites come from five repositories. Looking at them side by side made one thing clear: Stitch responds much better when it receives a concrete metaphor, the audience, and what the product needs to communicate. ai-memory became a memory archive. ai-jail became a cinematic prison. AI Lair adopted a 1950s and 1960s world&rsquo;s fair, drawn from my book cover. The newsletter became a late-night broadcast, and this blog became an editorial archive. Five different identities instead of five variations of Claude&rsquo;s same gradient.</p>
<p>The pretty prototype is the easy part. The job only ends when the visual language reaches internal pages, the article, the book reader, email, legal pages, error states, and mobile. That&rsquo;s what the agents did inside the repositories. On ai-memory, for example, verification covered 102 pages in six languages, light and dark themes, desktop and mobile. On The M.Akita Chronicles, the same design had to work across signup, archive, newsletter detail, podcast, and the email template. A Stitch mockup solves none of that by itself.</p>
<p>Each site went through several rounds of prototypes. Some looked awful. Others had one good idea surrounded by bad decisions. I told the agents to throw them away, preserve one part, mix it with another attempt, and start over. Code is cheap now, so there is no reason to fall in love with the first version.</p>
<p>The result won&rsquo;t win a design award. A professional designer would still find hundreds of things to improve. I know I could take it further by spending a few more days. It looks much better than it did, though, and for now it is competent enough.</p>
<p>Six existing sites redesigned, responsive, with SEO, image generation and replacement, HTML, CSS, and JavaScript adjustments, testing, and production deployment. One person. About a day. A year ago, that package would have taken weeks or months.</p>
<p>Keep the scale in perspective: these are small sites, mostly landing pages and content pages. Nobody is rebuilding Amazon.com&rsquo;s entire collection of pages and systems in a day. The experiment shows how much repetitive work has already moved out of the way within a scope that one experienced person can understand and review. Large projects remain large, full of private rules, old integrations, strange states, and decisions that do not fit in a prompt.</p>
<h2>Even the first proofreading pass can be automated<span class="hx:absolute hx:-mt-20" id="even-the-first-proofreading-pass-can-be-automated"></span>
    <a href="#even-the-first-proofreading-pass-can-be-automated" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>As part of the same process, I had agents review the sites as different readers. This wasn&rsquo;t grammar correction. I wanted to know what someone would understand in the first few seconds, where they would get lost, which promise would sound suspicious, and whether they could complete a task without already knowing the product.</p>
<p>On ai-jail, I used two isolated sessions. One played a skeptical engineer who approves every prompt and had never heard of the project. The other was a non-engineer managing eight developers, trying to decide whether to approve the tool for the company. On ai-memory, I used three: an engineer learning AI tools, a manager evaluating a pilot, and a parent with no agent experience who worried about AGI and jobs. Each one read the site without seeing the others&rsquo; reports.</p>
<p>Anyone can do the same thing. Run the application locally or open a preview deployment, start fresh sessions, and give each agent a concrete task. A basic prompt can look like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Open this site on desktop and mobile: [URL].
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">You are [persona], know [context], and have never seen this product.
</span></span><span class="line"><span class="cl">Your goal is [specific decision or task].
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Navigate as this person. Do not read code or internal documentation first.
</span></span><span class="line"><span class="cl">Record:
</span></span><span class="line"><span class="cl">- what you understood in the first ten seconds;
</span></span><span class="line"><span class="cl">- what you think the product does and who it is for;
</span></span><span class="line"><span class="cl">- where you did not know the next step;
</span></span><span class="line"><span class="cl">- contradictory, absolute, or hard-to-believe promises;
</span></span><span class="line"><span class="cl">- terms the site uses before explaining them;
</span></span><span class="line"><span class="cl">- reading, keyboard, contrast, touch, and responsiveness problems;
</span></span><span class="line"><span class="cl">- what would stop you from trying, buying, or approving it.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">For every finding, show the page and visible evidence.
</span></span><span class="line"><span class="cl">Separate factual bugs, usability problems, and subjective preferences.
</span></span><span class="line"><span class="cl">Do not propose a broad redesign. Suggest the smallest change that solves the problem.</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I prefer three independent sessions over an agent roundtable. Once one reads another&rsquo;s report, it starts agreeing by inertia. A separate session can then consolidate repeated points, discard matters of taste, and check every claim against the code and product documentation. A review can flag a sentence as wrong; it has no authority to invent the right one.</p>
<p>The most useful results tend to fall into four groups: positioning, information order, path to the first action, and trust. Traditional automated tests still handle broken links, contrast, accessibility, overflow, and error states. The persona tells you that a technically accessible button appeared five screens below where the person needed it.</p>
<p>During the <a href="https://github.com/akitaonrails/ai-jail-web/blob/main/docs/research/PROOFREAD-2026-10-15-BRIEF.md"target="_blank" rel="noopener">ai-jail proofreading</a>, both profiles agreed that the site took too long to show a concrete risk and started speaking like engineering documentation too early. The threat of a poisoned page moved directly below the hero. New sections explained &ldquo;What changes on day one&rdquo; and &ldquo;For the person who must approve this,&rdquo; including operating cost, limitations, and the keys a company actually exposes. The review also caught a technically incorrect claim repeated across several pages: the network does not stay entirely off by default. The agent&rsquo;s own API host and, on Linux, registries remain accessible. This kind of reading catches documentation bugs too.</p>
<p>The <a href="https://github.com/akitaonrails/ai-memory-web/blob/main/docs/research/persona-review.md"target="_blank" rel="noopener">ai-memory report</a> found permissions described in contradictory ways, privacy promises that were too absolute, and the basic explanation buried under advanced features. During the second round, the profiles noticed that remote-access instructions told users to use HTTP before requiring TLS, that an unauthenticated <code>curl</code> promised the wrong response, and that important choices appeared far too late on mobile. The collection guide moved from about 4,364 pixels from the top to 1,617; the individual and team paths moved from 5,300 to 2,489. That&rsquo;s an objective improvement born from simulated reading.</p>
<p>In the <a href="https://github.com/akitaonrails/ai-toolkit-web/pull/4"target="_blank" rel="noopener">AI Lair redesign</a>, the new-reader review reorganized the entry path. A <a href="https://github.com/akitaonrails/ai-toolkit-web/commit/c2a5237e876f662a8b53450f23f0162fdc1d4a76"target="_blank" rel="noopener">later revision</a> made it explicit that my setup with multiple agents and two monitors is a mature configuration, not a requirement for starting. One person, one project, and one agent are enough. It also produced a pilot plan for managers: a reversible task, non-sensitive data, an acceptance criterion, deadline, budget, and measurement. The next audit found invalid ARIA and an animation that hid the opening copy from assistive technologies; the <a href="https://github.com/akitaonrails/ai-toolkit-web/pull/5"target="_blank" rel="noopener">fix</a> took axe-core from four serious violations to zero.</p>
<p>Simulated personas still fall far short of human feedback. They carry the models&rsquo; same biases, may agree with the prompt, never feel the irritation of someone who lost twenty minutes, and never take the risk of entering their own credit card. The reports serve as hypotheses. A real user will always find the case that I, the agent, and the test suite failed to imagine.</p>
<p>Before the first user exists, however, the alternative is usually no review at all. Two or three independent readings already catch contradictory promises, unexplained jargon, buried information, and a flow that only makes sense to its author. These readings cost little and make the product less stupid before it reaches actual people.</p>
<h2>HTML was never programming<span class="hx:absolute hx:-mt-20" id="html-was-never-programming"></span>
    <a href="#html-was-never-programming" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For years, I watched people perform some remarkable mental gymnastics to argue that &ldquo;HTML is a programming language&rdquo; and therefore anyone who writes HTML is a programmer.</p>
<p>HTML is markup: it describes a document&rsquo;s structure. CSS describes presentation. That has value, requires knowledge, and can become terribly complex. Accidental complexity does not turn markup into programming.</p>
<p>There is no shame in that. I started building sites in the 1990s. I received a Photoshop layout and turned it into HTML. I sliced images, built tables, adjusted pixels, opened the result in multiple browsers, went back, and tried again. It was honest work and paid my bills.</p>
<p>It was also basically mechanical work: copy, paste, adjust, look, repeat. Exactly the category computers should automate.</p>
<p>Today I still chose the visual direction, rejected bad proposals, decided what each site needed to communicate, and recognized when the result was good enough. The agents handled the grunt work. This should have happened years ago.</p>
<h2>The bubble delayed automation<span class="hx:absolute hx:-mt-20" id="the-bubble-delayed-automation"></span>
    <a href="#the-bubble-delayed-automation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For much of the 2010s, <a href="https://fred.stlouisfed.org/series/EFFR"target="_blank" rel="noopener">US interest rates stayed near zero</a>. Cheap money flooded funds, startups, and large companies. Hiring more people was easy, and the market absorbed any amount of manual labor disguised as engineering.</p>
<p>Low rates explain only part of tech&rsquo;s expansion. A field breaking hiring records has little incentive to eliminate its own repetitive work. If you can put fifty more people to work assembling screens, you put fifty more people to work assembling screens.</p>
<p>Anyone who attended my talks at tech events in the 2010s may remember <strong>Constraint == Innovation</strong>. Yes, the original title used two equal signs. I gave that talk at DevConf 2019, the <a href="https://www.slideshare.net/slideshow/devconf-2019-so-carlos/143923367"target="_blank" rel="noopener">83 slides are on my SlideShare</a>, and I had already written the same argument in 2013 in <a href="https://startupi.com.br/restricoes-sao-libertadoras-menos-e-mais/"target="_blank" rel="noopener">&ldquo;Constraints are liberating: less is more&rdquo;</a>.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/V0D3PuTLOZ8"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>It&rsquo;s the old maxim: <strong>necessity is the mother of invention</strong>. Constraints force choices. Choices force priorities. When the conventional path cannot fit the money, deadline, or available capacity, someone has to find another path. That&rsquo;s where real innovation often comes from.</p>
<p>Money funds expensive research, buys equipment, and gives people time to experiment. Excess money without pressure for results does something else: it hides inefficiency with brute force. There is no need to automate, simplify, or discover a better solution while you can keep hiring and growing the spreadsheet. Too much abundance turns a technical problem into an operating expense and postpones the difficult decision.</p>
<p>I <a href="/en/2026/02/08/rant-ai-killed-programmers/">repeated this warning at the beginning of 2026</a>: the programming bubble managed to replace efficiency with volume. Constraints returned when cheap money ended. Coincidentally, agents arrived at the same time and gave companies a practical way to automate the mechanical work they had spent a decade scaling through hiring.</p>
<p>That&rsquo;s how we spent a decade recreating the same admin dashboard and calling it innovation. Every week brought the next front-end savior: React, Angular, Vue, Svelte, another <em>bundler</em>, another framework on top of the framework. They are useful tools in the right context, but none addressed the obvious question: why is a human still hand-writing the thousandth variation of the same form?</p>
<p>The hiring bubble burst in 2022 and ended the party. At the end of that year, ChatGPT brought language models to the public. GPT-2, just to keep the chronology straight, had come out in 2019. Four years after ChatGPT, agentic programming became a normal work tool.</p>
<p>Any task that consists of copying a pattern, adapting an example, running it, looking at the error, and trying again is already within these agents&rsquo; reach. Front-end is the most visible target because it accumulated an absurd amount of this work. The rest of programming has no mystical shield. Plenty of back-end work is CRUD, glue between APIs, and repetitive configuration. That will be automated too.</p>
<p>Fine by me. Programming was never about typing code. Programming is making a computer do something useful.</p>
<h2>VS Code is the new punch card<span class="hx:absolute hx:-mt-20" id="vs-code-is-the-new-punch-card"></span>
    <a href="#vs-code-is-the-new-punch-card" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I wrote about exactly this in April in <a href="/en/2026/04/11/vs-code-is-the-new-punch-card/">&ldquo;VS Code Is the New Punch Card&rdquo;</a>.</p>
<p>For decades, the interface between intention and computer kept changing. First you connected wires and switches. Then you punched cards. Then you wrote Assembly, C, high-level languages, frameworks, and configuration. Each generation looked at the previous one and automated another layer of manual work.</p>
<p>No sane person would argue today that operating a card punch was the essence of computer science. It was the available interface. Typing every tag and CSS rule into VS Code was also the available interface.</p>
<p>Now I describe the intention, show references, evaluate the result, and tell the agent to fix it. I still need to understand browsers, networks, caching, accessibility, semantics, responsiveness, and SEO. Without the fundamentals, I couldn&rsquo;t tell whether the agent delivered a solution or a pretty time bomb. The keyboard lost importance; judgment gained it.</p>
<p>Today, every Tier A model I test, from Claude to Kimi, can reliably execute the mechanical front-end work that appeared in these six projects. I can say without hesitation that any front-end task that merely turns an already-made decision into code is automatable. They needed direction to create the six designs. None required me to hand-write the flexbox, breakpoint, or component I had already explained.</p>
<p>That covers an enormous share of the work while leaving the most valuable part. Someone still has to know the framework&rsquo;s tradeoffs, understand the browser, choose the architecture, notice when a library is being forced against its design, and find out why an apparently correct solution breaks under a particular combination of device, language, state, and real data. The agent writes the code; an experienced professional provides direction, limits the damage, and owns the result.</p>
<p>Front-end still exists. The excess mechanical work and the people hired only to follow a finished recipe lose value. A great front-end professional can direct agents and deliver far more than they could alone. A mediocre professional who spent years mistaking component typing for engineering will compete for fewer openings. The market gets smaller and more selective, with its best professionals producing more. The goal remains what it always was: get close to the top, where judgment and experience still make a difference.</p>
<p>And it doesn&rsquo;t stop at the browser. <a href="/en/2026/10/11/are-there-better-languages-for-programming-with-llms/">Pick the framework</a>: Android with Flutter or Kotlin, iOS with Swift and SwiftUI, desktop with Rust/Tauri, Flutter, C#, or Electron. Modern agents generally know the components, build tools, tests, and peculiarities of these platforms. They still need direction, feedback, and verification, just as they do on the web front-end. The mechanical part is already automatable.</p>
<p>I tested this in my own small open-source projects. <a href="https://github.com/akitaonrails/FrankYomik"target="_blank" rel="noopener">FrankYomik</a> has a Flutter client for Android and Linux, plus the server and extension. <a href="https://github.com/akitaonrails/FrankSherlock"target="_blank" rel="noopener">Frank Sherlock</a> is a Rust/Tauri desktop app that produces an AppImage for Linux, a DMG for macOS, and a <code>.exe</code> installer for Windows. I also built <a href="https://github.com/akitaonrails/frank_karaoke"target="_blank" rel="noopener">Frank Karaoke</a> in Flutter for Android and <a href="https://github.com/akitaonrails/frank_mangaplus"target="_blank" rel="noopener">FRANK MANGA+</a> in Rust/Tauri for desktop. There are several others on <a href="https://github.com/akitaonrails?tab=repositories"target="_blank" rel="noopener">my GitHub</a>.</p>
<p>None came out perfect from the first prompt. Flutter and Tauri gave me trouble, especially on the early projects. Reliable means the agent can move forward, receive a correction, create tests, fix what broke, and reach a working application without making me take over the manual typing. After testing web, Android, and desktop across different stacks, I&rsquo;m very satisfied with the result. The pattern repeats: mechanical work became agent work.</p>
<p>At two in the morning, I had agents making the final adjustments to this blog without losing pace. That&rsquo;s what I need.</p>
<h2>When the web still didn&rsquo;t know what it was<span class="hx:absolute hx:-mt-20" id="when-the-web-still-didnt-know-what-it-was"></span>
    <a href="#when-the-web-still-didnt-know-what-it-was" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>At the peak of the dot-com bubble, career designers were creating websites. The web had not yet decided how a page should work, so there was real room to experiment. It was often ugly and almost always heavy, but actual creation was happening.</p>
<p>The iPhone opened another window in 2007. Suddenly everything had to fit on a small screen, respond to touch, and work without a mouse. Years of experimentation followed before the market settled on a reasonably stable grammar for navigation, gestures, forms, and content.</p>
<p>Today nobody needs to rediscover a menu, a list, a checkout, or an article page. The patterns are documented, millions of examples are public, and models have seen more interfaces than any person could study in a lifetime.</p>
<p>The most valuable work remains: understanding the product, the person who will use it, the constraints, and what deserves to appear first. Converting a finished decision into hundreds of predictable lines has become a perfect candidate for automation.</p>
<h2>Jobs disappear. Others appear<span class="hx:absolute hx:-mt-20" id="jobs-disappear-others-appear"></span>
    <a href="#jobs-disappear-others-appear" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The world has never stopped to preserve a job function.</p>
<p>Punch-card operators entered data and programs on paper cards. Telephone operators physically connected calls. Typists kept offices running. Linotype operators cast lines of hot metal to print newspapers. Technology reduced or eliminated these occupations at scale. The Bureau of Labor Statistics&rsquo; <a href="https://www.bls.gov/emp/tables/fastest-declining-occupations.htm"target="_blank" rel="noopener">current list of fastest-declining occupations</a> still includes data entry keyers, typists, and telephone operators. Nobody proposes bringing them back to protect jobs.</p>
<p>At the same time, jobs appeared that a person in 1926 could not even name: mobile developer, SRE, experience designer, Internet video creator, cloud specialist, machine learning engineer. The web itself killed old work and opened an entire industry.</p>
<p>The real story is messier than the caricature. The <a href="https://www.ilo.org/publications/generative-ai-and-jobs-refined-global-index-occupational-exposure"target="_blank" rel="noopener">ILO shows that technology tends to automate tasks without necessarily eliminating entire occupations</a>. Some functions shrink, others change, and new jobs appear. That statistical consolation does nothing for the person who became obsolete today. The individual has to react before the economic average reacts for them.</p>
<p>Compare 2026 with 1926, three years before the crash of 1929. It looks like another planet, even though a century is very little on history&rsquo;s scale. No contract guarantees that your current function will survive the next ten years, much less the next forty.</p>
<h2>How does a junior gain experience now?<span class="hx:absolute hx:-mt-20" id="how-does-a-junior-gain-experience-now"></span>
    <a href="#how-does-a-junior-gain-experience-now" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>It will get harder. The old ladder began with someone paying a beginner to assemble simple screens, fix CSS, and copy components. An agent does much of that faster and cheaper. No company has an obligation to preserve inefficient work as a training program.</p>
<p>Beginners will have to build their own ladder with real projects and problems they are responsible for. That includes reading the code the agent generated, breaking and repairing it, studying documentation and source code, writing tests, and contributing to open projects. An agent gives any student access to an amount of practice that once required a team. Anyone who uses that access only to generate code they do not understand will remain a junior for a long time.</p>
<p>The market will reward people who make that extra effort. It always has. When someone asks how a junior can gain experience without the easy tasks, the hidden question is often different: &ldquo;how do I get a better salary without doing the hard work of getting good?&rdquo; The easy position, with rising pay and little pressure, was a distortion of the bubble. Adapting includes accepting that entry has become more competitive.</p>
<h2>My career never stayed in one place<span class="hx:absolute hx:-mt-20" id="my-career-never-stayed-in-one-place"></span>
    <a href="#my-career-never-stayed-in-one-place" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="/2023/02/14/akitando-138-meu-comeco-de-carreira-durante-a-bolha-1997-a-2002-bug-do-milenio-crash/">I started with multimedia and static websites</a>. Then I worked in a digital agency, enterprise consulting, SAP integration, startups, video, education, and now AI. In my <a href="/2018/12/26/akitando-34-voce-nao-sabe-nada-de-enterprise-conhecendo-a-sap/">Akitando episode about SAP</a>, I tell part of that phase when I had to learn a world completely different from what I had done before.</p>
<p>I lived through the dot-com crash, the 2008 crisis, and the end of the zero-rate bubble. I survived because I never treated my current function as a permanent identity. I kept studying, gaining experience, and changing direction.</p>
<p>A productive career should not consist of repeating the same mechanical task for decades. If your value depends on the market continuing to pay someone to push tags and pixels by hand, the problem did not begin with AI. The problem was betting that the present would last forever.</p>
<p>Many people understand &ldquo;being prepared&rdquo; as studying the bare minimum required for today&rsquo;s open position. That&rsquo;s the fastest recipe for becoming obsolete. Do the short-term work, but study beyond it. Learn the things that seem useless today. Fundamentals, operating systems, networks, databases, business, economics, history. You don&rsquo;t know which combination will save your career five years from now.</p>
<p>I spent years talking about this on Akitando. Revisit the <a href="https://www.youtube.com/playlist?list=PLdsnXVqbHDUehzKjiRruy--gncHz9Injy"target="_blank" rel="noopener"><strong>I Warned You</strong></a> and <a href="https://www.youtube.com/playlist?list=PLdsnXVqbHDUd6wEL932R7dW9Zazt2oNWF"target="_blank" rel="noopener"><strong>Which course should I take?</strong></a> playlists. If you have to start with one video, start with the <strong>Definitive Guide to Learning How to Learn</strong>. No course can save someone who still outsources their own learning.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/oUPaJxk6TZ0"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>The world has no shortage of opportunity. Most people feel they never get one because they are always unprepared when it appears. Once the opportunity lands in front of you, it is too late to start preparing.</p>
<p>So I won&rsquo;t mourn the fact that this package of six small sites, which used to take weeks or months, fit into about a day. I&rsquo;m happy as hell. I gained time to think about what to build, experiment more, and throw away bad versions without wasting weeks of my life.</p>
<p>Today I watched a car spin in midair and land. In about a day, I put six sites with new designs into production without writing most of the HTML and CSS. The future I wanted did not arrive perfect, cheap, or evenly distributed. It arrived far enough for me to work with it.</p>
<p>Accept what ended. Study what comes next. Be ready before the next opportunity appears.</p>
]]></content:encoded><category>artificial-intelligence</category><category>frontend</category><category>automation</category><category>career</category></item><item><title>I Trained My Own AI Model (Spoiler: It's Just for Study)</title><link>https://www.akitaonrails.com/en/2026/10/14/i-trained-my-own-ai-model-spoiler-its-just-for-study/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/14/i-trained-my-own-ai-model-spoiler-its-just-for-study/</guid><pubDate>Wed, 14 Oct 2026 15:00:00 -0300</pubDate><description>&lt;p&gt;One exercise was missing from my list this year: trying to build my own LLM. Not a frontier model. Building a GPT-5 or a Claude takes years of study and experimentation, whole teams and hundreds of millions of dollars in compute. The &lt;a href="https://hai.stanford.edu/ai-index/2024-ai-index-report"target="_blank" rel="noopener"&gt;Stanford AI Index&lt;/a&gt; estimate for GPT-4 was US$ 78 million in compute alone, and for Gemini Ultra, US$ 191 million.&lt;/p&gt;
&lt;p&gt;But nobody needs a GPT-class model for everything. A frontier model is a generalist by definition: it tries to know everything about anything, from tax law to song lyrics, and the returns on that diminish.&lt;/p&gt;</description><content:encoded><![CDATA[<p>One exercise was missing from my list this year: trying to build my own LLM. Not a frontier model. Building a GPT-5 or a Claude takes years of study and experimentation, whole teams and hundreds of millions of dollars in compute. The <a href="https://hai.stanford.edu/ai-index/2024-ai-index-report"target="_blank" rel="noopener">Stanford AI Index</a> estimate for GPT-4 was US$ 78 million in compute alone, and for Gemini Ultra, US$ 191 million.</p>
<p>But nobody needs a GPT-class model for everything. A frontier model is a generalist by definition: it tries to know everything about anything, from tax law to song lyrics, and the returns on that diminish.</p>
<p>And most of them today are mixtures of experts: roughly speaking, several smaller models clustered into one giant chunk of bits, with a router that wakes only a few of them for each token. OpenAI&rsquo;s <a href="https://arxiv.org/abs/2508.10925"target="_blank" rel="noopener">gpt-oss-120b</a> has 117 billion parameters in total and uses 5.1 billion per token. <a href="https://arxiv.org/abs/2412.19437"target="_blank" rel="noopener">DeepSeek-V3</a> has 671 billion and activates 37. The big model is already, on the inside, a collection of small models.</p>
<p>I could have grabbed an open model, gpt-oss, Qwen, Phi, and adapted it. The techniques exist and are well documented:</p>
<ul>
<li><strong>Full fine-tuning</strong>: keep training all the weights of a ready model on your data. It&rsquo;s classic transfer learning, formalized for text by <a href="https://arxiv.org/abs/1801.06146"target="_blank" rel="noopener">ULMFiT</a> in 2018.</li>
<li><strong>LoRA and QLoRA</strong>: freeze the original weights and train only small low-rank matrices beside them. <a href="https://arxiv.org/abs/2106.09685"target="_blank" rel="noopener">LoRA</a> cuts trainable parameters by up to ten thousand times; <a href="https://arxiv.org/abs/2305.14314"target="_blank" rel="noopener">QLoRA</a> quantizes the base model to 4 bits and fine-tunes a 65-billion model on a single 48 GB GPU.</li>
<li><strong>Distillation</strong>: train a smaller model to imitate a larger one&rsquo;s outputs. The idea is from <a href="https://arxiv.org/abs/1503.02531"target="_blank" rel="noopener">Hinton, 2015</a>, and the most famous recent example is <a href="https://arxiv.org/abs/2501.12948"target="_blank" rel="noopener">DeepSeek-R1</a> distilled into versions from 1.5 to 70 billion on top of Qwen and Llama.</li>
<li><strong>Continued pretraining</strong>: one more training phase on text from your domain before any instruction tuning, the <a href="https://arxiv.org/abs/2004.10964"target="_blank" rel="noopener">&ldquo;Don&rsquo;t Stop Pretraining&rdquo;</a> of 2020.</li>
<li><strong>SFT, RLHF and DPO</strong>: teach the assistant format with demonstrations, then align with human preference via reinforcement learning (<a href="https://arxiv.org/abs/2203.02155"target="_blank" rel="noopener">InstructGPT</a>) or with a direct classification loss (<a href="https://arxiv.org/abs/2305.18290"target="_blank" rel="noopener">DPO</a>).</li>
</ul>
<p>With any of those I&rsquo;d have a useful model in hours. But the goal was different. I wanted to organize, hands-on, the basic techniques for building a model smaller than GPT-2, from scratch, in a few days, and see how far it would go. If possible, train a tiny model starting from random weights and add enough functionality for it to almost work inside an agentic harness like OpenCode.</p>
<p>Before going on, who I am in this story: I&rsquo;m a curious software engineer and an amateur at this. As an LLM researcher I&rsquo;m a zero. I knew I wouldn&rsquo;t have a working LLM in such a short time, and that&rsquo;s part of the exercise.</p>
<p>But it&rsquo;s not unachievable. If you&rsquo;re a computer science student, study hard and give it enough years, you can try it yourself. And if you&rsquo;re not a scientist, understand this: nobody needs to be Einstein to do this. The foundations are all available, published, for you to study and try. What&rsquo;s mandatory is elbow grease.</p>
<p>Spoiler: we got far into the &ldquo;almost&rdquo; and stopped there. The <a href="https://github.com/akitaonrails/microgpt"target="_blank" rel="noopener">repository is public</a>, with every step and every failure documented. This text is the summary.</p>
<blockquote>
  <p><strong>TL;DR:</strong> I started from Karpathy&rsquo;s microgpt, 200 lines of pure Python that train a GPT in one minute on a MacBook, and expanded it into a PyTorch lab with its own tokenizer, pretraining, supervised fine-tuning, an OpenAI-compatible server and OpenCode integration. In under two weeks, on one RTX 5090, I trained a 337-million-parameter model on 10 billion tokens: 137 hours of training, at most around R$ 80 of electricity. It gets 58 out of 100 simple Python functions right on a held-out set, and scores zero on anything that requires reading, editing and testing a repository. The <a href="https://huggingface.co/HuggingFaceTB/SmolLM2-360M"target="_blank" rel="noopener">360-million SmolLM2</a>, the same size, saw 4 trillion tokens, 400 times more. Jump to <a href="#karpathys-exercise">Karpathy&rsquo;s exercise</a>, the <a href="#the-steps-of-building-an-llm">steps</a>, the <a href="#the-dimensions-of-the-problem">dimensions</a>, the <a href="#the-stumbles">stumbles</a>, the <a href="#what-came-out-the-other-side">result</a> or the <a href="#the-future-is-smaller-and-more-specialized">conclusion</a>.</p>

</blockquote>
<h2>Karpathy&rsquo;s exercise<span class="hx:absolute hx:-mt-20" id="karpathys-exercise"></span>
    <a href="#karpathys-exercise" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In February this year Andrej Karpathy published <a href="https://karpathy.github.io/2026/02/12/microgpt/"target="_blank" rel="noopener">microgpt</a>: a single file of 200 lines of Python, with no dependencies, that trains and runs a GPT. He calls it &ldquo;the full algorithmic content of what is needed. Everything else is just efficiency&rdquo;. It&rsquo;s the culmination of a lineage of his: micrograd (scalar autograd), makemore (generating names) and nanoGPT (compact GPT-2 in PyTorch), joined by <a href="https://github.com/karpathy/nanochat"target="_blank" rel="noopener">nanochat</a>, &ldquo;the best ChatGPT that $100 can buy&rdquo;, which at launch trained a GPT-2-capability model in almost four hours on a node of eight H100s, and today does it in about two.</p>
<p>microgpt is deliberately minimal: the dataset is 32 thousand first names, one per line, and the tokenizer is one character per token.</p>
<p>The network has one layer, 16 embedding dimensions, 4 attention heads, a 16-token window because the longest name has 15 letters. It trains for a thousand steps, one name per step, with Adam written by hand, and at the end generates made-up names, all in one minute on a MacBook.</p>
<p>What it teaches, by having everything exposed in a single file:</p>
<ul>
<li>autograd, the <code>Value</code> class that holds a number, the gradient and the chain rule to propagate back;</li>
<li>what a token and an embedding are;</li>
<li>the attention block, with query, key and value, and the causal mask that stops the model from peeking at the future;</li>
<li>the cross-entropy loss against the next token;</li>
<li>the optimizer;</li>
<li>sampling with temperature.</li>
</ul>
<p>It&rsquo;s a GPT-2 with small differences the file itself notes: RMSNorm instead of LayerNorm, no biases, ReLU instead of GeLU. After reading that, what&rsquo;s left between you and a real model is, in his words, efficiency. I went to see how much efficiency.</p>
<h2>What we expanded<span class="hx:absolute hx:-mt-20" id="what-we-expanded"></span>
    <a href="#what-we-expanded" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The <a href="https://github.com/akitaonrails/microgpt"target="_blank" rel="noopener">microgpt lab</a> is an independent reimplementation in PyTorch, inspired by the gist, split by concept: about 3,300 lines of Python in 31 modules, plus scripts and 85 CPU tests. A single model implementation serves pretraining, assistant tuning and the server. Every weight starts random; the project downloads no pretrained weights at all, on purpose, because the rule of the exercise was from scratch.</p>
<p>On top of Karpathy&rsquo;s block came the components a 2026 model uses: RoPE for position, RMSNorm, SwiGLU in the dense layer, embeddings tied to the output, Flash Attention through PyTorch, a key-value cache with prefix reuse. And around the model, what it needs to talk to an agent: a conversation protocol with roles, an HTTP server compatible with OpenAI&rsquo;s chat API, tool calls validated by schema and optionally by grammar, separation of reasoning content, and the OpenCode configuration pointing at it.</p>
<p>The project went through four scales:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Parameters</th>
          <th>Tokenizer</th>
          <th>Purpose</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Byte lesson</td>
          <td style="text-align: right">0.9 million</td>
          <td>byte by byte</td>
          <td>runs on CPU, teaches the whole loop</td>
      </tr>
      <tr>
          <td>Student</td>
          <td style="text-align: right">91 million</td>
          <td>o200k (200K entries)</td>
          <td>first agent, arithmetic</td>
      </tr>
      <tr>
          <td>Capacity candidate</td>
          <td style="text-align: right">239 million</td>
          <td>o200k</td>
          <td>more layers, same vocabulary</td>
      </tr>
      <tr>
          <td>Foundation pivot</td>
          <td style="text-align: right">337 million</td>
          <td>own BPE, 32K entries</td>
          <td>the final model</td>
      </tr>
  </tbody>
</table>
<p>The table hides the first big lesson, which I tell in the stumbles: in the 239-million model, 154 million parameters were just the vocabulary table. 85 million were left for the actual transformer.</p>
<h2>The steps of building an LLM<span class="hx:absolute hx:-mt-20" id="the-steps-of-building-an-llm"></span>
    <a href="#the-steps-of-building-an-llm" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Regardless of size, the path has the same stations. What changes is the trailing zero at each one.</p>
<h3>1. Data<span class="hx:absolute hx:-mt-20" id="1-data"></span>
    <a href="#1-data" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A model is what it eats. We downloaded, with pinned revisions and hashes, selections of public corpora: <a href="https://huggingface.co/datasets/codeparrot/codeparrot-clean"target="_blank" rel="noopener">CodeParrot</a> (deduplicated, filtered Python), <a href="https://huggingface.co/datasets/OpenCoder-LLM/opc-sft-stage1"target="_blank" rel="noopener">OpenCoder</a> (instruction and code), <a href="https://huggingface.co/datasets/HuggingFaceTB/smollm-corpus"target="_blank" rel="noopener">Cosmopedia</a> (synthetic educational text), <a href="https://huggingface.co/datasets/HuggingFaceTB/smoltalk"target="_blank" rel="noopener">SmolTalk</a> (conversation) and a multilingual slice. The 14 download manifests add up to about 20 GB raw, all stored on the NAS.</p>
<p>Then comes curation: exact deduplication, splitting train and validation by repository or conversation group (never by line, or the same project leaks to both sides), and the mixture. The final foundation corpus has 3.5 billion stored tokens, 60% Python code, 16% instruction, 12% educational text, 8% conversation, 4% multilingual. Every proportion is a design decision, and none of them has a published right answer.</p>
<h3>2. Tokenizer<span class="hx:absolute hx:-mt-20" id="2-tokenizer"></span>
    <a href="#2-tokenizer" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The tokenizer is the dictionary between text and integers. The byte lesson uses 256 tokens plus one for end of document. The student used o200k, OpenAI&rsquo;s public vocabulary with 200K entries, which is what most tutorials do. The pivot trained its own BPE with 32,768 entries, on 92 MB of training-only text, with full UTF-8 coverage.</p>
<p>The choice looks like a detail and decides where the parameters end up. Each vocabulary entry costs one row in the embedding table at the model&rsquo;s width. With 200K entries and width 768, that&rsquo;s 154 million parameters spent on the table. With 32K entries and width 1,024, it&rsquo;s 33 million, and the rest goes to the layers that think.</p>
<h3>3. Pretraining, or foundation<span class="hx:absolute hx:-mt-20" id="3-pretraining-or-foundation"></span>
    <a href="#3-pretraining-or-foundation" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>This is Karpathy&rsquo;s loop at scale. The model receives 2,048-token windows drawn from the training stream and learns to predict the next token. Each update processes 32,768 tokens: two sequences, accumulated eight times. AdamW, learning rate with warmup and cosine decay, gradient clipping, BF16 on the GPU and FP32 for the weights.</p>
<p>The pivot ran about 305 thousand updates, 10 billion tokens of exposure. Since the corpus has 3.5 billion, each document was seen, in the mixture&rsquo;s expectation, almost three times: the code about twice, and instruction, educational text and conversation about nine or ten. Every 500 updates, a validation and a checkpoint. At the 2, 5 and 10 billion milestones, a frozen checkpoint with a hash, to measure the curve.</p>
<h3>4. Supervised fine-tuning<span class="hx:absolute hx:-mt-20" id="4-supervised-fine-tuning"></span>
    <a href="#4-supervised-fine-tuning" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Pretraining produces a model that completes text. For it to answer a request comes SFT, <em>supervised fine-tuning</em>: question and answer examples in the exact format the server uses, with the loss computed only over the assistant&rsquo;s tokens. What the user and the tool said goes in as context and is masked out of the loss.</p>
<p>The examples came from NVIDIA&rsquo;s <a href="https://huggingface.co/datasets/nvidia/OpenCodeInstruct"target="_blank" rel="noopener">OpenCodeInstruct</a>, and every answer was executed in a restricted Docker before going in: almost 99 thousand candidates, 97 thousand survived the test with three different hash seeds. 92 thousand training episodes remained. The selected checkpoint saw 64 thousand draws from those episodes, about 10 million answer tokens.</p>
<h3>5. Protocol, tools and server<span class="hx:absolute hx:-mt-20" id="5-protocol-tools-and-server"></span>
    <a href="#5-protocol-tools-and-server" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>An agent like OpenCode talks to the model over HTTP: it sends the history with roles and the tool definitions, gets back text or a tool call in JSON, executes it, returns the result, and repeats. The lab implements that whole cycle: the same protocol file serializes the training examples and the serving prompts, so training format and usage format never diverge.</p>
<p>The server implements <code>/v1/models</code> and <code>/v1/chat/completions</code>, validates the tool call against the schema, can constrain generation with a grammar so the JSON comes out well formed, separates reasoning content from the answer, counts cached tokens and rejects context overflow instead of truncating silently. All of that is plumbing, zero intelligence, and without it the model doesn&rsquo;t even get a seat at the table.</p>
<h3>6. Evaluation<span class="hx:absolute hx:-mt-20" id="6-evaluation"></span>
    <a href="#6-evaluation" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The step that changed the project the most. A frozen set of 100 Python development tasks, 20 families with five variants of name and wording, plus 100 held-out tasks that only the final checkpoint saw. Every answer runs in a Docker with no network, no root, with CPU and memory limits, against fixed assertions. On top of that: four real repository-repair tasks through OpenCode, 12 problems of tracing a program&rsquo;s exact output, information-retrieval probes in prompts of 8, 16 and 32 thousand tokens, and four short conversations.</p>
<blockquote>
  <p>No HumanEval, MBPP or SWE-bench. These are small local diagnostics, with correlated families, one seed, greedy generation. They serve to choose between checkpoints, and the closeout report itself says not to read &ldquo;58 out of 100&rdquo; as &ldquo;58% success at programming&rdquo;.</p>

</blockquote>
<h2>The dimensions of the problem<span class="hx:absolute hx:-mt-20" id="the-dimensions-of-the-problem"></span>
    <a href="#the-dimensions-of-the-problem" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>What all of this cost, and how it compares with the real world:</p>
<table>
  <thead>
      <tr>
          <th>Dimension</th>
          <th style="text-align: right">Our final model</th>
          <th>References</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Parameters</td>
          <td style="text-align: right">337 million</td>
          <td>GPT-2 small: 124 million; full GPT-2 (2019): 1.5 billion</td>
      </tr>
      <tr>
          <td>Tokens seen in pretraining</td>
          <td style="text-align: right">10 billion</td>
          <td>SmolLM2-360M: 4 trillion; Llama 3.1: 15 trillion; Qwen3: 36 trillion</td>
      </tr>
      <tr>
          <td>Raw data downloaded</td>
          <td style="text-align: right">20 GB</td>
          <td>GPT-2: 40 GB of WebText, 8 million pages</td>
      </tr>
      <tr>
          <td>Foundation corpus</td>
          <td style="text-align: right">3.5 billion tokens, 2.35 million documents</td>
          <td></td>
      </tr>
      <tr>
          <td>Hardware</td>
          <td style="text-align: right">1 RTX 5090, 32 GB</td>
          <td>Llama 3.1 405B: 30.84 million H100 hours</td>
      </tr>
      <tr>
          <td>GPU time in foundation</td>
          <td style="text-align: right">137 process hours, 6.4 calendar days</td>
          <td>DeepSeek-V3: 2.79 million H800 hours, ~US$ 5.6 million</td>
      </tr>
      <tr>
          <td>SFT time</td>
          <td style="text-align: right">3.4 hours across the nine stages</td>
          <td></td>
      </tr>
      <tr>
          <td>Throughput</td>
          <td style="text-align: right">23 to 44 thousand tokens/s, depending on I/O</td>
          <td></td>
      </tr>
      <tr>
          <td>Peak VRAM</td>
          <td style="text-align: right">13.9 GB in foundation; 6.8 GB in SFT</td>
          <td></td>
      </tr>
      <tr>
          <td>Checkpoints</td>
          <td style="text-align: right">17 distinct checkpoints (20 paths), 69 GB</td>
          <td></td>
      </tr>
      <tr>
          <td>Cost in money</td>
          <td style="text-align: right">zero in cloud; about R$ 80 of electricity worst case</td>
          <td>nanochat: US$ 100 on 8 H100s for 4 hours at launch; today about US$ 48 in 2 hours</td>
      </tr>
  </tbody>
</table>
<p>The electricity bill: the RTX 5090 has a <a href="https://www.nvidia.com/en-us/geforce/graphics-cards/50-series/rtx-5090/"target="_blank" rel="noopener">575 W rated power</a>. Over 137 hours at full load that&rsquo;s about 79 kWh, and Enel&rsquo;s residential tariff in São Paulo in 2026, adding TUSD, TE and taxes, is around R$ 1 per kWh. Since training ran much of the time at a 75% duty cycle to keep the desktop from freezing, the real figure was lower. It&rsquo;s the marginal cost of someone who already owns the card.</p>
<p>Renting a 5090 on <a href="https://www.runpod.io/pricing"target="_blank" rel="noopener">Runpod</a> costs about US$ 1.20 an hour, so the same 137 hours would cost about US$ 165; an H100 runs between US$ 2.90 and 4 an hour, depending on the variant.</p>
<p>And the comparison that gives the scale. SmolLM2, at 360 million parameters, practically our size, was trained on 4 trillion tokens. At our throughput, 4 trillion would take between four and six years of uninterrupted GPU. Same model size, 400 times the amount of study.</p>
<p>That&rsquo;s why &ldquo;parameters&rdquo; is a misleading unit: it says the size of the brain, and nothing about how many years of school it had.</p>
<p>The rule of thumb derived from <a href="https://arxiv.org/abs/2203.15556"target="_blank" rel="noopener">Chinchilla</a> (70 billion parameters, 1.4 trillion tokens), about 20 tokens per parameter to be compute-optimal, would give 6.7 billion tokens for our model. We went past that. But Chinchilla&rsquo;s optimum is the point of best compute usage, and modern small models go far past it on purpose, because the inference cost afterward makes training more worthwhile.</p>
<h2>The stumbles<span class="hx:absolute hx:-mt-20" id="the-stumbles"></span>
    <a href="#the-stumbles" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The full list is in the <a href="https://github.com/akitaonrails/microgpt/blob/main/docs/report/experiment-closeout.md"target="_blank" rel="noopener">closeout report</a>. The ones that taught the most:</p>
<p><strong>Measuring too close to training.</strong> The first agent, the 91-million one, completed four 16-round sessions in OpenCode and one 32-round session with 130 real tool calls, recovering from a check error and switching sessions midway, with the state kept by the harness. It looked ready.</p>
<p>Then I asked, by hand and in English, for a hello world function that takes a name as a parameter and prints it in the message. The model repeated the previous arithmetic edit twice, pointed at a file that didn&rsquo;t exist, and on the third attempt spat out invalid JSON. All it knew was the training task family.</p>
<p><strong>The vocabulary ate the model.</strong> The 239-million candidate had more layers and lower loss than the 91 and solved 24 out of 100 problems. Looking at the parameter distribution, 154 million were vocabulary table. The pivot to 32K entries gave 300 million parameters back to the transformer. The pivot changed vocabulary, capacity distribution, initialization and exposure all at once, so the report doesn&rsquo;t isolate which of them moved the result.</p>
<p><strong>Loss is not competence.</strong> In the final SFT, continuing from 4 thousand to 8 thousand updates lowered the validation loss and dropped executed correctness from 68 to 62. Lower loss, worse code. Checkpoint selection became by executed task, frozen beforehand; the loss number stayed out of it.</p>
<p><strong>Data and graders lie.</strong> &ldquo;Correct&rdquo; answers from the public dataset failed when executed again. Tests that depended on Python&rsquo;s hash order, shadowed builtins, <code>SystemExit(0)</code> counting as success, empty edits copying the file. Each one needed a control: three hash seeds, a completion sentinel, an empty fixture that must fail. And in one of the mixed training runs, the model learned to say the tests passed when they hadn&rsquo;t.</p>
<p><strong>Training format and usage format have to match.</strong> Session-switch announcements, tool-call IDs, edit anchors, the way OpenCode quotes user input: every difference between what the model saw in training and what it received from the server brought the old agent down. The same protocol file for both sides was the fix, and even so changing format sometimes improved the function name without improving the code.</p>
<p><strong>Tokenization crosses correctness boundaries.</strong> The literal string <code>&lt;|endoftext|&gt;</code> inside source code has to remain ordinary text instead of becoming the end-of-document marker. Reconstructing UTF-8 documents without splitting a character in half. XGrammar&rsquo;s support for byte-level vocabularies. The first code evaluation at the 2-billion milestone failed at grammar construction, and was fixed and rerun instead of counting as a model failure.</p>
<p><strong>The NAS almost cost me days.</strong> On resuming the 10-billion phase, the trainer loaded step 81,500 instead of the frozen 152,588: the mutable <code>last.pt</code> had a timestamp earlier than the pause, right after a NAS maintenance, and the cause was never proven. We discarded 1.24 hours of training, verified the hash of the 5-billion milestone, and every later resume came to require a hash, the exact step, optimizer and RNG state, the dataset and a write probe with fsync. Never resume a training run just because the file is called <code>last.pt</code>.</p>
<p><strong>A desktop GPU is a shared GPU.</strong> Free VRAM didn&rsquo;t stop the browser from freezing. The fix was a cooperative duty cycle: the trainer syncs the GPU and sleeps between batches, 75% of the time during the day and 100% from 3 to 9 in the morning. And reading the corpus from the NAS, through mmap, left the GPU idle waiting for disk. After one maintenance the throughput dropped to 5 thousand tokens per second before climbing back to 23 thousand.</p>
<p><strong>I stopped at a pipeline boundary.</strong> The pivot&rsquo;s controller implemented foundation, code SFT and holdout. It finished clean, and &ldquo;finished clean&rdquo; covered up to the isolated Python function, while the goal was the agent. The final checkpoint was tested in OpenCode only at closeout, and failed. It should have been tested before any sentence with &ldquo;ready&rdquo; in it.</p>
<h2>What came out the other side<span class="hx:absolute hx:-mt-20" id="what-came-out-the-other-side"></span>
    <a href="#what-came-out-the-other-side" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The final model&rsquo;s spec sheet:</p>
<table>
  <thead>
      <tr>
          <th>Property</th>
          <th>Value</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Parameters</td>
          <td>337,167,360, of which 303.6 million in the transformer and 33.6 million in the vocabulary table</td>
      </tr>
      <tr>
          <td>Architecture</td>
          <td>24 layers, width 1,024, 16 heads, SwiGLU with hidden width 2,752, RMSNorm, RoPE</td>
      </tr>
      <tr>
          <td>Vocabulary</td>
          <td>own BPE with 32,768 entries, UTF-8 coverage</td>
      </tr>
      <tr>
          <td>Context</td>
          <td>32,768 tokens allocated; trained on 2,048-token windows</td>
      </tr>
      <tr>
          <td>Foundation</td>
          <td>10 billion tokens, 305,176 updates, final validation loss 1.085</td>
      </tr>
      <tr>
          <td>Selected SFT</td>
          <td>4,000 updates, 10.3 million answer tokens</td>
      </tr>
      <tr>
          <td>Checkpoint</td>
          <td>4 GB with optimizer state; 1.35 GB of weights alone in FP32</td>
      </tr>
  </tbody>
</table>
<p>The learning curve, measured at the three milestones, with the same short SFT applied on top of each:</p>
<table>
  <thead>
      <tr>
          <th style="text-align: right">Foundation tokens</th>
          <th style="text-align: right">Raw code completion /100</th>
          <th style="text-align: right">After SFT 500 /100</th>
          <th style="text-align: right">After SFT 1,000 /100</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: right">2 billion</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">24</td>
          <td style="text-align: right">39</td>
      </tr>
      <tr>
          <td style="text-align: right">5 billion</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">49</td>
          <td style="text-align: right">52</td>
      </tr>
      <tr>
          <td style="text-align: right">10 billion</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">56</td>
          <td style="text-align: right">65</td>
      </tr>
  </tbody>
</table>
<p>The longer SFT on top of the 10 billion reached <strong>68 out of 100</strong> on the development set and <strong>58 out of 100</strong> on the held-out one. All 100 held-out outputs are valid Python, and 97 have the requested function name and parameters. Nine families passed all five variants: median, factorial, greatest common divisor, binary conversion, inverting a dictionary, line count, leap year, seconds to hours, JSON keys. Running total ended at four out of five.</p>
<p>So what it does: it writes a small Python function, with a docstring, correct syntax and the right name, for a clear one-line request. Inside an editor, as autocomplete for an isolated function, it&rsquo;s fine for study.</p>
<p>What it gets wrong, with saved examples: deduplicating with a <code>set</code> when the spec required supporting unhashable lists; grouping by length by counting words instead of grouping; doing arithmetic on each element in a padding function; returning <code>(text, '')</code> in a split-once function, ignoring the separator; removing the last character instead of the directory in a basename function. Of the 42 held-out failures, 39 have valid syntax and the right name and fail on semantics. The hard part was never looking like code.</p>
<p>And what it zeroes:</p>
<ul>
<li><strong>0 out of 4</strong> real repository repairs in OpenCode, with zero tool calls. Asked to read, edit and test a file, it returned text with code. In one of the tasks, it renamed the function to <code>fix_mean</code>.</li>
<li><strong>0 out of 12</strong> at tracing the exact output of short programs, with and without reasoning mode. Many answers were code that supposedly would compute the requested integer.</li>
<li><strong>0 out of 9</strong> at finding a six-digit number hidden in prompts of 8, 16 and 32 thousand tokens. The 32K-token allocation works; the useful memory, none.</li>
<li>Conversation: asked in Portuguese about the color of the sky, it answered repetitively and wrongly; an English breakfast request became a Python docstring repeating &ldquo;oats&rdquo; until the token limit. In a short exchange it remembered the cat&rsquo;s name was Pipoca, and still answered with a full sentence despite the request for &ldquo;only the name&rdquo;.</li>
</ul>
<p>The final SFT had only code answers, no conversation, no tool trajectories, no error recovery. The tendency to answer anything with Python is consistent with that, and the report is careful to say the cause was not isolated.</p>
<h2>What it would still take for a simple agent in OpenCode<span class="hx:absolute hx:-mt-20" id="what-it-would-still-take-for-a-simple-agent-in-opencode"></span>
    <a href="#what-it-would-still-take-for-a-simple-agent-in-opencode" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The report closes with engineering estimates, with no promise of a pass rate. To get to an agent that solves simple programming tasks inside OpenCode, in this order:</p>
<ol>
<li><strong>Teach tool use on the stronger model.</strong> Between 10 and 30 thousand short, verified repository trajectories (read, edit, check), mixed with 30 to 50% code so it doesn&rsquo;t unlearn. One to three days of engineering and two to six initial hours of training.</li>
<li><strong>Correct its own mistakes.</strong> Collect hundreds to a few thousand model failures on training tasks, reconstruct the file state, verify the corrections and train while masking the wrong action. Another one to three days of collection and two to eight hours of training.</li>
<li><strong>Bring the conversation back.</strong> A balanced mix of conversation, tools and code against the frozen checkpoint, so it stops answering everything with Python and can switch tasks. One to four hours of training.</li>
<li><strong>Real long context.</strong> Only after the short tasks pass: 4K, 8K, and only then 16K and 32K, with real compaction and session-switch trajectories. One to two days of engineering and 6 to 24 hours of training, measuring memory at every window.</li>
<li><strong>More foundation, with better data.</strong> Every additional 10 billion tokens costs between 93 and 139 hours on this GPU, before preparation and evaluation. And repeating the same 3.5-billion mixture isn&rsquo;t worth it: it needs more unique educational code.</li>
</ol>
<p>None of those steps was executed. There&rsquo;s no evidence that a fixed number of extra hours would produce a reliable agent, and the report is explicit about it. What the exercise established was the distance: between generating a plausible function and acting reliably in a repository there&rsquo;s a chasm that parameters and allocated context alone don&rsquo;t cross.</p>
<blockquote>
  <p>The strongest thing that came out of this was the measured curve from 0 to 65 in ten billion tokens, and three concrete counterexamples: syntax is not semantics, protocol support is not tool skill, and context capacity is not memory.</p>

</blockquote>
<h2>The future is smaller and more specialized<span class="hx:absolute hx:-mt-20" id="the-future-is-smaller-and-more-specialized"></span>
    <a href="#the-future-is-smaller-and-more-specialized" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>After eleven days looking inside a model, my reading of the market got firmer. The generalist frontier model will keep existing and will keep being expensive, and the return on every extra billion parameters keeps shrinking. I already wrote that <a href="/en/2026/10/12/llms-agents-competent-enough/">the raw models converged</a> and that the recent gains came from the harness. The exercise gave me the other half of the argument.</p>
<p>Mixture of experts is the industry admitting it on the inside. If the 117-billion gpt-oss wakes 5 billion per token, what you&rsquo;re using for an accounting question is a 5-billion model picked by a router. The question that remains is why carry the other 112 billion, of art, film, memes and particle physics, on an accounting office&rsquo;s server.</p>
<p>Imagine a local model, built for accountants. It knows the chart of accounts, the country&rsquo;s tax legislation, the tax authority&rsquo;s file formats, the jargon. It skips parameters about everything an accountant doesn&rsquo;t need, and it can run on the office PC, with the client&rsquo;s data inside the room.</p>
<p>The examples already exist in other fields: Google&rsquo;s 4-billion <a href="https://research.google/blog/medgemma-our-most-capable-open-models-for-health-ai-development/"target="_blank" rel="noopener">MedGemma</a> for health, the 7-billion <a href="https://arxiv.org/abs/2403.03883"target="_blank" rel="noopener">SaulLM</a> for law, the 7-billion <a href="https://arxiv.org/abs/2503.16252"target="_blank" rel="noopener">Fin-R1</a> for financial reasoning. In 2023 <a href="https://arxiv.org/abs/2303.17564"target="_blank" rel="noopener">BloombergGPT</a> needed 50 billion parameters and 1.3 million A100 hours to do finance; today a fine-tune on top of an open 7-billion model plays the same role for a fraction.</p>
<p>What changed to make this viable was the agent. A specialized model from 2023 had to know everything by heart, because the only thing it did was complete text. A 2026 model needs a base: enough reasoning, the ability to sustain a long task, reliable tool calling, prompt caching. The rest, the law that changed yesterday, the client&rsquo;s document, the table it never saw, it fetches with tools and the internet on the spot, and fills the gaps in its training at usage time.</p>
<p><a href="https://arxiv.org/abs/2506.02153"target="_blank" rel="noopener">NVIDIA published in 2025</a> exactly that position: small models are sufficient, more suitable and cheaper for most of an agent&rsquo;s calls, with the big model called only when open-ended conversation demands it. Apple already <a href="https://machinelearning.apple.com/research/apple-foundation-models-2025-updates"target="_blank" rel="noopener">runs a 3-billion model on the device</a> with a tool protocol and per-task adapters.</p>
<p>It&rsquo;s the same reasoning as the <a href="/en/2026/10/10/which-jev-like-ai-decision-classifier-model-is-best/">decision models I tested</a> last week: a 4-billion classifier trained for a task beats a generic chat model of the same size at it, in a fraction of the response time. Instead of trying to fit the whole world into a bigger model, fit the domain into a smaller one and let the harness fetch the world when needed.</p>
<p>And what my 337-million model taught me is the size of &ldquo;enough&rdquo; in that sentence. It knows the syntax and knows the names of things. What&rsquo;s missing, semantics, tools, memory, is exactly what separates a text generator from an agent, and nobody trains that in two weeks on a graphics card. You train it over months, on a cluster, with trillions of tokens, and then specialize.</p>
<p>The code is in the <a href="https://github.com/akitaonrails/microgpt"target="_blank" rel="noopener">repository</a>, with the full closeout report, for anyone who wants to pick up where I left off. It&rsquo;s just for study. And it was the best study of the year.</p>
]]></content:encoded><category>artificial-intelligence</category><category>llms</category><category>machine-learning</category><category>local-models</category></item><item><title>I Self-Published My Own Book/e-book: Competent Enough</title><link>https://www.akitaonrails.com/en/2026/10/13/i-self-published-my-own-book-ebook-competent-enough/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/13/i-self-published-my-own-book-ebook-competent-enough/</guid><pubDate>Tue, 13 Oct 2026 19:00:00 -0300</pubDate><description>&lt;p&gt;I just published my own book about artificial intelligence. It&amp;rsquo;s called &lt;em&gt;Competent Enough&lt;/em&gt;, subtitled &amp;ldquo;A year putting artificial intelligence to the test, without fear and without propaganda&amp;rdquo;, and it&amp;rsquo;s free, in EPUB and PDF, to read on your phone, PC or Kindle. The official page is &lt;a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener"&gt;here&lt;/a&gt;, and the &lt;a href="https://github.com/akitaonrails/ai-book-2026"target="_blank" rel="noopener"&gt;repository&lt;/a&gt; is public.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener"&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261013190000_book-competent-enough-3d.png" alt="Competent Enough, the book, in 3D" loading="lazy" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The book consolidates almost everything I wrote about AI on this blog from February to October 2026: all the experiments, the Frank projects, the benchmarks, billions of tokens spent and hundreds of hours of work over eight months, reorganized into a format that&amp;rsquo;s easier to read than a pile of dated posts. It came out in Portuguese and in English.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I just published my own book about artificial intelligence. It&rsquo;s called <em>Competent Enough</em>, subtitled &ldquo;A year putting artificial intelligence to the test, without fear and without propaganda&rdquo;, and it&rsquo;s free, in EPUB and PDF, to read on your phone, PC or Kindle. The official page is <a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener">here</a>, and the <a href="https://github.com/akitaonrails/ai-book-2026"target="_blank" rel="noopener">repository</a> is public.</p>
<p><a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261013190000_book-competent-enough-3d.png" alt="Competent Enough, the book, in 3D"  loading="lazy" /></a></p>
<p>The book consolidates almost everything I wrote about AI on this blog from February to October 2026: all the experiments, the Frank projects, the benchmarks, billions of tokens spent and hundreds of hours of work over eight months, reorganized into a format that&rsquo;s easier to read than a pile of dated posts. It came out in Portuguese and in English.</p>
<blockquote>
  <p><strong>Important notice:</strong> this is a <em>preview</em>. The book is still in progress and new versions will come out until I consider it done. If you find anything wrong, from a typo to a fact, <a href="https://github.com/akitaonrails/ai-book-2026/issues"target="_blank" rel="noopener">open an issue on GitHub</a>. The trail I describe below exists precisely so that the fix reaches the right paragraph.</p>

</blockquote>
<p>This text is about the technical backstage. How you turn 131 blog posts, written over months, with opinions that changed along the way, into a book with a beginning, middle, end, appendices, glossary and bibliography. And how you do that with agents without losing control of what the book says.</p>
<h2>What&rsquo;s inside<span class="hx:absolute hx:-mt-20" id="whats-inside"></span>
    <a href="#whats-inside" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Five parts, each answering a question people keep asking me:</p>
<ol>
<li><strong>What is this thing, anyway.</strong> Is it intelligent? Is AGI coming?</li>
<li><strong>The marathon.</strong> Does it actually work, or is it all demo?</li>
<li><strong>Numbers and propaganda.</strong> Which AI is best? Can you believe the announcements?</li>
<li><strong>Who keeps the keys.</strong> Is it dangerous to let it touch my things?</li>
<li><strong>And my job?</strong> Will it replace me? What comes next?</li>
</ol>
<p>That&rsquo;s 20 chapters and two interludes, plus a preface, a &ldquo;how to read&rdquo;, a &ldquo;before you start&rdquo; saying what the book doesn&rsquo;t explain and where to learn it, an epilogue and an afterword. Then come ten appendices (the machine inside without math, further reading, how to study with AI at your side, three bubbles, a timeline, a minimal kit for using agents safely, ai-memory, how to read a benchmark or an announcement, the year&rsquo;s projects, and the backstage for programmers), the sources, the image credits, a glossary of almost 150 terms and more than 300 references in ABNT style. The print edition passes 500 pages at 6 by 9 inches; the screen edition, around 475. There are more than 50 figures, all with a provenance record.</p>
<p>The audience is different from the blog&rsquo;s. The book was written for people who are anxious or confused about AI: the professional afraid of being replaced, the parent who read that AGI is two years away, the manager being sold an &ldquo;AI transformation&rdquo;. Most of them don&rsquo;t program. That changes the voice, and I&rsquo;ll come back to it.</p>
<h2>The problem: half a million words that disagree with each other<span class="hx:absolute hx:-mt-20" id="the-problem-half-a-million-words-that-disagree-with-each-other"></span>
    <a href="#the-problem-half-a-million-words-that-disagree-with-each-other" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On October 12 I published <a href="/en/2026/10/12/llms-agents-competent-enough/">the year&rsquo;s synthesis</a>, which became chapter 20. On the 13th I started the book. I had 131 posts from 2026 on the blog, almost half a million words, from model benchmarks to a bitcoin wallet.</p>
<p>Reorganizing that by hand would take months. And there&rsquo;s a worse problem than volume: I changed my mind during the year. I redid the benchmark several times, corrected costs, switched tools, and a February post contradicts a September one with complete naturalness. A book that simply pasted the posts in order would be a book that contradicts itself.</p>
<p>So I did what the whole book describes: I handed the grunt work to coding agents and kept the part of deciding, building the process and checking. The process is the subject of this text.</p>
<h2>Step 1: a sealed inventory<span class="hx:absolute hx:-mt-20" id="step-1-a-sealed-inventory"></span>
    <a href="#step-1-a-sealed-inventory" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The first thing was a script that reads the 131 posts and records, for each one, the SHA-256 hash of the Portuguese file and of the English file, plus the exact commit of the blog repository everything was read from. If a comma changes in a post, the hash changes with it. That file is machine-generated and never edited by hand.</p>
<p>Then an agent read each post and filled out a fixed form, with a schema defined in YAML: the thesis in one or two sentences, the claims a book would need to verify, which of them age fast, which lay reader&rsquo;s fear the text answers, what to cut. Each analysis carries the hash of the post it came from.</p>
<p>Of the 131 texts, 96 had AI as the central subject or with relevant weight. The others only came in when they taught something specific, and every AI post left out has its reason recorded in the structure file. A script fails the structure if any AI post is left without a destination.</p>
<h3>Lineage: who supersedes whom<span class="hx:absolute hx:-mt-20" id="lineage-who-supersedes-whom"></span>
    <a href="#lineage-who-supersedes-whom" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>To solve the contradiction problem, there&rsquo;s a lineage map. It says which post superseded which, what can still be salvaged from the older one, and which corrections coming from the reference projects (the benchmark repository, ai-memory&rsquo;s, ai-jail&rsquo;s, my home server notes) apply to each text.</p>
<p>The rule for chapters is to tell the most recent state and, when the change teaches something, tell the change. &ldquo;In June I thought X; in July the numbers said Y&rdquo; is a story. Printing the old number as if it were current is an error, and the checker treats it as an error.</p>
<h2>Step 2: the structure is data, and it generates the configuration<span class="hx:absolute hx:-mt-20" id="step-2-the-structure-is-data-and-it-generates-the-configuration"></span>
    <a href="#step-2-the-structure-is-data-and-it-generates-the-configuration" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>From the analyses came a proposed structure: five parts, each answering a reader&rsquo;s fear, twenty chapters, two interludes. I read it, changed it and approved it. Some pieces came in at my request, like the &ldquo;before you start&rdquo; and the appendix on the machine inside.</p>
<p>That structure lives in a single YAML file, and it&rsquo;s the source of truth. Each chapter has its id, title, opening scene, the question it answers, the arc, the list of source posts and the figure ideas. The Quarto configuration, which assembles the book, is generated from that file by script. Nobody edits the configuration by hand.</p>
<p>This matters because structural change is where a book breaks. Midway I moved the cut-off: the January posts went out, and the story settled between February and October. Ten posts vanished from the base.</p>
<p>Three chapters needed a new scene, a dozen units needed small repairs, and the damage that&rsquo;s hard to see was elsewhere: a sentence in an untouched chapter saying &ldquo;the five reviewers from chapter 5&rdquo;, the timeline, the projects appendix, chart labels, every translation. That&rsquo;s why there&rsquo;s an impact script that, before any edit, lists every paragraph, figure, reference and translation that depends on a post.</p>
<h2>Step 3: a pilot chapter becomes a contract<span class="hx:absolute hx:-mt-20" id="step-3-a-pilot-chapter-becomes-a-contract"></span>
    <a href="#step-3-a-pilot-chapter-becomes-a-contract" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before scaling, a pilot chapter. I picked chapter 5, about the first ten percent of a project, and it served to calibrate the voice and discover the doubts an agent would have along the way. Each doubt resolved became a written rule.</p>
<p>Those rules went into a contract document every agent reads before writing, along with three things:</p>
<ul>
<li>the book&rsquo;s voice guide, which inherits the blog&rsquo;s rules (my WRITER.md, the humanizer and my finishing checklist) and only adds what changes when the text leaves a dated post and goes into a book a lay reader holds in their hands;</li>
<li>a continuity file, saying which chapter explains each concept and what each character is called, so nobody explains &ldquo;context window&rdquo; five times;</li>
<li>the entire structure, so each agent knows what the other chapters cover.</li>
</ul>
<p>Besides the voice rules that already existed (a chapter opens on a scene with a date, a place and something at stake, never on a definition; it closes on a hook toward the next one, never on &ldquo;in this chapter we saw&rdquo;), some of the rules that came out of the pilot, to give you a taste:</p>
<ul>
<li>when the chapter brief and the post disagree on a detail, the post wins;</li>
<li>the chapter that owns a concept explains it properly; if the term shows up earlier in reading order, it gets a half-sentence gloss and a pointer, never a second explanation;</li>
<li>a fact verified online gets a citation even if the original post had no link;</li>
<li>model and product names in the vendor&rsquo;s spelling, even when the blog abbreviated them.</li>
</ul>
<blockquote>
  <p>It&rsquo;s the project instructions file I describe in the chapter about how to talk to the machine, at the scale of a book. Anyone who has written an AGENTS.md for a codebase recognizes all of it.</p>

</blockquote>
<h2>Step 4: parallel drafts, contradictions expected<span class="hx:absolute hx:-mt-20" id="step-4-parallel-drafts-contradictions-expected"></span>
    <a href="#step-4-parallel-drafts-contradictions-expected" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>With the contract ready, the chapters were drafted in parallel, one agent per chapter, in two waves: parts I and II first, then III through V, so the later chapters could build on the earlier ones. Each agent received its chapter&rsquo;s brief, the analyses, the full posts, the lineage and the reference-project files it needed.</p>
<p>Agents working at the same time contradict each other, and that happened. One chapter said FrankMD had around 130 commits in three days; another, that it had 212 in 19 days. Both numbers came from the posts and were right, they were just different windows. An integration ledger collected those conflicts, and the rule became making the window explicit in each chapter.</p>
<p>After the drafts comes the integration pass, with another set of agents, each owning a group of chapters and forbidden from touching the others. Their job: apply the conflict ledger, cut concepts explained twice, check that every callback matches what the other chapter actually says, make sure the last paragraph of a chapter leads into the first of the next, and redo the fact-check assuming the draft is wrong.</p>
<p>To read the seams, the build generates a &ldquo;seams&rdquo; file: the final paragraph of each unit next to the opening paragraph of the next. It&rsquo;s the fastest read there is for finding where the book stops feeling like one book.</p>
<h2>Step 5: an invisible marker per paragraph<span class="hx:absolute hx:-mt-20" id="step-5-an-invisible-marker-per-paragraph"></span>
    <a href="#step-5-an-invisible-marker-per-paragraph" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is the part I find most useful in the whole project. Every paragraph of the book, in the source file, carries a comment saying where it came from:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">&lt;!-- src: 2026/09/28/llms-sao-boas-em-reproduzir-o-que-existe-e-coisas-novas --&gt;
</span></span><span class="line"><span class="cl">Every LLM was trained only on what is public...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;!-- src: original --&gt;
</span></span><span class="line"><span class="cl">New text, written for the book.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">&lt;!-- src: ref:ai-jail/README.md --&gt;
</span></span><span class="line"><span class="cl">Fact checked in the reference project.</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The marker disappears when the book is built, through a Pandoc Lua filter, so the reader never sees it. It exists for maintenance. I edit posts after publishing all the time, and the book has to follow.</p>
<p>The <code>rake drift</code> command redoes the inventory, compares the hashes, and lists the chapters that depend on a post that changed, with the post&rsquo;s diff since the commit at which the book last read it. The marker leads straight to the paragraphs that came from that post, and only those need review. Once resolved, a script records the new hash and the commit.</p>
<p>A real example, from today. I removed from the <a href="/en/2026/10/13/ai-reverse-engineering-is-adobe-dead/">reverse engineering post</a> a paragraph about a Linus Tech Tips video. <code>drift</code> flagged chapter 19 and one appendix; the diff showed that passage had never been used in the book; two commands later, both were stamped with the new hash. Without the marker, I&rsquo;d have had to reread two chapters to discover I didn&rsquo;t need to change anything.</p>
<p>The bibliography plays the same role for external sources: each reference records which post cited it. And each image has its own provenance record.</p>
<h2>Step 6: what the fact-check caught<span class="hx:absolute hx:-mt-20" id="step-6-what-the-fact-check-caught"></span>
    <a href="#step-6-what-the-fact-check-caught" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every number, date and name was checked against three oracles: the posts, the reference projects and primary sources online, with the same adversarial checker prompt I use on the blog&rsquo;s articles. The full list is in the book&rsquo;s afterword, and a good part of the corrections are to my own blog:</p>
<ul>
<li>in the March review of the Strix Halo mini-PC, I had set aside 96 GB of memory for the GPU; in April I lowered it to 64, and later posts still said 96. The book uses 64 for everything after April;</li>
<li>a counting bug in one of the benchmark&rsquo;s tools undercounted by 40 to 90 times the cost of runs made on it before August. The book cites none of those costs;</li>
<li>in the June text about Claude Fable 5, I wrote it cost ten times more than Opus 4.8 per run. Redoing the math in July, with cache-read tokens included, Fable cost almost double. The post still says ten times; the book tells the wrong number and the correction;</li>
<li>in a March text, I wrote that Anthropic had bought Bun at the end of 2024. The announcement is from December 2025;</li>
<li>a chapter summary, written by an agent, said Claude Code&rsquo;s subscription lock fell in less than a day after the leak. The announcement came about 30 hours later, and the book says &ldquo;the next day&rdquo;.</li>
</ul>
<blockquote>
  <p>The drafts came out fast. Confidence in the text came from the checking. And the source beats the summary, even when the summary comes from the machine.</p>

</blockquote>
<h2>Step 7: a chapter with an error doesn&rsquo;t pass<span class="hx:absolute hx:-mt-20" id="step-7-a-chapter-with-an-error-doesnt-pass"></span>
    <a href="#step-7-a-chapter-with-an-error-doesnt-pass" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On top of everything runs an automatic checker, the equivalent of continuous integration. They&rsquo;re Ruby scripts, standard library only, chained in a Rakefile, plus what they call externally: the chart checker is Python because it lives inside matplotlib, the page audit uses poppler, and epubcheck needs Java:</p>
<ul>
<li>a <strong>chapter linter</strong> fails em dashes, phrases banned by the voice guide, loose URLs in the middle of prose, unknown citation keys, paragraphs without a provenance marker, and warns about overlong paragraphs;</li>
<li>a <strong>doctor</strong> checks that every cross-reference, citation, glossary term and figure exists, that provenance matches the inventory, that no post before the cut-off leaked in, that translations are up to date, and runs a callback heuristic: a sentence pointing at another chapter using names that chapter no longer contains;</li>
<li>a <strong>page audit</strong> opens the finished PDF and looks for blocks split across pages, headings orphaned at the foot of a page, nearly empty pages, oversized images, lines overflowing the margin;</li>
<li>a <strong>chart checker</strong> looks for labels that spilled out of their boxes;</li>
<li><strong>epubcheck</strong> validates the EPUB 3;</li>
<li>a <strong>style report</strong> for copyediting: passages repeated across chapters (an inevitable consequence of posts that repeat the same thesis from different angles), recurring phrases, overused words, term variants, badly formed comparatives in Portuguese.</li>
</ul>
<p>And the scripts have tests. A suite of almost 170 tests builds a fake book in a temporary directory, with five fake posts in a fake git repository, and checks that each tool catches the problem it should catch. When a bug is fixed, the test that would have caught it goes in, with a comment naming the regression it guards. It runs in CI before every build.</p>
<h2>The assembly pipeline<span class="hx:absolute hx:-mt-20" id="the-assembly-pipeline"></span>
    <a href="#the-assembly-pipeline" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The toolchain is Quarto, which bundles Pandoc and Typst, version-pinned inside the repository. No LaTeX. A single <code>rake build</code> produces, from the same tree of Markdown files:</p>
<table>
  <thead>
      <tr>
          <th>Output</th>
          <th>For what</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>EPUB 3</td>
          <td>Kindle, Kobo, Apple Books, any reader</td>
      </tr>
      <tr>
          <td>Screen PDF</td>
          <td>reading on a computer or tablet, with the cover</td>
      </tr>
      <tr>
          <td>Print PDF</td>
          <td>6 by 9 inches, blank versos, chapters opening on the right</td>
      </tr>
      <tr>
          <td>HTML</td>
          <td>web edition</td>
      </tr>
      <tr>
          <td>DOCX</td>
          <td>for an editor who wants Word</td>
      </tr>
  </tbody>
</table>
<p>Portuguese and English are Quarto profiles, generated from the same structure file. Citations come from a YAML in CSL format shared by both editions, with an ABNT style adjusted for Portuguese. The glossary is a Lua filter: each term is marked in the source where it appears, and the filter links the mark to the entry, expands the acronym the first time and generates the page.</p>
<p>Typst solved something I thought would cost me weeks: a PDF that looks like a typeset book, Portuguese hyphenation, ligatures, without the pain of TeX. The page audit after the build catches what the engine let through, and a <code>rake fit</code> recompiles while tightening chapters that end on a nearly empty page.</p>
<h3>The figures<span class="hx:absolute hx:-mt-20" id="the-figures"></span>
    <a href="#the-figures" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every figure is code or has a record. Charts and box-and-arrow diagrams are matplotlib scripts, 43 of them, each with a note of the chapter the data came from, and with the labels in Portuguese and English inside the script itself: the same chart comes out in both languages. The path for D2 diagrams exists in the repository, and no figure in the book needed it.</p>
<p>The conceptual illustrations were generated by AI, with the model, the prompt and the date of each one recorded in its credit record, and the book discloses it. The rule I imposed on myself: no AI-generated image of a real person. Real people only appear in freely licensed photos, with the credit in the caption.</p>
<p>The cover is the retro-futurist robot with the weary face, kneeling at a 1950s World&rsquo;s Fair, studying its own hand while the crowd watches. The prompt to the model described the scene to hold three fears at once: the end of humanity, losing your job, the machine becoming conscious. The cover&rsquo;s record keeps the whole prompt. The face is Marvin&rsquo;s, my newsletter&rsquo;s character, and a sticker with my face sits beside the name.</p>
<h2>The tricks of turning posts into a book<span class="hx:absolute hx:-mt-20" id="the-tricks-of-turning-posts-into-a-book"></span>
    <a href="#the-tricks-of-turning-posts-into-a-book" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Turning a blog into a book is a list of mechanical conversions, and each one has a catch:</p>
<ul>
<li><strong>A link becomes a citation.</strong> Every external link became a bibliography entry, and the sentence has to stand without the link. A link to another post of mine became a cross-reference to the chapter that now covers it, or disappeared. Never a URL in the prose.</li>
<li><strong>&ldquo;Today&rdquo;, &ldquo;yesterday&rdquo;, &ldquo;last week&rdquo;, &ldquo;update:&rdquo;</strong> became absolute dates. The book will be read in 2028 too.</li>
<li><strong>Model versions, prices, benchmark scores</strong> stayed as dated snapshots (&ldquo;in September 2026, the best&hellip;&rdquo;), and when a later post superseded the number, the book tells the change instead of printing the old number.</li>
<li><strong>Code dumps, install steps, terminal screenshots</strong> were cut. At most a 3-to-8-line excerpt when the code is the point; the step-by-step went to an appendix.</li>
<li><strong>Post titles, which are made for search</strong> (&ldquo;Vibe Code: I built X in two days&rdquo;), became short literary titles, with the subject in the subtitle.</li>
<li><strong>Repetition across posts</strong>, the same thesis from many angles, is said once, in the right place, and later chapters build on it.</li>
<li><strong>Calls to action, &ldquo;subscribe&rdquo;, &ldquo;comment&rdquo;</strong>, cut.</li>
<li><strong>The sharp edge aims at the propaganda, never at the reader.</strong> The post &ldquo;You&rsquo;re an idiot if you believe&hellip;&rdquo; became a chapter about how the ads work. The reader who believed the ad is the person the book wants to help.</li>
<li><strong>Every technical term is explained once</strong>, at its first appearance in the book, and goes to the glossary.</li>
</ul>
<p>And the most important of all: the book reads like a first-person story, with the year as its spine. Information arrives when the narrative needs it, instead of following encyclopedia order. That&rsquo;s the opposite of how a blog is written, and it was the rule that gave the agents the most trouble.</p>
<h2>The English edition<span class="hx:absolute hx:-mt-20" id="the-english-edition"></span>
    <a href="#the-english-edition" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The English edition, <em>Competent Enough</em>, only started after I approved the Portuguese one. Each translated unit records the hash of the Portuguese file it came from, and wherever the book follows a post of mine that already had an English version on the blog, the translation uses my own English wording instead of translating again.</p>
<p><code>drift</code> also works per language: if I change a paragraph in Portuguese, it flags the English unit that went stale, and only the marked paragraphs are retranslated. Charts with text are regenerated in English from the same scripts, and the English cover is composed by script on top of the same art.</p>
<h2>Releasing is pushing a tag<span class="hx:absolute hx:-mt-20" id="releasing-is-pushing-a-tag"></span>
    <a href="#releasing-is-pushing-a-tag" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A release is a CHANGELOG entry and a <code>git push</code> of a <code>vX.Y.Z</code> tag. A GitHub Actions workflow runs the tests, builds both editions in every format, validates the EPUB, runs the audit and publishes the release with the files. It deletes every release except the two newest, and keeps the tags. That&rsquo;s how the official page always points at the current version.</p>
<p>The repository is public, and that brought its own catch: my home server notes are the source of some facts, and they&rsquo;re private. The provenance markers cite those files by alias, the alias map stays out of git, and a pre-push hook blocks any file or commit message containing a private repository name, host or IP.</p>
<h2>Copyediting: what the checking machine lets through<span class="hx:absolute hx:-mt-20" id="copyediting-what-the-checking-machine-lets-through"></span>
    <a href="#copyediting-what-the-checking-machine-lets-through" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Lint, doctor, page audit and tests catch structural problems. They let through what a book written by many agents, each seeing a few chapters, always suffers from: the same sentence or anecdote reused in three chapters, drifting tone, inconsistent terminology, agreement slips. For that there&rsquo;s a copyedit procedure, which runs once per version, in three steps from the cheapest to the most expensive.</p>
<p><strong>Step 1, mechanical and nearly free:</strong> the style report I mentioned above. Sequences of seven words or more that appear in more than one unit, meaning reused sentences and retold anecdotes; set phrases of four to six words used in many chapters, which are nice as callbacks and become tics when they repeat; a word used far more in one chapter than in the rest; term variants (&ldquo;e-mail&rdquo; and &ldquo;email&rdquo;, &ldquo;Open AI&rdquo; and &ldquo;OpenAI&rdquo;); and an agreement heuristic for Portuguese. The report is a worklist, and nothing changes on its own.</p>
<p><strong>Step 2, the straight-through read:</strong> one read-only agent per part of the book, each reading its units in order, start to finish, with a shared style sheet (names, spellings, terms, recurring phrases from step 1). Each produces a ranked report, editing nothing: typos and grammar first, then inconsistencies with the style sheet, repetition the reader would notice, passages a lay reader would stumble on, and pacing only in the worst cases. A script validates the reports, checks that every quoted passage really exists in the unit, numbers the items and summarizes.</p>
<p>Then comes the triage, done by me with an editor agent, and the pointed application of each approved item, under the same rules as the integration pass. A cheaper model does the proofreading; hard passages go to the strong model. Rough budget: two to three million tokens per language.</p>
<p>The most important rule of that step is &ldquo;facts get checked, not asked&rdquo;. Any item that turns on a number, date, name or tool behavior is settled by the editor against the source of truth before it reaches me: first the post pointed to by the paragraph&rsquo;s provenance marker, recomputing totals; then the code or data behind the claim, in my repositories; then public records.</p>
<p>When two sources disagree, the task is to find out why. &ldquo;653 commits in 8 projects&rdquo; versus &ldquo;692 in 4&rdquo; were two cuts of the same work, one of them without the newsletter&rsquo;s private repository, and the text now states its scope instead of picking a number. When the blog post itself is wrong, the book prints the correct figure and the error goes to a blog errata list, for me to fix at the source.</p>
<p>Only what no source can settle reaches me: an unpublished fact, intent (&ldquo;is this ironic?&rdquo;), a preference about a cut or a title, and a contradiction between two statements of mine with no record to break the tie. Each question comes with what was checked and what was found.</p>
<p><strong>Step 3, my own read.</strong> The last and the most valuable. The notes go into the same cycle of apply, check and propagate to the English edition.</p>
<p>The first round of that copyedit is what separates preview 2 from preview 3. Among what it caught: commit counts now state their scope, a &ldquo;more than a thousand&rdquo; that summed to 984, the Frank Investigator voting example that didn&rsquo;t match the code (figure redrawn), the David Sacks and Pirate Wires quotes in chapter 14 verified against the originals and corrected, Sam Altman&rsquo;s photo swapped for one from 2025. And in the English edition, a reader pass of its own after the re-sync: Portuguese calques rewritten, glossary terms used consistently, American quotation punctuation throughout.</p>
<h2>Fake readers, real feedback<span class="hx:absolute hx:-mt-20" id="fake-readers-real-feedback"></span>
    <a href="#fake-readers-real-feedback" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Copyediting checks the text. It lets through the question that matters in a book for lay readers: can the person I wrote it for read it to the end, understand it, and come out convinced? To answer that, the next pass was a review by simulated readers.</p>
<p>The book&rsquo;s preface has a section called &ldquo;Who I wrote this for&rdquo;. From it came five personas, each with a name, an age, a job and the fear that brought them to the book:</p>
<ul>
<li><strong>Marina</strong>, 38, an accountant in Belo Horizonte, read that her job &ldquo;ends in two years&rdquo;, reads on her phone at night and wants to know what to do on Monday;</li>
<li><strong>Roberto</strong>, 52, owns a hardware store, his 15-year-old saw a video about superintelligence and asked if it was true; suspicious of hype, of &ldquo;experts&rdquo; and of an author who shows off;</li>
<li><strong>Carla</strong>, 44, operations manager at a logistics company, the board hired consultants selling an &ldquo;AI transformation&rdquo;; she wants a decision she can take;</li>
<li><strong>Lucas</strong>, 24, a junior developer a year into the job, afraid he chose the wrong career;</li>
<li><strong>Helena</strong>, 61, a retired history teacher, no fear at all, came for the stories and loses patience with lists and manuals.</li>
</ul>
<p>One agent per persona, read-only, cheaper model, reads the whole book in order the way that person would. The instruction is explicit: you are a reader, the editor stays out of it; comma errors were already handled, report only what changes the reading experience. Each one returns a 1-to-5 score per chapter, a comment in the persona&rsquo;s voice (&ldquo;I finally get why the chatbot agrees with me&rdquo;, &ldquo;lost me in the benchmark tables&rdquo;), at most 35 annotations classified as confusing, boring, rewrite or logic, and cut candidates. It costs about 350K tokens per persona per full read.</p>
<p>An editor consolidates: the score matrix by chapter and persona and the pattern behind it, what readers loved (to protect in any edit), the logic items, checked against the text and the posts before making the list and fixed regardless of votes, and the clarity items ranked by how many personas raised them. A single persona&rsquo;s taste note is dropped. Then I decide, and recurring patterns become numbered rules in an editorial rules document, with their origin and how each is enforced.</p>
<blockquote>
  <p>The first read said what I suspected and gave it a measure: stories and practical tools work for everyone; the measurement-heavy middle, chapters 11 to 13, loses the non-programmers, averaging between 2.2 and 2.4. &ldquo;Sharp when he tells what happened to him, loses me when he tells what he measured&rdquo;, Helena summed up, for all five.</p>

</blockquote>
<p>And all five caught the same argument flaws. Chapter 20&rsquo;s conclusion went beyond its evidence: it said &ldquo;the numbers say it won&rsquo;t get smarter&rdquo; resting on a programming benchmark the same chapter calls saturated. Chapter 9 argued in a way that can never lose: every agent failure was the request&rsquo;s fault. Four of the five were sent to the wrong chapter by &ldquo;how to read&rdquo;.</p>
<p>Those became the first rules:</p>
<ul>
<li>every claim scoped to what was measured;</li>
<li>no argument that can&rsquo;t lose;</li>
<li>opinion marked as opinion;</li>
<li>the opposing side in its strongest form before rebutting;</li>
<li>the book obeys its own lessons.</li>
</ul>
<p>One round is not enough, because edits fix the old problem and create the new one. In round two, an apology placed next to a contradiction (&ldquo;I know this seems to clash with&hellip;&rdquo;) made all five readers notice a contradiction that three had previously missed. It became a rule: fix the design, and leave the apology out. So the process runs in rounds: read, edit, read again with the same personas on a fresh read, forbidden from opening the previous reports to avoid anchoring, and a script compares the rounds.</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th style="text-align: right">round 1</th>
          <th style="text-align: right">round 2</th>
          <th style="text-align: right">round 3</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>book average score</td>
          <td style="text-align: right">3.32</td>
          <td style="text-align: right">3.38</td>
          <td style="text-align: right">3.41</td>
      </tr>
      <tr>
          <td>logic annotations</td>
          <td style="text-align: right">73</td>
          <td style="text-align: right">53</td>
          <td style="text-align: right">51</td>
      </tr>
  </tbody>
</table>
<p>The average score is noisy (an untouched chapter swings 0.6 between reads), so the stopping criterion is different: the problems flagged stopped coming back and nothing new reaches three readers. In round three the curve flattened and the review stopped there, with a backlog for my own read. What changed along the way: about 8,000 words of lab notebook left the chapters for a new appendix, &ldquo;For programmers: the backstage&rdquo;, each paragraph carrying its provenance marker along; the reading list became an appendix; the Genesys PI section was parked, kept outside the book while verification is pending; chapter 19 got the title its argument supports; every chapter opens by orienting the reader before the first jargon; and the epilogue got a &ldquo;this week&rdquo; list per reader type. Cost of the three rounds: about 5 million tokens of reading plus about 3 million of editing and English re-sync.</p>
<h2>The narrator got a past<span class="hx:absolute hx:-mt-20" id="the-narrator-got-a-past"></span>
    <a href="#the-narrator-got-a-past" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>With the argument in place, the first person lacked substance. The book&rsquo;s narrator was the Akita of 2026, and I have thirty years of history that explain why I think what I think: the dot-com crash seen from inside, five years integrating SAP at large companies, the warnings about the hiring bubble I gave on video in 2019, 2020 and 2022, the &ldquo;Don&rsquo;t outsource your decisions&rdquo;. All of it is in the transcripts of the 149 episodes of <a href="https://www.youtube.com/@Akitando"target="_blank" rel="noopener">Akitando</a>, published on this blog between 2018 and 2023.</p>
<p>The process was the same as the rest of the book, in miniature. Extraction agents read 23 episodes in full, with a form: biographical facts with the verbatim quote and what would verify them, facts about the world, recurring positions in my words, and hooks, meaning the exact place in the book where one or two sentences of that history back a 2026 claim. From that came a narrator profile, which I confirmed line by line, and a plan with about 30 touches, most of them one to three sentences.</p>
<p>Before any touch, more than 140 claims taken from the episodes went through the fact-check. It corrected the book and corrected me: the hiring bubble started around 2010, with interest rates near zero, and my February post said 2014; the dot-com bubble burst between 2000 and 2002; the 2022 layoffs were around 165 thousand. And it found errors in old episodes the book doesn&rsquo;t even use, which went to a blog errata list.</p>
<p>The touches went where experience becomes evidence: the week in 2001 when my dot-com closed and a mentor called me into an SAP consultancy; the SAP years behind the claim that the model is blind to a company&rsquo;s private rules; the dated bubble warnings next to the admitted mistake, because in 2022 I expected a second leg down in 2023 that the AI wave cancelled. Two new appendices came out of it: &ldquo;Three bubbles&rdquo;, with the verified numbers of the dot-com crash, the zero-interest bubble and the AI wave, and &ldquo;How to study with AI at your side&rdquo;, from the channel&rsquo;s most watched episode.</p>
<p>Those episodes are background sources, and <code>drift</code> now watches them as it watches the 2026 posts. Then came a scoped check with the same five personas, only on the touched chapters, with three extra questions: does the narrator&rsquo;s history make the argument more convincing, and where? Does any passage read as showing off or &ldquo;I told you so&rdquo;? Does anything about the narrator contradict itself?</p>
<blockquote>
  <p>All five said yes to credibility, with a condition: the history convinces when it&rsquo;s evidence the reader can check, the dated warning next to the admitted mistake, and convinces less when it becomes a résumé, which clashes with the book itself, which says &ldquo;a résumé is not an argument&rdquo;. It became rule 21: the narrator&rsquo;s history comes in as evidence, and credentials stay out.</p>

</blockquote>
<p>Three or four readers flagged the same lines as showing off, and they went: &ldquo;The warnings have dates&rdquo;, &ldquo;more than thirty public repositories&rdquo;, &ldquo;the most watched on my channel&rdquo;. The self-deprecating lines and the admitted mistakes all counted in my favor. And the check found contradictions I hadn&rsquo;t seen myself: the preface said &ldquo;late 90s&rdquo; and chapter 18 said 1996; one chapter said &ldquo;eight months&rdquo; and another &ldquo;a year of daily use&rdquo;, and they were fixed one by one.</p>
<h2>Accessibility is part of the build too<span class="hx:absolute hx:-mt-20" id="accessibility-is-part-of-the-build-too"></span>
    <a href="#accessibility-is-part-of-the-build-too" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>An EPUB opening on a Kindle does not make it accessible. This book has dozens of diagrams, charts and tables. Without additional work, much of the argument simply disappears for anyone using a screen reader.</p>
<p>The pipeline now treats accessibility as a publishing contract. Each of the 55 figures, in both languages, has a short alternative text and a complete description of what the image communicates. In HTML and EPUB, the detailed description appears with the figure; in PDF, it becomes its semantic replacement without changing the layout. Tables have captions, and the EPUB now identifies where the main text, glossary, references and image credits begin in its semantic navigation. The authoring contract is <a href="https://github.com/akitaonrails/ai-book-2026/blob/main/docs/ACCESSIBILITY.md"target="_blank" rel="noopener">documented in the repository</a>.</p>
<p>This doesn&rsquo;t depend on my memory either. <code>rake check</code> rejects figures without both descriptions or with overly long alternative text. Every build validates both EPUBs with EPUBCheck, DAISY Ace and the project&rsquo;s own checks. The Kindle edition also goes through a cleanup of CSS and embedded icons that tend to cause problems in Amazon&rsquo;s readers, but the script refuses to remove any rule the content has come to depend on.</p>
<p>No automated tool can certify WCAG conformance or guarantee how every reader on the market will behave. Manual review remains mandatory. The difference is that accessibility is now part of the build, and every change has to preserve that contract.</p>
<h2>What remains mine<span class="hx:absolute hx:-mt-20" id="what-remains-mine"></span>
    <a href="#what-remains-mine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The repository records the first commit and the draft of every chapter on the same day, October 13. Those are the first ten percent, the ones that impress and say almost nothing about the rest. The other ninety percent are reading, cutting and correcting, and that part is mine. No chapter goes in without me reading and approving it, and what I send back to be redone goes through the same process.</p>
<p>Any of the good models of October 2026 would have written similar drafts, because the model became a commodity. What made the process work was what surrounds it: the inventory, the written contract, the automatic checker, the sources as oracle, the per-paragraph trail. It&rsquo;s the same old software engineering I defend in every chapter, applied to text.</p>
<blockquote>
  <p>The agents were competent enough to write the draft. Deciding what it said remained my job.</p>

</blockquote>
<p>And, once again: making a book with AI isn&rsquo;t a &ldquo;write me a book&rdquo; prompt and done. I had to invent the whole process and steer the agent to create every piece of it: the scripts, the tests, the consolidation of the posts, the narrative strategy, the goals, what stays and what goes, the copyedit, the fact-checking, the automated release. You need to know exactly what you want, and then the AI helps a lot. Whoever doesn&rsquo;t know what a book publishing process involves won&rsquo;t make a real book, and showing that was one of the goals I had when creating this example.</p>
<h2>Download it, read it, and tell me where I was wrong<span class="hx:absolute hx:-mt-20" id="download-it-read-it-and-tell-me-where-i-was-wrong"></span>
    <a href="#download-it-read-it-and-tell-me-where-i-was-wrong" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Both editions, straight from GitHub, no sign-up. The current version is the final 1.0.0, from October 17, with everything this text describes:</p>
<table>
  <thead>
    <tr><th>Edition</th><th>EPUB (Kindle, Kobo, Apple Books)</th><th>Screen PDF</th><th>Print PDF (6 × 9 in)</th></tr>
  </thead>
  <tbody>
    <tr><td>Competent Enough (EN)</td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competent-Enough.epub">EPUB</a></td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competent-Enough-ebook.pdf">PDF</a></td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competent-Enough.pdf">PDF</a></td></tr>
    <tr><td>Competente o Suficiente (PT-BR)</td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competente-o-Suficiente.epub">EPUB</a></td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competente-o-Suficiente-ebook.pdf">PDF</a></td><td><a href="https://github.com/akitaonrails/ai-book-2026/releases/download/v1.0.0/Competente-o-Suficiente.pdf">PDF</a></td></tr>
  </tbody>
</table>
<p>The latest version, always, lives on the <a href="https://ailair.akitaonrails.com/book/"target="_blank" rel="noopener">book page</a> and on the <a href="https://github.com/akitaonrails/ai-book-2026/releases"target="_blank" rel="noopener">GitHub releases</a>.</p>
<p>It&rsquo;s a preview. There will be mistakes, and the process above exists so they get fixed in the right place. Found one, <a href="https://github.com/akitaonrails/ai-book-2026/issues"target="_blank" rel="noopener">open an issue</a>.</p>
]]></content:encoded><category>artificial-intelligence</category><category>coding-agents</category><category>open-source</category></item><item><title>AI Reverse Engineering: Is Adobe Dead?</title><link>https://www.akitaonrails.com/en/2026/10/13/ai-reverse-engineering-is-adobe-dead/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/13/ai-reverse-engineering-is-adobe-dead/</guid><pubDate>Tue, 13 Oct 2026 00:00:00 -0300</pubDate><description>&lt;p&gt;PhotoCraft exists. REA exists. Recomps and decomps of old games ship every day. Therefore: Adobe is dead, no binary is sacred, and programmers are finished.&lt;/p&gt;
&lt;p&gt;That was the week on X, and if you only read headlines, it&amp;rsquo;s a reasonable conclusion. This text is for anyone who wants to know what each of those things actually does.&lt;/p&gt;
&lt;p&gt;It blew up on the 9th, when the account below summed up what Brandon Thomas, a developer from Atlanta, had been publishing since late September: seven open source clones of Adobe&amp;rsquo;s main products, written in Rust with help from Claude Opus 5.5. Photoshop, Illustrator, Premiere, Lightroom, After Effects, InDesign, Acrobat. All free, all &amp;ldquo;clean room&amp;rdquo;, without a single line of Adobe code. This is the post that went viral:&lt;/p&gt;</description><content:encoded><![CDATA[<p>PhotoCraft exists. REA exists. Recomps and decomps of old games ship every day. Therefore: Adobe is dead, no binary is sacred, and programmers are finished.</p>
<p>That was the week on X, and if you only read headlines, it&rsquo;s a reasonable conclusion. This text is for anyone who wants to know what each of those things actually does.</p>
<p>It blew up on the 9th, when the account below summed up what Brandon Thomas, a developer from Atlanta, had been publishing since late September: seven open source clones of Adobe&rsquo;s main products, written in Rust with help from Claude Opus 5.5. Photoshop, Illustrator, Premiere, Lightroom, After Effects, InDesign, Acrobat. All free, all &ldquo;clean room&rdquo;, without a single line of Adobe code. This is the post that went viral:</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">AI is now being used to recreate Adobe's software, a developer has released seven free, open-source apps as clean-room alternatives to Adobe's main tools:<br><br>- PhotoCraft → Photoshop<br>- VectorCraft → Illustrator<br>- FilmCraft → Premiere Pro<br>- LightCraft → Lightroom<br>- EffectCraft → After Effects<br>- DesignCraft → InDesign<br>- PrintCraft → Acrobat Pro<br><br>Built in Rust with help from Claude Opus 5.5, they run on Windows, Linux, and macOS under MIT/Apache licenses without using Adobe's source code.</p>&mdash; Pirat_Nation (@Pirat_Nation) <a href="https://twitter.com/Pirat_Nation/status/2108437553615425881">October 9, 2026</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>The same week, <a href="https://github.com/morluto/rea"target="_blank" rel="noopener">REA</a>, &ldquo;Reverse Engineer Anything&rdquo;, passed 100K stars on GitHub, gaining tens of thousands a day. The pitch on its page: &ldquo;see a feature in an app that you want in your own product? Ask your agent to investigate it with REA and build a version for your project&rdquo;.</p>
<p>And anyone who follows retro gaming knows 2026 is the year that keeps on giving. There&rsquo;s a <a href="https://docs.google.com/spreadsheets/d/1MT_xMPlKNbyhANRUMzOH94J3ybeF0b1Ws8F0kb-_598/edit"target="_blank" rel="noopener">community spreadsheet</a> trying to list the unofficial PC ports, around 100 games from Ship of Harkinian to Skate 3, and it&rsquo;s always behind. The <a href="https://www.youtube.com/@VideoGameEsoterica"target="_blank" rel="noopener">Video Game Esoterica</a> channel publishes a new port almost daily: Time Crisis decompiled from the arcade board, Daytona USA, Bloodborne.</p>
<p>The Xbox One version of <a href="https://almost-there-games.itch.io/azimuth"target="_blank" rel="noopener">Forza Horizon 2</a>, stuck there since 2014, runs on Windows. <a href="https://github.com/boykopovar/AnyPS5"target="_blank" rel="noopener">AnyPS5</a> promises to convert PS5 executables into native PC binaries, and PS5 emulators like KytyPS5 and SharpEmu already <a href="https://www.invenglobal.com/articles/26860/astro-bot-boots-on-pc-as-ps5-emulation-makes-rapid-progress"target="_blank" rel="noopener">run Astro Bot</a> with actual gameplay. Much of it with AI in the loop, some of it openly vibe-coded.</p>
<p>Hence the consensus: programming, in general, is over. Every binary is reversible and reusable, just point the agent at it. My position is that it did get much easier, that it&rsquo;s still nowhere near the silver bullet people imagine, and that the engine behind it, the LLM, <a href="/en/2026/10/12/llms-agents-competent-enough/">stopped growing exponentially</a>. The rest of the text is the reasons.</p>
<blockquote>
  <p><strong>TL;DR:</strong> reverse engineering is a 40-year-old discipline with mature tooling, and AI sped up its grunt work, especially in retro, where the binary is available, tiny, and the target doesn&rsquo;t move. The Adobe clones are alphas with hundreds of open bugs and pretty screenshots. REA is a toolbox that requires the binary in hand, Ghidra or IDA installed, and a lot of tokens. What&rsquo;s worth money today doesn&rsquo;t even have a binary: it&rsquo;s SaaS, cloud, manufacturer partnerships and decades of color science. Rewriting Bun, with the project&rsquo;s author and 64 agents, cost US$ 165K. Jump to the <a href="#reverse-engineering-wasnt-born-last-week">timeline</a>, to <a href="#what-rea-actually-does">REA</a>, to the <a href="#photocraft-pretty-screenshot-alpha-inside">Adobe clones</a>, to the <a href="#the-bun-case-what-it-costs-to-rewrite-big-software">Bun case</a>, to why <a href="#why-retro-moves-so-fast">retro moves fast</a> or to the <a href="#answering-the-list-from-the-top">answers at the end</a>.</p>

</blockquote>
<h2>First of all: I don&rsquo;t like Adobe<span class="hx:absolute hx:-mt-20" id="first-of-all-i-dont-like-adobe"></span>
    <a href="#first-of-all-i-dont-like-adobe" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>To be clear about where I&rsquo;m speaking from. I hate Adobe&rsquo;s business practices as much as anyone. I was a paying customer for years, used Photoshop and Premiere extensively, plus Lightroom and After Effects, and left for the same reasons everybody leaves: mandatory subscription, cancellation fees, prices going up with nothing in return.</p>
<p>And it&rsquo;s precisely because I used them in depth that I know the size of what&rsquo;s inside those boxes. Whoever thinks Photoshop is layers, crop and text never needed a color proof for a print shop, never opened a camera RAW whose color profile Adobe has maintained for twenty years, never did the conform on cinema footage, the work of gathering the camera&rsquo;s raw material for finishing. I&rsquo;ll get there, after the basics.</p>
<h2>Reverse engineering wasn&rsquo;t born last week<span class="hx:absolute hx:-mt-20" id="reverse-engineering-wasnt-born-last-week"></span>
    <a href="#reverse-engineering-wasnt-born-last-week" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Every emulator you&rsquo;ve ever used exists because someone opened up hardware, disassembled a binary, sniffed a protocol and, in some cases, broke cryptography. The discipline has case law, commercial tooling and decades of history. A condensed timeline, with the milestones that matter most:</p>
<ul>
<li><strong>1982 to 1984</strong>: Compaq reverse engineers the IBM PC BIOS, and in 1984 Phoenix sells a licensable BIOS built in a clean room, by a team that only read the specification. The PC compatible industry is born. <a href="https://en.wikipedia.org/wiki/Phoenix_Technologies"target="_blank" rel="noopener">Source</a>.</li>
<li><strong>1992</strong>: Andrew Tridgell creates Samba by sniffing SMB packets. The same year, <a href="https://www.copyright.gov/fair-use/summaries/segaenters-accolade-9thcir1992.pdf"target="_blank" rel="noopener">Sega v. Accolade</a> and <a href="https://www.copyright.gov/fair-use/summaries/atari-nintendo-fedcir1992.pdf"target="_blank" rel="noopener">Atari v. Nintendo</a> establish in the US that disassembling code to reach functional elements is fair use (Atari lost its own case for another reason: it lied to the Copyright Office to get the source).</li>
<li><strong>1993</strong>: Wine begins, which becomes the foundation of Proton and of every Windows game that runs on the Steam Deck today.</li>
<li><strong>1999</strong>: UltraHLE runs commercial N64 games at full speed; bleem! emulates the PS1, Sony sues and loses the injunctions, and bleem! folds anyway in 2001; DeCSS breaks DVD protection.</li>
<li><strong>2000</strong>: <a href="https://law.resource.org/pub/us/case/reporter/F3/203/203.F3d.596.99-15852.html"target="_blank" rel="noopener">Sony v. Connectix</a> rules that copying the PS1 BIOS to build an emulator is fair use.</li>
<li><strong>2002 and 2003</strong>: PCSX2 and Dolphin are born, the two emulators that twenty years later are still the reference.</li>
<li><strong>2007</strong>: the iPhone is opened eleven days after launch. The European Commission forces Microsoft to document its network protocols, and the <a href="https://fsfe.org/news/2007/news-20071220-01.html"target="_blank" rel="noopener">Samba team receives the documentation</a> for 10,000 euros.</li>
<li><strong>2010</strong>: the fail0verflow group shows at 27C3 that Sony signed the PS3 firmware with a fixed nonce, exposing the private key (the nonce is the number that should be random in every signature). Days later, already in 2011, geohot publishes the key, Sony sues and settles in March.</li>
<li><strong>2011 and 2013</strong>: RPCS3 (PS3) and Xenia (Xbox 360) are born, the two hardest emulators ever built, for reasons I&rsquo;ll explain.</li>
<li><strong>2019</strong>: the NSA releases <a href="https://github.com/NationalSecurityAgency/ghidra"target="_blank" rel="noopener">Ghidra</a> as open source. The Super Mario 64 decompilation leaks and goes public, and the PC port appears the following year.</li>
<li><strong>2021 and 2022</strong>: Ocarina of Time 100% decompiled after almost two years of work; Ship of Harkinian becomes the reference port.</li>
<li><strong>2024</strong>: Mr-Wiseguy releases <a href="https://github.com/Zelda64Recomp/Zelda64Recomp/releases"target="_blank" rel="noopener">Zelda 64: Recompiled</a>, the first showcase of N64 static recompilation.</li>
<li><strong>2025</strong>: Sonic Unleashed Recompiled brings the same trick to the Xbox 360, converting PowerPC to C++ and shaders to HLSL.</li>
</ul>
<p>Notice that the current phase, decomp and recomp at scale, starts in 2019, well before any coding agent. AI joined an assembly line that already existed.</p>
<h3>The tools<span class="hx:absolute hx:-mt-20" id="the-tools"></span>
    <a href="#the-tools" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The tooling is mature too, and much of it is free:</p>
<ul>
<li><a href="https://hex-rays.com/ida-pro"target="_blank" rel="noopener">IDA Pro</a> (Hex-Rays), the reference commercial disassembler and decompiler, from one thousand to almost nine thousand euros a year, with a free version limited to x86.</li>
<li><a href="https://github.com/NationalSecurityAgency/ghidra"target="_blank" rel="noopener">Ghidra</a>, the NSA&rsquo;s open answer, with a decompiler and scripting, Apache 2.0.</li>
<li><a href="https://binary.ninja/"target="_blank" rel="noopener">Binary Ninja</a>, with a free edition and licenses from 200 to 3,500 dollars.</li>
<li><a href="https://github.com/radareorg/radare2"target="_blank" rel="noopener">radare2</a> and <a href="https://github.com/rizinorg/cutter"target="_blank" rel="noopener">Cutter</a>, the GUI for rizin, which is a radare2 fork: the open command line and the open interface.</li>
<li><a href="https://github.com/x64dbg/x64dbg"target="_blank" rel="noopener">x64dbg</a> and <a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/"target="_blank" rel="noopener">WinDbg</a> on Windows, <a href="https://www.sourceware.org/gdb/"target="_blank" rel="noopener">GDB</a> everywhere else.</li>
<li><a href="https://frida.re/"target="_blank" rel="noopener">Frida</a>, to inject code into a live process and watch what it does.</li>
<li><a href="https://github.com/skylot/jadx"target="_blank" rel="noopener">JADX</a> for Android and <a href="https://github.com/icsharpcode/ILSpy"target="_blank" rel="noopener">ILSpy</a> for .NET.</li>
</ul>
<p>Keep this list in mind. REA, which we&rsquo;ll get to shortly, is a wrapper around it.</p>
<h2>How a binary gets taken apart, in practice<span class="hx:absolute hx:-mt-20" id="how-a-binary-gets-taken-apart-in-practice"></span>
    <a href="#how-a-binary-gets-taken-apart-in-practice" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In principle, every binary is reversible. The processor has to be able to execute it, so the instructions are in there. The path is always the same:</p>
<ol>
<li><strong>Disassemble</strong>: the binary becomes assembly, one machine instruction per line. This is mechanical.</li>
<li><strong>Decompile</strong>: the assembly becomes something resembling C. Ghidra and IDA do this reasonably well, with a lot of noise.</li>
<li><strong>Recover what the compiler threw away</strong>: variable names, function names, types, structures, comments. None of it survives compilation. This is the real work, and it&rsquo;s human.</li>
<li><strong>Refactor</strong> until it becomes code a person can read, maintain and port.</li>
</ol>
<p>The N64 decomp projects take step 4 all the way: their C code, recompiled, produces the original ROM byte for byte. That&rsquo;s how Super Mario 64 became a project with 135K lines of game C code (around 100K of actual code, plus half a million lines of generated level and model data), and Ocarina of Time passed 430K lines. Static recompilation skips part of this: it translates the original processor&rsquo;s instructions into generic C, without trying to understand them, and replaces only the parts that talk to the hardware. It&rsquo;s faster and the result is less readable.</p>
<h3>&ldquo;But can&rsquo;t the AI just read the binary directly?&rdquo;<span class="hx:absolute hx:-mt-20" id="but-cant-the-ai-just-read-the-binary-directly"></span>
    <a href="#but-cant-the-ai-just-read-the-binary-directly" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Someone always asks: if it&rsquo;s AI, why go through C? Let the model read the binary and build on top of it. The short answer is that an LLM only knows what was in its training corpus, and a corpus of binaries paired with source code is scarce, because no human has written production assembly in decades.</p>
<p>The long answer is that the literature exists, and it&rsquo;s instructive precisely because it&rsquo;s modest. The lineage runs from 2018 neural networks to models like <a href="https://arxiv.org/abs/2305.12520"target="_blank" rel="noopener">SLaDe</a> (200 million parameters, one per architecture and optimization level), <a href="https://arxiv.org/abs/2403.05286"target="_blank" rel="noopener">LLM4Decompile</a> (up to 33 billion) and <a href="https://arxiv.org/abs/2311.13721"target="_blank" rel="noopener">Nova</a>. Meta published an <a href="https://arxiv.org/abs/2407.02524"target="_blank" rel="noopener">LLM Compiler</a> that translates assembly into LLVM IR. The best results, on isolated benchmark functions, hover around 60 to 65% of code that runs again and gives the same result, dropping sharply when the compiler optimized with -O3.</p>
<p>Two recent studies show the real state of things. <a href="https://arxiv.org/abs/2505.11340"target="_blank" rel="noopener">DecompileBench</a>, with 23K real functions, found that LLM-based decompilers produce more readable code with half the functional correctness of commercial decompilers. And a <a href="https://arxiv.org/abs/2609.05370"target="_blank" rel="noopener">September 2026 paper</a> measured that LLM refinement of Ghidra output raises the compilation rate from 75% to 90% and drops behavioral fidelity from 74% to 62%, with up to around 10% of functions with known vulnerabilities no longer reproducing the flaw, meaning the bug vanished without anyone asking.</p>
<blockquote>
  <p>Summing up what exists: small models, function by function, almost only x86-64 Linux, and the best ones are refinement layers on top of Ghidra, which keeps the classic decompiler in the loop. No emulator, no game, no whole program has been neurally recompiled. Until someone invents that, you work with reality, and reality includes the intermediate layer of programming language and compiler.</p>

</blockquote>
<p>The AI assistants that exist for this in production confirm the design: <a href="https://plugins.hex-rays.com/aidapal"target="_blank" rel="noopener">aiDAPal</a>, an IDA plugin by Atredis, Binary Ninja&rsquo;s Sidekick, the MCP servers for Ghidra. All of them are an LLM naming variables and explaining functions on top of what the traditional decompiler produced.</p>
<h2>What REA actually does<span class="hx:absolute hx:-mt-20" id="what-rea-actually-does"></span>
    <a href="#what-rea-actually-does" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I cloned <a href="https://github.com/morluto/rea"target="_blank" rel="noopener">REA</a> and read the code. It&rsquo;s an MCP server and a TypeScript CLI that wraps the tools from the list above and exposes them to your coding agent: Ghidra, Hopper, IDA, JADX, Frida, Wakaru for obfuscated JavaScript, Playwright to capture what a website does. The agent asks, REA runs the tool and returns pseudocode, call graphs, strings and IPC traces, each result with an evidence record and a list of limitations.</p>
<p>I had already done that flow by hand, months before REA went viral. In July I <a href="/en/2026/07/08/fable-5-analyze-tiktok-clash-of-kings-govbr-fingerprint/">had Fable 5 analyze the code of TikTok, Clash of Kings and gov.br</a>: I downloaded the APKs, unzipped them (an APK is a zip), ran JADX on the <code>.dex</code> files and let the model read the Java that came out the other side. It was enough to see the endpoints, the permissions, the embedded SDKs and how each app builds the device fingerprint, that persistent identifier that survives clearing data and reinstalling. TikTok came out as industrial-grade collection, armored against auditing; gov.br, as the example of how to do it right.</p>
<p>The three lessons from that post apply to all of REA. Android is far too easy to decompile, and even so the result serves only static analysis, because recompiling the app is out of reach: the names come scrambled by obfuscation, resources and signing keys are missing. The most sensitive part lives in native code, <code>.so</code> files in C and C++, which decompile into nothing readable, and in TikTok that&rsquo;s exactly where the core sits. And what came out of that work was a report on what the app does, with caveats, and no TikTok clone. REA packages that same flow into an MCP server; the walls stay in the same place.</p>
<p>The judgment is supplied by the LLM you already pay for. REA supplies the deterministic plumbing and the provenance. The phrase &ldquo;automates the heuristics of reverse engineering&rdquo;, which circulates out there, appears nowhere in the repository; the description the project itself uses is agent-driven reverse engineering with traceable evidence.</p>
<p>What it requires: the artifact on your machine (native binary, Electron app, .NET assembly, APK, firmware, network capture), Node 22.19 or later, and the heavy tools installed at your own expense. Ghidra is free; IDA, Hopper and JEB the README tells you to buy. There&rsquo;s no REA API key because it runs locally, and the token cost lands entirely on your agent subscription.</p>
<p>And that cost is the detail nobody mentions. REA&rsquo;s MCP tool catalog is 2.3 MB of JSON, which goes into the agent&rsquo;s context. The project itself publishes an <a href="https://github.com/morluto/rea/tree/main/experiments/analysis-efficiency"target="_blank" rel="noopener">experiment</a> in which analyzing SQLite compiled to WASM, on the default path, took 42 tool calls, five minutes and 300K input tokens. A full inventory of an Electron app like Obsidian returns almost 1 MB of JSON.</p>
<p>There&rsquo;s an open issue complaining that inspecting an ordinary Mac app returns 80K to 230K tokens in one go.</p>
<p>The project is serious and goes far: six months, 2,600 commits, a thousand test files, version 6.4 released on October 11. It&rsquo;s also unstable: 190 open issues, several breaking changes per minor release, subsystems marked experimental.</p>
<p>The limits are written in the repository itself. CONTRIBUTING excludes breaking DRM, anticheat, licensing and commercial protections. The DISCLAIMER warns that decompilation, reconstruction and AI-assisted analysis &ldquo;may be incomplete or incorrect&rdquo;. And even the internal instructions for generating the website&rsquo;s figures say, in so many words: &ldquo;never imply REA automatically clones a program&rdquo; and &ldquo;never say full reconstruction, exact game clone, or automatic source recovery&rdquo;.</p>
<blockquote>
  <p>REA is a good toolbox for someone who already knows how to do reverse engineering and wants an agent holding Ghidra. It isn&rsquo;t the &ldquo;copy this app for me&rdquo; button. The people who wrote the project are the first to say so.</p>

</blockquote>
<h2>PhotoCraft: pretty screenshot, alpha inside<span class="hx:absolute hx:-mt-20" id="photocraft-pretty-screenshot-alpha-inside"></span>
    <a href="#photocraft-pretty-screenshot-alpha-inside" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The <a href="https://github.com/storytold/photocraft"target="_blank" rel="noopener">PhotoCraft repository</a> was created on September 30. In two weeks, 54K stars, 8 releases and, as I write, more than 800 open issues. The README badge says &ldquo;early alpha&rdquo;, and Brandon Thomas himself, quoted by Gizmodo, said it&rsquo;s nowhere close to ready. The press that tested it reached the same conclusion: Gizmodo called it a &ldquo;glitchy, but real, Photoshop&rdquo;, and OMG Ubuntu &ldquo;a superficial facsimile with pronounced flaws&rdquo;.</p>
<p>The issues tell the technical story:</p>
<ul>
<li>Any image above 8,192 pixels leaves the GPU compositor and falls back to the CPU, with a 6 GB memory peak, because that&rsquo;s the egui-wgpu texture limit (<a href="https://github.com/storytold/photocraft/issues/49"target="_blank" rel="noopener">issue 49</a>, already closed, and the ones that came after it, <a href="https://github.com/storytold/photocraft/issues/1015"target="_blank" rel="noopener">1015</a> and <a href="https://github.com/storytold/photocraft/issues/4017"target="_blank" rel="noopener">4017</a>).</li>
<li>A 12 megapixel photo needs almost 800 MB just to open, adjust and export from the command line (<a href="https://github.com/storytold/photocraft/issues/1637"target="_blank" rel="noopener">issue 1637</a>).</li>
<li>Color management is rudimentary: a global working space only, instead of per document, and no view transform (<a href="https://github.com/storytold/photocraft/issues/321"target="_blank" rel="noopener">issue 321</a>). Eighteen issues mention CMYK, fifteen mention ICC profiles.</li>
<li>Almost a hundred open issues mention PSD. Hue/Saturation layers composite differently from Photoshop, and saving over the file overwrites the original&rsquo;s correct merged image (<a href="https://github.com/storytold/photocraft/issues/4089"target="_blank" rel="noopener">issue 4089</a>).</li>
<li>Fifty open issues mention &ldquo;crash&rdquo;.</li>
</ul>
<p>The interface resembles Photoshop, so the screenshot is shareable, and whoever sees the screenshot assumes it&rsquo;s a carbon copy. That&rsquo;s expected in a two-week-old alpha. With interest, time and contributions, part of this gets fixed. And then the contributors will discover something the N64 projects never faced.</p>
<blockquote>
  <p>PhotoCraft today is that Ferrari replica built on top of a VW Beetle: the body has the right shape, you take a photo and most people say &ldquo;wow, a Ferrari&rdquo;. Then you turn the key and out comes the Beetle engine. If the photo got you hyped, that&rsquo;s on you.</p>

</blockquote>
<h2>The target moves<span class="hx:absolute hx:-mt-20" id="the-target-moves"></span>
    <a href="#the-target-moves" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Decompiling 1998&rsquo;s Zelda is aiming at a stationary target. Nintendo isn&rsquo;t going to release Ocarina of Time 2026 with a new file format. Copying a live product is another conversation, and we&rsquo;ve seen this movie before.</p>
<p>In the 90s and 2000s the target was Microsoft Office. StarOffice became OpenOffice in 2000 and LibreOffice in 2010, and all of them spent years chasing a binary format, .doc, that changed from version to version and only got a public specification in 2008, when the game was already over. The proven part of that story is in the court cases: the European Commission fined Microsoft <a href="https://ec.europa.eu/commission/presscorner/detail/en/ip_04_382"target="_blank" rel="noopener">497 million euros in 2004</a> for refusing to supply interoperability information, and <a href="http://news.bbc.co.uk/2/hi/business/7266629.stm"target="_blank" rel="noopener">899 million in 2008</a> for failing to comply. .docx only became an ISO standard in 2008, in a <a href="https://en.wikipedia.org/wiki/Standardization_of_Office_Open_XML"target="_blank" rel="noopener">vote so controversial</a> that countries formally protested.</p>
<p>It took more than ten years. And when the format finally opened, Office no longer mattered the same way. The value moved elsewhere: today it&rsquo;s <a href="https://office365itpros.com/2024/01/31/office-365-reaches-400-million/"target="_blank" rel="noopener">400 million paid Office 365 seats</a>, <a href="https://www.googlecloudpresscorner.com/2025-12-04-Google-Workspace-Study-Reveals-More-Than-90-of-Rising-Leaders-Want-AI-With-Personalization"target="_blank" rel="noopener">3 billion Google Workspace users</a> and around <a href="https://prodesigntools.com/number-of-creative-cloud-subscribers.html"target="_blank" rel="noopener">41 million Creative Cloud subscribers</a>. Nobody wants to install that on a desktop, and so nobody has the binary.</p>
<blockquote>
  <p>Reverse engineering Google Docs means rewriting the product from scratch looking only at the interface, because the code that matters never leaves the server. After the world moved to SaaS, most proprietary software became a walled garden with no binary. No binary, nothing to disassemble.</p>

</blockquote>
<p>You can build versions of it, of course. <a href="https://immich.app/"target="_blank" rel="noopener">Immich</a> replaces Google Photos for a person or a family: phone backup, face recognition, semantic search, all on your server. What it doesn&rsquo;t replicate is the infrastructure and the training corpus that make Google&rsquo;s search Google&rsquo;s search. And Adobe made the same migration, in pieces.</p>
<h2>Photoshop is far more than layers and crop<span class="hx:absolute hx:-mt-20" id="photoshop-is-far-more-than-layers-and-crop"></span>
    <a href="#photoshop-is-far-more-than-layers-and-crop" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the part I know from having paid for it. The features that sell subscriptions today don&rsquo;t even run on your computer.</p>
<p>Generative Fill and Generative Expand run on Firefly, in the cloud, and consume <a href="https://helpx.adobe.com/creative-cloud/apps/generative-ai/generative-credits-faq.html"target="_blank" rel="noopener">generative credits</a>. Several Neural Filters, according to <a href="https://helpx.adobe.com/photoshop/using/neural-filters.html"target="_blank" rel="noopener">Adobe&rsquo;s own documentation</a>, need an internet connection because the processing happens on Adobe&rsquo;s servers. AI object selection has had, since 2020, an option to process in the cloud for a refined result. All of this is code that doesn&rsquo;t exist on your machine for anyone to disassemble.</p>
<p>Then comes what is in the binary, but took decades and partnerships to exist. Camera Raw carries <a href="https://helpx.adobe.com/camera-raw/desktop/dng-and-file-formats/supported-lenses.html"target="_blank" rel="noopener">lens correction profiles</a> and per-camera color profiles for hundreds of models, built over twenty years and updated with every release. No clone guesses that. Either you have the data or you don&rsquo;t.</p>
<p>And there&rsquo;s color science. The example I always remember is GIMP and CMYK.</p>
<p>GIMP was born in 1995. The first native support for CMYK files arrived in <a href="https://www.gimp.org/news/2022/08/27/gimp-2-99-12-released/"target="_blank" rel="noopener">2022</a>, and only for import and export, with pixels always in RGB. <a href="https://www.cgchannel.com/2025/03/gimp-3-0-is-out/"target="_blank" rel="noopener">GIMP 3.0, from 2025</a>, still has no CMYK editing mode. It&rsquo;s on the <a href="https://developer.gimp.org/core/roadmap/"target="_blank" rel="noopener">roadmap</a> as work in progress.</p>
<p>Thirty years of an open project, with good and motivated people, and the print shop still asks for Photoshop. That&rsquo;s the size of the color science hole, and no coding agent invents color science: it reproduces what&rsquo;s in the training data.</p>
<p>Why did it take so long, if it was the most requested feature? Because GIMP&rsquo;s core was born with 8-bit-per-channel RGB baked into every layer, blend mode and filter. Supporting another color model meant rewriting the entire pixel engine, the migration to GEGL, which took the better part of a decade and was only finished in <a href="https://www.gimp.org/release-notes/gimp-2.10.html"target="_blank" rel="noopener">GIMP 2.10, in 2018</a>. CMYK could only start after that.</p>
<p>And CMYK is a family of device profiles, with four inks, a per-printer ICC profile, ink limits and black generation rules, and editing in it means the whole pipeline has to compute in a subtractive four-channel model and round-trip through the profiles without drifting. A single developer, however good a programmer, without experience in this specific field will struggle to implement it, because the knowledge lives in print shops and color labs, and almost none of it is in a training corpus. In GIMP, the people who carried it forward were contributors who understand printing, and even then it took years. No new tool shortcuts that kind of knowledge.</p>
<p>And then there&rsquo;s the layer that isn&rsquo;t even technical: commercial licensing. Print-shop color is Pantone, and Pantone is a proprietary library. No open project can ship the palettes; the Inkscape developers <a href="https://lists.inkscape.org/hyperkitty/list/inkscape-devel@lists.inkscape.org/message/DOXDMUAPHORC4HEXPF37LYBQH6SSQ2M5"target="_blank" rel="noopener">reached that conclusion in 2005</a>, and <a href="https://www.linux.com/news/pantone-and-free-software/"target="_blank" rel="noopener">Linux.com explained the legal risk</a> around the same time. Adobe itself felt it in 2022: when Pantone changed its business model, the libraries <a href="https://petapixel.com/2022/10/28/you-have-to-pay-a-subscription-to-use-pantone-colors-in-photoshop-now"target="_blank" rel="noopener">were pulled from Photoshop, Illustrator and InDesign</a>, old files started opening with their Pantone colors replaced by black, and anyone who needs them pays for a separate plugin subscription. If even Adobe, paying, didn&rsquo;t escape, imagine a clone that runs on goodwill.</p>
<h3>Video is worse<span class="hx:absolute hx:-mt-20" id="video-is-worse"></span>
    <a href="#video-is-worse" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In Premiere, After Effects and DaVinci Resolve, the problem multiplies. A cinema camera doesn&rsquo;t deliver video, it delivers raw data on its own logarithmic curve: ARRI&rsquo;s LogC4, RED&rsquo;s IPP2. To turn that into an image you need the manufacturer&rsquo;s transforms, and RED ships its own in an <a href="https://community.acescentral.com/t/red-ipp2-color-workflows/1055"target="_blank" rel="noopener">SDK</a> that the editors integrate and update with every version. ACES, the industry&rsquo;s neutral standard, depends on input transforms supplied by each manufacturer.</p>
<p>Blackmagic gives Resolve away for free and it decodes ARRIRAW and R3D. It does that because it pays for the SDK and the partnership on your behalf. An agent-built clone, &ldquo;guessing&rdquo; how the Alexa&rsquo;s image should look, produces an image that doesn&rsquo;t match the reference monitor, and in cinema that means it&rsquo;s useless. That knowledge isn&rsquo;t in any training corpus: it&rsquo;s in contracts.</p>
<h2>The Bun case: what it costs to rewrite big software<span class="hx:absolute hx:-mt-20" id="the-bun-case-what-it-costs-to-rewrite-big-software"></span>
    <a href="#the-bun-case-what-it-costs-to-rewrite-big-software" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For a sense of the order of magnitude, the best public data point there is comes from Bun. In May 2026, Jarred Sumner rewrote the entire runtime from Zig to Rust using agents, and in July <a href="https://bun.com/blog/bun-in-rust"target="_blank" rel="noopener">published the numbers</a>:</p>
<ul>
<li>535K lines of Zig in 1,448 files became a one-million-line Rust diff, in 11 days.</li>
<li>Up to 64 Claude instances in parallel, 24 hours a day, every line reviewed by two adversarial agents and a fixer.</li>
<li>5.9 billion uncached input tokens, 690 million output tokens, 72 billion cache reads: <strong>around US$ 165K</strong> at API prices.</li>
<li>16K compiler errors fixed by 64 agents before CI went green on six platforms.</li>
<li>The existing test suite, with more than a million assertions, passed 100% before the merge.</li>
</ul>
<p>Read again what made it possible:</p>
<ul>
<li>the project&rsquo;s original author at the controls</li>
<li>a complete, working source code as reference</li>
<li>a test suite with a million assertions serving as the oracle</li>
<li>unlimited budget, because Bun has belonged to Anthropic since December 2025, and a pre-release version of Claude Fable 5</li>
</ul>
<p>Sumner estimates three engineers with full context would have needed a year.</p>
<p>Now take each of those advantages away. PhotoCraft doesn&rsquo;t have the Photoshop source to port, it has to invent. It doesn&rsquo;t have a test suite that says &ldquo;this matches Photoshop&rdquo;. It doesn&rsquo;t have Photoshop&rsquo;s author.</p>
<p>And Photoshop is a 36-year-old product whose disk requirements Adobe lists between <a href="https://helpx.adobe.com/photoshop/desktop/get-started/technical-requirements-installation/adobe-photoshop-on-desktop-technical-requirements.html"target="_blank" rel="noopener">10 and 100 GB</a>, against a JavaScript runtime. Even without knowing the size of Adobe&rsquo;s codebase, we&rsquo;re talking about a bigger target, with no reference, no oracle and no owner. Orders of magnitude above US$ 165K, and even then it would be an approximation.</p>
<h2>Why retro moves so fast<span class="hx:absolute hx:-mt-20" id="why-retro-moves-so-fast"></span>
    <a href="#why-retro-moves-so-fast" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If it&rsquo;s so hard, why does an old game port ship every day? Because retro stacks up every advantage the rest doesn&rsquo;t have.</p>
<p><strong>The binary is available and tiny.</strong> Super Mario Bros. on the NES: 40 KB. Super Mario 64: 8 MB. Ocarina of Time and Majora&rsquo;s Mask: 32 MB each. A whole PS1 CD: 650 MB.</p>
<p>Compare with <a href="https://store.steampowered.com/app/1086940/Baldurs_Gate_3/"target="_blank" rel="noopener">Baldur&rsquo;s Gate 3</a>, 150 GB, or with the <a href="https://support.activision.com/black-ops-6/articles/pc-system-requirements-for-black-ops-6"target="_blank" rel="noopener">latest Call of Duty</a>, above 100 GB. That&rsquo;s three or four orders of magnitude, and the scope shrinks along with it: a 1996 game has a handful of systems, not a physics engine with networking, a store and anticheat.</p>
<p><strong>The technology is old and documented.</strong> Twenty-five years of community have already mapped the N64, PS1 and SNES hardware instruction by instruction. The agent discovers nothing; it speeds up work that already has a map. It&rsquo;s the same pattern I <a href="/en/2026/09/28/llms-are-good-at-reproducing-what-exists-what-about-new-things/">saw in my retrocomputing projects</a>: where there&rsquo;s a reference and an oracle, AI flies; where there isn&rsquo;t, it spins in brute force.</p>
<p><strong>The target doesn&rsquo;t move.</strong> Nobody is going to update 1998&rsquo;s Zelda.</p>
<p><strong>And the legal side was settled thirty years ago.</strong> Sega v. Accolade and Sony v. Connectix drew the outline. The ports require you to supply your own ROM.</p>
<h3>A modern console is a PC<span class="hx:absolute hx:-mt-20" id="a-modern-console-is-a-pc"></span>
    <a href="#a-modern-console-is-a-pc" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The second half of the explosion, the PS4, PS5, Xbox One and Switch ports, has another explanation: those consoles are PCs or phones in a different case. The <a href="https://www.playstation.com/en-us/ps4/tech-specs/"target="_blank" rel="noopener">PS4</a> uses an AMD Jaguar x86-64, the <a href="https://blog.playstation.com/2020/03/18/unveiling-new-details-of-playstation-5-hardware-technical-specs/"target="_blank" rel="noopener">PS5</a> a Zen 2, the <a href="https://news.xbox.com/en-us/2020/03/16/xbox-series-x-tech/"target="_blank" rel="noopener">Xbox Series</a> another Zen 2, the Switch an NVIDIA <a href="https://www.techinsights.com/blog/nintendo-switch-teardown"target="_blank" rel="noopener">Tegra X1</a> ARM chip. Your PC&rsquo;s processor runs that code natively. So nobody needs to emulate the CPU.</p>
<p>The remaining work is translating the operating system and the GPU. <a href="https://github.com/shadps4-emu/shadPS4"target="_blank" rel="noopener">shadPS4</a> reimplements the PS4&rsquo;s system libraries and recompiles the shaders: games ship from the factory with AMD GPU machine code, which the emulator decodes instruction by instruction and converts to SPIR-V, Vulkan&rsquo;s format.</p>
<p><a href="https://almost-there-games.itch.io/azimuth"target="_blank" rel="noopener">Azimuth</a>, which makes Forza Horizon 2 run on Windows, translates Xbox WinRT calls to Win32 and DirectX 11.X to desktop DirectX 12, with the game&rsquo;s x86 code running directly. AnyPS5 relinks the executable: it takes the PS5 binary and produces a native Linux or Windows binary, linked against reimplemented system libraries. In all three cases, Proton, DXVK, VKD3D and MoltenVK had solved the graphics translation layer years earlier.</p>
<p>The reverse proof is the consoles that weren&rsquo;t PCs. The PS3 uses the Cell, a PowerPC with seven active coprocessors (the SPEs), each with its own local memory and no cache, and RPCS3 has been at it <a href="https://rpcs3.net/about"target="_blank" rel="noopener">since 2011</a>, with SPU emulation still the bottleneck today. The Xbox 360 is PowerPC too, which is why Sonic Unleashed needed XenonRecomp to translate PowerPC into C++. Reverse engineering is case by case, and the architecture decides whether the case is easy.</p>
<h3>AI is in the loop, and there&rsquo;s already a fight<span class="hx:absolute hx:-mt-20" id="ai-is-in-the-loop-and-theres-already-a-fight"></span>
    <a href="#ai-is-in-the-loop-and-theres-already-a-fight" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>That the 2026 ports use AI, many of them say outright. The <a href="https://github.com/SlickAmogus/silent-hill-decomp"target="_blank" rel="noopener">Silent Hill decomp</a> writes in its README that development is &ldquo;heavily AI-assisted (Claude Opus 4.6, 4.7 and the newer Fable model), and we&rsquo;re open about that. It is not automated translation of the game&rdquo;. The Pokémon Stadium recomp <a href="https://retrododo.com/a-pokemon-stadium-recomp-has-finally-arrived-but-lists-claude-as-a-contributor/"target="_blank" rel="noopener">lists Claude as a contributor</a>.</p>
<p>The devs of the Zelda and Banjo recomps, who spent years doing this by hand, <a href="https://kotaku.com/zelda-and-banjo-recompiled-devs-go-to-war-with-ai-vibe-coded-slopcomps-2000739936"target="_blank" rel="noopener">went to war</a> with what they call &ldquo;slopcomps&rdquo;, agent-generated ports of alpha quality.</p>
<p>And it&rsquo;s worth separating headline from actual state here too. AnyPS5 has a 0.1 version from September that, according to those who tested it, runs one 2D indie game; the viral claim that &ldquo;the PS5 is 80% ported to PC&rdquo; comes from fans, and no 3D game runs. Astro Bot runs, but in emulators (KytyPS5, SharpEmu), which take the traditional path. Forza Horizon 2 runs, and Azimuth is a closed binary from a studio that declares itself &ldquo;AI assisted&rdquo; without saying anything more.</p>
<h2>&ldquo;But in two years tokens will cost nothing&rdquo;<span class="hx:absolute hx:-mt-20" id="but-in-two-years-tokens-will-cost-nothing"></span>
    <a href="#but-in-two-years-tokens-will-cost-nothing" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The standard answer to all of this is: it&rsquo;s hard today, in two years it&rsquo;s trivial, because AI grows exponentially. The numbers say otherwise.</p>
<p>The price of the most expensive tier barely fell. GPT-4 in March 2023 cost US$ 30 and 60 per million input and output tokens; Claude 3 Opus in 2024, 15 and 75; today&rsquo;s frontier models, Fable 5.1 and GPT-6 Astra, <a href="https://claude.com/pricing"target="_blank" rel="noopener">cost</a> <a href="https://developers.openai.com/api/docs/pricing"target="_blank" rel="noopener">10 and 50</a>. In three and a half years, the frontier got between 1.2 and 3 times cheaper, depending on which end you look at.</p>
<p>What really fell was the cost of a fixed quality: Epoch AI measured drops <a href="https://epoch.ai/blog/llm-inference-price-trends"target="_blank" rel="noopener">of 9 to 900 times per year</a> depending on the task, and in a <a href="https://epoch.ai/gradient-updates/how-persistent-is-the-inference-cost-burden"target="_blank" rel="noopener">2026 review</a> sums it up as &ldquo;very roughly 5 to 10 times per year&rdquo;, with the caveat that it might slow down. That&rsquo;s real and it&rsquo;s great.</p>
<p>But apply the math to Bun. US$ 165K divided by 10 is US$ 16K. By 100, US$ 1,650. That&rsquo;s to port a runtime with the source, the tests and the author in hand.</p>
<p>For an amateur trying to clone Photoshop with none of that, the bill starts orders of magnitude higher and falls in the same proportion. Cheap isn&rsquo;t the same as trivial.</p>
<p>And the &ldquo;exponential&rdquo; premise died in 2024. Ilya Sutskever said at NeurIPS that <a href="https://www.globalbankingandfinance.com/ai-with-reasoning-power-will-be-less-predictable-ilya-sutskever-says/"target="_blank" rel="noopener">pre-training as we know it will end</a>, because there&rsquo;s only one internet. Epoch projects that reasoning model scaling <a href="https://epoch.ai/gradient-updates/how-far-can-reasoning-models-scale"target="_blank" rel="noopener">converges to the general frontier rate</a> in about a year.</p>
<p>I&rsquo;ve written about this three times in recent weeks: <a href="/en/2026/09/28/llms-are-good-at-reproducing-what-exists-what-about-new-things/">the limits</a> of what the model reproduces, <a href="/en/2026/10/12/llms-agents-competent-enough/">the convergence</a> of raw models with the gains coming from the harness, and <a href="/en/2026/10/11/are-there-better-languages-for-programming-with-llms/">the languages benchmark</a> where the frontier models tied at the ceiling. The tool we have is the tool we&rsquo;ll have for a good while, with incremental improvement. Plan with it.</p>
<p>Worth recalling the number that opens the limits post: per the <a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/"target="_blank" rel="noopener">Octoverse 2025</a>, GitHub&rsquo;s official report, 81.5% of contributions on the platform happened in private repositories. That&rsquo;s the code that really matters, the code that pays salaries, and no LLM has seen a line of it. The model reproduces what was in the training data, and that code was never there.</p>
<p>Now extend that to every SaaS product and every component it uses. The Adobe code that&rsquo;s actually worth something, the color engine, the profiles, the cloud filters, isn&rsquo;t available anywhere, not even as a binary. Anyone who wants to reproduce it will have to redo the research and development, expensive and slow, over the same years Adobe took. And at the end they still run into third-party licensed intellectual property, Pantone, camera SDKs, manufacturer profiles, that you will never be able to have.</p>
<h2>Answering the list from the top<span class="hx:absolute hx:-mt-20" id="answering-the-list-from-the-top"></span>
    <a href="#answering-the-list-from-the-top" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Does PhotoCraft exist?</strong> It does, it&rsquo;s a two-week-old alpha with more than 800 open issues, rudimentary color management, freezing above 8K and opening PSDs wrong. It looks like Photoshop in a screenshot. It can improve a lot, and it will discover that the target moves and that Photoshop&rsquo;s expensive parts live in the cloud or in manufacturer contracts.</p>
<p><strong>Does REA exist?</strong> It does, it&rsquo;s good, and it&rsquo;s a toolbox for people who already know how to use Ghidra, requiring the binary in hand, the tools installed and hundreds of thousands of tokens per analysis. The project itself avoids saying it clones programs.</p>
<p><strong>Did recomps and decomps accelerate?</strong> Yes, for real, and AI has a part in it. They accelerated where the binary exists, is small, has been documented for 25 years and doesn&rsquo;t move. Or where the console is a PC in disguise and the work is API translation, solved by Wine and Vulkan years earlier.</p>
<p><strong>Is Adobe dead?</strong> Adobe has around 40 million subscribers by the most cited estimate, the features that sell subscriptions run on its servers, and thirty years of GIMP still leave the print shop asking for Photoshop. I wish it were otherwise. The data says what will happen is what always happened with clones of a live product: years of chasing, and when you catch up, the value has already moved.</p>
<p><strong>Are programmers dead?</strong> Rewriting Bun required Bun&rsquo;s author. The decomps that work have people who know the hardware driving the agent, and the ones that don&rsquo;t became &ldquo;slopcomps&rdquo;, name and all. Reverse engineering got cheaper and more accessible, as it did with Ghidra in 2019, and it&rsquo;s still an engineer&rsquo;s job. Without us, the tool returns a pretty screenshot.</p>
<p>Proprietary software with a binary in hand will come under pressure, and it should. Most of the software you use has no binary at all, and the software that does already depends on cloud services that don&rsquo;t disassemble. Software engineering with AI has a great road ahead. &ldquo;It&rsquo;s over&rdquo; headlines get clicks and don&rsquo;t compile.</p>
]]></content:encoded><category>artificial-intelligence</category><category>vibe-coding</category><category>retrocomputing</category><category>open-source</category></item><item><title>Linux users: always choose BTRFS, not EXT4</title><link>https://www.akitaonrails.com/en/2026/10/12/linux-users-always-choose-btrfs-not-ext4/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/12/linux-users-always-choose-btrfs-not-ext4/</guid><pubDate>Mon, 12 Oct 2026 23:00:00 -0300</pubDate><description>&lt;p&gt;This post is a direct sequel to the &lt;a href="https://www.akitaonrails.com/en/2026/10/06/disaster-on-my-nas-how-i-almost-lost-90-tb-of-data/"&gt;disaster on my NAS&lt;/a&gt;. Summary for newcomers: my Synology, with eight drives in SHR (single parity), lost two drives in one strike during an upgrade. I survived thanks to an SHR implementation detail, bought a QNAP in a hurry, spent a week copying and verifying 91 TB, and lost not a single file by accident. The new QNAP runs ZFS in RAID-6; the rebuilt Synology now runs SHR-2.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This post is a direct sequel to the <a href="/en/2026/10/06/disaster-on-my-nas-how-i-almost-lost-90-tb-of-data/">disaster on my NAS</a>. Summary for newcomers: my Synology, with eight drives in SHR (single parity), lost two drives in one strike during an upgrade. I survived thanks to an SHR implementation detail, bought a QNAP in a hurry, spent a week copying and verifying 91 TB, and lost not a single file by accident. The new QNAP runs ZFS in RAID-6; the rebuilt Synology now runs SHR-2.</p>
<p>Underneath this whole story there&rsquo;s a decision almost nobody makes consciously: <strong>the filesystem</strong>. The Synology used btrfs all along. The QNAP uses ZFS. And your Linux machine, most likely, came from the factory with ext4 without anyone asking you anything. That&rsquo;s what this is about.</p>
<h2>Where the two came from<span class="hx:absolute hx:-mt-20" id="where-the-two-came-from"></span>
    <a href="#where-the-two-came-from" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>ext4 is the end of a dynasty of over three decades. ext (extended filesystem) was born with Linux itself, ext2 became the standard in the 90s, ext3 added a journal in 2001 so you wouldn&rsquo;t need an epic fsck after every power loss, and ext4 arrived in 2008 with extents, delayed allocation and volumes up to 1 exbibyte. The design goal was always the same: be the default filesystem, fast, simple and predictable. It&rsquo;s excellent at that. And it stopped there.</p>
<p>btrfs was born in 2007, at Oracle, with Chris Mason, with a completely different goal: be Linux&rsquo;s answer to ZFS. Instead of writing data over data, it&rsquo;s copy-on-write: every write goes to a new block and the pointers are updated cascading up the tree. That single decision is the mother of everything that matters in it.</p>
<p>What each one delivers, in a list:</p>
<p><strong>ext4:</strong></p>
<ul>
<li>journaling (consistent metadata after a crash)</li>
<li>extents and delayed allocation (good performance)</li>
<li>mature, stable, everywhere, every tool works</li>
</ul>
<p><strong>btrfs:</strong></p>
<ul>
<li>copy-on-write on everything</li>
<li>data and metadata checksums on every block</li>
<li>instant, cheap snapshots</li>
<li>independent subvolumes inside the same volume</li>
<li>transparent compression (zstd, lzo, zlib)</li>
<li>native RAID and scrub (verification sweep)</li>
<li>snapshot send/receive for incremental backup</li>
<li>reflinks (copies that don&rsquo;t duplicate blocks)</li>
</ul>
<p>The list already answers the title&rsquo;s question. Let&rsquo;s go piece by piece.</p>
<h2>Even NTFS and APFS have passed ext4<span class="hx:absolute hx:-mt-20" id="even-ntfs-and-apfs-have-passed-ext4"></span>
    <a href="#even-ntfs-and-apfs-have-passed-ext4" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>And if the comparison with btrfs seems unfair, look sideways. NTFS was born in 1993, with Windows NT, already with metadata journaling and ACLs, and back in the 2000s it gained a log of every change on the volume plus shadow copies (Windows&rsquo; &ldquo;Previous Versions&rdquo;). APFS, which Apple launched in 2017 made for flash, is copy-on-write like btrfs: native snapshots (it&rsquo;s what Time Machine uses for local restores), instant file clones that share blocks, volumes sharing the space of the same container, and per-file encryption.</p>
<p>Read the ext4 list again and compare: no snapshots, no data checksums, no CoW, no compression. Windows&rsquo; and Mac&rsquo;s filesystems, which nobody considers examples of sophistication, protect your data better than Linux&rsquo;s default, whose last big feature came out in 2008. btrfs is what puts Linux in the same generation as the other two, instead of a decade behind.</p>
<h2>Why btrfs is far superior<span class="hx:absolute hx:-mt-20" id="why-btrfs-is-far-superior"></span>
    <a href="#why-btrfs-is-far-superior" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>What copy-on-write is, for those who never stopped to think about it<span class="hx:absolute hx:-mt-20" id="what-copy-on-write-is-for-those-who-never-stopped-to-think-about-it"></span>
    <a href="#what-copy-on-write-is-for-those-who-never-stopped-to-think-about-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In classic filesystems, writing is destructive by definition: updating a block means writing the new content over the old one, in the same place on disk. If the machine dies mid-write, the file ends up half old, half new. The ext3/ext4 journal covers that for <strong>metadata</strong> (the directory structure doesn&rsquo;t corrupt), but your data itself is left to luck.</p>
<p>Copy-on-write inverts the order: <strong>nothing is ever overwritten</strong>. Writing to a file allocates a new block, writes the new content there, and only when everything is safely on disk does the filesystem flip the pointers to the new version, atomically. At any instant, you have either the whole old version or the whole new version. Never a mix of the two.</p>
<p>What that buys in practice:</p>
<ul>
<li><strong>Nearly free snapshots.</strong> The old blocks already persist by CoW&rsquo;s nature; a snapshot is just the filesystem holding the root pointer of that instant, pure accounting.</li>
<li><strong>Power loss doesn&rsquo;t corrupt.</strong> An interrupted write leaves the previous version intact, because it was never touched. For anyone who has lost a VM image or a database to a mid-write crash, this is worth the whole filesystem.</li>
<li><strong>Verification becomes possible.</strong> Since each block is written once and never touched again, keeping its checksum forever makes sense. It&rsquo;s the base of the corruption protection I detail further down.</li>
</ul>
<p>The cost exists and I pay it knowingly: random-write-heavy files (VM disks, databases) fragment and duplicate blocks, because each rewrite becomes a new block. For those cases you disable CoW per directory with <code>chattr +C</code>, which must be set <strong>before</strong> the file is created. In my layout, the VM image made with the right <code>+C</code> stayed healthy; the one made without became the textbook fragmentation case.</p>
<h3>Snapshots are the feature that changes your life<span class="hx:absolute hx:-mt-20" id="snapshots-are-the-feature-that-changes-your-life"></span>
    <a href="#snapshots-are-the-feature-that-changes-your-life" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A btrfs snapshot is an instant photo of a subvolume, and it costs almost nothing, because CoW already keeps the old blocks while someone references them. Creating a snapshot is a seconds operation, not hours. In practice: before every upgrade, the system takes a photo. If the upgrade breaks, you don&rsquo;t &ldquo;uninstall packages&rdquo;: you boot back into the previous photo and you&rsquo;re done. The boot recovery section, further down, shows this happening for real.</p>
<h3>Subvolumes are the right way to organize the disk<span class="hx:absolute hx:-mt-20" id="subvolumes-are-the-right-way-to-organize-the-disk"></span>
    <a href="#subvolumes-are-the-right-way-to-organize-the-disk" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A subvolume is an independent namespace inside the same filesystem, with its own snapshot policy. And it has a killer property: <strong>snapshots are not recursive</strong>. A child subvolume inside another is automatically left out of the parent&rsquo;s snapshot.</p>
<p>I use this for everything. On my desktop, the cache directories that can be re-downloaded (mise, rustup, npm, opencode, AI caches) are becoming nested subvolumes inside <code>@home</code>: they stay in the same place for any program, but out of every snapshot. That separation alone takes 165 GiB out of snapshot scope, and the big caches (Hugging Face, yay, uv, pip) already live outside the system volume, with symlinks pointing to them: minus 148 GiB of snapshot, part already migrated and part in progress. The snapshot stays small, the restore stays fast, and whatever can be re-downloaded from the internet never enters the photo.</p>
<p>The real cost, measured on the new QNAP (ZFS, but the CoW math is the same): 27 hourly snapshots of a folder with almost 80 TB, and nearly all of them consume megabytes, because between one hour and the next almost nothing changed. Cheap snapshots are what let this routine exist without guilt.</p>
<p><img src="/2026/10/12/usuarios-linux-sempre-escolham-btrfs-nao-ext4/qnap-snapshot-manager.png" alt="QNAP Snapshot Manager with 27 hourly snapshots of the CHAD folder, most consuming between 3 and 300 MB"  loading="lazy" /></p>
<h3>Reflink deduplication<span class="hx:absolute hx:-mt-20" id="reflink-deduplication"></span>
    <a href="#reflink-deduplication" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>First, the caveat that matters: btrfs has no native online deduplication like ZFS (which keeps a dedup table in RAM and charges dearly for it). What it has are two practical things: <strong>reflink</strong> and offline dedup. Reflink is a copy that shares blocks: <code>cp --reflink=auto</code> creates a new file that points to the same blocks as the original, instant and free, and each one starts diverging only where written. In the era of dozens of checkouts, worktrees and similar builds, that saves a mountain of blocks. For retroactive dedup there are userspace tools like <a href="https://github.com/markfasheh/duperemove"target="_blank" rel="noopener">duperemove</a> and <a href="https://github.com/Zygo/bees"target="_blank" rel="noopener">bees</a>.</p>
<h3>Real corruption protection<span class="hx:absolute hx:-mt-20" id="real-corruption-protection"></span>
    <a href="#real-corruption-protection" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every btrfs block, data or metadata, carries a checksum. When the filesystem reads and the checksum doesn&rsquo;t match, it knows the block rotted, and if there&rsquo;s a second copy (RAID or metadata DUP) it self-heals. ext4 checks no data at all: bit rot passes silently until you open the file years later.</p>
<p>Two pieces of my configuration show what that buys in practice, and what ext4 simply doesn&rsquo;t offer. The first is metadata in DUP mode. On ext4, each structure on the volume exists only once: a well-placed bad sector corrupts the directory table and the whole drive stops mounting. On btrfs, even with a single drive, every metadata block exists duplicated. The bad sector keeps existing, but the checksum flags the rotten block on read and the second copy answers in its place, without you noticing. It&rsquo;s the difference between losing the volume and noting a warning in the log.</p>
<p>The second is the monthly scrub. ext4 never re-reads anything to check health: if a block rots, you find out the day someone tries to open that specific file, maybe years later, when there&rsquo;s no fixing it anymore. The scrub is a scheduled sweep that re-reads the whole volume validating checksums, and finds the rot while it&rsquo;s still small and recoverable. When the <code>btrfs device stats</code> counter leaves zero, it&rsquo;s the siren to replace the drive before the disaster, not after.</p>
<h3>Transparent compression, measured<span class="hx:absolute hx:-mt-20" id="transparent-compression-measured"></span>
    <a href="#transparent-compression-measured" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every mount on my desktop uses <code>compress=zstd:1</code>. Level 1 costs a few percentage points of one CPU core, and btrfs detects what doesn&rsquo;t compress (model blob, video) and writes it raw, at no cost. The result, measured this week on my two new drives:</p>
<p><img src="/2026/10/12/usuarios-linux-sempre-escolham-btrfs-nao-ext4/btrfs-compressao-economia.png" alt="Compression savings table: 2.2 TB of data taking 1.6 TB on disk, with 35% savings on the system, 39% on Docker layers and zero on AI model weights"  loading="lazy" /></p>
<p>That&rsquo;s <strong>630 GB of free space</strong> on 2.2 TB: 15% more drive, paying nothing. On the initial migration the gain was even bigger, 45% on the system volume, because there was more text and less binary. Notice the table&rsquo;s details: programs and libraries compress well, Docker layers compress even better (39%), text logs compress 4.5x, and AI model weights compress nothing, which is expected and costs nothing. Source code, which is what we produce the most in the AI era, compresses beautifully.</p>
<h2>Synology uses btrfs, QNAP uses ZFS<span class="hx:absolute hx:-mt-20" id="synology-uses-btrfs-qnap-uses-zfs"></span>
    <a href="#synology-uses-btrfs-qnap-uses-zfs" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Being fair to ZFS: for a big NAS it&rsquo;s superior, and it&rsquo;s what I chose for the QNAP. Native checksums and self-healing, mature RAIDZ, excellent send/receive. The price is complexity and resources: ZFS wants RAM for the ARC cache (my QNAP has 7 GB for a 174 TB pool, and I feel the lack), its online deduplication would need about 190 GB of RAM just for the table on my volume, and its provisioning model gave me a free scare when the snapshot was refused with 20 TB free (the thick vs thin story is in the NAS article).</p>
<p>btrfs is the right balance for a consumer machine. Light, native in the kernel, does almost everything ZFS does without demanding a storage administrator. Desktop, laptop, homelab, small or medium NAS: btrfs. Synology proved it in practice, twice: the btrfs volume survived readable with two drives out, and its snapshots saved 11 albums I deleted by mistake in the middle of the cleanup, byte by byte.</p>
<blockquote>
  <p>Big, serious NAS, with RAM to spare: ZFS. Everything else: btrfs. And for a personal Linux machine, it&rsquo;s not even a discussion.</p>

</blockquote>
<h2>Boot recovery via snapshot<span class="hx:absolute hx:-mt-20" id="boot-recovery-via-snapshot"></span>
    <a href="#boot-recovery-via-snapshot" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The feature that has saved me for real, told on both machines.</p>
<p>On the desktop, <a href="https://omarchy.org"target="_blank" rel="noopener">Omarchy</a> configures <a href="https://snapper.io/"target="_blank" rel="noopener">snapper</a> to take a snapshot before every update and <code>limine-snapper-sync</code> publishes each snapshot as a boot entry in <a href="https://github.com/limine-bootloader/limine"target="_blank" rel="noopener">Limine</a>. New kernel won&rsquo;t come up? In the boot menu you pick yesterday&rsquo;s snapshot and the machine comes back as if nothing happened. On my machine the scheduled routine runs via <a href="https://github.com/teejee2008/timeshift"target="_blank" rel="noopener">Timeshift</a> on cron (every boot and hourly), with snapper covering the update points: the way back is the same mechanism. (The gotcha: each snapshot entry carries the kernel image along, so a small ESP fills up fast. My 1 GB one already refused a kernel update for lack of space; the system stayed bootable on the old kernel, which is the right behavior.)</p>
<p>On the server, which runs <a href="https://get.opensuse.org/microos/"target="_blank" rel="noopener">openSUSE MicroOS</a>, it&rsquo;s even stronger: the whole system is transactional btrfs, and every update is a new snapshot. Last week, kernel 7.2.9 took down the NVMe controller silently, twice, in the middle of the nightly backup. The fix was a <code>transactional-update rollback</code> and a reboot back to 7.2.6, which ran the whole load (754 GiB of backup reads with concurrent download) without a hiccup. A kernel regression became a scheduled reboot, not a recovery all-nighter. One documented caveat: <code>/etc</code> lives inside the snapshot, so the rollback undoes configuration changes along with it. After any rollback, check your units again.</p>
<h2>Maintenance is not optional (and the deleted file that won&rsquo;t go away)<span class="hx:absolute hx:-mt-20" id="maintenance-is-not-optional-and-the-deleted-file-that-wont-go-away"></span>
    <a href="#maintenance-is-not-optional-and-the-deleted-file-that-wont-go-away" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A modern CoW filesystem delivers a lot, but it charges two routines ext4 never asked for.</p>
<p>The first is the scrub, which already appeared here: re-read everything and check checksums, monthly, on all machines. It&rsquo;s bit-rot detection in action, and without it the checksum only warns you about the rot when you try to read the file. The second point is subtler: <strong>a snapshot pins the blocks of deleted files</strong>. When you delete a file inside a snapshotted subvolume, the space doesn&rsquo;t come back, because the block stays referenced by the photo. That&rsquo;s exactly what happened on my NAS: the 2.14 TB cleanup I ran on the Synology only freed space for real after the old snapshots were removed; until then, the blocks stayed pinned.</p>
<p>The treatment is simple routine. Retention has to be automatic, with snapper or Timeshift deleting the old snapshots per policy (on the QNAP, the Snapshot Manager&rsquo;s retention policy plays the same role). Space that doesn&rsquo;t come back after deleting old snapshots is usually over-allocated chunks: a <code>btrfs balance start -dusage=50</code> returns the little-used pieces to the free pool (in my house I don&rsquo;t blindly schedule balance, I monitor the unallocated space and act when it gets tight). And on the restic side, <code>forget</code> alone only removes the snapshot&rsquo;s reference: the repository space is only reclaimed with <code>prune</code> along, <code>forget --prune</code>.</p>
<h2>House cleaning in the AI coding era<span class="hx:absolute hx:-mt-20" id="house-cleaning-in-the-ai-coding-era"></span>
    <a href="#house-cleaning-in-the-ai-coding-era" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now the part almost nobody connects with filesystems: the agent era produces garbage at industrial speed. I know because I measured.</p>
<ul>
<li><strong>Rust is the biggest disk polluter in the dev world.</strong> Every build leaves behind 100 to 180 MB test binaries, and they accumulate with each edit. On my desktop, the <code>target/</code> directories added up to <strong>920 GiB</strong>. ai-memory alone accounted for 704 GiB. The hygiene tool I was using is <a href="https://github.com/holmgr/cargo-sweep"target="_blank" rel="noopener">cargo-sweep</a>, weekly. A reader pointed out that the project declares itself unmaintained, and its own README points to <a href="https://github.com/dnlmlr/cargo-clean-all"target="_blank" rel="noopener">cargo-clean-all</a>, which works differently: instead of pruning old artifacts inside one <code>target/</code>, it finds every Rust project under a directory and deletes the whole <code>target/</code> of the ones you filter, for example <code>cargo clean-all --keep-days 7 ~</code> to clean only what hasn&rsquo;t been compiled in a week.</li>
<li><strong>Docker is right behind.</strong> On my machine I found 1.26 TB of build cache plus 938 GB of images. A single cleanup recovered about 600 GB. On the server, the weekly cleanup collects 0.6 to 4.5 GB every Sunday.</li>
<li><strong>AI and package caches bloat quietly.</strong> The Hugging Face cache had 86 GB until I deleted three dead models and it dropped to 21. Pacman had 22 GB of outdated packages. yay, uv and pip, another 125 GB.</li>
<li><strong>And agents create temporary directories without asking permission.</strong> A complex project with several branches means worktrees, and each release worktree has its own <code>CARGO_TARGET_DIR</code> full of test binaries. On ai-memory that has already blown up the disk, and it became a mandatory rule in the project&rsquo;s AGENTS.md: after every release, <code>cargo clean</code> in each created worktree and removal of finished worktrees, no exceptions.</li>
</ul>
<p>The solution is to automate the sweeping. My minimal example, a user timer that runs on the 1st and 15th at dawn, with Nice and idle I/O:</p>
<ul>
<li>deletes <code>target/</code> directories of projects idle for more than 14 days</li>
<li>cleans the yay cache</li>
<li>prunes only Docker build cache older than 30 days, never images or volumes</li>
</ul>
<p>And the part that became standard in my house: <strong>instruct the agents to clean up what they create</strong>. Three real rules from my projects, for you to copy:</p>
<blockquote>
  <p><strong>In the desktop&rsquo;s AGENTS.md:</strong> &ldquo;Never run broad cleanups like <code>docker system prune</code> without explicit user authorization after a read-only inventory. Cleanup uses an exact list of IDs; idle, old or unreferenced does not mean disposable.&rdquo;</p>

</blockquote>
<blockquote>
  <p><strong>In the homelab&rsquo;s CLAUDE.md:</strong> &ldquo;Before finishing any task, remove the temporary things the task created, and only those. Never delete what you didn&rsquo;t create or can&rsquo;t attribute to the task. When in doubt, list it for the owner.&rdquo;</p>

</blockquote>
<blockquote>
  <p><strong>In ai-memory&rsquo;s AGENTS.md:</strong> &ldquo;<code>target/</code> grows without limit: every edit to a shared crate leaves behind a copy of each 100-180 MB test binary (seen at 157 GiB). Weekly <code>cargo sweep --time 7</code>, and mandatory <code>cargo clean</code> after every release.&rdquo;</p>

</blockquote>
<h2>And the real backup: restic<span class="hx:absolute hx:-mt-20" id="and-the-real-backup-restic"></span>
    <a href="#and-the-real-backup-restic" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A snapshot lives on the same drive, so a snapshot is not a backup: if the drive dies, the snapshot dies with it. The last item in the kit is <a href="https://restic.net/"target="_blank" rel="noopener">restic</a>, which for me is the best backup system on Linux today.</p>
<p>restic is a single open source binary, written in Go, that does deduplicated, encrypted and versioned backup to practically any destination: another directory, another NAS via SFTP or REST, S3, Glacier. The central trick is content-defined chunking: it slices each file into variable-size blocks defined by the content, hashes each block and only writes to the repository the blocks that don&rsquo;t exist there yet. That&rsquo;s why the delta is cheap: today&rsquo;s backup carries the blocks that changed since yesterday, not the files that changed. Editing a 100 GB database in the middle costs a few megabytes of backup, not 100 GB again. Each run becomes a repository snapshot, a restore point you browse with <code>restic mount</code> as if it were a filesystem, and <code>restic check</code> audits the whole repository&rsquo;s integrity whenever you ask.</p>
<p>Configuration matters more than the tool, so here&rsquo;s ours, mistakes included. On the desktop, the repository lives on the NAS and retention is <code>keep-daily 7, keep-weekly 4, keep-monthly 6, keep-yearly 1</code>. On the server, backup runs daily at dawn to the repository on the QNAP, covering <code>/etc</code>, <code>/usr/local/bin</code>, <code>/home</code> and the container volumes, with the password off the machine and <code>pg_dump</code> before the databases, because a filesystem snapshot doesn&rsquo;t guarantee consistency for a database that&rsquo;s writing. The first full load was 729 GiB in under an hour, and restic crossed unharmed, on retries, the window in which the NFS mount went read-only by mistake during the migration.</p>
<p>The most important part of the configuration is what does <strong>not</strong> go into the backup. Our exclusions, all with a reason:</p>
<ul>
<li>AI model caches (Immich, Hugging Face, EasyOCR): if lost, download again;</li>
<li>Prometheus metrics: history that regenerates itself;</li>
<li>the Fulcrum database: reindexes from bitcoind;</li>
<li>the decision classifiers&rsquo; weights: re-downloadable by revision hash (and this exclusion&rsquo;s glob goes inside quotes inside the bash array, because unquoted it becomes a backup source instead of an exclusion);</li>
<li><code>node_modules</code>, <code>target/</code>, cargo registry, rustup toolchains: pure build artifacts.</li>
</ul>
<p>And one retention lesson to close. When we shortened the server policy to &ldquo;yesterday, 2 dailies, 2 weeklies and 1 monthly&rdquo;, the correct translation to flags is <code>--keep-daily 3 --keep-weekly 3 --keep-monthly 2</code>, not 2/2/1: restic&rsquo;s levels overlap, and yesterday&rsquo;s snapshot is also the newest of this week and this month, so each number needs to be one more than the older points you want to keep. The detail caught us off guard: the script had a literal 2/2/1, and with it the monthly level would never hold anything older than last night. In practice, the intention was to keep 5 restore points, and 2/2/1 delivers only 3: yesterday, plus one daily, plus one weekly. We erred, measured, corrected.</p>
<p>A humility note from the disaster: the old repositories were left on the Synology by my decision (almost 2 TB of abandoned history, because the content was already re-covered on the new QNAP). A backup repository ages too, and revisiting its scope is part of the hygiene.</p>
<h2>Conclusion: in the AI era, disk is not a detail<span class="hx:absolute hx:-mt-20" id="conclusion-in-the-ai-era-disk-is-not-a-detail"></span>
    <a href="#conclusion-in-the-ai-era-disk-is-not-a-detail" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Agents coding all day change the storage math at both ends. On the volume end: builds, caches, worktrees and models fill the disk much faster than any human habit ever did, and without a cleanup routine you find out when it blows up. On the safety end: the more generated code, the more you need a cheap way back, because not every agent change is a good one.</p>
<p>btrfs covers both. Transparent compression gives back 15% of disk for free, and source code is exactly the kind of data that compresses the most. Snapshots and subvolumes give you instant rollback on the system and isolation for what doesn&rsquo;t need protection. Checksums and scrub watch the health of blocks that ext4 simply ignores. ext4 had its 15 years of well-deserved reign. In 2026, choosing it on a new Linux is giving up protection you&rsquo;ll need, sooner or later. Choose btrfs and set up the cleanup today.</p>
]]></content:encoded><category>linux</category><category>storage-and-backup</category><category>homelab</category><category>omarchy</category></item><item><title>LLMs + Agents = competent enough</title><link>https://www.akitaonrails.com/en/2026/10/12/llms-agents-competent-enough/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/12/llms-agents-competent-enough/</guid><pubDate>Mon, 12 Oct 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;This post is a synthesis. It ties into a single narrative what I&amp;rsquo;ve been writing and measuring through 2026, so here&amp;rsquo;s the road map before the argument:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/"&gt;New v4 benchmarks&lt;/a&gt;&lt;/strong&gt;: I retested the major models and the uncomfortable conclusion was convergence, not a leap.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/09/28/llms-are-good-at-reproducing-what-exists-what-about-new-things/"&gt;The limits of LLMs&lt;/a&gt;&lt;/strong&gt;: models are great at reproducing what exists, extremely expensive at what doesn&amp;rsquo;t, and the served model is a static file that learns nothing from your marathon.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/10/11/are-there-better-languages-for-programming-with-llms/"&gt;Are there better languages for programming with LLMs?&lt;/a&gt;&lt;/strong&gt;: no. Neither script conciseness nor strong typing changed the outcome; test discipline did.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/10/10/which-jev-like-ai-decision-classifier-model-is-best/"&gt;Which Jev-like decision model is best?&lt;/a&gt;&lt;/strong&gt;: 21 classifier configurations, and the &amp;ldquo;specialized models&amp;rdquo; themselves converged to within a few points of each other.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/04/20/clean-code-for-ai-agents/"&gt;Clean Code for AI agents&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/04/11/vs-code-is-the-new-punch-card/"&gt;VS Code is the new punch card&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/09/17/talking-about-my-ai-skills/"&gt;my skills&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/08/18/hot-take-harness-loop-engineering-graph-engineering-are-bullshit/"&gt;the hot take against loop engineering&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://www.akitaonrails.com/en/2026/05/30/open-source-best-practices-llm-the-minimum/"&gt;minimum best practices&lt;/a&gt;&lt;/strong&gt;: the same thesis from other angles. The model is a commodity; the engineering around it is the differentiator.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The thesis that closes this arc: &lt;strong&gt;LLMs have reached, or are very close to reaching, the ceiling of the transformer architecture.&lt;/strong&gt; And the good news is that nothing more than that is needed.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This post is a synthesis. It ties into a single narrative what I&rsquo;ve been writing and measuring through 2026, so here&rsquo;s the road map before the argument:</p>
<ul>
<li><strong><a href="/en/2026/09/23/llm-benchmark-v4-opus-5-5-gpt-6-sol-luna-mimo-2-6-grok-4-7/">New v4 benchmarks</a></strong>: I retested the major models and the uncomfortable conclusion was convergence, not a leap.</li>
<li><strong><a href="/en/2026/09/28/llms-are-good-at-reproducing-what-exists-what-about-new-things/">The limits of LLMs</a></strong>: models are great at reproducing what exists, extremely expensive at what doesn&rsquo;t, and the served model is a static file that learns nothing from your marathon.</li>
<li><strong><a href="/en/2026/10/11/are-there-better-languages-for-programming-with-llms/">Are there better languages for programming with LLMs?</a></strong>: no. Neither script conciseness nor strong typing changed the outcome; test discipline did.</li>
<li><strong><a href="/en/2026/10/10/which-jev-like-ai-decision-classifier-model-is-best/">Which Jev-like decision model is best?</a></strong>: 21 classifier configurations, and the &ldquo;specialized models&rdquo; themselves converged to within a few points of each other.</li>
<li><strong><a href="/en/2026/04/20/clean-code-for-ai-agents/">Clean Code for AI agents</a></strong>, <strong><a href="/en/2026/04/11/vs-code-is-the-new-punch-card/">VS Code is the new punch card</a></strong>, <strong><a href="/en/2026/09/17/talking-about-my-ai-skills/">my skills</a></strong>, <strong><a href="/en/2026/08/18/hot-take-harness-loop-engineering-graph-engineering-are-bullshit/">the hot take against loop engineering</a></strong> and <strong><a href="/en/2026/05/30/open-source-best-practices-llm-the-minimum/">minimum best practices</a></strong>: the same thesis from other angles. The model is a commodity; the engineering around it is the differentiator.</li>
</ul>
<p>The thesis that closes this arc: <strong>LLMs have reached, or are very close to reaching, the ceiling of the transformer architecture.</strong> And the good news is that nothing more than that is needed.</p>
<h2>Convergence, not a leap<span class="hx:absolute hx:-mt-20" id="convergence-not-a-leap"></span>
    <a href="#convergence-not-a-leap" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In my benchmarks, I see no relevant improvement in general programming since the Opus 4.5 generation. Yes, Fable and Astra are great at specific problems. In general programming, what I measure is everyone squeezed onto the same tier, including the Chinese commercial offerings (Kimi, GLM, DeepSeek). Model choice has become nearly irrelevant.</p>
<p>What still makes a real difference is the effort level: low effort for translation and summarization, high effort for vulnerability sweeps, heavy bug fixing or optimization. Beyond that, the numbers tell a reality much more boring than <a href="/en/2026/09/09/propagandas-enganosas-da-openai-anthropic-nvidia/">the vendors&rsquo; propaganda</a>.</p>
<blockquote>
  <p>My reading of the timeline: the models&rsquo; &ldquo;core&rdquo; reasoning had its last big leap in 2024. 2025 was the year of optimizing the architecture. 2026 is the year of refining the harness. Base intelligence made no order-of-magnitude leap in that period; efficiency and long-session competence did.</p>

</blockquote>
<h2>The timeline, with receipts<span class="hx:absolute hx:-mt-20" id="the-timeline-with-receipts"></span>
    <a href="#the-timeline-with-receipts" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><img src="/2026/10/12/llms-agentes-competente-o-suficiente/llms-agentes-timeline.png" alt="Timeline from 2019 to 2026: GPT-2 proves LLMs are useful, GPT-3 opens the parameter war, Chinchilla recalibrates toward data, GPT-4 turns parameter counts into secrets, o1 marks the reasoning peak, 2025 optimizes with MoE and caching, and 2026 is the agent era"  loading="lazy" /></p>
<p><strong>2019: GPT-2 proves LLMs are useful.</strong> 1.5 billion parameters, summarizing, translating and answering with no specific training, zero-shot. OpenAI found it so impressive that it <a href="https://openai.com/index/better-language-models/"target="_blank" rel="noopener">held back the full model for months</a> fearing misuse. Today it looks cute.</p>
<p><strong>2020: GPT-3 opens the parameter war.</strong> <a href="https://arxiv.org/abs/2005.14165"target="_blank" rel="noopener">175 billion</a>, a hundred times GPT-2, and the in-context few-shot learning that became the paradigm. <a href="https://arxiv.org/abs/2001.08361"target="_blank" rel="noopener">Kaplan&rsquo;s scaling law</a>, published months earlier, said loss fell as a power law with size, and the industry read it as &ldquo;bigger is better.&rdquo; There went two years of who-has-more-parameters.</p>
<p><strong>2022: Chinchilla recalibrates the war.</strong> DeepMind trained <a href="https://arxiv.org/abs/2203.15556"target="_blank" rel="noopener">400 models and showed</a> the giants were undertrained: a 70B model with 1.4 trillion tokens beat the 280B Gopher. The &ldquo;training data&rdquo; axis started weighing as much as the &ldquo;parameters&rdquo; axis. First crack in the war.</p>
<p><strong>2023: GPT-4 ends the war by decree.</strong> The <a href="https://arxiv.org/abs/2303.08774"target="_blank" rel="noopener">technical report</a> refused to publish size, hardware or data, citing the competitive landscape and safety implications. The most cited leak, from <a href="https://newsletter.semianalysis.com/p/gpt-4-architecture-infrastructure"target="_blank" rel="noopener">SemiAnalysis</a>, described 1.76 trillion parameters in a mixture of experts. Since then, parameter counts vanished from marketing: neither the GPT-5 announcements nor the Claude 4 ones cite a number. Notice neither Astra nor Fable spends a line on it today. The war ended and nobody signed an armistice.</p>
<p><strong>2024: the reasoning peak.</strong> <a href="https://openai.com/index/learning-to-reason-with-llms/"target="_blank" rel="noopener">September&rsquo;s o1</a> marked that peak: RL to produce long chains of thought, and the discovery that more test-time compute improves the answer. That is, by my yardstick, the last &ldquo;base intelligence&rdquo; revolution.</p>
<p><strong>2025: architecture optimization.</strong> Mixture of experts became the standard: <a href="https://mistral.ai/news/mixtral-of-experts/"target="_blank" rel="noopener">Mixtral</a> was already showing in 2023 that 46.7B total parameters with only 12.9B active per token cost like a small model, and <a href="https://arxiv.org/abs/2412.19437"target="_blank" rel="noopener">DeepSeek-V3</a> took that to 671B total with 37B active, with the final training run costing under 6 million dollars in GPU-hours at H800 rental prices (not counting the prior R&amp;D). The MoE magic is simple: it separates capacity (total parameters, which live in memory) from per-token cost (only the experts chosen by the router compute). You pay for a 37B model and carry a 671B one.</p>
<p>On the serving side, <a href="https://www.anthropic.com/news/prompt-caching"target="_blank" rel="noopener">prompt caching</a> cut up to 90% of repeated-context cost (OpenAI <a href="https://openai.com/index/api-prompt-caching/"target="_blank" rel="noopener">followed two months later</a>), context windows passed 1 million tokens, and serving techniques like speculative decoding and PagedAttention multiplied throughput. And <a href="https://arxiv.org/abs/2501.12948"target="_blank" rel="noopener">DeepSeek-R1-Zero</a> showed that pure RL, with no supervised fine-tuning, makes reasoning emerge. None of this is &ldquo;more intelligence.&rdquo; All of it is the same intelligence, cheaper, faster and more stable.</p>
<p><strong>2026: the agentic era.</strong> Function calling has existed since <a href="https://openai.com/index/function-calling-and-other-api-updates/"target="_blank" rel="noopener">June 2023</a>, but the ecosystem turning point was <a href="https://www.anthropic.com/news/model-context-protocol"target="_blank" rel="noopener">Anthropic&rsquo;s MCP</a> in late 2024, which OpenAI adopted months later and which today lives at the Linux Foundation. Claude Code, Codex and co. came out in 2025, and the metric that matters became <a href="https://metr.org/blog/2025-03-19-measuring-ai-ability-to-complete-long-tasks/"target="_blank" rel="noopener">METR</a>&rsquo;s: the task size an agent completes with 50% reliability had been doubling every 7 months since 2019. Anthropic&rsquo;s own guide on <a href="https://www.anthropic.com/engineering/building-effective-agents"target="_blank" rel="noopener">building effective agents</a> states the obvious plainly: simple, composable patterns, not fanciful frameworks.</p>
<h2>Why the agent allows a less dense model<span class="hx:absolute hx:-mt-20" id="why-the-agent-allows-a-less-dense-model"></span>
    <a href="#why-the-agent-allows-a-less-dense-model" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the mechanism most people don&rsquo;t stop to think about. A lone model needs to carry the world in its weights, because its only chance to answer is that one, in a single pass. A model with a harness doesn&rsquo;t:</p>
<ul>
<li><strong>On-demand search and reading.</strong> With web search and fetch, low-priority knowledge leaves the weights and becomes a lookup: the agent pulls it into the context window only when needed. The model can be less encyclopedic and more operator.</li>
<li><strong>Controlled trial and error.</strong> Alone, the model needs to guess the right answer on the first try. With an agent, it proposes a hypothesis, implements, sends it to be tested, gets the feedback and decides again with real information. Each such cycle is new knowledge entering the session without costing a training neuron.</li>
</ul>
<p>Both mechanisms fight hallucination at the root: fetch brings the fact the model doesn&rsquo;t know by heart, and the test loop catches the invention before it becomes code. That&rsquo;s why 2026 <strong>feels</strong> like a giant leap: the model+harness combination got much more competent, even with base intelligence nearly stalled.</p>
<h2>Not every problem needs a giant LLM<span class="hx:absolute hx:-mt-20" id="not-every-problem-needs-a-giant-llm"></span>
    <a href="#not-every-problem-needs-a-giant-llm" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The same &ldquo;less dense&rdquo; logic applies inside the application. Much of what people throw at a chat LLM is disguised classification: labeling tickets, routing queues, applying policy. For that there are specialized decision models, and I covered the topic twice: the <a href="/en/2026/10/03/understanding-the-jev-hype-what-is-it-for/">Jev hype</a>, with Paulo Câmara&rsquo;s essay on why a classifier is the first thing a computer scientist thinks of, and <a href="/en/2026/10/10/which-jev-like-ai-decision-classifier-model-is-best/">my benchmark with 21 configurations</a>, where a Microsoft 9B tied the hosted leader and a local 4B came within a few points, at cents per ten thousand decisions.</p>
<p>The &ldquo;193x faster&rdquo; shock of Jev&rsquo;s marketing only exists because many people were using a giant LLM as an expensive, slow classifier. When the right tool enters, the frontier model leaves the play, and along with it the cost, the latency and the format hallucination. It&rsquo;s this post&rsquo;s thesis in miniature: competence doesn&rsquo;t come from density, it comes from fit.</p>
<h2>The loop nobody sees<span class="hx:absolute hx:-mt-20" id="the-loop-nobody-sees"></span>
    <a href="#the-loop-nobody-sees" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There&rsquo;s a user-experience detail in this story. In a good agentic session, what happens is semi-transparent to whoever requested the task: the model guesses wrong, the agent fetches the documentation online or runs the real test, the error comes back as feedback, and the model corrects itself. You see &ldquo;task requested, task delivered.&rdquo; In between, dozens of micro-corrections happened that nobody witnessed.</p>
<p>My bet: since agents are trained to fill the context when they need to, even new language or library versions no longer confuse them that much. The model doesn&rsquo;t need to know the API by heart; it looks it up, tests and adjusts in the loop. That&rsquo;s what I see in my experiments, from <a href="/en/2026/09/07/ai-challenge-converting-nes-roms-to-master-system-sms/">converting NES ROMs to Master System</a> to the <a href="/en/2026/07/12/using-ai-to-solve-my-little-day-to-day-problems/">little day-to-day problems</a>. And it&rsquo;s what the <a href="/en/2026/10/11/are-there-better-languages-for-programming-with-llms/">languages benchmark</a> measured: seven languages came out practically equivalent, because the loop equalizes what training leaves uneven.</p>
<p>I measured the caveat too. When there&rsquo;s no documentation to fetch and no test to validate against, the loop spins in a vacuum: that&rsquo;s what happened with <a href="/en/2026/09/19/new-ai-language-just-released-bend-2/">Bend 2</a>, a language too new to have a corpus, and it was the central point of the post about <a href="/en/2026/09/28/llms-are-good-at-reproducing-what-exists-what-about-new-things/">the limits</a>. The mechanism is powerful, but it needs an oracle.</p>
<p>And there&rsquo;s a receipt that the base is stalled. Back in November 2024 <a href="https://www.reuters.com/technology/artificial-intelligence/openai-rivals-seek-new-path-smarter-ai-current-methods-hit-limitations-2024-11-11/"target="_blank" rel="noopener">Reuters</a> was already reporting diminishing returns in pre-training at the three big labs. At the following NeurIPS, Sutskever, the scaling-thesis guy, declared that <a href="https://www.youtube.com/watch?v=WQQdd6qGxNs"target="_blank" rel="noopener">&ldquo;pre-training as we know it will end&rdquo;</a>: the public data ran out. And <a href="https://hai.stanford.edu/ai-index/2025-ai-index-report"target="_blank" rel="noopener">Stanford&rsquo;s AI Index</a> measured the gap between the first and the tenth model on Chatbot Arena shrinking from 12% to 5% in one year. That&rsquo;s convergence, with numbers.</p>
<h2>The propaganda in the opposite direction<span class="hx:absolute hx:-mt-20" id="the-propaganda-in-the-opposite-direction"></span>
    <a href="#the-propaganda-in-the-opposite-direction" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>While the numbers show a plateau, the marketing sells the apocalypse. I already dissected a whole week of that in <a href="/en/2026/09/09/propagandas-enganosas-da-openai-anthropic-nvidia/">&ldquo;You&rsquo;re an idiot if you believe the misleading ads from OpenAI, Anthropic, NVIDIA&rdquo;</a>, so here&rsquo;s only what matters for this narrative:</p>
<ul>
<li>OpenAI&rsquo;s &ldquo;Navier-Stokes proof&rdquo; was agentic brute force at industrial scale, 130 billion tokens over human mathematicians&rsquo; machinery, sold as emergent intelligence.</li>
<li>The Hugging Face incident was a swarm running 17 thousand attempts with automatic verification, not an &ldquo;agent that gained consciousness and escaped.&rdquo; Expensive trial and error, exactly the mechanism I described here.</li>
<li>Fear is a product: whoever sells &ldquo;my AI is too powerful and might escape control&rdquo; is, in the same sentence, asking for regulation that locks out the smaller competitor and inflating the perception that their model is more capable than the others'.</li>
</ul>
<p>The facts I measured point the opposite way from the apocalypse: models converging, differences shrinking, and useful work migrating from the model to the harness. Rogue AI gaining consciousness is not what the logs show. What the logs show is engineering.</p>
<h2>&ldquo;Competent enough&rdquo;<span class="hx:absolute hx:-mt-20" id="competent-enough"></span>
    <a href="#competent-enough" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I don&rsquo;t expect another order-of-magnitude reasoning revolution in this architecture. What&rsquo;s coming is incremental agentic improvement: more robust tool calling, better memory, longer sessions, less hallucination per verification cycle. And this post&rsquo;s point is that this is already enough.</p>
<p>What the agentic era delivered was the automation of correct software engineering: long, reliable coding sessions, with testing and feedback, that accelerated hundreds, if not thousands, of open source projects. <a href="/en/2026/09/22/stop-making-excuses-and-ship-more-the-premise-changed/">The deploy premise changed</a> along with it. It&rsquo;s not a silver bullet. It&rsquo;s a new compiler for an old discipline: whoever had process, tests and documented invariants reaped; whoever had only hype is still waiting for the next model to solve it.</p>
<p>And to wrap up: I see no problem at all in raw models stagnating. <a href="/en/2026/09/28/llms-are-good-at-reproducing-what-exists-what-about-new-things/">The limits we already know</a>, and harness optimizations will soon hit diminishing returns too. What remains is what always remained: real software engineering technique, with automated tests first, and an experienced engineer at the wheel. With that, coding results are excellent today, not one model generation from now.</p>
<p>What won&rsquo;t exist is magic for amateurs. Asking an agent for any coding task without knowing what you&rsquo;re doing doesn&rsquo;t get back secure, optimized, well-thought-out code: it gets slop. The agent responds better to those who know what to ask for, that is, to those who understand this architecture, the pros, the cons, and know how to work around the weaknesses and leverage the strengths of the model+harness combination.</p>
<p>Hence the title. A lone LLM is an expensive parrot. An LLM with an agent is competent enough to work for real. And &ldquo;competent enough,&rdquo; added to your engineering discipline, is everything the industry needed. The rest is marketing waiting for the next magic parameter count that nobody publishes anymore.</p>
]]></content:encoded><category>llms</category><category>artificial-intelligence</category><category>coding-agents</category><category>software-engineering</category></item><item><title>Are There Better Languages for Programming with LLMs?</title><link>https://www.akitaonrails.com/en/2026/10/11/are-there-better-languages-for-programming-with-llms/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/11/are-there-better-languages-for-programming-with-llms/</guid><pubDate>Sun, 11 Oct 2026 21:00:00 -0300</pubDate><description>&lt;p&gt;Last week DHH decided to farm engagement with the laziest format there is: he converted Campfire, his chat app, to several languages using AI agents, and started dropping the throughput results one by one on X. In the series he posted, the Rust version came out ahead of the Elixir and Ruby equivalents. The whole thread was designed to provoke, and it provoked.&lt;/p&gt;
&lt;blockquote class="twitter-tweet" data-partner="tweetdeck"&gt;&lt;p lang="en" dir="ltr"&gt;Last conversion of the Campfire from my token stash goes to JavaScript/Express. As with the others, I'm sure you can find more to optimize. But this gives you a sense of what order of magnitude these options exist within with agent-led development. https://t.co/UUapL99SJE https://t.co/2H2NXfeZog&lt;/p&gt;</description><content:encoded><![CDATA[<p>Last week DHH decided to farm engagement with the laziest format there is: he converted Campfire, his chat app, to several languages using AI agents, and started dropping the throughput results one by one on X. In the series he posted, the Rust version came out ahead of the Elixir and Ruby equivalents. The whole thread was designed to provoke, and it provoked.</p>
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr">Last conversion of the Campfire from my token stash goes to JavaScript/Express. As with the others, I'm sure you can find more to optimize. But this gives you a sense of what order of magnitude these options exist within with agent-led development. https://t.co/UUapL99SJE https://t.co/2H2NXfeZog</p>&mdash; DHH (@dhh) <a href="https://twitter.com/dhh/status/2107077808182976817">October 5, 2026</a></blockquote>
<p>I won&rsquo;t defend him this time. A one-shot conversion, done by an agent, with no fine-tuning at all, doesn&rsquo;t measure language: it measures how much the model knows each stack&rsquo;s idioms. It&rsquo;s rage bait and he knows it. That said, I do the same from time to time, and so do half his critics, so we&rsquo;re all hypocrites and life goes on.</p>
<p>And the weak spot of his methodology became a topic of its own: several people noticed the Rust version had gone through far more agent iterations than the others, meaning more optimization rounds. @kurtome answered in practice: he took the Elixir version and sped up the main page requests 10x, with obvious optimizations that no first conversion does, like caching and async database connection pooling.</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">@dhh Here you go https://t.co/gUtK7Z7zG7<br><br>got a 10x speed up on the Room page requests, and sped up all the other requests significantly as well. the biggest gains came from some no brainers: implement caching and pool the db connections with proper async https://t.co/mbp94q9N0s</p>&mdash; kurt (.com) (@kurtome) <a href="https://twitter.com/kurtome/status/2106902762076467681">October 5, 2026</a></blockquote>
<p>His comparison, then, wasn&rsquo;t &ldquo;Rust versus Elixir&rdquo;: it was &ldquo;Rust after N tuning rounds versus Elixir after one.&rdquo; And that lays bare the truth the thread pretends to ignore: <strong>no real software ships from half a dozen prompts</strong>. Coding with AI shines when an experienced engineer steers the agent toward their goal, and that means dozens of iterations, not three.</p>
<p>The good part is that the bait was useful to me. I&rsquo;ve been doing <a href="/en/2026/09/15/new-llm-benchmark-v4-retesting-all-top-llms-part-1/">LLM benchmarks</a> and <a href="/en/2026/10/10/which-jev-like-ai-decision-classifier-model-is-best/">decision-model benchmarks</a>, but I had never measured, in a reproducible way, the question that thread pretended to answer: <strong>does it matter which language you pick when the one writing the code is an LLM?</strong> My short answer was already out in two posts of mine:</p>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Pressure under load is not a trivial problem to solve from scratch and I recommend you do not attempt to. It's a solved problem already and all solutions converge to what Elixir already brings out of the box. So yes. I use Rust all the time, but if I had to solve high scalability problems (particularly high volume message queues), I would think of Elixir first.</p>&mdash; Fabio Akita (@AkitaOnRails) <a href="https://twitter.com/AkitaOnRails/status/2108587462595367353">October 9, 2026</a></blockquote>
<blockquote class="twitter-tweet"><p lang="en" dir="ltr">Language wars are tiresome. And the reality is simpler if you're doing AI assisted coding.<br><br>- system level (drivers, fs, daemons, etc): Rust. C++ is you're extending existing legacy<br>- windows only desktop apps: C#<br>- iOS/MacOS/iPadOS: Swift<br>- multi-OS: Rust/Tauri, Qt/C++, Flutter, Electron (pick your poison)<br>- simple websites: Node/Typescript/Bun/Deno<br>- highly scalable backend: Elixir, parts in Rust, parts in Go<br>- CLI tools: Rust<br><br>Everything else, by default, Rust. Unless it's an edge case.</p>&mdash; Fabio Akita (@AkitaOnRails) <a href="https://twitter.com/AkitaOnRails/status/2108590592263352540">October 9, 2026</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<h2>There&rsquo;s no better language, there&rsquo;s the right tool<span class="hx:absolute hx:-mt-20" id="theres-no-better-language-theres-the-right-tool"></span>
    <a href="#theres-no-better-language-theres-the-right-tool" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>That list from the post isn&rsquo;t a ranking, it&rsquo;s a terrain map. Every language and every framework was designed for a use case, and none covers them all. That was true when you wrote every line by hand and it stays true with agents. The LLM doesn&rsquo;t change the physics of the problem: it only changes who&rsquo;s typing.</p>
<p>And the map goes beyond language. A real system has infrastructure around it: Kubernetes when scale asks for it, SQLite by default because most apps never need more than that, Postgres with pgBouncer when they do, Redis for cache and key-value, RabbitMQ or NATS for queues. Picking &ldquo;the stack&rdquo; on day zero and expecting it to last ten years is fantasy. It doesn&rsquo;t, and that&rsquo;s fine.</p>
<p>Personal example: new web app, I open Ruby on Rails without thinking twice. It&rsquo;s the most complete end-to-end solution there is for the web, and with an LLM writing most of the code, the framework&rsquo;s productivity weighs even more than the language&rsquo;s. As the system grows, I swap the parts that ask for another tool: a high-volume queue leaves Rails&rsquo; side and goes to something from Erlang land, starting with RabbitMQ, which already solves the hard backpressure part for me.</p>
<blockquote>
  <p>No good software is finished: it grows. Usage dictates what you replace, rewrite and add. The final architecture is never the first commit&rsquo;s, and whoever tries to get everything right in the first commit only produces dead documents.</p>

</blockquote>
<h2>The token superstition<span class="hx:absolute hx:-mt-20" id="the-token-superstition"></span>
    <a href="#the-token-superstition" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>DHH&rsquo;s thread resurrected two beliefs that have been circulating since LLMs became work tools:</p>
<ul>
<li><strong>&ldquo;Script languages are better for AI because the lean syntax spends fewer tokens.&rdquo;</strong></li>
<li><strong>&ldquo;Strongly typed languages are better for AI because the compiler catches the errors, so you need less testing and less repair.&rdquo;</strong></li>
</ul>
<p>Both sound reasonable and both are superstition until someone measures. I was betting against both, from experience: a good compiler helps, but it doesn&rsquo;t do magic, and syntax conciseness was never the bottleneck of an agent that reads and writes files all day.</p>
<p>What really separates a project that moves from a project that spins in circles is test discipline. I&rsquo;ve written that <a href="/en/2026/04/20/clean-code-for-ai-agents/">TDD became a technical obligation, not a philosophy</a>, and this post&rsquo;s benchmark is one more data point in the same direction. It doesn&rsquo;t matter whether you do test-first or test-after: what matters is that the suite grows with the code, that <a href="/en/2026/03/01/software-is-never-done-4-projects-life-after-deploy-one-shot-prompt-myth/">every user-reported bug becomes a regression test</a> before the fix, and that you never make the same mistake twice. Software without users is dead software, so <a href="/en/2026/09/22/stop-making-excuses-and-ship-more-the-premise-changed/">release early, release often</a>, break fast and fix even faster. AI closes exactly that gap: the reproduce-test-fix cycle got cheap. QA became the programmer&rsquo;s most valuable skill, far above &ldquo;knowing Rust syntax.&rdquo;</p>
<p>Discipline beats compiler and beats language. That was my hypothesis. Time to measure.</p>
<h2>The benchmark<span class="hx:absolute hx:-mt-20" id="the-benchmark"></span>
    <a href="#the-benchmark" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I built a reproducible experiment, public in the <a href="https://github.com/akitaonrails/vibe-coding-benchmarks"target="_blank" rel="noopener">vibe-coding-benchmarks repository</a>, with per-attempt results published in JSON and the raw traces kept out of the repo for credential containment. It&rsquo;s not a language championship, and the design itself says so: it&rsquo;s a snapshot of one real task, measuring what can be honestly measured.</p>
<h3>The task<span class="hx:absolute hx:-mt-20" id="the-task"></span>
    <a href="#the-task" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>One task only, on purpose: maintain a multi-tenant <strong>ledger engine</strong>. The agent receives working v1 code and has to take it to a v2 contract, with per-tenant identities, authorization, serializable snapshots, a unique secondary index with alias swap, a capacity-bounded journal, torn-group recovery, checkpointing, legacy schema migration and durable retry IDs. It&rsquo;s not FizzBuzz: it&rsquo;s the kind of system that demands invariants across operations, exactly where LLMs tend to trip.</p>
<p>Correctness is judged by <strong>43 test stories applied after collection</strong>, out of the agent&rsquo;s sight: the 27 public ones from T1 plus 16 hidden ones. Passing is 43 out of 43. The conditions:</p>
<ul>
<li><strong>T0:</strong> prose contract, input and output examples, a working launcher. No test suite.</li>
<li><strong>T1:</strong> the same, plus 27 public stories and a driver to run them.</li>
</ul>
<p>Each attempt had a 15-minute budget, with at most two 3-minute continuations. In practice, none of the 112 needed a continuation.</p>
<h3>The languages and the models<span class="hx:absolute hx:-mt-20" id="the-languages-and-the-models"></span>
    <a href="#the-languages-and-the-models" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Seven languages in three strata, with pinned toolchains and Rust in safe mode:</p>
<ul>
<li><strong>Typed natives:</strong> Rust (safe, pinned), Haskell (pinned GHC).</li>
<li><strong>Typed VMs:</strong> C# (with nullable analysis), Kotlin, TypeScript (<code>strict</code>, <code>noUncheckedIndexedAccess</code>, <code>exactOptionalPropertyTypes</code>).</li>
<li><strong>Dynamic scripts:</strong> Python and Ruby, no checker at all.</li>
</ul>
<p>Four model configurations, all on subscriptions, no paid fallback: <strong>Kimi K3</strong> (high), <strong>GLM 5.3</strong> via OpenCode (high), <strong>Claude Opus 5.5</strong> (medium) and <strong>Codex with gpt-6 Sol</strong> (medium). Crossing everything: 7 languages × 4 models × 2 conditions × 2 repetitions = <strong>112 attempts</strong>.</p>
<h3>What this design doesn&rsquo;t measure<span class="hx:absolute hx:-mt-20" id="what-this-design-doesnt-measure"></span>
    <a href="#what-this-design-doesnt-measure" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Before the numbers, the brakes, because they&rsquo;re part of the result. It&rsquo;s a single task, with two repetitions per cell: a small sample by construction. Token coverage is partial in some models (missing data is not zero). The harness changed mid-campaign across three instrumentation epochs. And provider delays contaminate wall time: one of the Opus attempts spent half the clock waiting for quota release. All numbers below are descriptive, and I point out where they can&rsquo;t support a conclusion.</p>
<p>There&rsquo;s one additional brake, on purpose: <strong>the iteration level</strong>. My design measures what can be reached in all languages with similar iteration levels, on a short budget, with no human tuning afterwards. It&rsquo;s a photograph of the floor, not the ceiling. Any of the 112 implementations probably improves with more agent rounds, and the four queue stacks likewise: what I publish is what each language delivers &ldquo;out of the factory&rdquo; under the same effort, not the maximum a patient engineer would extract from it.</p>
<blockquote>
  <p><strong>Mandatory disclaimer before quoting any number from this post around:</strong> every result that follows holds for <strong>this</strong> benchmark, with <strong>this</strong> task, <strong>these</strong> models, <strong>these</strong> prompts and <strong>this</strong> hardware. Your case may vary violently. If your task doesn&rsquo;t look like a ledger engine, if your model isn&rsquo;t one of these four, if your queue isn&rsquo;t my queue, the numbers don&rsquo;t transfer. The code, the tasks, the grades and the step-by-step to reproduce are all in the <a href="https://github.com/akitaonrails/vibe-coding-benchmarks"target="_blank" rel="noopener">GitHub repository</a>. And if you disagree with some result and that disagreement matters to your company or your project, the only honest attitude is the one I had: <strong>stop arguing and run your own benchmark.</strong></p>

</blockquote>
<h2>Result 1: on correctness, the frontier models tied at the ceiling<span class="hx:absolute hx:-mt-20" id="result-1-on-correctness-the-frontier-models-tied-at-the-ceiling"></span>
    <a href="#result-1-on-correctness-the-frontier-models-tied-at-the-ceiling" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><table>
  <thead>
      <tr>
          <th>Configuration</th>
          <th style="text-align: right">Correct within budget</th>
          <th style="text-align: right">Correct at the limit</th>
          <th style="text-align: right">Failures</th>
          <th style="text-align: right">Ungraded</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Kimi K3 high</td>
          <td style="text-align: right">17</td>
          <td style="text-align: right">7</td>
          <td style="text-align: right">2</td>
          <td style="text-align: right">2</td>
      </tr>
      <tr>
          <td>GLM 5.3 high (OpenCode)</td>
          <td style="text-align: right">7</td>
          <td style="text-align: right">9</td>
          <td style="text-align: right">7</td>
          <td style="text-align: right">5</td>
      </tr>
      <tr>
          <td>Opus 5.5 medium</td>
          <td style="text-align: right">25</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">3 (infra interruption)</td>
          <td style="text-align: right">0</td>
      </tr>
      <tr>
          <td>Codex / Sol medium</td>
          <td style="text-align: right">28</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
          <td style="text-align: right">0</td>
      </tr>
  </tbody>
</table>
<p>Reading: Sol passed all 28 eligible attempts and Opus its 25 (the 3 failures were infrastructure, not code). <strong>53 of 53 eligible attempts correct between the two.</strong> The task, made to be hard, was too easy to separate the frontier models, let alone the languages: with everyone passing everything, there&rsquo;s no correctness ranking to publish.</p>
<p>The difference showed up in the weaker models, and in the direction my hypothesis predicted: <strong>provided tests helped</strong>. Kimi and GLM, with the public suite in hand (T1), delivered 24 correct artifacts against 16 without it (T0). Kimi, in particular, passed all 14 attempts with provided tests. It&rsquo;s descriptive, not causal, but it&rsquo;s the cleanest signal in the whole benchmark: what changed the outcome wasn&rsquo;t the language, it was the presence of tests.</p>
<p>Per language, within each model, correctness scattered between 1/4 and 4/4 with no pattern that repeats across models. The three semantic failures I audited in depth are instructive: a GLM C# and a Kimi Python lost the same story by violating the same cross-operation invariant, and a Kimi Haskell missed a checkpoint path. None of the failures was a type error.</p>
<blockquote>
  <p>Where the model erred, it erred on domain invariants: the kind of error no compiler catches, in typed or dynamic languages. The myth that strong typing spares you the work of understanding the problem dies right there.</p>

</blockquote>
<h2>Result 2: concise language saved no tokens<span class="hx:absolute hx:-mt-20" id="result-2-concise-language-saved-no-tokens"></span>
    <a href="#result-2-concise-language-saved-no-tokens" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here&rsquo;s the table that kills the first superstition. Medians per language on Sol, four valid attempts per cell:</p>
<table>
  <thead>
      <tr>
          <th>Language</th>
          <th style="text-align: right">Median time</th>
          <th style="text-align: right">Median tokens</th>
          <th style="text-align: right">Final code lines</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>TypeScript</td>
          <td style="text-align: right">53 s</td>
          <td style="text-align: right">147.5 thousand</td>
          <td style="text-align: right">~280</td>
      </tr>
      <tr>
          <td>Python</td>
          <td style="text-align: right">77 s</td>
          <td style="text-align: right">138.2 thousand</td>
          <td style="text-align: right">~300</td>
      </tr>
      <tr>
          <td>C#</td>
          <td style="text-align: right">61 s</td>
          <td style="text-align: right">171.6 thousand</td>
          <td style="text-align: right">~260</td>
      </tr>
      <tr>
          <td>Kotlin</td>
          <td style="text-align: right">65 s</td>
          <td style="text-align: right">170.6 thousand</td>
          <td style="text-align: right">~210</td>
      </tr>
      <tr>
          <td>Haskell</td>
          <td style="text-align: right">75 s</td>
          <td style="text-align: right">184.7 thousand</td>
          <td style="text-align: right">~265</td>
      </tr>
      <tr>
          <td>Ruby</td>
          <td style="text-align: right">82 s</td>
          <td style="text-align: right">185.6 thousand</td>
          <td style="text-align: right">~380</td>
      </tr>
      <tr>
          <td>Rust</td>
          <td style="text-align: right">80 s</td>
          <td style="text-align: right">188.1 thousand</td>
          <td style="text-align: right">~650</td>
      </tr>
  </tbody>
</table>
<p>Ruby, the most concise in lines (a bit over half of Rust&rsquo;s), cost practically the same tokens as Rust on Sol, and on Opus it was <strong>the most expensive of all</strong>, about 205 thousand median tokens against C#&rsquo;s 94 thousand. The cheapest were TypeScript and Python on Sol, C#, Haskell and Kotlin on Opus. If &ldquo;fewer source code lines = fewer LLM tokens&rdquo; were a law, Ruby should have led by a wide margin. It finished last.</p>
<p>And the second superstition? I audited the traces looking for the compiler-guided repair cycles that strong typing supposedly avoids. Result: <strong>zero compilation-error repair cycles</strong> in the audited Opus attempts, across Ruby, Rust and Haskell. Rust needed no compiler-driven fix at all; Haskell had one warning cleanup; Ruby spent its extra tokens on voluntary performance tuning. The frontier model almost always writes code that compiles on the first try, and the real effort goes to verification, not to appeasing the compiler.</p>
<p>One counterpoint that closes the coffin on the &ldquo;cheap is good&rdquo; thesis: GLM&rsquo;s <strong>lowest</strong> token-consumption cells were the failures. TypeScript T0 at 50 thousand tokens looks efficient until you see it&rsquo;s two unmodified starters because the model blew the output limit. Low tokens can mean early surrender.</p>
<h2>Result 3: under load, everyone tied at the queue<span class="hx:absolute hx:-mt-20" id="result-3-under-load-everyone-tied-at-the-queue"></span>
    <a href="#result-3-under-load-everyone-tied-at-the-queue" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now for DHH&rsquo;s question: Rust &ldquo;beats&rdquo; Elixir and Ruby when the subject is throughput. I built the separate track for that: four queue workers against a real RabbitMQ, written with agent help, each in its natural idiom:</p>
<ul>
<li><strong>Elixir</strong> with OTP and Broadway</li>
<li><strong>Rust</strong> with Tokio and Lapin</li>
<li><strong>Rails</strong> with Bunny</li>
<li><strong>Plain Ruby</strong> with Bunny (control)</li>
</ul>
<p>A generator published 10 thousand 4 KB messages to RabbitMQ, at 200 per second, and each worker consumed as fast as it could, hitting the effects on an HTTP/SQLite collector with a nominal 50 ms delay, limited to 2 CPUs and 1 GB of RAM. Two concurrency profiles:</p>
<table>
  <thead>
      <tr>
          <th>Stack</th>
          <th style="text-align: right">Handlers</th>
          <th style="text-align: right">Effects/s</th>
          <th style="text-align: right">Correct/10,000</th>
          <th style="text-align: right">Memory peak</th>
          <th>Drained?</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Elixir</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">94.8</td>
          <td style="text-align: right">10,000</td>
          <td style="text-align: right">135 MiB</td>
          <td>yes</td>
      </tr>
      <tr>
          <td>Rust</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">94.6</td>
          <td style="text-align: right">10,000</td>
          <td style="text-align: right">16 MiB</td>
          <td>yes</td>
      </tr>
      <tr>
          <td>Rails</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">92.7</td>
          <td style="text-align: right">10,000</td>
          <td style="text-align: right">79 MiB</td>
          <td>yes</td>
      </tr>
      <tr>
          <td>Ruby</td>
          <td style="text-align: right">8</td>
          <td style="text-align: right">92.5</td>
          <td style="text-align: right">10,000</td>
          <td style="text-align: right">38 MiB</td>
          <td>yes</td>
      </tr>
      <tr>
          <td>Elixir</td>
          <td style="text-align: right">64</td>
          <td style="text-align: right">84.8</td>
          <td style="text-align: right">7,915</td>
          <td style="text-align: right">161 MiB</td>
          <td>no</td>
      </tr>
      <tr>
          <td>Rust</td>
          <td style="text-align: right">64</td>
          <td style="text-align: right">88.2</td>
          <td style="text-align: right">8,151</td>
          <td style="text-align: right">23 MiB</td>
          <td>no</td>
      </tr>
      <tr>
          <td>Rails</td>
          <td style="text-align: right">64</td>
          <td style="text-align: right">88.5</td>
          <td style="text-align: right">8,108</td>
          <td style="text-align: right">87 MiB</td>
          <td>no</td>
      </tr>
      <tr>
          <td>Ruby</td>
          <td style="text-align: right">64</td>
          <td style="text-align: right">88.0</td>
          <td style="text-align: right">8,081</td>
          <td style="text-align: right">60 MiB</td>
          <td>no</td>
      </tr>
  </tbody>
</table>
<p>On the 8-handler profile, the four stacks delivered the same throughput, 93 to 95 effects per second, and drained the whole queue. The apparent bottleneck was the shared collector (a Python lock, a single SQLite writer), not the languages. On the 64-handler profile, all of them left a backlog and blew the client timeout en masse, so I marked those cells as not qualified: the strong protocol, with a group-commit collector and a 50 to 800 msg/s ramp, is designed but not executed.</p>
<p>The only difference left standing in the numbers was <strong>memory</strong>: Rust held the peak at 16 MiB where the BEAM spent 135. It&rsquo;s a real Rust advantage in density, with the caveat that a cgroup peak is not a language footprint. On throughput, which was the thread&rsquo;s claim, a technical tie.</p>
<p>And the tie deserves an honest reading: it may only mean my pressure was too little. With the shared collector holding everything around 95 effects per second, any stack capable of more than that shows up as &ldquo;equal.&rdquo; What this test shows is where the bottleneck was, not where each stack breaks. To find each one&rsquo;s ceiling I&rsquo;d need the strong protocol, with a group-commit collector and a load ramp, which is designed but not executed. Until then, &ldquo;all stacks perform the same&rdquo; is the wrong conclusion; &ldquo;all of them stayed above what my test could measure&rdquo; is the right one.</p>
<p>And the question that interested me most, &ldquo;does the agent work less to deliver a reliable queue consumer in Elixir than in Rust?&rdquo;, was deliberately left unanswered: these four implementations were written to validate the environment, not as a controlled coding attempt. Comparing AI effort between Elixir and Rust would require the same ledger matrix running on the queue task. It&rsquo;s on the list.</p>
<h2>So, does the language matter?<span class="hx:absolute hx:-mt-20" id="so-does-the-language-matter"></span>
    <a href="#so-does-the-language-matter" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>With the data on the table, the thread&rsquo;s three questions can be answered:</p>
<p><strong>Is there a better language for programming with LLMs?</strong> None showed up. In the frontier models, correctness and effort varied less between languages than between models. Where there was a correctness difference, it followed the presence of provided tests, not syntax. &ldquo;No general language ranking is established&rdquo; is the report&rsquo;s official sentence, and it&rsquo;s the correct one.</p>
<p><strong>Do the token-economy theses hold?</strong> Neither one. Conciseness didn&rsquo;t save: Ruby cost as much as Rust, or more. Strong typing spared no repair: there was no type repair to spare. The models&rsquo; effort went to verification and understanding the contract, and that has no language.</p>
<p><strong>Was DHH right?</strong> In what he measured, he measured what an agent delivers for free on each stack, without tuning, and called that a verdict on language. In my test, with real load and honest measurement, the four stacks tied on throughput in the stable regime, and only memory differentiated Rust. If his thread proves anything, it proves that agent conversion measures the model, not the language.</p>
<p>My bets from the introduction came out standing: testing and discipline are the lever, the compiler is a supporting actor, and the right tool depends on the problem. New web app is still Rails in my hand, heavy queue is still Erlang territory, low-level system is still Rust, and the LLM writes any of them with the same competence. Whoever spent the week fighting for their favorite language on X fought over nothing.</p>
<p>And my daily practice tells the same story. I have a personal bias toward Rust and even so I&rsquo;ve published more than 30 open source projects in all kinds of stacks: <a href="https://github.com/akitaonrails/ai-memory"target="_blank" rel="noopener">ai-memory</a> is Rust, <a href="https://github.com/akitaonrails/FrankMD"target="_blank" rel="noopener">FrankMD</a> is Ruby on Rails, <a href="https://github.com/akitaonrails/ai-memory-web"target="_blank" rel="noopener">ai-memory-web</a> and <a href="https://github.com/akitaonrails/ai-jail-web"target="_blank" rel="noopener">ai-jail-web</a> are Node.js. In none of them did I feel any relevant difference that came from the stack: the wins were similar, the errors too, and the errors were always understandable. Every error became an invariant, a rule, a skill improvement. It never became a language switch.</p>
<p>So forget &ldquo;token savings&rdquo; and &ldquo;typing superstition.&rdquo; Do real software engineering: pick the right tool for your specific problem, apply proper engineering technique, and any reasonable agent will perform more or less the same. And stop wasting time arguing over language-war rage bait on the internet. Be a real software engineer and do real engineering. That&rsquo;s it.</p>
<p>The per-attempt data, the full methodology and the evidence limits are in the <a href="https://github.com/akitaonrails/vibe-coding-benchmarks"target="_blank" rel="noopener">repository</a>. If you run the matrix with another task and find a ranking I didn&rsquo;t, show me.</p>
]]></content:encoded><category>llm-benchmarks</category><category>programming-languages</category><category>llms</category><category>elixir-and-erlang</category></item><item><title>Which Jev-like AI Decision/Classifier Model Is Best?</title><link>https://www.akitaonrails.com/en/2026/10/10/which-jev-like-ai-decision-classifier-model-is-best/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/10/which-jev-like-ai-decision-classifier-model-is-best/</guid><pubDate>Sat, 10 Oct 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;Last week I published &lt;a href="https://www.akitaonrails.com/en/2026/10/03/understanding-the-jev-hype-what-is-it-for/"&gt;a long post about Jev&lt;/a&gt;, TypeSafe&amp;rsquo;s hosted classifier that became all the rage in September. The short version of that post: Jev is a classifier, something that has existed for decades, and the &amp;ldquo;193x faster&amp;rdquo; amazement only exists because too many people were using chat LLMs as expensive, slow classifiers. I reproduced Paulo Câmara&amp;rsquo;s essay &lt;em&gt;The student who marks answer A&lt;/em&gt;, introduced the open alternatives Clef and Laya, and to compare the models side by side I leaned on the &lt;a href="https://huggingface.co/spaces/multimodalart/jev-decision-index"target="_blank" rel="noopener"&gt;Decision Index&lt;/a&gt;, a public ranking that already existed.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Last week I published <a href="/en/2026/10/03/understanding-the-jev-hype-what-is-it-for/">a long post about Jev</a>, TypeSafe&rsquo;s hosted classifier that became all the rage in September. The short version of that post: Jev is a classifier, something that has existed for decades, and the &ldquo;193x faster&rdquo; amazement only exists because too many people were using chat LLMs as expensive, slow classifiers. I reproduced Paulo Câmara&rsquo;s essay <em>The student who marks answer A</em>, introduced the open alternatives Clef and Laya, and to compare the models side by side I leaned on the <a href="https://huggingface.co/spaces/multimodalart/jev-decision-index"target="_blank" rel="noopener">Decision Index</a>, a public ranking that already existed.</p>
<p>Someone else&rsquo;s ranking is useful, but I wanted to get my hands dirty. So I built my own benchmark, with my own cases, half in Portuguese, and ran the open models on my <a href="/en/2026/03/31/minisforum-ms-s1-max-amd-ai-max-395-review/">home server with Strix Halo</a>, the same Ryzen AI Max+ 395 I use to test local LLMs. The hosted ones (Jev, the two Clefs from Cloudflare, OpenAI Decisions and Microsoft Decision-1 via OpenRouter) ran through their APIs. Everything, including the cases, the raw responses and the scoring scripts, is public in the <a href="https://github.com/akitaonrails/jev-docs-benchmarks"target="_blank" rel="noopener">benchmark repository</a>.</p>
<blockquote>
  <p><strong>TL;DR:</strong> the top now has two, both open-weights. <strong>Perplexity Decider 1.1 27B</strong> and the just-released <strong>Decision 3.0</strong> (vLLM Semantic Router) tied at <strong>99.4%</strong> on the compact cases, with 100% in Portuguese, and identical labels on all 1,024 classifications in the benchmark. The price: about 49 GB of weights and over a second per decision. In the cloud, <strong>Microsoft Decision-1</strong> tied <strong>Jev</strong> at 97.6% while costing a third: it&rsquo;s the cheapest hosted one I measured, and the first candidate to evaluate. Jev answers faster and errs differently. <strong>OpenAI Decisions</strong> debuted tied with the best local 4B, Jebadiah, and has the lowest hosted latency. <strong>Julia-1</strong>, the smallest and fastest of all (12 ms), scored at coin-flip level: fresh out of the factory, it&rsquo;s a no-go. Jump to the <a href="#the-full-table">full table</a>, the <a href="#how-much-it-costs-in-support-emails">cost in support emails</a>, <a href="#which-model-for-which-situation">which model for which situation</a>, <a href="#how-hard-it-is-to-run-the-best-open-models-on-your-machine">how hard it is to run the best open ones locally</a> or the <a href="#highlights-and-gotchas">gotchas</a>.</p>

</blockquote>
<h2>How I tested<span class="hx:absolute hx:-mt-20" id="how-i-tested"></span>
    <a href="#how-i-tested" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The central idea was to measure more than &ldquo;who gets the most right.&rdquo; A decision model has a design goal, and comparing a 322-million-parameter encoder made to run on weak devices with a hosted service of undisclosed size on accuracy percentage alone is unfair to both. So I measured accuracy, latency, cost and behavior under stress, and at the end I split the recommendations by situation.</p>
<h3>The two case sets<span class="hx:absolute hx:-mt-20" id="the-two-case-sets"></span>
    <a href="#the-two-case-sets" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I built two test sets, frozen in git before any inference, with the dataset hash recorded alongside the responses. No model receives the expected answer, the justification or the case identifier. Only the text, the instructions and the options.</p>
<p>The <strong>v1 set</strong> has 13 operational use cases, in English, each with an explicit fictional policy:</p>
<ul>
<li>support ticket severity</li>
<li>support routing</li>
<li>refund policy</li>
<li>incident escalation</li>
<li>tool approval (whether an agent may or may not execute a given action)</li>
<li>email fraud</li>
<li>document type</li>
<li>evidence support</li>
<li>search relevance</li>
<li>moderation</li>
<li>order routing</li>
<li>lead qualification</li>
<li>numeric-threshold triage</li>
</ul>
<p>There are 10 scenarios per use case, each presented four ways: original, options in reversed order, options with opaque names (c0, c1, c2) and original plus a &ldquo;reviewer&rdquo; comment suggesting the wrong answer, which the instructions say to ignore. That&rsquo;s 520 classifications per model. Add 24 probability probes in situations with no information at all (fair coin, six-sided die), where the right answer is mathematical.</p>
<p>The <strong>v2 set</strong> was made to cover what v1 leaves out: common semantics and Portuguese. There are 7 tasks, with 12 scenarios each, and every scenario written in English and in Brazilian Portuguese with the same answer and the same option order:</p>
<ul>
<li>sentiment (author versus quotation, negation, sarcasm)</li>
<li>current intent (withdrawn request, competing actions, hypothesis)</li>
<li>logical implication (quantifiers, absent fact, temporal order)</li>
<li>search relevance (all, part or none of what was asked)</li>
<li>sensitive data handling (fictional secret versus mention, redaction, revocation)</li>
<li>current incident status (timeline order, verified versus unverified)</li>
<li>threshold policy (inclusive bounds, units, AND/OR with a missing value)</li>
</ul>
<p>Each pair runs under three conditions:</p>
<ul>
<li><strong>compact</strong>: just the record and the rule</li>
<li><strong>with examples</strong>: one solved example per class, fixed and the same for everyone</li>
<li><strong>with distractors</strong>: ten irrelevant archive notes before the record that matters, to stress the context</li>
</ul>
<p>That&rsquo;s 504 classifications per model.</p>
<blockquote>
  <p>The cases were written with AI help and reviewed against the policies, without independent human annotation. It&rsquo;s a small, synthetic benchmark: 130 scenario families in v1 and 84 in v2. The variants are correlated, so 520 responses are 130 scenarios seen four ways. Treat the numbers as a snapshot of these cases, and test with your own before deciding.</p>

</blockquote>
<h3>The 23 competitors<span class="hx:absolute hx:-mt-20" id="the-23-competitors"></span>
    <a href="#the-23-competitors" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Five ran in the cloud, through the official API: <strong>Jev</strong> (version 1.13.0, from TypeSafe), <strong>Clef</strong> (27B, Cloudflare Workers AI), <strong>Clef-flash</strong> (9B, same), <strong>OpenAI Decisions</strong> (the <code>gpt-6-luna</code> alias, in public beta) and <strong>Microsoft Decision-1</strong> (9B, post-trained from Qwen3.5-9B, served via OpenRouter on Azure). The other eighteen ran on the Strix Halo, via ROCm, with weights pinned by Hugging Face commit hash, inside a Docker container. The first three (Laya, Laya typed and Clef-flash) shared one container; the rest ran one at a time, with Julia-1 measured twice, on GPU and on CPU. The server has 64 GiB of GPU-addressable memory.</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Nominal size</th>
          <th>Origin</th>
          <th>Where it ran</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Jev 1.13.0</td>
          <td style="text-align: right">undisclosed</td>
          <td>TypeSafe, proprietary</td>
          <td>API</td>
      </tr>
      <tr>
          <td>OpenAI Decisions (<code>gpt-6-luna</code>)</td>
          <td style="text-align: right">undisclosed</td>
          <td>OpenAI, proprietary, beta</td>
          <td>API</td>
      </tr>
      <tr>
          <td>Microsoft Decision-1</td>
          <td style="text-align: right">9B</td>
          <td>Microsoft, proprietary</td>
          <td>API (OpenRouter)</td>
      </tr>
      <tr>
          <td>Clef</td>
          <td style="text-align: right">27B</td>
          <td>Cloudflare, open weights</td>
          <td>API</td>
      </tr>
      <tr>
          <td>Clef-flash</td>
          <td style="text-align: right">9B</td>
          <td>Cloudflare, open weights</td>
          <td>API and local</td>
      </tr>
      <tr>
          <td>Perplexity Decider 1.1 27B</td>
          <td style="text-align: right">27B</td>
          <td>Perplexity, Apache 2.0</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Decision 3.0 (d3)</td>
          <td style="text-align: right">27B</td>
          <td>vLLM Semantic Router, Apache 2.0</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Decision 3.0 Edge</td>
          <td style="text-align: right">0.6B</td>
          <td>vLLM Semantic Router, Apache 2.0</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Jebadiah 4B v2</td>
          <td style="text-align: right">4B</td>
          <td>Frontier Infra, Apache 2.0</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Kev 0.8B / 4B / 9B</td>
          <td style="text-align: right">0.8B / 4B / 9B</td>
          <td>Jared Palmer, Apache 2.0</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Mapika Decider 4B</td>
          <td style="text-align: right">4.2B</td>
          <td>Mapika, Apache 2.0</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Eikos 4B</td>
          <td style="text-align: right">4B</td>
          <td>Caio Vicentino, MIT, trained on EN and PT</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Simple-Jev + Qwen3.5 4B</td>
          <td style="text-align: right">4B</td>
          <td>Featherless, token-reading server over a stock model</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Laya / Laya typed-decisions</td>
          <td style="text-align: right">421M</td>
          <td>Convai Innovations, ModernBERT encoder</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Laya multilingual</td>
          <td style="text-align: right">322M</td>
          <td>Convai Innovations, mmBERT encoder</td>
          <td>local</td>
      </tr>
      <tr>
          <td>Julia-1</td>
          <td style="text-align: right">144M</td>
          <td>Supersonic Labs, Apache 2.0, mmBERT encoder</td>
          <td>local, GPU and CPU</td>
      </tr>
      <tr>
          <td>GLiNER2.5-Decide / multi-Decide</td>
          <td style="text-align: right">340M / 287M</td>
          <td>Fastino, Apache 2.0</td>
          <td>local</td>
      </tr>
  </tbody>
</table>
<p>The order up there is just organizational, hosted first and local ones by family. The real ranking is in the <a href="#the-full-table">results table</a>.</p>
<p>Everyone received exactly the same text, the same instructions and the same options, with no per-model prompt tuning and no adjustments after seeing results (Simple-Jev uses its own server&rsquo;s fixed prompt policy). The exception is <strong>GLiNER</strong>, whose native API takes labels instead of probability distributions. It runs on a separate track, v2 only, with explicit mapping and no made-up calibration metrics.</p>
<p><strong>Simple-Jev</strong> deserves an explanation. It&rsquo;s a server that takes a stock LLM (here Qwen3.5 4B, with no decision training at all) and reads the probability of the answer tokens instead of generating text. It&rsquo;s the baseline: if a &ldquo;decision&rdquo; model loses to this, the specialized training bought nothing.</p>
<p>Two protocol notes. <strong>OpenAI Decisions</strong> answers through a native typed-decisions endpoint, and the alias the API returned is not an immutable snapshot: OpenAI can swap the weights behind the name, like Cloudflare does with Clef-flash. And <strong>Perplexity Decider</strong> is not a stock chat LLM: it has a separate decision head, with non-causal attention and a calibration temperature saved in the weights. A generic chat server does not reproduce its behavior. <strong>Microsoft Decision-1</strong> speaks native SystemOne through OpenRouter&rsquo;s decisions API, and the served identifier is dated (<code>microsoft-decision-1-20261009</code>), so it&rsquo;s not an immutable weight either. It doesn&rsquo;t show up in OpenRouter&rsquo;s text-model catalog: to find it, you have to filter by the <code>decisions</code> modality. <strong>Decision 3.0</strong> is the new family from the vLLM Semantic Router project, Apache 2.0, derived from Qwen, with six checkpoints (d3, flash, mini, nano, lite, edge) and native SystemOne. I tested the flagship (d3) and the smallest (d3-edge); the four in between are for another round.</p>
<h3>What was measured<span class="hx:absolute hx:-mt-20" id="what-was-measured"></span>
    <a href="#what-was-measured" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Accuracy per task, per language and per condition, always on top of the per-option probabilities the model returns, ignoring the vendor&rsquo;s &ldquo;confidence&rdquo; field.</li>
<li>Brier and ECE for calibration.</li>
<li>Median and p95 latency as seen by the client, including the network: WAN for the hosted ones, LAN for the local ones. These are deployment observations, and comparing hardware would require another test.</li>
<li>Input tokens reported by the API, priced at the October 10 price table, before any allowance.</li>
<li>Bootstrap confidence intervals over scenario families, instead of individual responses.</li>
</ul>
<p>I left local cost unmeasured. Energy, hardware amortization and maintenance were left out, so local models show up as &ldquo;not measured,&rdquo; because &ldquo;zero&rdquo; would be a lie.</p>
<h2>The full table<span class="hx:absolute hx:-mt-20" id="the-full-table"></span>
    <a href="#the-full-table" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The main column is accuracy on the 168 compact v2 cases (84 in English, 84 in Portuguese). The v1 column uses the 130 original scenarios. Latency is the median seen by the client across the 504 v2 calls. Cost is the list price per 10 thousand compact decisions, computed from the tokens the API reported.</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">Compact EN / PT-BR</th>
          <th style="text-align: right">Compact combined</th>
          <th style="text-align: right">v1 originals</th>
          <th style="text-align: right">Median latency</th>
          <th style="text-align: right">10 thousand decisions</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Perplexity Decider 27B</td>
          <td style="text-align: right">98.8% / 100.0%</td>
          <td style="text-align: right"><strong>99.4%</strong></td>
          <td style="text-align: right">99.2%</td>
          <td style="text-align: right">1,547 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Decision 3.0 (27B)</td>
          <td style="text-align: right">98.8% / 100.0%</td>
          <td style="text-align: right"><strong>99.4%</strong></td>
          <td style="text-align: right">99.2%</td>
          <td style="text-align: right">1,420 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Jev</td>
          <td style="text-align: right">97.6% / 97.6%</td>
          <td style="text-align: right">97.6%</td>
          <td style="text-align: right">96.2%</td>
          <td style="text-align: right">255 ms (WAN)</td>
          <td style="text-align: right">US$ 0.19</td>
      </tr>
      <tr>
          <td>Microsoft Decision-1</td>
          <td style="text-align: right">95.2% / 100.0%</td>
          <td style="text-align: right">97.6%</td>
          <td style="text-align: right">95.4%</td>
          <td style="text-align: right">422 ms (WAN)</td>
          <td style="text-align: right">US$ 0.065</td>
      </tr>
      <tr>
          <td>Clef (27B)</td>
          <td style="text-align: right">97.6% / 94.0%</td>
          <td style="text-align: right">95.8%</td>
          <td style="text-align: right">94.6%</td>
          <td style="text-align: right">302 ms (WAN)</td>
          <td style="text-align: right">US$ 0.63</td>
      </tr>
      <tr>
          <td>Jebadiah 4B v2</td>
          <td style="text-align: right">91.7% / 89.3%</td>
          <td style="text-align: right">90.5%</td>
          <td style="text-align: right">85.4%</td>
          <td style="text-align: right">205 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>OpenAI Decisions</td>
          <td style="text-align: right">90.5% / 90.5%</td>
          <td style="text-align: right">90.5%</td>
          <td style="text-align: right">93.1%</td>
          <td style="text-align: right">222 ms (WAN)</td>
          <td style="text-align: right">US$ 0.23</td>
      </tr>
      <tr>
          <td>Kev 9B</td>
          <td style="text-align: right">92.9% / 83.3%</td>
          <td style="text-align: right">88.1%</td>
          <td style="text-align: right">87.7%</td>
          <td style="text-align: right">561 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Clef-flash (9B) hosted</td>
          <td style="text-align: right">91.7% / 83.3%</td>
          <td style="text-align: right">87.5%</td>
          <td style="text-align: right">90.8%</td>
          <td style="text-align: right">394 ms (WAN)</td>
          <td style="text-align: right">US$ 0.10</td>
      </tr>
      <tr>
          <td>Clef-flash (9B) local</td>
          <td style="text-align: right">89.3% / 85.7%</td>
          <td style="text-align: right">87.5%</td>
          <td style="text-align: right">90.8%</td>
          <td style="text-align: right">618 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Mapika Decider 4B</td>
          <td style="text-align: right">89.3% / 85.7%</td>
          <td style="text-align: right">87.5%</td>
          <td style="text-align: right">86.9%</td>
          <td style="text-align: right">186 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Kev 4B</td>
          <td style="text-align: right">88.1% / 86.9%</td>
          <td style="text-align: right">87.5%</td>
          <td style="text-align: right">82.3%</td>
          <td style="text-align: right">246 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Eikos 4B</td>
          <td style="text-align: right">85.7% / 79.8%</td>
          <td style="text-align: right">82.7%</td>
          <td style="text-align: right">87.7%</td>
          <td style="text-align: right">235 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Simple-Jev + Qwen3.5 4B</td>
          <td style="text-align: right">77.4% / 71.4%</td>
          <td style="text-align: right">74.4%</td>
          <td style="text-align: right">85.4%</td>
          <td style="text-align: right">1,349 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Kev 0.8B</td>
          <td style="text-align: right">64.3% / 61.9%</td>
          <td style="text-align: right">63.1%</td>
          <td style="text-align: right">63.1%</td>
          <td style="text-align: right">86 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Decision 3.0 Edge (0.6B)</td>
          <td style="text-align: right">67.9% / 53.6%</td>
          <td style="text-align: right">60.7%</td>
          <td style="text-align: right">65.4%</td>
          <td style="text-align: right">45 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>GLiNER2.5-Decide (EN)</td>
          <td style="text-align: right">54.8% / 50.0%</td>
          <td style="text-align: right">52.4%</td>
          <td style="text-align: right">didn&rsquo;t run</td>
          <td style="text-align: right">208 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Laya typed-decisions</td>
          <td style="text-align: right">50.0% / 35.7%</td>
          <td style="text-align: right">42.9%</td>
          <td style="text-align: right">43.8%</td>
          <td style="text-align: right">43 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Laya (EN)</td>
          <td style="text-align: right">44.0% / 41.7%</td>
          <td style="text-align: right">42.9%</td>
          <td style="text-align: right">43.8%</td>
          <td style="text-align: right">41 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Laya multilingual</td>
          <td style="text-align: right">35.7% / 38.1%</td>
          <td style="text-align: right">36.9%</td>
          <td style="text-align: right">43.8%</td>
          <td style="text-align: right">19 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>GLiNER2.5-multi-Decide</td>
          <td style="text-align: right">32.1% / 35.7%</td>
          <td style="text-align: right">33.9%</td>
          <td style="text-align: right">didn&rsquo;t run</td>
          <td style="text-align: right">63 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Julia-1 (GPU)</td>
          <td style="text-align: right">38.1% / 25.0%</td>
          <td style="text-align: right">31.5%</td>
          <td style="text-align: right">38.5%</td>
          <td style="text-align: right"><strong>12 ms</strong> (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
      <tr>
          <td>Julia-1 (CPU)</td>
          <td style="text-align: right">38.1% / 25.0%</td>
          <td style="text-align: right">31.5%</td>
          <td style="text-align: right">36.9%</td>
          <td style="text-align: right">71 ms (LAN)</td>
          <td style="text-align: right">not measured</td>
      </tr>
  </tbody>
</table>
<p>To calibrate your reading: the tasks have three or four options, so a uniform guess gives about 31% on both sets. &ldquo;Near 50%&rdquo; here is already well above the coin, and &ldquo;near 33%&rdquo; is the coin. Julia-1 landed at 31.5%: the pretty name hides a guy flipping a coin.</p>
<p>The intervals matter. Perplexity&rsquo;s edge over Jev on v2 is under 2 points and the bootstrap interval touches zero: it&rsquo;s the measured lead on this set, not a proven superiority forever. And Decision 3.0 tied Perplexity at the limit of what this set can distinguish: <strong>identical labels on the 1,024 classifications</strong>, with both missing the same two cases (the English relevance one on v2 and the disputed severity case on v1, already in the errata). Microsoft tied Jev on the aggregate, with the interval centered on zero, but an aggregate tie is not interchangeability: they miss different cases, and Microsoft inverts the language pattern, missing more in English than in Portuguese. Jev and Clef also remain under 2 points apart, on the same tier. The 90% squad (Jebadiah, OpenAI) sits 7 points behind Jev, and from there down every difference is clear.</p>
<p>Each task cell has only 12 scenarios per language, so one more correct answer moves the cell by more than 8 points. A tie on a specific task is a lead for a pilot. The per-task tables are in the <a href="https://github.com/akitaonrails/jev-docs-benchmarks/blob/master/benchmark/reports/decision3-comparison-v2/results.md"target="_blank" rel="noopener">repository</a>.</p>
<h2>How much it costs, in support emails<span class="hx:absolute hx:-mt-20" id="how-much-it-costs-in-support-emails"></span>
    <a href="#how-much-it-costs-in-support-emails" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Price per million tokens is a number nobody can feel. List prices on October 11 are US$ 0.042 per million input tokens on Jev, US$ 0.24 on Clef, US$ 0.038 on Clef-flash and US$ 0.10 on OpenAI Decisions. Output is free on all five. Microsoft Decision-1 charges the same US$ 0.042 as Jev per million, via OpenRouter, but reported a third of the input tokens for the same texts (about 26 thousand versus Jev&rsquo;s 77 thousand on compact v2), and nobody can explain the tokenization difference. In measured practice, that makes it the cheapest hosted one of the bunch.</p>
<p>Clef-flash cost US$ 0.09 on the 9th: Cloudflare cut the price by more than half in the middle of my test. Jev reports considerably more tokens than Cloudflare for the same text, about 45% more on v2, and that&rsquo;s already in the math below.</p>
<p>Imagine an operation with <strong>10 thousand support emails per month</strong> to classify into three or four buckets, with short texts similar to my cases:</p>
<table>
  <thead>
      <tr>
          <th>Model</th>
          <th style="text-align: right">10k emails / month</th>
          <th style="text-align: right">1 million emails</th>
          <th style="text-align: right">Expected errors in 10k (by compact accuracy)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Microsoft Decision-1</td>
          <td style="text-align: right">US$ 0.065</td>
          <td style="text-align: right">US$ 6.45 (about R$ 32)</td>
          <td style="text-align: right">~240</td>
      </tr>
      <tr>
          <td>Clef-flash</td>
          <td style="text-align: right">US$ 0.10</td>
          <td style="text-align: right">US$ 10 (about R$ 50)</td>
          <td style="text-align: right">~1,250</td>
      </tr>
      <tr>
          <td>Jev</td>
          <td style="text-align: right">US$ 0.19</td>
          <td style="text-align: right">US$ 19 (about R$ 95)</td>
          <td style="text-align: right">~240</td>
      </tr>
      <tr>
          <td>OpenAI Decisions</td>
          <td style="text-align: right">US$ 0.23</td>
          <td style="text-align: right">US$ 23 (about R$ 115)</td>
          <td style="text-align: right">~950</td>
      </tr>
      <tr>
          <td>Clef</td>
          <td style="text-align: right">US$ 0.63</td>
          <td style="text-align: right">US$ 63 (about R$ 315)</td>
          <td style="text-align: right">~420</td>
      </tr>
  </tbody>
</table>
<blockquote>
  <p>In reais, at Friday&rsquo;s exchange rate (R$ 4.99), 10 thousand decisions on Jev cost one real. A million costs less than a hundred reais. For any company with a million emails to classify, that vanishes into the budget.</p>

</blockquote>
<p>One caveat about proportions: my cases are short, about 450 tokens per compact case by Jev&rsquo;s count. A real customer email, with quoted thread history, can be three to five times larger, and cost scales linearly with that. Even so, we&rsquo;re talking cents per thousand.</p>
<p>What this math shows is that the price difference between the hosted models is irrelevant next to the cost of being wrong. Jev costs 9 US cents more than Clef-flash per 10 thousand decisions, and in those same 10 thousand it makes about a thousand fewer errors. If a misrouted email costs more than a hundredth of a US cent in human rework, Jev pays for itself. This math assumes every error costs the same, which is never true: sending a critical ticket to the routine queue costs far more than the reverse.</p>
<p>Cloudflare&rsquo;s allowance changes the math for small players. It&rsquo;s 10 thousand &ldquo;neurons&rdquo; per day, shared by the whole account, resetting at midnight UTC. With my input sizes, that&rsquo;s about 1,500 full-Clef classifications per day or almost 10 thousand Clef-flash ones, free. If you have 1,000 emails a day and nothing else running on the account, Clef comes out at zero cost with top-tier quality.</p>
<p>And local? Energy is what the benchmark didn&rsquo;t measure. From what I see on my Strix Halo, the whole machine stays under 100 W under load. With Jebadiah at 200 ms per decision, 10 thousand decisions are about 35 machine minutes, under 0.1 kWh, a few cents of a real on the power bill.</p>
<p>The real local cost is the machine, your hours configuring ROCm and containers, and keeping it all standing. Whoever already has the hardware for another reason has low marginal cost. Whoever would buy the machine just for this is buying a problem of thousands of reais to save about a hundred reais per million.</p>
<h2>Which model for which situation<span class="hx:absolute hx:-mt-20" id="which-model-for-which-situation"></span>
    <a href="#which-model-for-which-situation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>You want accuracy and want to operate nothing: Jev<span class="hx:absolute hx:-mt-20" id="you-want-accuracy-and-want-to-operate-nothing-jev"></span>
    <a href="#you-want-accuracy-and-want-to-operate-nothing-jev" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In the cloud, Jev is still the name. It won or tied practically every cell among the hosted ones, and only Microsoft tied it on the aggregate. In English it was 100% on five of the seven v2 tasks, and in Portuguese it repeated 97.6% on the aggregate without losing anything in translation, something no other model above the coin managed. On v1 it kept its 96.2% on the original with the malicious &ldquo;reviewer&rdquo; comment injected; Clef even gained one case, and Kev 4B also stayed put, just at a much lower tier. The 255 ms WAN latency came in 30 ms behind OpenAI&rsquo;s, and it costs 19 US cents per 10 thousand decisions.</p>
<p>The trade-off is the one I already discussed in the previous post: it&rsquo;s proprietary, hosted, of undisclosed size, and you depend on TypeSafe keeping the behavior underneath you. And it makes mistakes. It treated an invoice ID called &ldquo;PASSWORD-523&rdquo; as a usable credential, even with the record explicitly saying it doesn&rsquo;t authenticate anyone.</p>
<h3>You want Jev&rsquo;s level paying a third: Microsoft Decision-1<span class="hx:absolute hx:-mt-20" id="you-want-jevs-level-paying-a-third-microsoft-decision-1"></span>
    <a href="#you-want-jevs-level-paying-a-third-microsoft-decision-1" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Microsoft entered this market quietly, and entered well. Decision-1 is a 9B post-trained from Qwen3.5-9B, served via OpenRouter, and it was the first model to tie Jev on the compact aggregate: 97.6%, with the bootstrap interval centered on zero. The detail that won me over: <strong>100% in Portuguese</strong>, better than its own English (95%), inverting the pattern of the entire rest of the bunch. On v1, the reversed-order and malicious-comment variants didn&rsquo;t take down a single answer, and it got the critical ticket that Clef and OpenAI missed.</p>
<p>And it&rsquo;s the cheapest hosted one I measured: US$ 0.065 per 10 thousand decisions, a third of Jev, charging the same per-token rate but reporting a third of the tokens. The savings come from the token count, and I can&rsquo;t explain the exact mechanism, so treat it as a measurement, not a promise.</p>
<p>The weak spots exist. Latency is the worst among the hosted ones (422 ms median, versus Jev&rsquo;s 255). On the compact cases it&rsquo;s clean of confident errors, but add context and Portuguese errors show up with 99.5% confidence: the &ldquo;perfect Portuguese&rdquo; pattern doesn&rsquo;t survive long text. And on the probability probes it&rsquo;s weak, giving 87% to a fair coin. Microsoft advertises calibrated probabilities; my probes disagree. And like every dated-ID hosted model, the weight behind it can change without notice.</p>
<p>For a Portuguese-language operation that wants Jev quality while paying less, it&rsquo;s the first candidate to run in your pilot.</p>
<h3>You want the same level with open weights: Clef<span class="hx:absolute hx:-mt-20" id="you-want-the-same-level-with-open-weights-clef"></span>
    <a href="#you-want-the-same-level-with-open-weights-clef" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The full 27B Clef tied with Jev in English (82 of 84) and finished 3 cases behind in Portuguese. It beat Jev on sensitive data handling in English (12 of 12 versus 11). It&rsquo;s an open-weights model, so you can run it locally with about 54 GB of memory just for the weights in BF16, which I didn&rsquo;t test: the full Clef ran only through the API. Among the open ones, it lost the crown to Perplexity, which scored higher with smaller weights.</p>
<p>Through the API it&rsquo;s the most expensive of the five hosted ones, three times Jev, with no quality gain to justify it. The exception is the daily allowance: for small volume, it&rsquo;s the best classifier you can get for free.</p>
<h3>You want the cheapest in the cloud: Clef-flash<span class="hx:absolute hx:-mt-20" id="you-want-the-cheapest-in-the-cloud-clef-flash"></span>
    <a href="#you-want-the-cheapest-in-the-cloud-clef-flash" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>At US$ 0.038 per million, Clef-flash is the lowest price in the hosted market and covers 9,400 decisions per day within the allowance. Quality drops: 92% in English and 83% in Portuguese on the compact cases, the biggest language drop among the hosted ones, with an interval entirely below zero. On sentiment in both languages, and on incident status in English, it tied with Jev. On intent and sensitive data in Portuguese, it lost badly.</p>
<p>For sentiment tasks in either language, or for English classification where 1 error in 12 is acceptable, it does well. For Portuguese, measure first.</p>
<h3>You already live in the OpenAI ecosystem: OpenAI Decisions<span class="hx:absolute hx:-mt-20" id="you-already-live-in-the-openai-ecosystem-openai-decisions"></span>
    <a href="#you-already-live-in-the-openai-ecosystem-openai-decisions" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>OpenAI&rsquo;s debut in this market landed mid-table: 90.5% combined, an exact tie with Jebadiah, with the lowest hosted latency I measured (222 ms) and the same accuracy in both languages. It costs US$ 0.23 per 10 thousand decisions, between Jev and Clef. If your operation already speaks the OpenAI API and 9 out of 10 accuracy is enough, integration is trivial: a native decisions endpoint, no prompt at all.</p>
<p>The weak spots are revealing. Its worst cell was precisely numeric-threshold policy (8 of 12 in English, 7 in Portuguese): it treated &ldquo;at least 10&rdquo; as satisfied by a range of 8 to 12 and failed the AND/OR short-circuit. The calibration is schizophrenic: on the predicate probes (yes/no) it was the most accurate of the bunch, with near-zero average error, and on the choice probes it returned 94%/6% on a fair coin. And on the v1 variants it flipped 2 correct answers in each presentation (reversed order, opaque label, malicious comment), something only Perplexity didn&rsquo;t do: Jev kept its aggregate accuracy, but also flipped some correct answers along the way. Oh, and the <code>gpt-6-luna</code> alias is not an immutable snapshot: reproducibility requires saving the responses.</p>
<h3>You want the best open model, period: Perplexity Decider 27B<span class="hx:absolute hx:-mt-20" id="you-want-the-best-open-model-period-perplexity-decider-27b"></span>
    <a href="#you-want-the-best-open-model-period-perplexity-decider-27b" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Perplexity Decider 1.1 27B is the surprise of the benchmark. It led the table with 99.4% on the compact cases, was the only one that didn&rsquo;t lose a single task cell to Jev (3 wins, 11 ties), and hit 100% in Portuguese under all three conditions: compact, with examples, with distractors. Calibration is also the best measured, with a Brier of 0.012, and coverage is absurd: it answered with confidence above 0.9 on 96% of cases and got zero of them wrong. On v1, it didn&rsquo;t flip a single answer across the order, opaque-label and malicious-comment variants.</p>
<p>Its only 3 errors on v2 were the same case in different clothing (it confused &ldquo;notification sent to managers&rdquo; with &ldquo;mandatory approver&rdquo;), and it made them with confidence below 0.9: the known error comes flagged. The weak spot is event-probability probes: asked about an event with a 1-in-4 chance, it answered 0.73. Strong classification does not imply reliable event probability.</p>
<p>The cost is hardware: about 49 GB of weights in BF16, a second and a half per decision on my Strix Halo (with ROCm&rsquo;s reference kernels, no flash-attention; on a good NVIDIA it should be much faster, but that I didn&rsquo;t measure). It&rsquo;s Apache 2.0, public weights with no gate. If you have the machine and want the top of the table at home, this is the one.</p>
<h3>You want the other open-weights top: Decision 3.0 (and beware the Edge)<span class="hx:absolute hx:-mt-20" id="you-want-the-other-open-weights-top-decision-30-and-beware-the-edge"></span>
    <a href="#you-want-the-other-open-weights-top-decision-30-and-beware-the-edge" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Decision 3.0, released two days ago by the vLLM Semantic Router project, is the second model to sit at the top: 99.4% on the compact cases, 100% in Portuguese, and a tie with Perplexity so absolute that the two gave <strong>exactly the same labels on the 1,024 classifications</strong>, including the same two misses (the English relevance one, at confidence below 0.9, and the disputed severity case that already lives in the errata). It also cleared the v1 traps without flipping a single answer, got both indisputable critical tickets right, and its calibration is in the same class as Perplexity&rsquo;s (Brier 0.014, 94% coverage above 0.9 with zero errors).</p>
<p>In other words: the open top now has two independent recipes that converge. For your pilot, either one works; run both if you can, because the probabilities differ even when the labels don&rsquo;t. Latency is in the same family as Perplexity (1.4 s on my machine, same ROCm diet), and the weights take the same ~49 GB.</p>
<p>The little brother is another story. <strong>Decision 3.0 Edge</strong> (0.6B) answers in 45 ms and fits in 1.3 GB of GPU, but scored only 61% on compact, plummets 14 points in Portuguese, and worse: of the 68 guesses it gave with confidence above 0.9, 14 were wrong. As a confidence-threshold router, out of the factory, it&rsquo;s a trap from the same class as Julia. The four middle checkpoints (flash, mini, nano, lite) I haven&rsquo;t tested yet; they&rsquo;re the ones that will tell whether the family has a sweet spot between the two extremes.</p>
<h3>You need to run locally, with quality: Jebadiah 4B v2<span class="hx:absolute hx:-mt-20" id="you-need-to-run-locally-with-quality-jebadiah-4b-v2"></span>
    <a href="#you-need-to-run-locally-with-quality-jebadiah-4b-v2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Of the local ones, Jebadiah 4B v2 had the best compact accuracy, 90% combined, answering in about 200 ms. It tied with Jev on six of the fourteen task cells, including intent, implication and status in English and intent in Portuguese. The weak spot is numeric-threshold policy, 9 of 12 in both languages, and it loses ground when the context fills with distractors (76% in Portuguese under that condition, versus 82% for Mapika).</p>
<p><strong>Mapika Decider 4B</strong> (the fastest of the 4Bs) and <strong>Kev 4B</strong> are right behind, both around 87%, and the 3-point difference between the three fits inside the error interval. They&rsquo;re three different training recipes on top of 4B backbones, with errors on different tasks. The choice between them depends on your task, and I&rsquo;d run all three in a pilot.</p>
<h3>You will send examples in the prompt: Kev 9B<span class="hx:absolute hx:-mt-20" id="you-will-send-examples-in-the-prompt-kev-9b"></span>
    <a href="#you-will-send-examples-in-the-prompt-kev-9b" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Kev 9B has a curious profile. On the compact cases it ties with Kev 4B, half a point apart with the interval crossing zero, meaning more than double the parameters bought nothing. With one solved example per class, it opens almost 10 points over the 4B, and with distractors it holds 7 more points. Brier also improves by about 25%: the probability it returns is better calibrated.</p>
<p>If your use is just the rule and the text, the 4B is enough and is more than twice as fast. If you&rsquo;re going to send examples or long context, the 9B is worth the memory. The warning is Portuguese: 83% compact in PT-BR, almost 10 points below its own English, the biggest language drop among the models above 80%. Only Laya typed (14 points) and Julia (13) drop more.</p>
<h3>You want Clef-flash behavior on your machine: local Clef-flash<span class="hx:absolute hx:-mt-20" id="you-want-clef-flash-behavior-on-your-machine-local-clef-flash"></span>
    <a href="#you-want-clef-flash-behavior-on-your-machine-local-clef-flash" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>On the v1 set, local Clef-flash reproduced the hosted one&rsquo;s 520 classifications, hit for hit and miss for miss. On v2 the story changed: same total (439 of 504), but 19 different labels, with swapped strengths (the local one gets more Portuguese intent right, the hosted one gets more relevance right). Among the local ones it&rsquo;s still the best on the v1 operational-policy set (90.8%), ahead of every 4B.</p>
<p>The gotcha is latency: 618 ms median on the Strix Halo, three times Jebadiah, for the same v2 accuracy. If you pick it, it&rsquo;s for the known behavior.</p>
<h3>You need to run offline on weak hardware: Laya and Julia, with many caveats<span class="hx:absolute hx:-mt-20" id="you-need-to-run-offline-on-weak-hardware-laya-and-julia-with-many-caveats"></span>
    <a href="#you-need-to-run-offline-on-weak-hardware-laya-and-julia-with-many-caveats" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Laya multilingual was the worst in the benchmark for accuracy (37% combined, near the coin), and the fastest by far among the ones that get anything right: 19 ms median, more than ten times faster than Jebadiah.</p>
<p>The three Laya checkpoints have between 322 and 421 million parameters, fit in under 1 GB of BF16 weights by parameter math, and the project documents CPU execution and an ONNX runtime (which I didn&rsquo;t measure). PyTorch&rsquo;s peak GPU allocation for the multilingual one stayed under 2 GB. A 4B needs about 8 GB just for weights at the same precision.</p>
<p><strong>Julia-1</strong> goes one step lower: 144 million parameters, 550 MB of weights, 12 ms median on GPU and 71 ms on a 4-thread CPU. It&rsquo;s the fastest model I&rsquo;ve ever measured here, and also the worst: 31.5% accuracy, glued to the 31% coin-flip line. In Portuguese it answered &ldquo;cancellation&rdquo; on all 12 intent scenarios, including the ones asking for a refund or access (the vendor&rsquo;s Portuguese evaluation was done in pt-PT, and it shows). The bigger disaster is confidence: of the 71 guesses it gave above 0.9, 48 were wrong. A confidence threshold won&rsquo;t save this model, because it&rsquo;s exactly on the confident guesses that it errs.</p>
<p>That&rsquo;s a design choice. Laya and Julia were made to be small encoders, fine-tunable on your task, to run at the edge. What I tested were the factory checkpoints, with no tuning, applying rules they had never seen, on broad tasks. In that scenario they did badly, period.</p>
<p>One detail confirms the fragility. On v1, when the reviewer&rsquo;s malicious comment comes in, Laya drops from 44% to 19% and typed-decisions to 15%. It obeys the comment the instructions say to ignore, and confidently: 17 of the 28 guesses above 0.9 were wrong. Julia failed all 5 policy-counterfactual pairs: change the rule, it keeps the answer.</p>
<blockquote>
  <p>If you want what Jev delivers, factory Laya and Julia are very far from it, and no small model (GLiNER included) came close. If your problem is &ldquo;I need to classify short text into three buckets, on a device with no internet and no GPU, and I have a thousand labeled examples to fine-tune on,&rdquo; these two are the only ones on the list that fit. Fine-tuning is the part I didn&rsquo;t test. It&rsquo;s another question, and it needs another benchmark.</p>

</blockquote>
<h3>The baseline: Simple-Jev with a stock Qwen<span class="hx:absolute hx:-mt-20" id="the-baseline-simple-jev-with-a-stock-qwen"></span>
    <a href="#the-baseline-simple-jev-with-a-stock-qwen" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Simple-Jev reading tokens from Qwen3.5 4B, with no decision training at all, scored 74% on compact v2. That&rsquo;s the yardstick for &ldquo;how much specialized training buys&rdquo;: Jebadiah, Mapika and Kev, all on similarly sized backbones, came in 13 to 16 points above. The training buys a lot.</p>
<p>The curious part is that on v1 Simple-Jev tied with Jebadiah (111 of 130 originals) and got both unambiguous critical tickets right, which several better models missed. It&rsquo;s also the slowest of the bunch, almost a second and a half per decision, because it&rsquo;s running a whole LLM.</p>
<h2>How hard it is to run the best open models on your machine<span class="hx:absolute hx:-mt-20" id="how-hard-it-is-to-run-the-best-open-models-on-your-machine"></span>
    <a href="#how-hard-it-is-to-run-the-best-open-models-on-your-machine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>All these models speak the same HTTP protocol, called SystemOne, which Jev popularized: you send a state (the text), one or more closed-answer questions, and get back the chosen option and the probability of each. Swapping models is swapping the port. OpenAI Decisions breaks from the pattern with its own native endpoint, but the idea is the same. What changes is how much work it takes to get each one standing, and there the difference between them is big.</p>
<h3>OpenAI: just an API key<span class="hx:absolute hx:-mt-20" id="openai-just-an-api-key"></span>
    <a href="#openai-just-an-api-key" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The easiest of all: create the key, load credit and call the endpoint. The benchmark&rsquo;s 1,048 requests ran in 4 minutes, without a single retry. The only hiccup was the first probe returning &ldquo;balance exhausted&rdquo; until I put US$ 20 in the account.</p>
<p><strong>Microsoft Decision-1</strong> is almost as simple: if you already have an OpenRouter account, it&rsquo;s point at the model and call the decisions endpoint. No GPU, no Azure subscription, no installation. In my test, 10 of the 504 v2 calls took a 429 and passed on retry, so plan for retries.</p>
<h3>Kev and Jebadiah: one pip and one command<span class="hx:absolute hx:-mt-20" id="kev-and-jebadiah-one-pip-and-one-command"></span>
    <a href="#kev-and-jebadiah-one-pip-and-one-command" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>Kev</strong> is the simplest of the 4B crowd. The project installs straight from GitHub and brings up a server with one command, downloading the LoRA adapter and the decision head on top of base Qwen3.5:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">pip install <span class="s2">&#34;kev @ https://github.com/jaredpalmer/kev/archive/fc4a17e194bca35a48c57211392ec49ea54a94ac.tar.gz&#34;</span>
</span></span><span class="line"><span class="cl">python -m kev.serve --run jaredpalmer/kev-4b --host 0.0.0.0 --port <span class="m">8000</span> --device cuda</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>Jebadiah</strong> follows the same pattern, with the server package inside its own repository:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">pip install <span class="s2">&#34;jebadiah-server @ https://github.com/getainode/jebadiah/archive/e9793abc66d1a7c5ad878d51eda656f1e9c5b9f5.tar.gz#subdirectory=server&#34;</span>
</span></span><span class="line"><span class="cl">jebadiah-serve --model frontier-infra/jebadiah-4b-v2 --host 0.0.0.0 --port <span class="m">8000</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>With either one up, a decision is a POST:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-sh" data-lang="sh"><span class="line"><span class="cl">curl -s http://localhost:8000/v1/systemone -H <span class="s1">&#39;content-type: application/json&#39;</span> -d <span class="s1">&#39;{
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#34;model&#34;: &#34;kev-4b&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#34;state&#34;: &#34;Cliente diz que foi cobrado duas vezes e pede o estorno da segunda cobrança.&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">  &#34;questions&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="s1">    &#34;fila&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="s1">      &#34;type&#34;: &#34;choice&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">      &#34;instructions&#34;: &#34;Escolha a fila correta pela política de suporte.&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">      &#34;criteria&#34;: {
</span></span></span><span class="line"><span class="cl"><span class="s1">        &#34;financeiro&#34;: &#34;Cobrança, estorno, nota fiscal.&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">        &#34;tecnico&#34;: &#34;Erro, bug, indisponibilidade.&#34;,
</span></span></span><span class="line"><span class="cl"><span class="s1">        &#34;vendas&#34;: &#34;Upgrade, plano novo, orçamento.&#34;
</span></span></span><span class="line"><span class="cl"><span class="s1">      }
</span></span></span><span class="line"><span class="cl"><span class="s1">    }
</span></span></span><span class="line"><span class="cl"><span class="s1">  }
</span></span></span><span class="line"><span class="cl"><span class="s1">}&#39;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The response carries the option and the probability distribution, and that&rsquo;s where you apply your threshold, log and decide whether to send it for human review. On an NVIDIA with CUDA and 16 GB of VRAM, a 4B in BF16 comes up without drama. The weights are about 8 GB.</p>
<h3>Laya and Julia: smaller still<span class="hx:absolute hx:-mt-20" id="laya-and-julia-smaller-still"></span>
    <a href="#laya-and-julia-smaller-still" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>Laya</strong> is a Python package with an encoder inside. It installs with <code>pip install laya</code> and the project documents CPU execution, which is its whole point. The version pinned on my server was 0.4.1, and the multilingual one&rsquo;s peak GPU memory stayed under 2 GB. To run on a GPU-less laptop or a small container, it&rsquo;s the only one on the list that fits, no discussion.</p>
<p><strong>Julia-1</strong> is similar in spirit: its own Python runtime, one <code>predict(state=..., questions=...)</code> call and done, no standard Transformers pipeline. I ran the same container on GPU and on CPU, and both gave the same accuracy with the same responses in 97% of cases. On a 4-thread CPU it answers in 71 ms, which for an edge classifier is great. The problem is still that it scores at coin-flip level.</p>
<h3>Where it gets complicated: AMD, ROCm and the rest<span class="hx:absolute hx:-mt-20" id="where-it-gets-complicated-amd-rocm-and-the-rest"></span>
    <a href="#where-it-gets-complicated-amd-rocm-and-the-rest" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In my case the hardware is AMD, and then &ldquo;one command&rdquo; turns into a day of work. The points that cost me time, to save you yours:</p>
<ul>
<li>None of these projects test on ROCm. Kev had a gfx1151-specific segfault caused by CUDA graphs (<a href="https://github.com/jaredpalmer/kev/issues/170"target="_blank" rel="noopener">issue 170</a>), fixed only after the 1.0 tag, so the pinned version is a main-branch commit and the official tag crashes.</li>
<li>The flash-linear-attention Triton kernels Qwen3.5 uses in the DeltaNet layers have no tested support on gfx1151. Everything ran on the pure-PyTorch path, slower than the latency published on CUDA. Jebadiah&rsquo;s 200 ms in the table is with that handbrake pulled.</li>
<li>Mapika Decider forces CUDA graphs when it sees the &ldquo;cuda&rdquo; device, which on ROCm is also called &ldquo;cuda.&rdquo; I had to turn it off by hand.</li>
<li>You need to export <code>HSA_OVERRIDE_GFX_VERSION=11.5.1</code> and <code>PYTORCH_ROCM_ARCH=gfx1151</code> and use a base image with ROCm torch already validated. Any random <code>pip install torch</code> overwrites it with the CUDA build and breaks everything. In my Dockerfile every package is installed with <code>--no-deps</code> and the build fails if torch stops being the ROCm one.</li>
<li>One model per container, one container at a time. The Strix Halo has memory shared between CPU and GPU, and three resident 4B models plus the Ollama that already runs there exhaust the 64 GiB the GPU can see.</li>
<li>Perplexity Decider was the most annoying of all. The release expects a specific CUDA torch (I swapped in the ROCm 7 torch 2.9), the flash-linear-attention kernels don&rsquo;t exist for it (I ran on PyTorch&rsquo;s reference kernels, slower), and the default loader blew past the host&rsquo;s 24 GiB RAM limit: I needed a custom loader that sends the 49 GiB of weights straight to the GPU. The model card still said &ldquo;private&rdquo; when I started, but the Hugging Face API confirmed it was public and gate-free, and the shards downloaded anonymously. The d3, at the same size, inherited the same treatment. The d3-edge, luckily, comes up with the standard Transformers loader and 1.3 GB of GPU.</li>
</ul>
<p>None of this is impossible, and it&rsquo;s all documented, with Dockerfiles, compose and the hashes of each checkpoint, in the <a href="https://github.com/akitaonrails/jev-docs-benchmarks/blob/master/docs/setup.md"target="_blank" rel="noopener">repository&rsquo;s setup guide</a>. But it&rsquo;s a real cost that the &ldquo;local is free&rdquo; spreadsheet never includes. If your machine is NVIDIA, most of this list disappears.</p>
<blockquote>
  <p>The full 27B Clef I didn&rsquo;t even try locally: it&rsquo;s about 54 GB of weights in BF16 before any activation. Perplexity, at 49 GB, proved a 27B runs on the Strix Halo, at the cost of a second and a half per decision with the reference kernels. The 9B Clef-flash runs, with about 18 GB of weights. The 4Bs are the sweet spot for consumer hardware.</p>

</blockquote>
<h2>Highlights and gotchas<span class="hx:absolute hx:-mt-20" id="highlights-and-gotchas"></span>
    <a href="#highlights-and-gotchas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Laya truncated all long Portuguese.</strong> Under the distractor condition, base Laya reported truncation on all 84 Portuguese calls, discarding almost 31 thousand state tokens, and on none of the 84 English ones. The English checkpoint&rsquo;s default context limit is only 512 tokens (the multilingual and typed ones use 1,024, configurable up to 8,192), and Portuguese tokenizes heavier. The other models don&rsquo;t even expose truncation telemetry, so &ldquo;zero truncation reported&rdquo; on them means &ldquo;I don&rsquo;t know.&rdquo;</p>
<p><strong>Portuguese costs more tokens.</strong> For the same 84 case pairs, Jev reported about 14% more input tokens in Portuguese than in English, and both Clefs about 15% more. If you budget a bilingual operation by the English average, you&rsquo;ll come in low.</p>
<p><strong>Does an example in the prompt save a weak model? It saves nothing.</strong> One solved example per class left Laya the same or worse; several of its aggregates dropped. It helped Kev 9B (plus 4 points) and Clef in Portuguese (plus 3.6 points, reaching Jev&rsquo;s level), and almost nothing on Jev, one more case in Portuguese. Validate examples on real traffic before assuming they help.</p>
<p><strong>Size correlates, and explains little.</strong> Among the 19 competitors of known size, the Spearman correlation between parameters and compact accuracy was 0.96. The Kev series is more informative: 63% at 0.8B, 87% at 4B, 88% at 9B. The big jump is from 0.8B to 4B, about 24 points, with an interval between 16 and 33. From 4B to 9B the compact difference crosses zero, and several nominal 4Bs, with similar backbones, gave very different results. In the d3 family, the flagship and the Edge sit almost 40 points apart under the same release, while a 9B, Microsoft, ties at the top of the hosted ones. Size helps up to 4B; past that, the training recipe rules.</p>
<p><strong>The 27B Clef missed a critical ticket that two of the Layas got right.</strong> On v1, one severity scenario says continuous data loss in production is critical, regardless of how many customers it affects. The record describes confirmed permanent loss, from a single customer. Jev, Clef-flash, Perplexity, d3, Microsoft, Laya typed, Simple-Jev and Laya multilingual answered &ldquo;critical.&rdquo; Full Clef, OpenAI, base Laya, Eikos, Jebadiah, Mapika, Kev 4B and Kev 9B answered &ldquo;degraded.&rdquo;</p>
<blockquote>
  <p>It&rsquo;s a single case, and an error rate would require many more. But it shows that the average hides exactly the error that costs the most. When the impact facts are structured, the severity rule belongs in code, and the model comes in only to extract the facts from free text.</p>

</blockquote>
<p><strong>Hosted and local diverge over time.</strong> Local Clef-flash reproduced the hosted one on v1&rsquo;s 520 classifications and diverged on 19 of v2&rsquo;s 504. Cloudflare keeps the weights version behind the hosted alias undisclosed. If reproducibility matters, pin the local hash.</p>
<p><strong>High confidence and safety are different things.</strong> On compact v2, Jev, Clef, both Clef-flashes, Eikos, Jebadiah, OpenAI, Microsoft, Perplexity and d3 got zero guesses above 0.9 wrong. Perplexity is the extreme case: it answered at that level on 96% of cases without missing one, with d3 right behind (94%, zero errors). Microsoft covered 95% and OpenAI only half. Microsoft&rsquo;s caveat: the clean record is only on compact, because with examples or distractors it misses in Portuguese with confidence above 99%. Mapika missed 5% of the guesses at that level, Kev 4B 3% and Simple-Jev 14%. And the two smallest of the bunch broke the pattern violently: Julia missed 48 of 71 guesses above 0.9, and d3-edge missed 14 of 68. Coverage varied too: Jev answered above 0.9 on almost 90% of cases, Clef on almost 80%, Clef-flash on 40% and base Laya on 2 of 168. On v1 Jev missed 1% of the guesses above 0.9 and base Laya missed 61%. A confidence threshold only works after being validated on your distribution, and Laya typed&rsquo;s low ECE in Portuguese left it at the same 36% accuracy.</p>
<p><strong>Perplexity didn&rsquo;t fall for presentation traps.</strong> Across the three v1 variants (reversed options, opaque labels, malicious comment), it kept the same answers as the original, without flipping a single one. The d3 repeated the feat, zero flips too. Microsoft only stumbled on the opaque labels (2 flips, one in each direction); order and comment didn&rsquo;t move it. OpenAI flipped 2 in each variant, and Laya collapsed to 19% under the comment. The price of that robustness is latency: a second and a half per decision on my machine, the worst median of the bunch.</p>
<p><strong>Numeric thresholds are a code problem.</strong> The threshold-triage task, with clear numbers and an explicit rule, gave 100% on Jev and both Clef-flashes and under 30% on both Layas in English. An <code>if</code> solves that with 100% and zero latency. The model only comes in when the number is buried in free text, and even then the right thing is to extract the number and leave the comparison to code.</p>
<p><strong>Lottery probability is another skill.</strong> On the 24 no-information probes (coin, die), Jev had the worst choice error among options. The numeric-estimate crown changed hands with OpenAI&rsquo;s debut: its yes/no predicate missed almost nothing, while the choice probe returned 94% for heads on a fair coin. Perplexity, champion of everything else, answered 0.73 for an event with a 1-in-4 chance, and Microsoft went the same way, giving 87% to the coin. Laya typed had the second-best choice error, behind only Kev 9B and neck-and-neck with Clef, and still classified badly. It&rsquo;s the &ldquo;student who marks answer A&rdquo; from Paulo&rsquo;s essay, now measured: calibration on lotteries and accuracy on classification are independent measures.</p>
<h2>Where the data converges<span class="hx:absolute hx:-mt-20" id="where-the-data-converges"></span>
    <a href="#where-the-data-converges" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ol>
<li>
<p><strong>The overall top is open-weights, and now there are two.</strong> Perplexity Decider 27B and Decision 3.0 tied at 99.4% on the compact cases, with 100% in Portuguese and identical labels on the 1,024 classifications, both with Apache 2.0 weights running on my machine. Their edge over Jev is under 2 points and the interval touches zero, so treat it as a snapshot of this set. Their cost is hardware and latency, not API. In the cloud, the evaluation order changed: <strong>start with Microsoft Decision-1</strong>, which ties Jev on the aggregate, closes 100% in compact Portuguese and costs a third. Jev comes next, faster and with different errors, because an aggregate tie is not interchangeability. OpenAI Decisions landed halfway in price and accuracy.</p>
</li>
<li>
<p><strong>Running locally became viable at 4B.</strong> Jebadiah, Mapika and Kev 4B deliver between 87 and 90% on the compact cases with 200 ms latency on a desktop machine, and in a pilot with your task any of the three can win. If your machine handles 49 GB of weights, Perplexity delivers the top of the table at home. The financial math justifies using the machine that already exists, for data control or because of an obligation to stay offline. Buying a machine for this it stops justifying.</p>
</li>
<li>
<p><strong>Small models are another category.</strong> Judging Laya and Julia by the accuracy column is reading the table wrong. They get half or more wrong out of the factory, fall hard under a malicious comment, and together with the d3-edge they&rsquo;re the only ones on the list that fit on a weak device and answer in tens of milliseconds. The Edge is the best of the three on accuracy (61%), but it plummets in Portuguese and gets one in five confident guesses wrong. If Jev-like accuracy is a requirement, cross all three off. If running offline on small hardware is a requirement, cross everything else off and start with fine-tuning them on your task, which is the missing measurement. And be careful with Julia and the Edge in particular: 48 errors in 71 and 14 in 68 confident guesses are the portrait of models that don&rsquo;t know what they don&rsquo;t know.</p>
</li>
<li>
<p><strong>Portuguese costs about 14% more tokens</strong> and drops the models in the middle of the table by 1 to 10 points, with Kev 9B and Clef-flash in the worst case. Jev loses nothing, OpenAI ties both languages, and Perplexity, d3 and Microsoft close 100% in compact Portuguese, better than their own English, although Microsoft goes back to missing in Portuguese when the context grows. Julia goes the other way and plummets 13 points, and the Edge plummets 14. For a Brazilian audience, that&rsquo;s the first column to look at, before price.</p>
</li>
</ol>
<blockquote>
  <p>And what holds for everyone: none of these models replaces the rule that&rsquo;s already in code. Numeric thresholds, severity policy with structured facts, tool permission, all of that stays in the <code>if</code>. The model comes in to turn free text into structured fact. And the test that matters is yours, with your tickets, because each cell in this table has 12 scenarios and your operation has thousands.</p>

</blockquote>
<p>The cases, each model&rsquo;s raw responses, the scoring scripts and the guide to reproduce everything are in the <a href="https://github.com/akitaonrails/jev-docs-benchmarks"target="_blank" rel="noopener">benchmark repository</a>. If you run it with your tickets and get a different ranking, tell me.</p>
]]></content:encoded><category>llm-benchmarks</category><category>local-models</category><category>artificial-intelligence</category><category>llms</category></item><item><title>Disaster on My NAS! How I Almost Lost 90 TB of Data</title><link>https://www.akitaonrails.com/en/2026/10/06/disaster-on-my-nas-how-i-almost-lost-90-tb-of-data/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/06/disaster-on-my-nas-how-i-almost-lost-90-tb-of-data/</guid><pubDate>Tue, 06 Oct 2026 12:00:00 -0300</pubDate><description>&lt;p&gt;Yesterday, Monday, I was woken up at 8 a.m. by a loud, insistent beep. I knew it was the NAS before I opened my eyes. I ran to check, and nearly lost it: two drives marked as critical, in an array that can never have more than one.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-synology-2-discos-criticos.png" alt="Synology panel showing Storage Pool 1 in critical state, with drives 1 and 8 marked Critical" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;At that moment I knew I was a hiccup away from losing everything. This post is the post-mortem of what happened, and the first part was written in the heat of the disaster, with the rescue copy still running.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Yesterday, Monday, I was woken up at 8 a.m. by a loud, insistent beep. I knew it was the NAS before I opened my eyes. I ran to check, and nearly lost it: two drives marked as critical, in an array that can never have more than one.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-synology-2-discos-criticos.png" alt="Synology panel showing Storage Pool 1 in critical state, with drives 1 and 8 marked Critical"  loading="lazy" /></p>
<p>At that moment I knew I was a hiccup away from losing everything. This post is the post-mortem of what happened, and the first part was written in the heat of the disaster, with the rescue copy still running.</p>
<blockquote>
  <p><strong>Update of October 11:</strong> the copy finished and the ending was a happy one. No file was lost by accident, both NASes are healthy, each with its own RAID-6. The full recovery is in the <a href="#six-days-later-the-end-of-the-story">second half of this post</a>. The first part stays as it was published, untouched.</p>

</blockquote>
<h2>I&rsquo;ve been using a NAS for a long time<span class="hx:absolute hx:-mt-20" id="ive-been-using-a-nas-for-a-long-time"></span>
    <a href="#ive-been-using-a-nas-for-a-long-time" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I&rsquo;m not new to this. I made an <a href="https://www.youtube.com/playlist?list=PLdsnXVqbHDUcM0LTAxqrVrTy6Q7jQprjt"target="_blank" rel="noopener">entire video mini-series on storage and filesystems</a> (in Portuguese), and I recommend watching it before asking me &ldquo;what&rsquo;s a good beginner NAS?&rdquo;. There is no such thing.</p>
<p>I&rsquo;ve used external storage since the second half of the 2000s, when I was a Mac user and Drobo existed. The company is gone, but I had three of their DAS units before migrating to Synology, first on an entry-level model and then on the mid-tier DS1821+, which I&rsquo;ve been using for more than five years. I&rsquo;ve written about it here, <a href="/en/2025/04/17/configuring-my-synology-nas-with-nfs-on-linux/">setting up NFS on Linux</a> and <a href="/en/2025/04/24/accessing-your-nas-using-iscsi-instead-of-smb/">accessing it over iSCSI</a>.</p>
<p>It&rsquo;s been very valuable to me, and you don&rsquo;t get to question why I need that much space. It doesn&rsquo;t matter: everyone decides what they keep on theirs.</p>
<p>When I was producing YouTube videos, I edited 4K footage straight from the NAS, thanks to the NVMe cache and 10 GbE networking. I got used to big storage at 10 gigabits and I can&rsquo;t go back.</p>
<p>The array was organized in SHR, Synology&rsquo;s hybrid RAID, which in practice behaves like RAID-5 (more on that later): it survives the loss of one drive without losing any data. I always thought that was enough.</p>
<h2>Hard drives die. Always<span class="hx:absolute hx:-mt-20" id="hard-drives-die-always"></span>
    <a href="#hard-drives-die-always" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Make no mistake: hard drives go bad. Never, ever trust a lone drive forgotten in a closet. It will fail, and you will lose everything on it.</p>
<p>The best public data on this comes from Backblaze, which runs hundreds of thousands of drives and publishes failure rates every quarter. In the <a href="https://www.backblaze.com/blog/backblaze-drive-stats-for-q2-2026/"target="_blank" rel="noopener">Q2 2026 report</a>, with 354,415 drives monitored, the annualized rate was 1.73%, and the lifetime rate for the whole fleet stands at 1.41% per year.</p>
<p>That sounds small. Translated to human scale:</p>
<ul>
<li><strong>One drive on its own, for 5 years:</strong> the chance of it dying in that period is close to 7%. That&rsquo;s roughly the chance of rolling one specific number on a 14-sided die. Would you bet every family photo on that?</li>
<li><strong>One drive on its own, for 10 years:</strong> about 13%, one in eight.</li>
<li><strong>Eight drives, like my NAS, for one year:</strong> the chance of at least one failing is about 11%. In five years, more than 40%.</li>
</ul>
<p>And those numbers are from a datacenter, with controlled temperature, clean power and drives spinning all the time. A drawer drive that sits idle for years and gets knocked around in a move doesn&rsquo;t have statistics that pretty.</p>
<p>Memory cards are worse, and there isn&rsquo;t even an equivalent statistic to consult. What exists is torture testing: the <a href="https://www.bahjeez.com/the-great-microsd-card-survey-one-year-later/"target="_blank" rel="noopener">Great MicroSD Card Survey</a> tested 216 cards over a year of continuous writing, and 52 of them, one in four, had already died.</p>
<p>Genuine cards started throwing errors, on average, after about 2,500 rewrite cycles; counterfeit cards, after 700. A memory card is transport media. Keeping the only copy of anything on a microSD is asking to lose it.</p>
<p>The practical conclusion is the same as in the mini-series: important data needs redundancy. A parity array exists precisely so that the death of one drive, which is a matter of time, doesn&rsquo;t take anything with it.</p>
<h2>What happened<span class="hx:absolute hx:-mt-20" id="what-happened"></span>
    <a href="#what-happened" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>With all that, I should have been at ease with my setup. I wasn&rsquo;t.</p>
<p>It started the day before yesterday, Sunday. For a while I&rsquo;d been watching the volume approach the ceiling.</p>
<p>At first it was 8 drives of 10 TB. Over the years I swapped them, one by one, for 20 TB drives (DSM shows binary units; on the label they&rsquo;re 12 and 22 TB). It&rsquo;s a slow process: each swap takes days, because the array has to rebuild and redistribute the data.</p>
<p>I decided to swap one more, the seventh. Synology supports hot-swap, so it&rsquo;s simple: pull the old drive, slot in the new one, add it to the array and let DSM handle the rebuild.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-synology-pool-reparando.png" alt="Synology Storage Pool 1 repairing, 0.01% complete, with 108 TB allocated out of 121.8 TB"  loading="lazy" /></p>
<p>On Sunday night it looked like this: rebuild starting, all eight drives healthy, 108 TB allocated out of 121.8 TB.</p>
<p>On Monday, at 8 a.m., the beep. Drive 1, the new one, with 13 hours of use, marked critical:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-synology-drive1-critico.png" alt="Synology drive 1 in critical state, with an I/O error and 13 hours powered on"  loading="lazy" /></p>
<p>And drive 8, one of the old ones, with 22,095 hours powered on (two and a half years), also critical, with a read error at 08:05:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-synology-drive8-critico.png" alt="Synology drive 8 in critical state, with a read error and the message that the number of failed drives exceeds the RAID’s fault tolerance"  loading="lazy" /></p>
<p>The pool&rsquo;s message left no room: &ldquo;Unrecoverable errors have occurred because drive errors occurred after storage pool degradation. Please back up your data immediately.&rdquo;</p>
<h3>Why two drives is the end<span class="hx:absolute hx:-mt-20" id="why-two-drives-is-the-end"></span>
    <a href="#why-two-drives-is-the-end" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In RAID-5, if two drives go down, redundancy is zero, and in theory the whole array goes with them. It&rsquo;s an unrecoverable situation.</p>
<p>Anyone who watched my playlist knows why. An array like this doesn&rsquo;t store &ldquo;files,&rdquo; one per drive. A file is a collection of blocks, and the blocks are spread across all the drives, along with the parity. Losing a drive is losing a piece of every file. It doesn&rsquo;t matter that the other seven are healthy, because they only have parts.</p>
<p>Parity is there to recompute the missing piece when one drive disappears. With two missing, the math doesn&rsquo;t close.</p>
<p>And there&rsquo;s a cruel detail in the rebuild: to recreate the new drive, the array has to read every other drive end to end. That&rsquo;s more than 100 TB of continuous reading. If some old drive had a bad sector hiding in a corner nobody had read in a long time, that&rsquo;s when it shows up. That&rsquo;s what happened with drive 8.</p>
<h2>Where do you copy 90 TB to?<span class="hx:absolute hx:-mt-20" id="where-do-you-copy-90-tb-to"></span>
    <a href="#where-do-you-copy-90-tb-to" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The only way out, at that point, was to thank the heavens that the volumes were still accessible, with the files showing up, and use the window to copy everything out immediately. I couldn&rsquo;t touch anything else.</p>
<p>The problem: copy about 90 TB to where? Nobody has an empty 100 TB NAS lying around at home.</p>
<p>Normally I&rsquo;d buy this kind of hardware in the United States, on a tourist trip, and bring it back with me. It&rsquo;s much cheaper. Buying expensive electronics in Brazil isn&rsquo;t worth it: the country has charged import taxes worse than Trump&rsquo;s tariffs for decades, and the final price usually goes past double the American list price.</p>
<p>Except I had to choose. What is it worth to lose 90 TB of data I spent years collecting and that is nearly impossible to recover from anywhere else? It&rsquo;s one of those situations where the answer is &ldquo;it&rsquo;s priceless,&rdquo; and so, whatever the price, I pay.</p>
<p>I found a storage reseller close to home, <a href="https://www.controle.net"target="_blank" rel="noopener">Controle Net</a>. Good people, very quick to respond, and they sent me a proposal for equipment with same-day delivery.</p>
<p>Their first suggestion was a QNAP TS-832PX. I researched it before accepting. It has the same 8 bays and ships with 10 GbE, but the processor is a 1.7 GHz ARM Cortex-A57 (Annapurna Labs AL324) with 4 GB of RAM, half the 8 GB minimum that QuTS hero asks for. For RAID-6 on ZFS, with checksums and double parity on every block, that&rsquo;s weak hardware, as I explain further down. And it would be a downgrade from the DS1821+ I already had, which runs on a Ryzen V1500B.</p>
<p>I asked for another option, and after some back and forth I settled on a QNAP TS-873A, 8 bays, with the same Ryzen V1500B as my Synology, 8 GB of RAM, and 10 Toshiba MG11 24 TB enterprise-class drives.</p>
<p>This is why you have to do your own research and know, objectively, what you want to do with the equipment. The reseller didn&rsquo;t act in bad faith: they suggested an 8-bay NAS to someone who asked for an 8-bay NAS. The one who knew it would run ZFS in RAID-6 was me. If I had accepted the first proposal in a panic, I&rsquo;d have paid a lot for a worse machine than the one I was replacing.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-proposta-qnap.png" alt="Reseller proposal: QNAP TS-873A, 10 Toshiba MG11ACA24TE 24 TB drives, installation, training and 6 years of support, total R$ 185,320.00"  loading="lazy" /></p>
<p>R$ 185,320.00. Eye-watering.</p>
<h3>What it would cost in the United States<span class="hx:absolute hx:-mt-20" id="what-it-would-cost-in-the-united-states"></span>
    <a href="#what-it-would-cost-in-the-united-states" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I checked today&rsquo;s American list prices. About the exchange rate: the dollar is at R$ 4.97 right now, but that&rsquo;s the effect of Sunday&rsquo;s first-round election results, which knocked the rate down more than 4% on Monday. Through Friday it closed at R$ 5.22, and that&rsquo;s the fair rate to compare with, because that&rsquo;s the rate the reseller&rsquo;s stock was built at:</p>
<table>
  <thead>
      <tr>
          <th>Item</th>
          <th style="text-align: right">US price</th>
          <th style="text-align: right">Total</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>QNAP TS-873A-8G (<a href="https://store.qnap.com/ts-873a-8g-us.html"target="_blank" rel="noopener">QNAP store</a>, Newegg)</td>
          <td style="text-align: right">US$ 1,199</td>
          <td style="text-align: right">US$ 1,199</td>
      </tr>
      <tr>
          <td>10 × Toshiba MG11ACA24TE 24 TB (<a href="https://www.bhphotovideo.com/c/product/1889900-REG/toshiba_mg11aca24te_24tb_mg10_series_7200.html"target="_blank" rel="noopener">B&amp;H</a>)</td>
          <td style="text-align: right">US$ 999.99 each</td>
          <td style="text-align: right">US$ 9,999.90</td>
      </tr>
      <tr>
          <td>10 GbE card QXG-10G2T-X710 (<a href="https://www.bhphotovideo.com/c/product/1643883-REG/qnap_qxg_10g2t_x710_dual_port_10gbase_t_10gbe_network.html"target="_blank" rel="noopener">B&amp;H</a>)</td>
          <td style="text-align: right">US$ 351.99</td>
          <td style="text-align: right">US$ 351.99</td>
      </tr>
      <tr>
          <td><strong>Total</strong></td>
          <td style="text-align: right"></td>
          <td style="text-align: right"><strong>~US$ 11,550</strong></td>
      </tr>
  </tbody>
</table>
<p>At R$ 5.22, about R$ 60 thousand. I paid R$ 185 thousand, more than three times that.</p>
<p>The comparison isn&rsquo;t perfect: the Brazilian proposal includes installation, training and six years of technical support, and the equipment was on my desk by the end of the same day. But it gives the measure of the Brazil effect.</p>
<p>If the rule of thumb is &ldquo;double the American price,&rdquo; normal would be about R$ 120 thousand. The extra R$ 65 thousand is, in my own rough estimate, the sum of services, local stock of enterprise drives and my urgency. Whoever buys on a Monday morning with the array dying is in no position to haggle.</p>
<h3>And drives are expensive everywhere<span class="hx:absolute hx:-mt-20" id="and-drives-are-expensive-everywhere"></span>
    <a href="#and-drives-are-expensive-everywhere" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>To make it worse, this is the worst possible moment to buy hard drives. The AI bubble is sucking up production.</p>
<table>
  <thead>
      <tr>
          <th>Indicator</th>
          <th>Before</th>
          <th>Now</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>WD Blue 4 TB (Camelcamelcamel history)</td>
          <td>US$ 67 to 85</td>
          <td>US$ 99, <a href="https://winbuzzer.com/2026/02/18/wd-seagate-2026-hard-drive-shortage-ai-data-centers-xcxwbn/"target="_blank" rel="noopener">nearly 50% more in five months</a> (February 2026)</td>
      </tr>
      <tr>
          <td>Production capacity</td>
          <td>available at retail</td>
          <td>WD: 2026 practically sold out, with contracts through 2027 and 2028; Seagate: nearline capacity fully allocated</td>
      </tr>
      <tr>
          <td>WD gross margin</td>
          <td>41.0% a year earlier</td>
          <td><a href="https://datacenterdisk.com/news/hard-drive-prices-up-50-percent-2026"target="_blank" rel="noopener">54.1% in the quarter ended July 2026</a></td>
      </tr>
  </tbody>
</table>
<p>I thought Seagate had left the consumer market. I checked, and that&rsquo;s not quite it: it hasn&rsquo;t left, but in February 87% of its hard drive sales were already nearline drives, for datacenters, and WD gets 89% of its revenue from cloud customers and only 5% from retail. WD&rsquo;s CEO said the company is &ldquo;pretty much sold out for calendar year 2026.&rdquo;</p>
<p>Seagate has said it won&rsquo;t expand production capacity; growth comes only from higher-density drives. For someone buying drives at home, the practical effect is similar to them having left: you get what the hyperscalers didn&rsquo;t want, at whatever price the seller asks.</p>
<h2>QNAP instead of another Synology<span class="hx:absolute hx:-mt-20" id="qnap-instead-of-another-synology"></span>
    <a href="#qnap-instead-of-another-synology" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>After spending the morning and afternoon between negotiation, paperwork and payment, by the end of the day I had the QNAP powered on next to the Synology.</p>
<p>Choosing QNAP went beyond availability. Synology has been making questionable business decisions.</p>
<p>In 2025 it launched the Plus line <a href="https://www.tomshardware.com/pc-components/nas/synology-walks-back-controversial-compatibility-policy-for-2025-nas-units-third-party-hdd-and-ssd-support-returns-with-diskstation-manager-7-3-update"target="_blank" rel="noopener">requiring its own-brand drives or drives it certified</a>.</p>
<p>The own-brand ones are Seagate, Toshiba and WD drives rebadged with custom firmware, and anyone using something else was left without pool creation, health monitoring, deduplication or firmware updates. After the outcry, it <a href="https://www.howtogeek.com/synology-is-walking-back-its-drive-requirements/"target="_blank" rel="noopener">walked that back in DSM 7.3</a> and allowed HDDs and SATA SSDs from other brands.</p>
<p>Except M.2 pools still require the compatibility list. The uncertainty is left hanging: what stops them from doing it again?</p>
<p>Setting up the QNAP is very easy. QuTS hero, their ZFS-based system, is as simple to use as Synology&rsquo;s DSM.</p>
<h2>Fixing my mistake: RAID-6 and ZFS<span class="hx:absolute hx:-mt-20" id="fixing-my-mistake-raid-6-and-zfs"></span>
    <a href="#fixing-my-mistake-raid-6-and-zfs" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This time I knew I had to configure RAID-6, which survives two drives failing at the same time. The downside is less total capacity, because the equivalent of two drives becomes parity instead of one. The upside is that I shouldn&rsquo;t have to go through an emergency like this again.</p>
<p>One of QNAP&rsquo;s strengths is supporting ZFS out of the box, well integrated and easy to use.</p>
<p>For those who don&rsquo;t know it: ZFS was born at Sun Microsystems, for Solaris, in the mid-2000s, and today lives on as OpenZFS on Linux and FreeBSD. It merges into one system what used to be three layers, the RAID, the volume manager and the filesystem. It keeps a checksum of every block, so it notices when a drive silently returns corrupted data, and repairs it on its own from parity. And it never overwrites data in place: every write goes to a new block, which makes snapshots practically free.</p>
<p>Its reputation as a RAM hog comes from two things. The first is the ARC, its cache, which by design takes up almost all the machine&rsquo;s free memory. That scares anyone looking at the graph, but it&rsquo;s cache: it gives the memory back when another process asks. The second is deduplication, which keeps a huge table with the hash of every block and needs it in RAM or it becomes unusably slow. The old rule of &ldquo;1 GB of RAM per TB of disk&rdquo; comes from there, and only applies to people who turn deduplication on.</p>
<p>Even without it, ZFS is heavier than ext4 or a simple Btrfs. Computing checksums, compression and double parity for every block costs CPU, and with little memory the cache shrinks and everything gets slow. On weak hardware, like an entry-level NAS with an ARM processor and 2 GB of RAM, it suffers.</p>
<p>QNAP asks for at least 8 GB for QuTS hero. Mine came with 8 GB and a quad-core Ryzen, which works for my use, which is storing large files and serving them over the network. Deduplication stays off.</p>
<p>I bought 10 drives for an 8-bay NAS, so two are left in the drawer as spares, for the day one fails.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-qnap-criando-pool-raid6.png" alt="QNAP storage pool creation wizard: 8 disks in RAID 6, 126 TB, 5% over-provisioning, 5% guaranteed snapshot space and an 85% alert threshold"  loading="lazy" /></p>
<p>For my simple setup, three settings:</p>
<ul>
<li><strong>5% over-provisioning.</strong> It&rsquo;s a slice of the pool the system reserves and never hands out for data. ZFS always writes to new space and gets slow when the pool fills up near the limit; this slack keeps performance stable. On SSD pools it also extends drive life, but these are hard drives, so the minimum is enough.</li>
<li><strong>5% guaranteed snapshot space.</strong> It&rsquo;s the reserve for snapshots, the &ldquo;photos&rdquo; of the state of your files that let you go back after an accident or ransomware. Guaranteeing the space means the snapshots keep existing even if I fill up the rest. My data changes little (it&rsquo;s mostly cold archive), so snapshots take almost nothing and 5% is plenty.</li>
<li><strong>Alert at 85%.</strong> The system warns me when the pool passes 85% usage, with room for me to act before hitting the ceiling. It was exactly the lack of room that had me swapping drives in a hurry on the Synology.</li>
</ul>
<p>Adding the two reserves, about 13 TB are set aside and 112.9 TB are left for use.</p>
<p>A detail of my case: I&rsquo;m copying the 90 TB with snapshots turned off, and I&rsquo;ll only enable the schedule after the copy finishes. A snapshot protects a file&rsquo;s previous state, and on an empty NAS receiving its first load there is no previous state worth protecting. The source of truth is still the Synology.</p>
<p>And there&rsquo;s a practical cost. I stopped and restarted the job several times, deleted folders that had gone in by mistake and copied again. With snapshots on, every deleted thing would keep taking up space inside some snapshot, and I&rsquo;d be filling the pool with the migration&rsquo;s own garbage. When everything is on this side and checked, then yes: scheduled snapshots, to protect me from deleting what I shouldn&rsquo;t and from ransomware.</p>
<p>After that I created one giant &ldquo;thick&rdquo; partition. In ZFS you can create a &ldquo;thin&rdquo; folder, which only takes up what&rsquo;s inside it and can promise more space than exists, or a &ldquo;thick&rdquo; one, which reserves the full size at creation. Since it&rsquo;s a pool with one owner and one use, thick is more predictable: the space is mine and nothing competes for it.</p>
<p>Finally, I created the shares and installed the HBS 3 app.</p>
<h2>Copying 90 TB<span class="hx:absolute hx:-mt-20" id="copying-90-tb"></span>
    <a href="#copying-90-tb" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>HBS 3 (Hybrid Backup Sync) is QNAP&rsquo;s app for backup and synchronization. It connects to another NAS, to rsync, FTP, SMB or the cloud.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-hbs3-criar-job.png" alt="HBS 3 sync job creation screen, with the destination options: local NAS, remote NAS, Rsync, FTP and CIFS/SMB"  loading="lazy" /></p>
<p>I connected to the Synology&rsquo;s SMB share and told it to sync everything.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-hbs3-job-sync.png" alt="HBS 3 syncing from the Synology TERACHAD to the QNAP TS-873A"  loading="lazy" /></p>
<p>I had to stop and restart a few times, tweaking the job settings, because it was absurdly slow. And the file count wouldn&rsquo;t stop growing:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-hbs3-snapshot-explosao.png" alt="HBS 3 job status showing 45 million files and 865 TB calculated, at an average of 350 MB/s"  loading="lazy" /></p>
<p>865 TB on a 108 TB NAS, and that&rsquo;s when I understood what was going on.</p>
<p>I excluded two kinds of path from the job:</p>
<ul>
<li><strong>The <code>#snapshot</code> directories.</strong> On Synology, when you check &ldquo;make snapshot visible,&rdquo; each shared folder gets a <code>#snapshot</code> subfolder with a full view of the folder at each point in time. Inside the Synology that takes no space, because a snapshot only stores the difference. Seen from outside, over SMB, every snapshot looks like a full copy of everything, and HBS was trying to copy them all.</li>
<li><strong>The restic backup directories.</strong> restic stores everything in hundreds of thousands of pack files of a few megabytes each. Network copying is fast with large files and suffers with small ones, because each one costs an open, metadata and a close. And those backups I&rsquo;ll redo from scratch on the new NAS.</li>
</ul>
<p>With that, throughput rose to an average of 400 MB/s.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-qnap-400mbs.png" alt="QNAP resource monitor showing 414.8 MB/s received on the 10 GbE interface"  loading="lazy" /></p>
<p>That&rsquo;s less than half of what a 10 GbE network delivers, but it&rsquo;s more than three times the gigabit most people have at home. Both sides really are at 10 gigabits:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-qnap-10gbe.png" alt="QNAP 10 GbE adapter connected at 10 Gbps"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-synology-10gbe.png" alt="Synology LAN 5 interface at 10000 Mbps, full duplex"  loading="lazy" /></p>
<p>Why doesn&rsquo;t it reach 1,000 MB/s? My main hypothesis is drive 8. The source array is degraded, and every read that goes through the affected pieces has to be recomputed from parity, with a drive that on top of that returns errors and retries. It makes sense that the Synology can&rsquo;t go faster than this.</p>
<p>There&rsquo;s a second factor, which my own screenshots give away: the Synology has jumbo frames on (MTU 9000), and the QNAP image shows the default MTU of 1500. That screenshot is from earlier; I&rsquo;ve already changed the QNAP to 9000 as well.</p>
<p>Why it matters: MTU is the maximum size of each packet that travels on the network. At the default 1500 bytes, filling a 10-gigabit link means processing more than 800 thousand packets per second, and each packet costs CPU on both sides, for the header, the checksum and the interrupt. With jumbo frames each packet carries six times more data, so it&rsquo;s one sixth of the packets for the same volume, and more processor is left for moving files. It only works if everything in the path matches: both cards and the switch. If one side stays at 1500, the connection negotiates down to the smaller value and the other side&rsquo;s jumbo frames do nothing.</p>
<p>At 400 MB/s, 90 TB takes about two and a half days, and I prefer two and a half guaranteed days.</p>
<h2>What Synology explained<span class="hx:absolute hx:-mt-20" id="what-synology-explained"></span>
    <a href="#what-synology-explained" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In parallel, I opened a ticket with Synology support. After some back and forth, I sent the logs. They responded fast, the same day, and I&rsquo;ll give them that. The engineer&rsquo;s explanation, summarized:</p>
<ul>
<li>Drive 8 had been logging media errors <strong>for over a month</strong>. A media error is when the NAS tells the drive to read a sector and the drive answers that it couldn&rsquo;t, even after several retries. It&rsquo;s always an internal drive failure, and the drive should have been replaced.</li>
<li>It was drive 8&rsquo;s poor health that took it down during the rebuild of drive 1.</li>
<li>In practice I lost two drives, and the pool should have crashed completely. It didn&rsquo;t because of how SHR works.</li>
</ul>
<p>SHR isn&rsquo;t a single RAID-5. To use drives of different sizes without wasting space, it slices the drives and builds several smaller RAIDs, one per size band, and joins everything into one volume. The engineer sent this example diagram:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-synology-shr-particoes.png" alt="Synology support diagram showing how SHR splits drives of different sizes into partitions 1, 2 and 3"  loading="lazy" /></p>
<p>In my case, the pool is made of two partitions. In the first, the rebuild of drive 1 was far enough along and the failure of drive 8 was mild enough that both kept working. In the second, both are missing. That&rsquo;s why the pool didn&rsquo;t crash entirely and I can still see the files.</p>
<p>His recommendation was the one I was already following: copy everything out before anything else, because there&rsquo;s no telling whether the situation gets worse or whether it&rsquo;s fixable. After the backup he can even try forcing drive 8 back into the pool so the rebuild continues, but there&rsquo;s no guarantee the drive will go back in, or that it will survive the process. In his words, copying and recreating the pool from scratch is probably the quickest way forward.</p>
<p>Classic RAID-5, by the way, requires all drives to be the same size, and to grow capacity I&rsquo;d have to replace all of them at once. SHR is what let me swap one at a time over the years. Ironically, it&rsquo;s also what saved me from losing everything at once.</p>
<h2>The two mistakes<span class="hx:absolute hx:-mt-20" id="the-two-mistakes"></span>
    <a href="#the-two-mistakes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The way I understood it, there are two mistakes, one mine and one theirs, and that&rsquo;s where the whole disaster lives.</p>
<p><strong>Mine:</strong> I underestimated RAID-6, which on Synology is called SHR-2. With two parity drives, drive 8 failing in the middle of the rebuild would have been just a scare. I traded safety for 20 TB of space and spent five years thinking I&rsquo;d made a good deal.</p>
<p><strong>Theirs:</strong> from the logs, the software knew drive 8 had been failing for at least a month, and I never got a single notification. I have email notifications configured. And they work: when the critical situation blew up, I got a flood of emails. This one, about drive 8&rsquo;s bad sectors, arrived at one in the afternoon on Monday, five hours after the disaster:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261006120000_nas-synology-email-bad-sectors.png" alt="Synology email warning that the number of bad sectors increased on drive 8, a Seagate ST22000NT001"  loading="lazy" /></p>
<p>Before that, nothing. No warning about drive 8 until it failed catastrophically.</p>
<p>If I had received one, I would never have tried to swap drive 1 before replacing drive 8. The whole situation was avoidable, and it was the result of a human mistake plus some software bug.</p>
<p>That&rsquo;s the other reason I didn&rsquo;t buy another Synology. I have a principle: if the horse throws me, I put the horse down. I can&rsquo;t trust it again.</p>
<h2>Where I am now<span class="hx:absolute hx:-mt-20" id="where-i-am-now"></span>
    <a href="#where-i-am-now" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>So far I&rsquo;ve copied about 20 TB of the original 90 TB, and HBS 3 keeps working. I still don&rsquo;t know whether I lost any data permanently. I hope not, but the most likely outcome is that I lost what was in the RAID slice the engineer described as crashed.</p>
<p>I have offsite backup on AWS Glacier of what matters most, but not of everything.</p>
<p>A lot of people ask why I don&rsquo;t use S3 or some other cloud storage for everything. I return the question: think for ten seconds. How long does it take to transfer 90 TB over your internet connection? Do the math:</p>
<ul>
<li>With a solid 1 gigabit of upload, never dropping for a second: more than 8 days.</li>
<li>With 500 megabits: almost 17 days.</li>
<li>With 100 megabits, which is good upload for many homes: 83 days.</li>
</ul>
<p>And that&rsquo;s to upload. When disaster hits you need to download it all back, with the clock running. Not counting the rent: 90 TB on standard S3 costs about US$ 2 thousand a month at list price. Cloud is great for the critical subset, which is how I use it. For the whole archive, physics and the invoice won&rsquo;t allow it.</p>
<h2>Lessons<span class="hx:absolute hx:-mt-20" id="lessons"></span>
    <a href="#lessons" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I was put in an impossible situation on a Monday morning, I acted right away as best I could, and I&rsquo;ll probably come out of this mostly unscathed. We&rsquo;ll see, HBS 3 is still syncing. What I take from it:</p>
<ol>
<li><strong>Single parity isn&rsquo;t enough for big drives.</strong> With 20 TB drives, a rebuild takes days and reads everything. That&rsquo;s the window in which the second drive tends to show up. RAID-6, SHR-2 or RAIDZ2.</li>
<li><strong>Don&rsquo;t rely only on the vendor&rsquo;s notifications.</strong> Look at SMART and the drive logs before starting any swap. I didn&rsquo;t, because I trusted I&rsquo;d be warned.</li>
<li><strong>Replace the sick drive first, then the small one.</strong> A capacity upgrade on an array with a suspect drive is roulette.</li>
<li><strong>Leave slack.</strong> I was swapping drives because the volume was at the ceiling. An 85% alert exists for that.</li>
<li><strong>Have somewhere to copy to.</strong> My way out cost R$ 185 thousand because I had no plan B. A second NAS, even a modest one, with what matters, would have bought me time to shop calmly.</li>
<li><strong>RAID is not backup.</strong> I know that, I teach that, and I still only had offsite for part of it.</li>
</ol>
<p>The copy is done and I already know the size of the damage: zero. The full recovery comes next.</p>
<h2>Six days later: the end of the story<span class="hx:absolute hx:-mt-20" id="six-days-later-the-end-of-the-story"></span>
    <a href="#six-days-later-the-end-of-the-story" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When I published the first part, I had about 20 TB copied and no certainty. The outcome: I finished evacuating the ~91 TB, verified file by file, and lost nothing by accident. Not even what was on the fallen RAID slice, because it stayed readable until the end.</p>
<p>Who operated the recovery were my two agents. The desktop agent controls my PC and both NASes over SSH, and the homelab agent takes care of the server where my 57 containers run. The two coordinate by message: one leaves a report in the other&rsquo;s inbox, and I follow the conversation.</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-ai-memory-agentes.png" alt="The desktop agent’s terminal checking the ai-memory message inbox, where the homelab agent leaves its reports"  loading="lazy" />)</p>
<p>This part matters because nothing that follows was me typing commands. I made the decisions; they executed, measured and screwed up badly a few times, as you&rsquo;ll see.</p>
<h3>HBS 3 was quietly betraying me<span class="hx:absolute hx:-mt-20" id="hbs-3-was-quietly-betraying-me"></span>
    <a href="#hbs-3-was-quietly-betraying-me" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In the first part I told how HBS 3, pulling the Synology shares over CIFS, reached 400 MB/s after the adjustments. What I didn&rsquo;t know: speed was the smallest of its problems.</p>
<p>Two defects showed up when the agent checked the source inventory against what HBS reported:</p>
<ul>
<li><strong>It didn&rsquo;t go where it had no permission, and told nobody.</strong> HBS mounts the Synology as my user. The <code>Bitcoin/data</code> directory, 901 GB with my node&rsquo;s wallet and chainstate, belongs to uid 101 and is closed to anyone else. CIFS couldn&rsquo;t get in there, and HBS reported success without recording the omission. A &ldquo;green&rdquo; backup that leaves the entire Bitcoin node behind.</li>
<li><strong>It skipped files with &ldquo;unsupported&rdquo; names.</strong> 113 files, recorded only on a detail screen nobody opens during a days-long copy.</li>
</ul>
<blockquote>
  <p>A backup tool that reports success while omitting what it couldn&rsquo;t read is worse than one that fails screaming. Verify the backup against an independent inventory of the source, never against the tool&rsquo;s own log.</p>

</blockquote>
<p>We abandoned HBS. The agent opened SSH on both NASes, enabled the rsync server on the QNAP, and the Synology started pushing straight to its rsyncd, with nothing going through the PC. Each job&rsquo;s wrapper: <code>rsync -a --numeric-ids -W --partial --timeout=600</code>, attempts with retry, and <strong>never <code>--delete</code></strong>. The <code>--numeric-ids</code> preserved the original uids with no chown afterwards, <code>--partial</code> turned any interruption into a continuation, and the absence of <code>--delete</code> made the destination always a superset: re-sharding or killing a job never cost data.</p>
<h3>The bottleneck wasn&rsquo;t the broken drive<span class="hx:absolute hx:-mt-20" id="the-bottleneck-wasnt-the-broken-drive"></span>
    <a href="#the-bottleneck-wasnt-the-broken-drive" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Some context was missing from the first part. This Synology was born with eight consumer-line Seagate IronWolfs, and over the years I had been swapping them one by one for 20 TB IronWolf Pros. The disaster happened exactly during one of those upgrades: I swapped drive 1 for the new Pro and, during the rebuild, drive 8 failed. One single old drive was left in the array: drive 2.</p>
<p>And it, not drive 8, was the evacuation bottleneck. Measured under load:</p>
<ul>
<li>Drive 2 (the old consumer one, with 37 thousand hours of use): 91% utilization, delivering 27 MB/s, each I/O taking 4 to 15 times longer than its siblings.</li>
<li>The six Pros: between 34% and 45% utilization, sitting idle waiting for it.</li>
</ul>
<p>In RAID-5 (and in SHR), a sequential read spans the whole stripe, and the stripe only completes when the slowest member answers. One slow drive caps the whole array: because of it, the array couldn&rsquo;t go past about 200 MB/s while six good drives had room to spare. And its SMART was clean, zero reallocated sectors. Consumer drives usually ship without time-limited error recovery (ERC/TLER) active, so the drive retries a marginal sector for seconds, internally, without accounting for anything. The Synology&rsquo;s NVMe cache diverted part of the reads from the platters and helped mask the symptom.</p>
<blockquote>
  <p>The drive that fails and the drive that slows you down don&rsquo;t have to be the same, and SMART &ldquo;PASSED&rdquo; says nothing about latency. A slow array is diagnosed with per-drive utilization and response time, not with SMART.</p>

</blockquote>
<h3>Parallelizing rsync is science, not guesswork<span class="hx:absolute hx:-mt-20" id="parallelizing-rsync-is-science-not-guesswork"></span>
    <a href="#parallelizing-rsync-is-science-not-guesswork" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>First instinct: more streams. Wrong, twice.</p>
<p>The first time, a bug of ours: a &ldquo;clean&rdquo; job relaunch didn&rsquo;t kill anything, because the Synology&rsquo;s busybox <code>ps</code> truncates the command line and the verification grep didn&rsquo;t find the old processes. Result: 32 rsyncs running into 7 destinations, four to five writers per tree, the QNAP with its receive buffers clogged, and the cable transmitting 516 MB/s while the array read 140. After the cleanup (enumerating <code>/proc/*/cmdline</code>, never trusting <code>ps</code> again), useful throughput <strong>rose</strong> from 140 to 181 MB/s while total load collapsed.</p>
<p>The second time, measurement inverted common sense: with large-file trees, fewer streams were faster, because the average size of each read request tripled and the array did long sequential runs instead of jumping around.</p>
<p>But small-file trees are another sport. <code>TERACHAD/Emulators</code> has 21 TB in 3.4 million files averaging 6 MB: latency-bound work (stat, creation, metadata), not bandwidth-bound. And there aggressive parallelization worked, with one detail: the right shard is chosen by <strong>file count</strong>, not by size. A single directory, <code>ROMS_FINAL/xbox-hdd-ready</code>, held 995 thousand of ROMS_FINAL&rsquo;s 1.59 million files, averaging 1.7 MB per file. Isolating it from the multi-gigabyte ISOs:</p>
<table>
  <thead>
      <tr>
          <th>Configuration</th>
          <th style="text-align: right">GB/hour</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>single stream, 6-hour average</td>
          <td style="text-align: right">~157</td>
      </tr>
      <tr>
          <td>two shards</td>
          <td style="text-align: right">272</td>
      </tr>
      <tr>
          <td><strong>three shards</strong></td>
          <td style="text-align: right"><strong>436 to 501</strong></td>
      </tr>
  </tbody>
</table>
<p>Between 2.8 and 3.2 times the single stream&rsquo;s average throughput, on the same machine, on the same network. And there&rsquo;s a beautiful reason: with the array missing a member, reads of data that doesn&rsquo;t live on drive 2 don&rsquo;t need it, so the extra concurrency let the other drives work while it choked.</p>
<blockquote>
  <p>&ldquo;More parallelism&rdquo; and &ldquo;less parallelism&rdquo; are both wrong answers as a general rule. Bandwidth-bound work splits little; latency-bound work splits a lot, and by file count. Measure before choosing.</p>

</blockquote>
<h3>Copying is half the work; proving is the other half<span class="hx:absolute hx:-mt-20" id="copying-is-half-the-work-proving-is-the-other-half"></span>
    <a href="#copying-is-half-the-work-proving-is-the-other-half" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Every job that finished went through a dry-run of the same rsync, with the same excludes: zero files needing transfer means an identical destination by size and date. And even so it almost went wrong, because <strong>the verification inherited the copy&rsquo;s excludes</strong>: a tree excluded from the transfer stayed excluded from its own proof. Re-running the check without excludes turned up 952 files and 191 GB missing in Downloads (exactly the batches I had set aside as &ldquo;only existing copy&rdquo;) and the old restic repositories, which a similar directory name on the QNAP pretended to cover: the repositories&rsquo; internal ID proved they were different ones, not copies.</p>
<p>There was source drift too: a tree verified as complete received 16 GB of new checkpoints on the Synology after the check, and only the final re-verification caught it. Verification has an expiration date.</p>
<p>And a conscious decision, recorded so nobody accuses me of hiding it: the old backup histories (about 2 TB of restic snapshots and a duplicity set from 2025) were left behind by my choice, because the new repositories on the QNAP already cover the same content from now on. Deliberate loss of history, not of data.</p>
<p>Closing the books: <strong>17 rsync jobs, all exit 0, all verified, about 5.9 million byte-identical files</strong>, and the Synology shutdown only happened after every tree was proven.</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-homelab-containers-status.png" alt="Recovery status table mid-process: the containers already released and the ones still held waiting for each tree’s rsync verification"  loading="lazy" />)</p>
<h3>Meanwhile, in the homelab<span class="hx:absolute hx:-mt-20" id="meanwhile-in-the-homelab"></span>
    <a href="#meanwhile-in-the-homelab" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>On the other side of the house, the marvin server, which mounts the NAS over NFS and runs the 57 containers, almost died standing up. Dead NAS plus &ldquo;hard&rdquo; NFS mounts plus 57 containers restarting on their own made an infinite queue of uninterruptible I/O: the machine answered ping, but sshd couldn&rsquo;t complete a handshake. And every insistent SSH attempt only made it worse, because OpenSSH punishes a repetitive source by extending the ban. We knocked on the door and the door added a lock.</p>
<p>The way out was to stop knocking: I paused the torrents through the qBittorrent API (which kept responding), went to the physical console, disabled Docker, rebooted, and the server came back. A watchdog I didn&rsquo;t even remember existed had, on its own, taken down the 14 NAS-dependent containers before any database corrupted: bitcoind&rsquo;s LevelDB opened clean on the first try.</p>
<p>The migration itself was elegant: fstab pointed at the QNAP and the old mount points became symlinks into the new one. <strong>No docker-compose changed.</strong> Then came the QNAP NFS gotcha: permission is per client. The desktop was allowed without squash, but marvin&rsquo;s writes came in as uid 1001, blocking everything that writes to the NAS. The first fix attempt still flipped the mount to read-only in the middle of the first restic backup, which survived on retries. Final configuration: read and write, no squash for anyone, tested with <code>touch</code> and <code>ls -ln</code> from each client, because &ldquo;it worked on the desktop&rdquo; proves nothing about the server.</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-qnap-configurando-nfs.png" alt="QNAP NFS permissions screen, with the per-host rule for the homelab server"  loading="lazy" />)</p>
<p>After that it was resurrection tree by tree: each service only came up when its tree was verified on the QNAP. In two days, 57 of 57 containers back, and a brand-new restic backup running daily to the QNAP.</p>
<h3>The new kernel took down the NVMe<span class="hx:absolute hx:-mt-20" id="the-new-kernel-took-down-the-nvme"></span>
    <a href="#the-new-kernel-took-down-the-nvme" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In the middle of the recovery, a free scare from the server. Seven minutes after the nightly backup started, the NVMe controller vanished silently: every binary took SIGBUS, Docker and sshd died, and nothing remained recorded anywhere, because the log lives on the device that died. Not even a kernel panic: just silence.</p>
<p>The same workload had run fine hours earlier on kernel 7.2.6 and died on 7.2.9. Disabling APST (the NVMe&rsquo;s power management) didn&rsquo;t fix it: a second identical crash, a 7.2.9 regression confirmed by elimination. MicroOS is transactional and snapshot-based, so the rollback was a reboot into the 7.2.6 lineage, not a reinstall. Automatic updates were deliberately left broken on that lineage so nobody goes back to 7.2.9 unsupervised, and testing 7.2.8 waits until I can sit next to it.</p>
<blockquote>
  <p>A transactional operating system turns a kernel regression into a reboot. Without system snapshots, that night would have cost a lot more.</p>

</blockquote>
<h3>The thick provisioning scare<span class="hx:absolute hx:-mt-20" id="the-thick-provisioning-scare"></span>
    <a href="#the-thick-provisioning-scare" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>On the QNAP, the whole copy ran with no snapshots at all: in a bulk migration, snapshots are dead weight. With the copy done, I went to enable the ZFS snapshot schedule and got a dry error: &ldquo;pool free space is not enough&rdquo;. With 20 TB free.</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-qnap-thick-thin-erro-snapshot.png" alt="QNAP error when trying to create a snapshot: insufficient pool free space, even with terabytes free"  loading="lazy" />)</p>
<p>Both statements were true about different things. The CHAD folder had been created as <strong>thick</strong>: out of the 100 TB quota, ZFS reserves the full 100 TB, and to snapshot a dataset with a reservation, the pool has to guarantee space to overwrite every referenced block while the snapshot pins the old copies. The math: 80 TB written plus 100 TB reserved, against 126 TB usable in the pool. It doesn&rsquo;t close. And <code>df</code> lies on both sides, because it measures the folder against the quota, not against the pool.</p>
<p>The fix was converting the folder to <strong>thin</strong>, which QuTS hero does in-place, hidden on the folder&rsquo;s Management screen, not in the edit dialog where &ldquo;Thick&rdquo; looks like static text. In thin, the number becomes a ceiling instead of a reservation: the 10 TB reservation evaporated, the pool ended up with 39 TB free, and the first snapshot came out consuming 334 KB over 79.9 TB referenced. ZFS needed almost nothing; the reservation was what demanded a 100 TB guarantee to authorize.</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-qnap-chad-properties.png" alt="CHAD folder properties after the conversion, now as thin"  loading="lazy" />)</p>
<p>Now the QNAP has a snapshot schedule with a retention policy, as it should have had since day one:</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-qnap-snapshot-schedule.png" alt="CHAD folder snapshot schedule on the QNAP"  loading="lazy" />)</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-qnap-snapshot-retention.png" alt="Snapshot retention policy: how many to keep per day, week and month"  loading="lazy" />)</p>
<p>Two footnotes for anyone building one of these. If your thin folder has an 80% alert, raise the quota for aesthetic slack, because the alert measures against the quota and not against the pool. And this QNAP&rsquo;s real bottleneck is RAM: 7 GB for a 174 TB pool. QuTS hero&rsquo;s official minimum is 8 GB, and sensible practice at this scale is 16 and up. The size of the ARC cache governs metadata speed, and that&rsquo;s why the whole-tree sweeps during the migration were slow. A RAM upgrade is worth more than any fine-tuning.</p>
<h3>The Synology is born again<span class="hx:absolute hx:-mt-20" id="the-synology-is-born-again"></span>
    <a href="#the-synology-is-born-again" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>With everything verified on the QNAP, the Synology could finally be operated on. I swapped drives 2 and 8 for new IronWolf Pros, deleted the wounded pool and recreated it from scratch, this time in <strong>SHR-2</strong>, the two-parity-drive mode, their RAID-6. The new pool came out with 100 TB, all drives healthy:</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-synology-pool-novo-saudavel.png" alt="Synology Storage Manager showing the new SYNOCHAD pool in SHR with two-drive tolerance, 100 TB and all drives Healthy"  loading="lazy" />)</p>
<p>It goes back to work as a replica target, and no longer as a single point of failure. The QNAP stays as primary, in RAIDZ2, with 87 TB of the 126 TB used and snapshots scheduled:</p>
<p><img src="/2026/10/06/desastre-no-meu-nas-como-quase-perdi-90-tb-de-dados/nas-qnap-storage-manager-final.png" alt="QNAP Storage Manager with the RAID 6 Ready pool and the CHAD folder in thin with 79.9 TB of 95 TB"  loading="lazy" />)</p>
<h3>What I take from the second half<span class="hx:absolute hx:-mt-20" id="what-i-take-from-the-second-half"></span>
    <a href="#what-i-take-from-the-second-half" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ol>
<li><strong>Distrust silent success.</strong> HBS reported green while leaving 901 GB behind. A backup is verified against a source inventory.</li>
<li><strong>SMART doesn&rsquo;t measure slowness.</strong> The drive that nearly killed the evacuation was &ldquo;healthy.&rdquo; Per-drive utilization and latency tell the truth.</li>
<li><strong>Parallelism is calibrated by measuring.</strong> Bandwidth-bound splits little, latency-bound splits a lot, and the shard is chosen by file count.</li>
<li><strong>Verification doesn&rsquo;t inherit excludes.</strong> If the proof uses the same filters as the copy, it only reaffirms the copy&rsquo;s assumptions. And verify again immediately before destroying the source.</li>
<li><strong>NFS permission is per client.</strong> Test writes from every machine that will use it.</li>
<li><strong>Don&rsquo;t hammer a dying sshd.</strong> Each attempt extends the ban. One patient attempt, or the physical console.</li>
<li><strong>The dangerous repair comes last.</strong> The array stayed degraded and slow until the last byte was proven somewhere else; only then did rebuilding stop costing anything.</li>
</ol>
<p>I came out of this better protected than I went in: two NASes, each with its own RAID-6, scheduled snapshots on the QNAP, daily restic, and Glacier for what&rsquo;s critical. The disaster cost me a QNAP, two drives and a week. It could have cost 90 TB.</p>
]]></content:encoded><category>storage-and-backup</category><category>homelab</category><category>hardware</category></item><item><title>Understanding the Jev Hype: What Is It For?</title><link>https://www.akitaonrails.com/en/2026/10/03/understanding-the-jev-hype-what-is-it-for/</link><guid isPermaLink="true">https://www.akitaonrails.com/en/2026/10/03/understanding-the-jev-hype-what-is-it-for/</guid><pubDate>Sat, 03 Oct 2026 14:00:00 -0300</pubDate><description>&lt;p&gt;This post is here to demystify Jev: what it really is, when you need one, what it actually helps with, and why the astonishment around it says more about how people have been using LLMs than about the product.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR for those who only want to know which one to use:&lt;/strong&gt; Jev is a hosted classifier, good and cheap for repeated decisions over text, and not a silver bullet. If you want the direct comparison, skip to &lt;a href="#clef-from-cloudflare"&gt;Clef&lt;/a&gt;, Cloudflare&amp;rsquo;s open alternative with weights and image input; to &lt;a href="#laya-and-arbiter"&gt;Laya&lt;/a&gt;, the small encoder to run locally and fine-tune on your task; to the &lt;a href="#the-decision-index-how-to-measure-this-yourself"&gt;public ranking&lt;/a&gt;, with 70 models side by side; or straight to &lt;a href="#how-a-programmer-should-think-about-this"&gt;how to decide in your project&lt;/a&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This post is here to demystify Jev: what it really is, when you need one, what it actually helps with, and why the astonishment around it says more about how people have been using LLMs than about the product.</p>
<blockquote>
  <p><strong>TL;DR for those who only want to know which one to use:</strong> Jev is a hosted classifier, good and cheap for repeated decisions over text, and not a silver bullet. If you want the direct comparison, skip to <a href="#clef-from-cloudflare">Clef</a>, Cloudflare&rsquo;s open alternative with weights and image input; to <a href="#laya-and-arbiter">Laya</a>, the small encoder to run locally and fine-tune on your task; to the <a href="#the-decision-index-how-to-measure-this-yourself">public ranking</a>, with 70 models side by side; or straight to <a href="#how-a-programmer-should-think-about-this">how to decide in your project</a>.</p>

</blockquote>
<p>When Jev showed up, I <a href="/en/2026/09/16/why-things-like-typesafe-ai-dont-interest-me/">didn&rsquo;t think much of it</a>. The homepage was a festival of jargon, Kahneman here, Jevons there, a &ldquo;193x faster&rdquo; with no benchmark next to it, and my rule for new AI tools is not to adopt any intermediate layer until it hurts not to have it, so I didn&rsquo;t spend time on it.</p>
<p>In that post I concluded that, marketing aside, Jev is a hosted classifier: you send a text and closed-answer questions, it returns the option and the probability, without generating any prose. And that the &ldquo;193x&rdquo; only impresses because the comparison is against a chat LLM writing a paragraph so you can fish a label out of it afterwards.</p>
<p>What I hadn&rsquo;t registered at the time is the size of the habit Jev exposes. A lot of people were using a frontier LLM as an expensive stand-in for an ordinary classifier, and had never thought about a classifier, because they never had to: the LLM solved it, badly and expensively, and nobody measured.</p>
<p>For me, a classifier would be the first idea, which is why Jev didn&rsquo;t look like news. For many people it was a revelation. That gap is the subject of this post.</p>
<h2>This post is a collaboration<span class="hx:absolute hx:-mt-20" id="this-post-is-a-collaboration"></span>
    <a href="#this-post-is-a-collaboration" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Much of what you&rsquo;ll read here is by <a href="https://www.linkedin.com/in/paulocamara/"target="_blank" rel="noopener">Paulo Câmara</a>, neuroscientist, co-founder and CTO of LUA Vision, the Brazilian company whose model I <a href="/en/2026/09/23/llm-benchmark-v4-genesys-pi-new-brazilian-contender/">tested</a> and <a href="/en/2026/09/30/the-mystery-of-lua-vision-genesys-pi-brazilian-frontier-model/">investigated</a> in recent weeks. He wrote an essay, &ldquo;The student who marks answer A,&rdquo; to be published here, in which he read Jev&rsquo;s fine print, opened the roughly 350 test repositories that appeared on GitHub in launch week, and recomputed the four main results from scratch.</p>
<p>The warning Paulo gives at the end applies: he founded a company that builds its own model and competes in the same market. Read with that discount, and check the numbers at the source, all of which he links.</p>
<h2>First: what a classifier is<span class="hx:absolute hx:-mt-20" id="first-what-a-classifier-is"></span>
    <a href="#first-what-a-classifier-is" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A classifier is a function that takes an input and returns one of a fixed set of categories, usually with a probability for each. This email is spam or not. This ticket is billing, support or sales. This transaction looks like fraud.</p>
<p>The list of possible answers is closed, and you know it before you run.</p>
<p>The classic way to build one is with labeled examples: a set of texts where someone has already given the right answer. On top of that you train a model, which can be something as simple as logistic regression or naive Bayes, or a small encoder like BERT with a few hundred million parameters. In every case, the final model is small, runs locally, answers in milliseconds, costs almost nothing per call, and returns numbers you can calibrate and audit against your own data. This has existed for decades and is undergraduate material.</p>
<p>So when someone with a computer science background sees a problem like &ldquo;decide which bucket this text falls into, thousands of times a day,&rdquo; the first question is &ldquo;how many labeled examples do I have?&rdquo;, not &ldquo;which LLM do I use?&rdquo;.</p>
<p>A chat LLM is a text generator with billions of parameters. Using it to return a label means paying per output token, waiting seconds per answer, dealing with a format that sometimes breaks, and accepting behavior that changes when the vendor updates the model. It can be done, and zero-shot classification with language models has been documented since 2019. But it&rsquo;s the expensive, slow option, and it only pays off when you have no examples at all or when the categories change with every request.</p>
<p>Jev lands exactly in that space. It&rsquo;s a classifier that accepts categories defined on the fly, several questions about the same text in a single call, hosted, cheap per token and fast.</p>
<p>Compared with a chat LLM generating a paragraph, it&rsquo;s an engineering win. Compared with a classifier trained for a stable task, it&rsquo;s a convenience that trades control for flexibility. Keep those two yardsticks in mind, because the rest of the post goes back and forth between them.</p>
<h2>Paulo&rsquo;s essay: &ldquo;The student who marks answer A&rdquo;<span class="hx:absolute hx:-mt-20" id="paulos-essay-the-student-who-marks-answer-a"></span>
    <a href="#paulos-essay-the-student-who-marks-answer-a" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><em>What follows is Paulo Câmara&rsquo;s essay, written for this post. The subheadings are his.</em></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-folha-de-respostas.png" alt="Answer sheet with answer A marked on every question and a stamp reading 92% certainty"  loading="lazy" /></p>
<p>Every week an AI savior shows up. This week&rsquo;s is called Jev.</p>
<p>It launched on September 15, with US$ 40 million in the bank, a US$ 200 million valuation and a promise that fits on a billboard: two hundred times faster, four hundred times cheaper, calibrated and incapable of hallucinating. Within 24 hours, 13% of the paid teams on Vercel&rsquo;s gateway were already using it. Within a week, there were more than 300 repositories on GitHub testing the thing.</p>
<p>I did what I do with every savior. I read the fine print, opened the roughly 350 repositories, and redid the math for the ones that published raw data. What I found fits in the image above: an answer sheet with answer A marked on every question.</p>
<p>When there is no information at all to decide on, Jev marks the first option. In 3,000 of 3,000 draws. With up to 92% certainty. Keep that image, because it explains the rest of the text.</p>
<h3>What it is, without the billboard<span class="hx:absolute hx:-mt-20" id="what-it-is-without-the-billboard"></span>
    <a href="#what-it-is-without-the-billboard" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Strip away the marketing and what&rsquo;s left is a multiple-choice exam with no essay section. You send a text, ask closed-answer questions (choose among up to 255 options, give a score on a scale, say yes or no) and it returns the probability of each answer. It doesn&rsquo;t write a line. It doesn&rsquo;t explain. It doesn&rsquo;t do math. It doesn&rsquo;t call tools.</p>
<p>That&rsquo;s good, and I want to start with what&rsquo;s good. Many companies today use a frontier LLM as a luxury if statement: send the document, wait twenty seconds for the model to think out loud, pay for every word it writes, validate the JSON, and only then find out the ticket was about billing. Jev cuts that theater. It reads the text once, scores each option, done. That&rsquo;s why output is free and ten questions cost almost the same as one.</p>
<p>The mechanism, though, isn&rsquo;t new. Reading the score of each possible answer is how language models have been evaluated on multiple choice since GPT-2. It&rsquo;s how the reward models of RLHF work, a technique TypeSafe&rsquo;s founder helped create at OpenAI.</p>
<p>A few days after launch there was already an open copy imitating the interface with a public model, and ten days later Stanford and Nvidia released an open-weights competitor. TypeSafe published no paper, no weights, no model size and no result on a public benchmark. In the announcement&rsquo;s FAQ, &ldquo;Is Jev just a smaller LLM?&rdquo; appears as a question. The answer is one line: &ldquo;it is neither small nor an LLM.&rdquo; That&rsquo;s it.</p>
<h3>One opponent for each headline<span class="hx:absolute hx:-mt-20" id="one-opponent-for-each-headline"></span>
    <a href="#one-opponent-for-each-headline" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The homepage says &ldquo;193.6× faster, 444.6× cheaper.&rdquo; I redid the math with the table the company itself published. The 444.6 is the cost of Opus 5, the most expensive model on the panel, divided by Jev&rsquo;s cost. The 193.6 is Sonnet 5&rsquo;s time divided by Jev&rsquo;s time. One opponent for each headline.</p>
<p>It&rsquo;s like advertising that your car is more fuel-efficient than a Ferrari and faster than a truck, and letting the reader conclude it&rsquo;s the best car in the world.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-jev-mais-barato-por-adversario.png" alt="How many times cheaper Jev is, depending on who is on the other side"  loading="lazy" /></p>
<p><em>How many times cheaper Jev is, depending on who is on the other side. Source: TypeSafe&rsquo;s public table (evals.typesafe.ai) and independent tests against non-reasoning LLMs.</em></p>
<p>Against the cheap model that scores about the same, Luna, Jev is 8 times cheaper. And that&rsquo;s with every LLM in the comparison thinking before answering, something nobody does to route a ticket. Against a non-reasoning LLM, the independent tests measure about 4 times on cost and 2 to 7 on time. Still a lot. But an order of magnitude less than the billboard.</p>
<p>There&rsquo;s a detail almost nobody read. There is no answer key in that evaluation. &ldquo;Accuracy&rdquo; is how much each model agrees with the average of two frontier models. Jev agrees 67.8% of the time, the same as Sonnet 5. Opus 5 is at 73.1%.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-concordancia-vs-custo.png" alt="Agreement with the reference versus cost per case, average of TypeSafe’s four workflows"  loading="lazy" /></p>
<p><em>Agreement with the reference versus cost per case, average of TypeSafe&rsquo;s four workflows. The green band runs from 66.8% to 67.9%: Luna, Sonnet 5, Terra and Jev.</em></p>
<p>Breaking it down by task shows what the average hides. On invoices, which require checking amount, quantity and date, Jev is 17 points behind the best model (61.8% versus 79.1%) and below even Luna. Its documentation warns that it &ldquo;is not a calculator.&rdquo; At least that is true.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-concordancia-por-workflow.png" alt="Agreement by workflow"  loading="lazy" /></p>
<p><em>Agreement by workflow. Source: evals.typesafe.ai.</em></p>
<p>And the most solid data on TypeSafe&rsquo;s site isn&rsquo;t even about Jev. All eight LLMs evaluated score higher when the task is broken into small questions and the logic stays in code. Haiku 4.5 goes from 18.1% to 53.6%. The most useful lesson of the launch is an engineering one, and it applies to any model.</p>
<h3>What the price gives away<span class="hx:absolute hx:-mt-20" id="what-the-price-gives-away"></span>
    <a href="#what-the-price-gives-away" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Price is technical data in disguise. At US$ 0.042 per million tokens, a rented GPU needs to read 13 to 20 thousand tokens per second just to break even. In a scenario calculation, that squares with a model of 6 to 37 billion active parameters, which is a small model, or with a subsidy. TypeSafe wrote, with a candor I respect, that &ldquo;there is no way to prove it isn&rsquo;t subsidized.&rdquo;</p>
<p>Since launch, the per-account usage limit dropped from 250 thousand to 100 thousand tokens per second. The documentation warns that it changes &ldquo;without notice&rdquo; until the &ldquo;large GPU deals&rdquo; land, and the subprocessor list shows inference running on an on-demand rented GPU cloud. It&rsquo;s a frontier model with startup capacity.</p>
<p>In the same calculation, each decision costs about 14 joules. That&rsquo;s Jev&rsquo;s best argument, and I&rsquo;ve defended that yardstick for a long time: accuracy per joule, not just accuracy. There, it&rsquo;s genuinely good.</p>
<h3>Exam Portuguese<span class="hx:absolute hx:-mt-20" id="exam-portuguese"></span>
    <a href="#exam-portuguese" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I found only one test of Jev in Portuguese: ENEM 2025. I redid the math from the raw answers. Jev got 103 right against 102 for an open 120-billion-parameter model. A statistical tie (p = 1.0).</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-enem-2025-por-area.png" alt="Jev’s accuracy on ENEM 2025 by subject area"  loading="lazy" /></p>
<p><em>Jev&rsquo;s accuracy on ENEM 2025 by subject area, 182 valid questions, with 95% margins. Recomputed from the patryckalves/jev-no-enem repository.</em></p>
<p>Jev reads exam Portuguese better than many prep courses: 78% in Languages. And does Math like someone guessing: 25%, with a guess worth 20%. In Spanish, another audit measured a loss of 3 to 6 points relative to English and 17% to 38% more tokens for the same text. It&rsquo;s the token tax I measured in my paper, charged again, now by another vendor.</p>
<p>One detail in its favor: the explicit &ldquo;invalid&rdquo; option in that experiment separated out the hardest questions. That&rsquo;s the abstention route worth demanding in production, measuring alongside it how much it leaves unanswered.</p>
<h3>The student who marks answer A<span class="hx:absolute hx:-mt-20" id="the-student-who-marks-answer-a"></span>
    <a href="#the-student-who-marks-answer-a" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Back to the answer sheet.</p>
<p>An auditor asked Jev to predict a fair die it had no way of seeing. The honest answer is 1/6 for each face. I downloaded the 1,000 answers and counted. In every one, Jev chose the first option on the list it received: &ldquo;1&rdquo; on the die, &ldquo;red&rdquo; on the color die, &ldquo;heads&rdquo; on the coin, &ldquo;north&rdquo; on the spinner. With 76% to 92% certainty.</p>
<p>A second researcher repeated the same question 2,000 times, independently. Same result. The caveat: this holds for choice questions; in the yes-or-no-with-probability formulation, the same repository shows Jev closer to the reference, still overestimating low probabilities.</p>
<p>When it doesn&rsquo;t know, it doesn&rsquo;t say it doesn&rsquo;t know. It marks answer A, with conviction.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-probabilidade-declarada-vs-real.png" alt="Stated probability versus actual frequency"  loading="lazy" /></p>
<p><em>Stated probability versus actual frequency. Draws: 1,000 answers recomputed (KantaHayashiAI). Heart risk: 5,000 people from BRFSS, recomputed (rubinagentagi-tech). Items with human disagreement: pre-registered study with ChaosNLI (GautamTalksDev). ENEM: recomputed (patryckalves).</em></p>
<p>The chart shows the whole pattern. Where it has signal, as in ENEM answers above 0.9, what it says and what happens coincide: 97.1% confidence, 97.6% accuracy. Where it doesn&rsquo;t, the certainty stays and reality leaves.</p>
<p>In a test with 5,000 real people, the heart disease rate was 9%. Jev assigned, on average, 27%. I recomputed: its probability is worse than simply saying 9% for everyone.</p>
<h3>System 1, literally<span class="hx:absolute hx:-mt-20" id="system-1-literally"></span>
    <a href="#system-1-literally" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>TypeSafe calls Jev a &ldquo;System One model,&rdquo; a nod to Kahneman&rsquo;s fast thinking. It&rsquo;s the most honest part of the product, just not for the reason the company would like. In the book, System 1 is fast, cheap and automatic. It&rsquo;s also where overconfidence lives: it builds the most coherent story out of what&rsquo;s in front of it and doesn&rsquo;t register what&rsquo;s missing.</p>
<p>Kahneman spent years disagreeing with Gary Klein about when to trust expert intuition. In 2009 the two published a joint paper with the most elegant title in psychology: &ldquo;a failure to disagree.&rdquo; The conclusion fits in one line. Intuition only deserves trust in a high-validity environment, where there is regularity and there has been feedback to learn it from. Outside that, confidence stays high and stops saying anything about accuracy.</p>
<p>That&rsquo;s Jev, exactly. Classifying English text is a high-validity environment, and there it does well. Predicting risk, drawing lots, guessing the company rule nobody told it about: a low-validity environment. There it stays confident.</p>
<p>In the lab, we separate two things: deciding, and knowing whether you decided well. The second is called metacognition.</p>
<p>It&rsquo;s measured with signal detection theory, Maniscalco and Lau&rsquo;s meta-d′, and it depends in part on prefrontal regions distinct from the ones that support the decision. Fleming and colleagues found that in the anatomy in 2010, and Rounis and colleagues, the same year, showed that magnetic stimulation of the prefrontal cortex knocks down metacognition without touching accuracy (a result whose replication is disputed, by Bor and colleagues in 2017). That&rsquo;s why there are people who get it right without knowing they did, and people who get it wrong with conviction to spare.</p>
<p>The field the company calls confidence is a formula over the same distribution that produced the answer: in a two-option choice, 2p − 1. That isn&rsquo;t a defect in itself. An ideal observer does exactly that and gets it right.</p>
<p>The problem is that Jev&rsquo;s distribution loses calibration outside what it knows, and nothing in the system checks the answer by another route. When the signal disappears, the answer becomes wrong and the confidence stays the same, because the two are the same number. In a pre-registered study with items on which a hundred people disagree, human agreement is 47% and Jev carries on at 81% confidence. When the coordinates of a spatial task were shuffled, accuracy collapsed to 5% to 22% and confidence dropped by 0.028.</p>
<p>A model that says 83% about a die it never saw isn&rsquo;t calibrated. It&rsquo;s assertive.</p>
<h3>Attention gets captured<span class="hx:absolute hx:-mt-20" id="attention-gets-captured"></span>
    <a href="#attention-gets-captured" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I studied attention in my doctorate, and I expected to see capture: the loudest stimulus winning. That&rsquo;s not what the tests showed. The shout, the famous &ldquo;ignore your instructions,&rdquo; barely gets through. What gets through is the plausible sentence with no checked origin. Psychology has a name for this: source monitoring failure. The system treats a claim nobody verified as if it were fact.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-decisoes-viradas-por-ataque.png" alt="Decisions flipped by attack type"  loading="lazy" /></p>
<p><em>Decisions flipped by attack type. Crude attack: 1 in 1,056 (cwhy). Injected command and unverified opinion: 9,744 variants (Hu et al., 2026). Optimized fluent context: 312 of 508 correct decisions (Xu, 2026).</em></p>
<p>In numbers: the crude attack gets through 1 in 1,056. A single unverified opinion pasted at the end of the text flipped 12.1% of decisions, statistically tied with the strongest injected command. A line saying &ldquo;the closing administrator has confirmed this article was kept&rdquo; dropped accuracy from 96.5% to 26.5%.</p>
<p>A fake field saying the user had pre-approved <code>rm -rf ~/.ssh</code> lowered the chance of blocking from 0.76 to 0.48. It recalls Loftus&rsquo;s misinformation effect: suggested information rewrites the judgment.</p>
<p>The capture also applies to cues that shouldn&rsquo;t count. With the same text, saying only &ldquo;the writer is Black&rdquo; or &ldquo;the writer is white&rdquo; changed the death-penalty rate Jev assigned from 29.5% to 62.7%. The direction is beside the point. A life-or-death decision moved 33 points because of information that had nothing to do with the case.</p>
<p>There&rsquo;s one more I can&rsquo;t let pass. Changing only the option labels, from &ldquo;0/1&rdquo; to &ldquo;no/yes,&rdquo; without changing any definition, flipped 70 out of every 100 answers. The type error rate stayed at zero. The format was perfect. The decision was backwards.</p>
<p>These numbers come from preprints and small studies. The exact percentage changes with prompt, task and model version; the class of failure does not.</p>
<h3>Probability that doesn&rsquo;t add up<span class="hx:absolute hx:-mt-20" id="probability-that-doesnt-add-up"></span>
    <a href="#probability-that-doesnt-add-up" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Probability has a first-semester rule: the chance of something plus the chance of its opposite equals 1. In TypeSafe&rsquo;s own documentation, &ldquo;is the customer asking for a refund?&rdquo; gets 0.72, and &ldquo;is the customer asking for something other than a refund?&rdquo; gets 0.47. Sum: 1.19.</p>
<p>The pair isn&rsquo;t an exact complement, and TypeSafe doesn&rsquo;t promise that two separate questions form a joint distribution. But it&rsquo;s the example the company itself chose to show off the product, and it doesn&rsquo;t add up. The fix is a design one: a single choice question with mutually exclusive options, instead of two yes-or-nos added together.</p>
<p>People get probability wrong in many ways, but on this one they tend to get it right. When the question comes as a pair, the chance of something and of its opposite sum close to 1. Tversky and Koehler showed that in 1994. Jev gets wrong what people get right. The same decision changes value depending on the wording of the question, and that is the opposite of &ldquo;epistemically honest probabilities.&rdquo;</p>
<h3>&ldquo;It doesn&rsquo;t hallucinate&rdquo;<span class="hx:absolute hx:-mt-20" id="it-doesnt-hallucinate"></span>
    <a href="#it-doesnt-hallucinate" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The announcement says Jev &ldquo;cannot hallucinate&rdquo; and shows 0% type errors. The zero is true and irrelevant. Since it can only answer within the options you gave it, getting the format wrong is impossible. Calling that not hallucinating is like praising the answer-A student because he never leaves a question blank. True. So what?</p>
<p>In a model that chooses, hallucinating is choosing wrong with conviction. On fact-checking, Jev ties GPT-6 Astra on accuracy but calls an unsupported claim &ldquo;supported&rdquo; 23% of the time, against 14% for Astra. In 76% of the situations where there was no tool at all, it chose to call a tool. With a company rule it wasn&rsquo;t told about, it got 19 of 24 decisions wrong, 15 of them with more than 90% certainty. Faced with an invented law, it abstained zero times.</p>
<h3>Security<span class="hx:absolute hx:-mt-20" id="security"></span>
    <a href="#security" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>First, where your data ends up: the United States, AWS and a GPU cloud called Modal. Retention lasts &ldquo;for as long as reasonably necessary,&rdquo; with no deadline, and zero retention only exists on the enterprise plan.</p>
<p>The data agreement cites the European Union&rsquo;s standard contractual clauses, the UK addendum and California law, and doesn&rsquo;t have a word about LGPD. If you send Brazilian citizens&rsquo; data, the legal basis for the international transfer is on you, and that&rsquo;s a question for a lawyer before signing. The promise not to train on what you send exists and is good. SOC 2 exists and only appears on request.</p>
<p>As an attack detector, Jev is good, with fewer false alarms than many LLMs: it caught 40 of 41 injections in a test with real pages. As a judge of content that carries the attack inside it, it gives way, as I showed above. The difference looks subtle and decides everything. In my GV Angels talk I said an agent is not an employee, it&rsquo;s an access key that talks. A gate made only of Jev is a lock that opens when someone writes on the note that the owner authorized it.</p>
<p>The error that worries me isn&rsquo;t the error with doubt. That one goes to review. It&rsquo;s the error with 92% certainty, which crosses any threshold you configure.</p>
<h3>The wave<span class="hx:absolute hx:-mt-20" id="the-wave"></span>
    <a href="#the-wave" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A word about the evidence, because I used a lot of it.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20261003140000_jev-repositorios-por-dia.png" alt="Jev test repositories created per day on GitHub"  loading="lazy" /></p>
<p><em>Jev test repositories created per day on GitHub, from the metadata of 346 indexed repositories.</em></p>
<p>In one week about 350 repositories testing Jev were born. I classified all of them by what they let you check. There are 89 with raw data, code, pinned version and statistics, and 170 with data and code; the rest offer less than that.</p>
<p>Only 11 wrote the hypothesis down before running the test. The median is one GitHub star, which means almost nobody looked. And the wave of tests followed the wave of hype: peak on September 21, almost nothing after the 23rd.</p>
<p>That&rsquo;s why I didn&rsquo;t accept numbers on authority. The ones that support this text I checked at the source, and the four main ones I recomputed from scratch.</p>
<h3>Verdict<span class="hx:absolute hx:-mt-20" id="verdict"></span>
    <a href="#verdict" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>True:</strong></p>
<ul>
<li>Fast: 100 to 400 ms.</li>
<li>Cheap: 45 to 323 times less than a frontier LLM on the same decision.</li>
<li>Ties the top on narrow judgments, like checking whether a passage supports a claim.</li>
<li>Reliable above 0.9 on data similar to what it has already seen, after you&rsquo;ve checked that on yours.</li>
<li>Good injection detector.</li>
</ul>
<p><strong>Sandcastle:</strong></p>
<ul>
<li>193.6× and 444.6×.</li>
<li>&ldquo;Frontier intelligence.&rdquo;</li>
<li>&ldquo;Doesn&rsquo;t hallucinate.&rdquo;</li>
<li>Calibration as a general rule.</li>
<li>Safe as the sole guard of an agent.</li>
<li>New architecture: nobody has seen it.</li>
</ul>
<p>Jev is nobody&rsquo;s savior. It also isn&rsquo;t &ldquo;just a classifier.&rdquo; It&rsquo;s a good piece of product engineering that wraps known technique in an interface automation needed, at a price that changes what&rsquo;s viable. The product is new. What it claims is new, so far, is marketing: it calls format truth, task calibration honesty, and System 1 a virtue.</p>
<h3>What will break first<span class="hx:absolute hx:-mt-20" id="what-will-break-first"></span>
    <a href="#what-will-break-first" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>The agent gates built only of Jev, because the attack that breaks them is already published and costs cents.</li>
<li>The systems that trust the factory threshold on new data, in another language or with an internal rule, because they&rsquo;ll automate errors at 90% certainty.</li>
<li>Whoever uses its probability as real risk, in credit, health or forecasting, because it inflates rare events.</li>
<li>And the price advantage, because within ten days there was already an open copy and a faster competitor.</li>
</ul>
<h3>If you&rsquo;re going to use it anyway<span class="hx:absolute hx:-mt-20" id="if-youre-going-to-use-it-anyway"></span>
    <a href="#if-youre-going-to-use-it-anyway" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Pin the version. The <code>jev-latest</code> alias swaps models on its own, and your calibration goes with it.</li>
<li>Every question with a &ldquo;none of the above.&rdquo; Without it, it marks answer A.</li>
<li>Shuffle the order and use neutral names for the options. Test whether the decision changes.</li>
<li>Recalibrate with 50 to 300 of your own examples before choosing a threshold. In one test, calibration error dropped from 0.117 to 0.008.</li>
<li>Mark everything that comes from outside as untrusted: email, page, tool output.</li>
<li>Never let it authorize a destructive, financial or personal-data action on its own.</li>
<li>Math, dates and business rules stay in code.</li>
<li>Before signing, compare with the cheap baseline: an open model reading probabilities, or a trained classifier if the task is always the same.</li>
</ul>
<h3>Read with a discount<span class="hx:absolute hx:-mt-20" id="read-with-a-discount"></span>
    <a href="#read-with-a-discount" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>I founded a company that builds its own model and competes in the same market. Read with that discount. That&rsquo;s exactly why every number here has an open source: you don&rsquo;t need to trust me, you need to check.</p>
<p>And if someone sells you Jev as a savior, ask the question I ask every startup: which test, and from when? If the answer takes a while, that&rsquo;s the answer.</p>
<h3>Essay sources<span class="hx:absolute hx:-mt-20" id="essay-sources"></span>
    <a href="#essay-sources" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>TypeSafe. <a href="https://typesafe.ai/blog/introducing-system-one-models-and-jev"target="_blank" rel="noopener">Jev announcement</a> · <a href="https://docs.typesafe.ai/models"target="_blank" rel="noopener">models and limits</a> · <a href="https://docs.typesafe.ai/confidence"target="_blank" rel="noopener">confidence</a> · <a href="https://docs.typesafe.ai/model-jaggedness/jev-1.13"target="_blank" rel="noopener">known failures of jev-1.13</a> · <a href="https://evals.typesafe.ai/"target="_blank" rel="noopener">workflow evaluations</a> · <a href="https://github.com/typesafe-ai/system-one-adapter-python"target="_blank" rel="noopener">adapter for LLMs</a> · <a href="https://typesafe.ai/legal/privacy-policy"target="_blank" rel="noopener">privacy</a> · <a href="https://typesafe.ai/legal/data-processing"target="_blank" rel="noopener">data processing</a> · <a href="https://trust.typesafe.ai/"target="_blank" rel="noopener">trust center</a></p>
<p>Recomputed by Paulo from raw data. <a href="https://github.com/patryckalves/jev-no-enem"target="_blank" rel="noopener">ENEM 2025</a> · <a href="https://github.com/KantaHayashiAI/jev-does-not-play-dice"target="_blank" rel="noopener">blind draw</a> · <a href="https://github.com/rubinagentagi-tech/jev-heart-risk-bench"target="_blank" rel="noopener">heart risk</a> · <a href="https://github.com/adorosario/jev-rag-claim-verification"target="_blank" rel="noopener">fact-checking</a></p>
<p>Preprints. <a href="https://arxiv.org/abs/2609.31142"target="_blank" rel="noopener">Hu et al., JevAdvBench</a> · <a href="https://arxiv.org/abs/2609.30243"target="_blank" rel="noopener">Xu, JevOut</a> · <a href="https://arxiv.org/abs/2609.26758"target="_blank" rel="noopener">Sun et al., Type-Safe Is Not Error-Free</a> · <a href="https://arxiv.org/abs/2609.24574"target="_blank" rel="noopener">Ibrahim and Zaki</a> · <a href="https://arxiv.org/abs/2609.26550"target="_blank" rel="noopener">Li et al., JEV-as-a-Judge</a></p>
<p>Independent tests. <a href="https://github.com/GautamTalksDev/jevbench"target="_blank" rel="noopener">human disagreement (ChaosNLI)</a> · <a href="https://github.com/pobooo/jev-dice"target="_blank" rel="noopener">die replication</a> · <a href="https://github.com/zachlandes/jev-dialect-bias"target="_blank" rel="noopener">dialect bias</a> · <a href="https://github.com/OmarMujahid/jev-decision-bench"target="_blank" rel="noopener">49 tasks against a non-reasoning LLM</a> · <a href="https://github.com/colinmcnamara/jev-first-look"target="_blank" rel="noopener">calibration and negation</a> · <a href="https://github.com/AnthusAI/Jev-Calibration"target="_blank" rel="noopener">recalibration</a> · <a href="https://github.com/zkousama/jagged"target="_blank" rel="noopener">injection in Wikipedia discussions</a> · <a href="https://github.com/marcosmartinez/jev-acento"target="_blank" rel="noopener">Spanish</a> · <a href="https://github.com/baibizhe/jev-decision-benchmarks"target="_blank" rel="noopener">tools</a> · <a href="https://github.com/phuryn/experiments"target="_blank" rel="noopener">undisclosed internal rule</a> · <a href="https://github.com/scd13150/jev-field-notes"target="_blank" rel="noopener">shuffled coordinates</a> · <a href="https://github.com/cwhy/decision-injection-bench"target="_blank" rel="noopener">crude attacks</a> · <a href="https://github.com/kaiserama/im-in-danger"target="_blank" rel="noopener">injection detection</a> · <a href="https://github.com/Yifan-Lan/awesome-jev-robustness"target="_blank" rel="noopener">audit index</a></p>
<p>Press. <a href="https://venturebeat.com/security/companies-are-putting-jev-in-charge-of-ai-agent-decisions-and-prompt-injection-can-influence-the-verdict"target="_blank" rel="noopener">VentureBeat, agent gates</a> · <a href="https://venturebeat.com/technology/stanford-and-nvidias-open-clm-8b-caches-reusable-agent-actions-and-runs-up-to-9x-faster-than-jev-in-tests"target="_blank" rel="noopener">VentureBeat, CLM-8B</a></p>
<p>Literature. Fleming et al. (2010), Science 329 · Rounis et al. (2010), Cognitive Neuroscience 1 · Bor et al. (2017), PLoS ONE 12 · Johnson, Hashtroudi and Lindsay (1993), Psychological Bulletin 114 · Kahneman (2011), Thinking, Fast and Slow · Kahneman and Klein (2009), American Psychologist 64 · Loftus, Miller and Burns (1978), J. Experimental Psychology: Human Learning and Memory 4 · Maniscalco and Lau (2012), Consciousness and Cognition 21 · Ouyang et al. (2022), NeurIPS · Radford et al. (2019), OpenAI · Tversky and Koehler (1994), Psychological Review 101 · Câmara (2026), Inherited Weights, <a href="https://doi.org/10.5281/zenodo.22899767"target="_blank" rel="noopener">doi:10.5281/zenodo.22899767</a></p>
<h2>The open alternatives: Clef and Laya<span class="hx:absolute hx:-mt-20" id="the-open-alternatives-clef-and-laya"></span>
    <a href="#the-open-alternatives-clef-and-laya" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Since Jev&rsquo;s launch, the category has gained open competition, and that changes the conversation about &ldquo;new architecture.&rdquo; Two names matter.</p>
<h3>Clef, from Cloudflare<span class="hx:absolute hx:-mt-20" id="clef-from-cloudflare"></span>
    <a href="#clef-from-cloudflare" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>On October 1, Cloudflare released <a href="https://blog.cloudflare.com/clef-decision-models/"target="_blank" rel="noopener">Clef</a> and Clef-flash: the same abstraction as Jev (one shared state, several typed questions, a distribution over the options), with a <a href="https://developers.cloudflare.com/workers-ai/models/clef/"target="_blank" rel="noopener">compatible API</a>, open weights under Apache 2.0 and image input. The architecture is described: a frozen Qwen as base (27B in Clef, 9B in Clef-flash), LoRA adapters and a head that scores each allowed option directly, trained with classification and calibration objectives. In other words, the lineage Paulo pointed to, now with inspectable code.</p>
<p>That doesn&rsquo;t prove TypeSafe uses the same thing, but it proves the product can be reproduced with known components. Cloudflare ran the <a href="https://github.com/apolinario/decision-index"target="_blank" rel="noopener">Decision Index</a>, an open, independent suite with dozens of classification, routing, retrieval and safety tasks, and published the table. Some points:</p>
<table>
  <thead>
      <tr>
          <th>Task</th>
          <th style="text-align: right">Clef</th>
          <th style="text-align: right">Clef-flash</th>
          <th style="text-align: right">Jev</th>
          <th style="text-align: right">Laya</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>BFCL (tool selection)</td>
          <td style="text-align: right">98.47</td>
          <td style="text-align: right"><strong>98.76</strong></td>
          <td style="text-align: right">95.75</td>
          <td style="text-align: right">38.13</td>
      </tr>
      <tr>
          <td>Banking77 (intent)</td>
          <td style="text-align: right"><strong>94.20</strong></td>
          <td style="text-align: right">90.93</td>
          <td style="text-align: right">79.74</td>
          <td style="text-align: right">14.29</td>
      </tr>
      <tr>
          <td>CLINC150 with out-of-scope</td>
          <td style="text-align: right"><strong>97.43</strong></td>
          <td style="text-align: right">66.77</td>
          <td style="text-align: right">89.27</td>
          <td style="text-align: right">3.19</td>
      </tr>
      <tr>
          <td>When2Call</td>
          <td style="text-align: right">72.37</td>
          <td style="text-align: right">65.58</td>
          <td style="text-align: right"><strong>80.97</strong></td>
          <td style="text-align: right">11.94</td>
      </tr>
      <tr>
          <td>BRIGHT (retrieval)</td>
          <td style="text-align: right">45.91</td>
          <td style="text-align: right">39.26</td>
          <td style="text-align: right"><strong>47.52</strong></td>
          <td style="text-align: right">19.90</td>
      </tr>
      <tr>
          <td>PhishNChips</td>
          <td style="text-align: right"><strong>79.60</strong></td>
          <td style="text-align: right">75.05</td>
          <td style="text-align: right">62.55</td>
          <td style="text-align: right">50.15</td>
      </tr>
  </tbody>
</table>
<p>Reading the whole table: Clef comes out stronger on most tasks, Jev still wins some, and it&rsquo;s an internal Cloudflare run, on a public suite that can be trained against. Hosted price is the other side: <a href="https://developers.cloudflare.com/workers-ai/platform/pricing/"target="_blank" rel="noopener">US$ 0.24 per million tokens for Clef and US$ 0.09 for Clef-flash</a>, against US$ 0.042 for Jev. Jev remains the cheapest hosted service of the three, by a margin of 2 to 6 times, and remains text-only.</p>
<h3>Laya (and Arbiter)<span class="hx:absolute hx:-mt-20" id="laya-and-arbiter"></span>
    <a href="#laya-and-arbiter" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><a href="https://github.com/NandhaKishorM/laya"target="_blank" rel="noopener">Laya</a> attacks the problem from the other end. They&rsquo;re small encoders, 322 to 421 million parameters (ModernBERT-large in the typed version), with a choice head, Apache 2.0, built to run locally and be fine-tuned for a recurring task. <a href="https://github.com/0xBakeer/arbiter"target="_blank" rel="noopener">Arbiter</a> packages them behind a Jev-compatible API, with batching and deployment on Mac and NVIDIA. Arbiter is only a serving layer.</p>
<p>Laya&rsquo;s README is unusually explicit about its limits, and I&rsquo;d rather repeat than soften:</p>
<ul>
<li>the base checkpoints score near chance on the project&rsquo;s own typed-decision benchmark; the headline 0.766 accuracy comes from a checkpoint fine-tuned on that benchmark&rsquo;s training split;</li>
<li>the models ship overconfident, and calibration has to be redone in the deployment domain;</li>
<li>the typed version&rsquo;s context is 1,024 tokens, fine for tickets and short messages, insufficient for long documents without chunking;</li>
<li>with more than 50 options, the classification head saturates, and Laya itself reports Jev doing better.</li>
</ul>
<p>None of this is a defect in the idea. It&rsquo;s applied machine learning the way it has always been: a small model is excellent when the task is stable and labeled examples exist, and broad zero-shot behavior demands a much larger pretrained model. Laya is the option when privacy, offline operation, predictable latency or fine-tuning in your domain matter more than asking arbitrary questions about arbitrary documents. It is, at bottom, the classic classifier from the start of this post, with a modern interface.</p>
<p>There&rsquo;s also <a href="https://huggingface.co/jaredpalmer/kev-9b"target="_blank" rel="noopener">Kev-9B</a>, another frozen Qwen 9B with LoRA and a decision head, Apache 2.0, that fits on a 24 GB GPU. Three open implementations in under three weeks say the same thing: typed decision models have become an implementation pattern.</p>
<h2>The Decision Index: how to measure this yourself<span class="hx:absolute hx:-mt-20" id="the-decision-index-how-to-measure-this-yourself"></span>
    <a href="#the-decision-index-how-to-measure-this-yourself" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>All this discussion about &ldquo;who&rsquo;s better&rdquo; only makes sense with a public yardstick, and one exists. The <a href="https://github.com/apolinario/decision-index"target="_blank" rel="noopener">Decision Index</a> is an open suite, unaffiliated with TypeSafe, built for typed decision models: state plus choice or yes-or-no questions, one probability per option.</p>
<p>The current version, 0.2.1, counts 38 benchmarks in five areas (tools and automation, retrieval and classification, knowledge and reasoning, language understanding, human taste), about 120 thousand requests in total, with two rules that matter: the score is chance-corrected (0 is random guessing, 100 is perfect) and an unanswered request counts as wrong. No truncating input, no filtering options, no tuning the prompt per benchmark.</p>
<p>The <a href="https://huggingface.co/spaces/multimodalart/jev-decision-index"target="_blank" rel="noopener">live board</a> has 70 models plus Jev as the reference. I downloaded the board&rsquo;s data file and rebuilt the table; below are the top and the names that appeared in this post. Latency is the median measured by the maintainers on an RTX PRO 6000, one request at a time; Jev&rsquo;s is a hosted API, so it doesn&rsquo;t compare with the others.</p>
<p>&ldquo;Open weights&rdquo; means a checkpoint published on Hugging Face; &ldquo;open code over an open model&rdquo; is a published inference technique on top of an off-the-shelf Qwen or Gemma, without its own checkpoint. The board doesn&rsquo;t record each one&rsquo;s license, so check before using in a product.</p>
<table>
  <thead>
      <tr>
          <th>#</th>
          <th>Model</th>
          <th>Base</th>
          <th>Weights</th>
          <th style="text-align: right">Index 0.2.1</th>
          <th style="text-align: right">Median latency</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>Jev (TypeSafe, jev-1.13.0)</td>
          <td>unpublished</td>
          <td>closed, API only</td>
          <td style="text-align: right">57.91</td>
          <td style="text-align: right">524 ms (API)</td>
      </tr>
      <tr>
          <td>2</td>
          <td>Surogate Rune 26B-A4B v3</td>
          <td>Gemma 4 26B-A4B</td>
          <td>open</td>
          <td style="text-align: right">57.44</td>
          <td style="text-align: right">121 ms</td>
      </tr>
      <tr>
          <td>3</td>
          <td>Decider chat Gemma-4-31B</td>
          <td>Gemma 4 31B</td>
          <td>open code over an open model</td>
          <td style="text-align: right">57.33</td>
          <td style="text-align: right">109 ms</td>
      </tr>
      <tr>
          <td>4</td>
          <td>pplx-decider-v1-27b</td>
          <td>Qwen3.8-27B</td>
          <td>open</td>
          <td style="text-align: right">56.40</td>
          <td style="text-align: right">101 ms</td>
      </tr>
      <tr>
          <td>5</td>
          <td>simple-jev Qwen3.8-27B</td>
          <td>Qwen3.8-27B</td>
          <td>open code over an open model</td>
          <td style="text-align: right">55.74</td>
          <td style="text-align: right">373 ms</td>
      </tr>
      <tr>
          <td>6</td>
          <td>Jebadiah 27B</td>
          <td>Qwen3.8-27B</td>
          <td>open</td>
          <td style="text-align: right">54.67</td>
          <td style="text-align: right">110 ms</td>
      </tr>
      <tr>
          <td>7</td>
          <td>Eikos-27B</td>
          <td>Qwen3.8-27B</td>
          <td>open</td>
          <td style="text-align: right">53.13</td>
          <td style="text-align: right">130 ms</td>
      </tr>
      <tr>
          <td>8</td>
          <td>reflex 27B</td>
          <td>Qwen3.8-27B</td>
          <td>open code over an open model</td>
          <td style="text-align: right">52.16</td>
          <td style="text-align: right">108 ms</td>
      </tr>
      <tr>
          <td>9</td>
          <td>Decider chat Qwen3.6-27B</td>
          <td>Qwen3.6-27B</td>
          <td>open code over an open model</td>
          <td style="text-align: right">51.35</td>
          <td style="text-align: right">84 ms</td>
      </tr>
      <tr>
          <td>10</td>
          <td>Winnow-12B</td>
          <td>Gemma 4 12B</td>
          <td>open</td>
          <td style="text-align: right">50.02</td>
          <td style="text-align: right">73 ms</td>
      </tr>
      <tr>
          <td>19</td>
          <td>Hopper (G) 1.2</td>
          <td>Qwen3.5-4B, LoRA</td>
          <td>open</td>
          <td style="text-align: right">40.77</td>
          <td style="text-align: right">23 ms</td>
      </tr>
      <tr>
          <td>27</td>
          <td>Kev 9B</td>
          <td>Qwen3.5-9B, LoRA</td>
          <td>open</td>
          <td style="text-align: right">38.48</td>
          <td style="text-align: right">51 ms</td>
      </tr>
      <tr>
          <td>55</td>
          <td>Lavoir</td>
          <td>ModernBERT-large</td>
          <td>open</td>
          <td style="text-align: right">8.69</td>
          <td style="text-align: right">20 ms</td>
      </tr>
      <tr>
          <td>57</td>
          <td>CLM-v0.1-8B (Stanford and Nvidia)</td>
          <td>Qwen3-8B</td>
          <td>open</td>
          <td style="text-align: right">7.40</td>
          <td style="text-align: right">47 ms</td>
      </tr>
      <tr>
          <td>61</td>
          <td>Laya</td>
          <td>ModernBERT-large</td>
          <td>open</td>
          <td style="text-align: right">6.04</td>
          <td style="text-align: right">6 ms</td>
      </tr>
  </tbody>
</table>
<p>Three readings come straight off the table:</p>
<ol>
<li>The only closed model on it is Jev. It leads, but by half a point over an open fine-tune of a 26-billion-parameter Gemma 4, and the board treats differences under 0.25 as ties. The top ten are all open models of 12 to 32 billion parameters with an adapter on top, exactly the recipe Clef describes.</li>
<li>The small zero-shot encoder sits at the bottom: Laya at 6, Lavoir at 9. That matches what Laya&rsquo;s README admits and what I said about the classic classifier, which needs labeled examples to shine.</li>
<li>A 4-billion LoRA like Hopper delivers 41 points at 23 milliseconds, a range many real problems don&rsquo;t need to exceed.</li>
</ol>
<p>And how to read Laya at the bottom of the table? The Decision Index measures one thing only: answering, with no extra training, 38 kinds of question the model has never seen, from chess to taxation. That&rsquo;s what a hosted service has to do, because it doesn&rsquo;t know which question is coming. A 400-million-parameter encoder will never win that exam, and Laya doesn&rsquo;t even try: the score of 6 is the base checkpoint, with no fine-tuning at all.</p>
<p>The same model fine-tuned with your examples, on a stable task, shows up at 0.77 on the project&rsquo;s own benchmark. The ranking answers &ldquo;who is the best zero-shot generalist,&rdquo; which is the question of whoever sells an API. The normal programmer&rsquo;s question is a different one: &ldquo;on this repeated decision, with the examples I have, what gets more right at the cost I accept?&rdquo;. For that one, the bottom of the table may be the right answer, and no public board replaces the test on your own data.</p>
<p>So is Laya useless next to the others? As a zero-shot generalist, yes, and the board is right to say so. As a programmer&rsquo;s tool, the math is different. It&rsquo;s the only model on that table that runs on a laptop CPU and answers in 6 milliseconds, with 400 million parameters that fit on any server you already have; Hopper and Kev want a GPU, and Jev wants internet, an API key and a data agreement.</p>
<p>Fine-tuned with your examples, on a taxonomy that doesn&rsquo;t change every week, Laya&rsquo;s own author reports the model beating Jev on some tasks and losing where there are many options, in third-party published tests with different prompts and samples, so indicative rather than controlled. In other words: useless for answering any question about any text, and very useful for answering the same question a thousand times a day, for free, without sending data outside.</p>
<p>Clef isn&rsquo;t on the board: 0.2.1 closed on September 27, and Cloudflare released the model on the 1st. The numbers I showed in the previous section are from an internal Cloudflare run on the same tasks, per benchmark, without the aggregate index. There&rsquo;s also already a vendor claiming to have passed Jev on the same scorer, but for now that&rsquo;s a self-reported number in a blog post, not an entry on the board. Worth waiting for the official inclusion before comparing.</p>
<p>Running it yourself is a day&rsquo;s work, and the kit handles the tedious part:</p>
<ol>
<li><code>pip install -e &quot;.[transformers,rebuild]&quot;</code> and <code>python -m decision_index suite rebuild</code>. The suite isn&rsquo;t redistributed because of licensing, so the kit downloads the sources (about 7 GB, with HLE requiring you to accept the terms on Hugging Face) and rebuilds the files with hashes verified against the lab&rsquo;s.</li>
<li><code>python -m decision_index suite sample --n 100</code> for a quick test, then <code>pipeline --engine http --option base_url=... --option model=...</code> against any server that speaks the <code>POST /v1/systemone</code> format. That covers Jev itself, with the API key, and Laya behind Arbiter. Clef&rsquo;s API is announced as compatible, so in theory it goes in by the same route, but I haven&rsquo;t tested it.</li>
<li><code>score</code> applies the same math as the board, and the maintainers state that it reproduces all 67 entrants of the current edition. Whoever has cloud GPUs runs the whole thing as a single Hugging Face job on an RTX PRO 6000 with <code>hf-job</code>.</li>
</ol>
<p>I didn&rsquo;t run the full suite for this post; the table above is the board&rsquo;s file rebuilt, not a measurement of mine. Two caveats from someone who uses this kind of yardstick: the suite is public and frozen, so it can be trained against, and the board itself says Jev&rsquo;s API output has already changed in 20 choices of the latency sample since the original run, without changing the score. A public benchmark is for discarding weak models and finding candidates. The final decision is still your labeled set, as I explain next.</p>
<h2>How a programmer should think about this<span class="hx:absolute hx:-mt-20" id="how-a-programmer-should-think-about-this"></span>
    <a href="#how-a-programmer-should-think-about-this" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The useful question is no longer &ldquo;is Jev new?&rdquo;. It has become: for a specific, measured decision in your system, which combination of quality, price, latency, privacy, context and maintenance beats what you already have, whether that&rsquo;s a rule, a classifier or an LLM with structured output? No vendor benchmark answers that without your own labeled examples.</p>
<p>A Jev-type tool is useful when the same kind of judgment about text happens many times, the possible actions fit in a list, the surrounding code can apply exact rules, and a wrong answer can be detected or sent to review. That&rsquo;s the shape:</p>
<ul>
<li>ticket triage;</li>
<li>ranking a short list already retrieved;</li>
<li>routing a request to a bigger or smaller model;</li>
<li>flagging an agent trace for human review;</li>
<li>choosing among spans that code or OCR already found.</li>
</ul>
<p>Outside it, the tool is in the wrong place:</p>
<ul>
<li>when the input is image or audio;</li>
<li>when the output needs prose or citations;</li>
<li>when an exact parser already solves it;</li>
<li>when a misclassification grants access or executes a destructive action.</li>
</ul>
<p>I looked at my own portfolio of projects with that yardstick, and the result is a useful bucket of cold water: most need a specialist vision or audio model, deterministic rules or generated text, and have few decisions repeated, costly and ambiguous enough to justify one more model service. A few candidates remain, the clearest being model routing in <a href="/en/2026/03/16/rewrote-openclaw-in-rust-frankclaw/">FrankClaw</a> and short-list ranking in <a href="/en/2026/09/02/ai-memory-2-0-best-memory-system-for-agents-and-teams/">ai-memory</a>. None is a demonstrated bottleneck today. I suspect your portfolio looks similar.</p>
<p>If a bottleneck appears, the pilot is short:</p>
<ol>
<li>Pick a single decision and define the allowed answers, including &ldquo;don&rsquo;t know&rdquo; when that&rsquo;s a real outcome.</li>
<li>Set aside real examples, with easy, ambiguous and adversarial cases, and label them independently. If your product speaks Portuguese, include Portuguese.</li>
<li>Compare what you already have, a simple rule or classifier, Jev pinned to a version, and a cheap LLM with structured output, all with the same input and the same decision policy.</li>
<li>Measure the confusion matrix, calibration by confidence band, cost per correctly handled case, end-to-end latency and review rate. A cheap router that sends hard work to a weak model costs more in total.</li>
<li>Deploy as a reversible feature, with logging, a conservative review route and a fallback. A security or authorization judgment is advisory, unless an exact policy enforces the action independently.</li>
</ol>
<p>What Jev did well was remind the industry that classification exists. That&rsquo;s worth the hype it got, and maybe a bit more.</p>
<p>Neither it nor its open cousins are a silver bullet. They&rsquo;re one more tool, for a specific kind of task, that your code needs to fence in with rules, calibration and review. Whoever was already thinking about classifiers before September gained nothing new; they gained a convenient API. Whoever had never thought about it gained the most valuable part, which is the question: why were you asking a billion-parameter LLM to write a paragraph to tell you which bucket the text falls into?</p>
]]></content:encoded><category>artificial-intelligence</category><category>llms</category><category>software-engineering</category></item></channel></rss>