<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Riley Li</title>
    <description>The latest articles on DEV Community by Riley Li (@datago_8008).</description>
    <link>https://dev.to/datago_8008</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4063686%2F6f072a33-11f2-4c39-8fd2-f947a648c222.png</url>
      <title>DEV Community: Riley Li</title>
      <link>https://dev.to/datago_8008</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/datago_8008"/>
    <language>en</language>
    <item>
      <title>Pick a Free, Paid, or Self-Hosted Agent Seat by the Lease You Can End</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Sun, 11 Oct 2026 21:34:48 +0000</pubDate>
      <link>https://dev.to/datago_8008/pick-a-free-paid-or-self-hosted-agent-seat-by-the-lease-you-can-end-4k8d</link>
      <guid>https://dev.to/datago_8008/pick-a-free-paid-or-self-hosted-agent-seat-by-the-lease-you-can-end-4k8d</guid>
      <description>&lt;p&gt;The right agent seat is the one you can close without losing the only copy of the work. I would rather take a shorter paid lease, or run a box I operate, than keep a free chat I cannot audit. A seat is a temporary grant of model access, context, and side effects, not a teammate you quietly adopt for the week. If you cannot name the exit evidence before the first prompt, you have not chosen a tool yet.&lt;/p&gt;

&lt;p&gt;Recent discussion keeps returning to a plain tension, even when the headlines change from week to week. Model quality can move in a week, while the release path does not automatically move with it. I am not treating any weekly roundup as evidence, because a trending title is only a topic signal. A topic signal is not a measurement I can cite, and it is not a reason to skip the lease card.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start from the exit, not the invoice
&lt;/h2&gt;

&lt;p&gt;Have you ever left a session open because closing it felt like throwing the reasoning away? That small hesitation is how a free hour becomes an unofficial path into the release branch. I now write the ending before I write the prompt, and I keep that ending in the repository rather than in a vendor tab. The invoice matters only after the ending is a file that a reviewer can open without me.&lt;/p&gt;

&lt;p&gt;I have already used other gates for blast radius and review time, so this note does not rebuild those checks. The question here is narrower, and it is easy to dodge when the model feels helpful. Which seat can I actually end today, and which committed file proves that I ended it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Ask four questions before the session exists
&lt;/h2&gt;

&lt;p&gt;I use the same four questions for a bugfix, a documentation edit, and a spike that might be deleted. Each answer is a word or a small integer, because a paragraph of enthusiasm is not a decision. If any answer is mushy, I shrink the task until the answer fits on one line.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What data class may enter the prompt?&lt;/strong&gt; I allow a public sample, internal code that contains no secrets, or a resident class that must stay on hardware I control. When the class is unclear, I stop, and I do not try a redacted version inside the same unbounded chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How many retries is the review time worth?&lt;/strong&gt; I write an integer, usually one to three, and I stop when the counter reaches zero. Another retry without a new failing test is just a slower guess, even when the seat did not charge me.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Which artifact leaves with me?&lt;/strong&gt; I want a diff, a failing test name, or a rejected hypothesis written on the lease card. A transcript that exists only in a browser tab is not an artifact I can hand to someone else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who can say no before the merge?&lt;/strong&gt; If the honest answer is nobody, the seat is wrong for that change, including the seat that costs nothing. A free run can still ship a confident mistake, and the price of the mistake is not on the pricing page.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Would you still sign the diff if the model name were missing from the commit message? If the answer is no, the seat did not finish the job, and another hour will not finish it either.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep a lease card the branch can diff
&lt;/h2&gt;

&lt;p&gt;I store the card beside the task notes, and I commit it when the choice itself needs a trail. The script below is a proposal, not a benchmark I executed for this article, so the printed labels are decisions rather than measurements. It refuses a recommendation when the exit fields are empty, which is the behavior I want on a tired afternoon.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Proposal: label a one-task agent lease. Not a measured benchmark.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Lease&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data_class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;  &lt;span class="c1"&gt;# public | internal | resident
&lt;/span&gt;    &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;artifact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;  &lt;span class="c1"&gt;# diff | test_name | hypothesis
&lt;/span&gt;    &lt;span class="n"&gt;reviewer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;  &lt;span class="c1"&gt;# self | teammate | none
&lt;/span&gt;    &lt;span class="n"&gt;needs_long_context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;can_operate_a_server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;choose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Lease&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewer&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;artifact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stop: no exit evidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;resident&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;can_operate_a_server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self-hosted: you accepted the restart duty&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stop: residency without an operator&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;needs_long_context&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid: continuity is the product you are buying&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free: short lease, keep the artifact, drop the transcript&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;internal&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reviewer&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;teammate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid or free-with-policy: only if current terms allow this data class&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stop: shrink the task or rewrite the card&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lease&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Lease&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;data_class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data_class&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="n"&gt;artifact&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;artifact&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;reviewer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reviewer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;needs_long_context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;needs_long_context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
        &lt;span class="n"&gt;can_operate_a_server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;can_operate_a_server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;choose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lease&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;A public fixture card can live in the issue, and it should be boring enough to review in a minute. I keep secrets out of the sample on purpose, because a teaching card that leaks a token is already a failed lease. If the real task cannot be reduced to this shape, the free row is the wrong row. The JSON is an example of the input, not a log from a session I ran.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data_class"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"retries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"artifact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"diff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reviewer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"needs_long_context"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"can_operate_a_server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Run the label before the first prompt
&lt;/h2&gt;

&lt;p&gt;I hash the prompt and the card together, so a later edit cannot pretend it was the authorized task. These commands stay on my own machine, and they do not call a model provider at all. If the hash changes after I start, I treat that as a new lease rather than as a continuation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 lease_seat.py &amp;lt; lease.json
&lt;span class="nb"&gt;sha256sum &lt;/span&gt;prompt.md lease.json | &lt;span class="nb"&gt;tee &lt;/span&gt;lease.sha256
git diff &lt;span class="nt"&gt;--stat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the script prints &lt;code&gt;stop&lt;/code&gt;, I do not open a session to see what the model might say. Curiosity without an artifact is how the retry counter becomes a suggestion instead of a rule. If the script prints &lt;code&gt;free&lt;/code&gt;, I still copy the diff into the branch, and I keep whatever the card promised to keep. Does a larger context window change the hash I already wrote down beside the lease card?&lt;/p&gt;

&lt;p&gt;The hash does not move when the window grows, and that mismatch is the useful part. The hash records the task I authorized, not the confidence the model expressed after it saw more files. I would rather fail the check in ten seconds than discover the scope creep during review. Have you watched a session helpfully open files that you never placed on the lease card?&lt;/p&gt;

&lt;h2&gt;
  
  
  Work the lease in five steps
&lt;/h2&gt;

&lt;p&gt;I walk these five steps in order, and I do not skip to the model because the card feels obvious. The script is only a reminder, not a boss, but I still run it when I am tempted to improvise. Have you noticed that the improvised path is usually the one that touches one extra file?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I write the four answers on the card before I open any model tab, including a tab that is free.&lt;/li&gt;
&lt;li&gt;I run the proposal script against that card, and I treat a printed stop line as a finished decision.&lt;/li&gt;
&lt;li&gt;I hash the prompt beside the card, and I start only when the label matches the data class.&lt;/li&gt;
&lt;li&gt;I copy the artifact into the branch, and I stop when the retry integer on the card hits zero.&lt;/li&gt;
&lt;li&gt;I add the closing line under the card, and I do not reopen the session to polish a rejected hypothesis.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Read the three seats as fit criteria
&lt;/h2&gt;

&lt;p&gt;Free model access fits a short public or synthetic task when the artifact is a diff or a named test and the retry count stays small. I do not put secrets, production credentials, or an irreversible migration on that seat, even for a minute. What is missing is not a slogan about quality, but a retention and uptime promise I have checked on the current terms page.&lt;/p&gt;

&lt;p&gt;Paid access fits when I am buying continuity, a team audit trail, or a support path I can actually open. The same card still applies, because a larger invoice does not invent a reviewer who was absent at the start. If the current terms forbid my data class, the paid column is a stop, not a quieter upgrade. Why would I pay to repeat a data-class mistake I could have caught on paper?&lt;/p&gt;

&lt;p&gt;Self-hosting fits when the data class is resident, or when prompts and logs must stay on hardware I operate. That fit includes patches, disk, and the hour when the process dies while I am offline. If I cannot name the person who restarts it, I am choosing a hope with extra steps, not self-hosting. The box can be cheaper on paper and still be the most expensive seat if nobody owns the restart.&lt;/p&gt;

&lt;p&gt;I keep these tradeoffs in one table so the argument does not hide inside a paragraph. The cells are fit notes, not scores, and they assume you already answered the four questions. A blank cell means I would stop, rather than pretend that the seat is secretly fine. Can you place your real task into one row without quietly inventing a reviewer for it?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Free seat&lt;/th&gt;
&lt;th&gt;Paid seat&lt;/th&gt;
&lt;th&gt;Self-hosted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Data class&lt;/td&gt;
&lt;td&gt;Public or synthetic sample&lt;/td&gt;
&lt;td&gt;Internal code only if current terms allow it&lt;/td&gt;
&lt;td&gt;Resident data on hardware you operate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Continuity&lt;/td&gt;
&lt;td&gt;One short session, then exit&lt;/td&gt;
&lt;td&gt;Multi-step context you are willing to pay for&lt;/td&gt;
&lt;td&gt;As long as you can keep the process healthy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Exit evidence&lt;/td&gt;
&lt;td&gt;Diff or test name you copy out&lt;/td&gt;
&lt;td&gt;Same evidence, plus a log you are allowed to export&lt;/td&gt;
&lt;td&gt;Logs on disk you already control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retry budget&lt;/td&gt;
&lt;td&gt;One or two, then stop&lt;/td&gt;
&lt;td&gt;The integer on the card, not an open tab&lt;/td&gt;
&lt;td&gt;The same integer, paid in your own time&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Skip when&lt;/td&gt;
&lt;td&gt;Secrets, migrations, or no reviewer&lt;/td&gt;
&lt;td&gt;Terms conflict, or nobody can say no&lt;/td&gt;
&lt;td&gt;No named operator for patches and restarts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Place a free server only where the card already allowed it
&lt;/h2&gt;

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

&lt;p&gt;MonkeyCode shows up in this method only as a candidate for the free row on the card. For this draft I am relying on two availability claims only: free model access, and a free server option. I am not stating a token quota, a hardware shape, a duration, or a comparison score. Those details were not verified for this draft, and product figures like that go stale quickly.&lt;/p&gt;

&lt;p&gt;Before I rely on either claim, I read the current product terms and confirm that my data class is permitted. If the terms are silent or confusing, I leave the card on stop and edit in a local tool I already trust. I would not move a hosted seat into the resident row unless I control the deployment and have checked that path myself. A free server is still a lease with an owner, a log policy, and an end time you should assume can change.&lt;/p&gt;

&lt;p&gt;If you want to rehearse the exit on a throwaway public fixture, a free model seat is enough for that drill. Save the diff, discard the transcript, and ignore the seat when the script told you to stop. I would not use that rehearsal as proof that the seat is safe for internal code. The rehearsal only proves that you can end a session you were willing to throw away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should leave this card on the shelf
&lt;/h2&gt;

&lt;p&gt;Skip this approach when you need a formal threat model, a compliance signature, or a measured comparison of model quality. The script does not score accuracy, latency, or money, and I did not execute it against a live provider while writing this note. Skip it when the change touches credentials, customer data, or a migration you cannot roll back before the day ends. Also skip it if you came for a vendor ranking, because I am not publishing one.&lt;/p&gt;

&lt;p&gt;The limitation I watch most carefully is the false comfort that comes from a tidy label. A printed free line can still hide a sloppy prompt, a flaky test, or a terms page I skimmed too quickly. The card governs my behavior, and it is not a certificate that the model was right. If the label and the diff disagree, which one are you actually planning to trust in review?&lt;/p&gt;

&lt;h2&gt;
  
  
  Close the lease before the day ends
&lt;/h2&gt;

&lt;p&gt;I end the session when the artifact is on the branch, or when the retry counter hits zero, whichever arrives first. Then I add one line under the card saying I kept the diff, or I rejected the hypothesis. That closing line remains useful even if every product name is later deleted from the page. The seat you can end cleanly is the only seat you were really allowed to start.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>python</category>
    </item>
    <item>
      <title>A Review-Hour Gate for Free, Paid, and Local Agent Work</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Sat, 10 Oct 2026 17:57:52 +0000</pubDate>
      <link>https://dev.to/datago_8008/a-review-hour-gate-for-free-paid-and-local-agent-work-33ne</link>
      <guid>https://dev.to/datago_8008/a-review-hour-gate-for-free-paid-and-local-agent-work-33ne</guid>
      <description>&lt;p&gt;I do not choose a free, paid, or self-hosted agent seat by the invoice that arrives later. I choose it by the review hours I can still spend on the diffs that seat will emit. If I cannot read the patch, the cheaper seat is not a bargain, and the expensive seat is not safer. The question I keep asking is simple: whose eyes are actually on this change before it lands?&lt;/p&gt;

&lt;p&gt;A seat is only a place where an agent edits files, runs commands, and talks back to me. The free option, the paid box, and the machine under my desk all fail in different ways when my attention runs out. I want a worksheet I can rerun on a laptop, not a slogan about which vendor feels modern this month. Would I sign the resulting commit after a tired afternoon, or would I rubber-stamp it because the queue already moved on?&lt;/p&gt;

&lt;h2&gt;
  
  
  What this decision is, and what it is not
&lt;/h2&gt;

&lt;p&gt;I am deciding where a bounded agent task may run, and what evidence must come back with it. I am not deciding which model is smartest, because I have not measured that on this repository. I am not deciding a permanent architecture, because availability, quotas, and hardware change without asking me. Can I name the files the agent may touch, and can I name the files it must never open?&lt;/p&gt;

&lt;p&gt;Three seats stay on the table until the sheet says otherwise, and I do not drop one early. A free hosted seat means free model access plus a free server option, when those are currently offered, and nothing more specific. A paid hosted seat means I am buying priority, retention, or a support path I can name in a contract. A self-hosted seat means I already own the runner, the logs, and the failure, including the night it falls over.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. I mention MonkeyCode here because its free model access and free server option are one concrete way to fill the free hosted column. I do not treat that mention as a measurement of quality, uptime, token allowance, or model identity. If a quota, a model name, or a hardware shape matters to you, read the current docs before you plan a sprint around them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fit criteria I refuse to skip
&lt;/h2&gt;

&lt;p&gt;I score each seat against the questions below, and I write the answers in plain text next to the task. What data class sits in the workspace: a public fixture, internal code without secrets, or anything regulated? How many review minutes can I honestly give this task before the week ends and the context fades? Can I export the diff, the test log, and the prompt, and who reruns the job if the seat vanishes?&lt;/p&gt;

&lt;p&gt;A free hosted seat fits a public fixture or a synthetic bug, when losing the session would only cost a rerun. It does not fit when secrets, customer data, or a release branch sit in the same tree as the task. A paid hosted seat fits when I need a named retention window or a support contact, and when review time is already funded. A self-hosted seat fits when the data cannot leave, and when I can actually patch the runner myself.&lt;/p&gt;

&lt;p&gt;Would I still pick the free seat if the docs changed the allowance tomorrow morning without notice? Only if the task is disposable and the evidence already lives on my disk, where a vanished tab cannot take it. Would I pick self-hosted for a one-file typo in a public sample that nobody is waiting on? Probably not, because I would spend the afternoon nursing a runner instead of reading the diff itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  A local gate you can reread
&lt;/h2&gt;

&lt;p&gt;The script below is a proposal, not a benchmark I have executed against a live vendor. It reads a small JSON description of the task and prints which seats remain eligible today. You can change the thresholds, but do not pretend those numbers came from a measured lab. I keep the inputs boring on purpose, so a teammate can argue with a field instead of arguing with a vibe.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Proposal only: gate agent seats by data class and review budget.

Unexecuted example. It does not call a vendor API and it does not
measure model quality. Replace the sample task before you trust it.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data_class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;  &lt;span class="c1"&gt;# public_fixture | internal_code | regulated
&lt;/span&gt;    &lt;span class="n"&gt;review_minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;expected_diff_lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;needs_named_support&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;can_export_locally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;secrets_in_tree&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;eligible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;leaves_blocked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;secrets_in_tree&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;regulated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;leaves_blocked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blocked: data must not leave the machine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blocked: data must not leave the machine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;public_fixture&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;can_export_locally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eligible: disposable work and local evidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;internal_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;can_export_locally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hold: confirm current data terms before use&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blocked: no local export path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;leaves_blocked&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;needs_named_support&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;review_minutes&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eligible: support or a funded review window&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;leaves_blocked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;optional: only if the contract names retention&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;leaves_blocked&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;internal_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eligible: you keep the runner and the logs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expected_diff_lines&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;review_minutes&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;skip: runner care exceeds the diff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;reasons&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;optional: use if you already operate the box&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reasons&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;data_class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data_class&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;review_minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review_minutes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="n"&gt;expected_diff_lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expected_diff_lines&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="n"&gt;needs_named_support&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;needs_named_support&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="n"&gt;can_export_locally&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;can_export_locally&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
        &lt;span class="n"&gt;secrets_in_tree&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secrets_in_tree&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;eligible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;The command below only runs that local script, and it does not call a remote agent or upload the fixture. Swap the JSON for your own notes, and keep secrets out of the file even on your laptop. If you cannot describe the task without pasting a credential, stop and shrink the workspace first. A worksheet that requires a secret in order to run is already telling you the free hosted column is closed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 seat_gate.py &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="sh"&gt;'
{
  "data_class": "public_fixture",
  "review_minutes": 40,
  "expected_diff_lines": 60,
  "needs_named_support": false,
  "can_export_locally": true,
  "secrets_in_tree": false
}
&lt;/span&gt;&lt;span class="no"&gt;JSON
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I feed it a fixture that looks like the work, not like a marketing page I saw this week. A public parser bug with a short guess and half an hour of review should not drag a regulated workspace into the same decision. If the printout says hold, I stop and read the terms, because a script cannot grant a permission that policy never gave. Would I be comfortable pasting that JSON into the ticket where my reviewer can see every field?&lt;/p&gt;

&lt;h2&gt;
  
  
  Steps I follow before I trust a column
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I copy the task into a scratch repository that contains no secrets, no customer dumps, and no production environment files. If I cannot make that copy, the free hosted column is already closed, and I do not negotiate with myself. A missing fixture is a data decision, not a tooling inconvenience I can wave away later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I write the expected diff size in lines, then I reserve review minutes at about one minute per five changed lines. I add fifteen minutes to read the test log, and I raise that guess when the patch touches concurrency or authentication. That ratio is a personal planning habit, not a measured law you should quote as science.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I run the worksheet and I keep every hold or blocked line in the pull request description. A green eligible mark is permission to try a seat, not permission to merge the result. Would I still merge if the reviewer asked me to explain the prompt from memory alone?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I capture evidence on my own disk before I close the session: the diff, the command, and the short prompt. A free server option is useful only when that capture still works after the browser tab dies. I use a local archive so the seat cannot become the only copy of the reasoning.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; handoff &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git diff &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; handoff/agent.diff
&lt;span class="c"&gt;# Replace the echo with the real prompt. Do not paste secrets.&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"prompt: reproduce the public fixture only"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; git status &lt;span class="nt"&gt;--short&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; handoff/notes.txt
&lt;span class="nb"&gt;sha256sum &lt;/span&gt;handoff/agent.diff handoff/notes.txt &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; handoff/SHA256SUMS
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;&lt;p&gt;I compare the three columns only after that archive already exists on my own laptop disk. Free hosted stays in the running when the fixture is public and the archive is complete. Paid hosted stays when I need a support path or a retention promise I can point to in writing. Self-hosted stays when the data class forbids leaving, and when I can operate the box without stealing review time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I rerun the same fixture once on the seat I picked, and once locally from the saved diff, before I talk about speed. If the local rerun fails, the seat did not save me time, because I still cannot explain the change. How many of last week's agent patches could I still rebuild from the notes I actually kept?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tradeoffs I want written down
&lt;/h2&gt;

&lt;p&gt;I keep a short table so the argument does not collapse into a price screenshot from a vendor page. The cells are fit notes, not scores I measured on identical hardware during some quiet week. I will not fill those cells with token counts, GPU names, or uptime percentages I cannot re-check next week. A number I cannot point to in a current primary document is not a decision input for this sheet.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Free hosted&lt;/th&gt;
&lt;th&gt;Paid hosted&lt;/th&gt;
&lt;th&gt;Self-hosted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;May the workspace leave your network?&lt;/td&gt;
&lt;td&gt;Treat as yes until current terms say otherwise&lt;/td&gt;
&lt;td&gt;Treat as yes unless the contract says otherwise&lt;/td&gt;
&lt;td&gt;No, if the runner stays inside your boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What you might be paying with&lt;/td&gt;
&lt;td&gt;Review time, plus a rerun if the session dies&lt;/td&gt;
&lt;td&gt;Money, contract reading, and the same review time&lt;/td&gt;
&lt;td&gt;Review time plus runner maintenance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What a bad day looks like&lt;/td&gt;
&lt;td&gt;Allowance or session changes under you&lt;/td&gt;
&lt;td&gt;The bill grows while your review hours stay fixed&lt;/td&gt;
&lt;td&gt;Box care steals the afternoon you reserved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What you must already hold&lt;/td&gt;
&lt;td&gt;A local archive of diff, command, and prompt&lt;/td&gt;
&lt;td&gt;That archive, plus the clause you relied on&lt;/td&gt;
&lt;td&gt;That archive, plus notes a teammate can boot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If MonkeyCode's free model access or free server option is the free hosted candidate, confirm the live limits before you start. Write those limits into the ticket yourself, with the date you read them, so next week's reader is not guessing. I am not claiming a token grant, a duration, or a hardware shape, because no primary source for those figures was attached here. Would you trust a sprint plan that depended on a number nobody could open in a browser today?&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should walk away
&lt;/h2&gt;

&lt;p&gt;This sheet does not tell you which model writes better patches, and it will not catch a subtle bug because the fixture was public. It assumes you can make a secret-free copy, which is false for plenty of real services that mix config into the tree. It also assumes a human still merges, which is false if your pipeline applies agent output without a reviewer in the loop. Do not use this approach for production credentials, regulated records, or any path where an agent can push alone.&lt;/p&gt;

&lt;p&gt;Do not use a free hosted seat as a silent default for the whole monorepo just because that column looked cheap. Do not use self-hosted as a moral upgrade if nobody on the team can restore the runner after a bad image. Do not use a paid seat to skip the archive step, because a receipt is not a diff you can explain later. I would rather throw away a free exploration than explain a missing prompt three days after the session died.&lt;/p&gt;

&lt;p&gt;If the worksheet marks a public fixture as eligible for a free hosted seat, that is when I open the current MonkeyCode docs. I check whether free model access and the free server option still match the task I wrote down. I keep the same fixture, the same archive commands, and the same refusal rules if I later move that task. The seat can change next week, but the evidence I am willing to merge should not change with the invoice.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>A Parser Contract Before Free Agent Compute Joins the Release Path</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Fri, 09 Oct 2026 14:31:17 +0000</pubDate>
      <link>https://dev.to/datago_8008/a-parser-contract-before-free-agent-compute-joins-the-release-path-2c00</link>
      <guid>https://dev.to/datago_8008/a-parser-contract-before-free-agent-compute-joins-the-release-path-2c00</guid>
      <description>&lt;p&gt;I would not keep free agent compute on a release path until a schema swap drill still passes on a fallback seat. A low invoice does not prove that your parser will survive a seat change next Tuesday. If the saved output drifts, the discount was never the cost that your on-call rotation actually paid. Would you sign the merge when a week-old screenshot is the only evidence you can show?&lt;/p&gt;

&lt;h2&gt;
  
  
  Start from the contract, not the invoice
&lt;/h2&gt;

&lt;p&gt;Hosted agent seats feel easy because the first prompt returns quickly and the setup screen looks generous. The fragile part arrives later, when a review script and a human habit both assume one response shape. A model string can drift, a timeout can move, or a teammate can paste a real ticket into a toy seat. I treat each of those shifts as a contract problem, not as a surprise the vendor owes me to explain.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. The operator supplied two availability claims only: free model access, and a free server option you can try. I am not stating a token quota, a hardware shape, a duration, or a benchmark, because I have not verified those figures. Read the current product documents on the day you decide, and treat this page as a method rather than a price sheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a passing swap actually proves
&lt;/h2&gt;

&lt;p&gt;This drill does not crown a winner among free compute, a paid hosted plan, and a self-hosted stack. It asks whether saved outputs still satisfy one schema when you swap the seat and keep the fixture fixed. A pass means the release parser can survive the swap, while a fail keeps the free seat in a scratch lane. Why would you let a parser exception become the opening slide of your next incident review?&lt;/p&gt;

&lt;p&gt;I am describing a local check on files you already saved, not a live call against a vendor endpoint. I have not executed this checker against a live vendor server, and I am not publishing timings or scores. You should label your own run the same way until a teammate can open the log and repeat it. Would a reviewer trust a pass that exists only in your memory and not in the repository?&lt;/p&gt;

&lt;h2&gt;
  
  
  Fit criteria before any seat touches a branch
&lt;/h2&gt;

&lt;p&gt;The table below is a fit guide, and it is not a ranking that I measured on shared hardware. Use it to decide which questions must be true before a seat may draft, review, or release. The free column stays attractive when the fixture is fake and a second seat already passes the same schema. It stops being attractive when the prompt holds customer text, secrets, or an unattended release gate.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fit question&lt;/th&gt;
&lt;th&gt;Free hosted option&lt;/th&gt;
&lt;th&gt;Paid hosted plan&lt;/th&gt;
&lt;th&gt;Self-hosted stack&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who runs the process?&lt;/td&gt;
&lt;td&gt;The vendor, on terms you re-read&lt;/td&gt;
&lt;td&gt;The vendor, if the plan names a support path&lt;/td&gt;
&lt;td&gt;Your team&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What may enter the prompt under this method?&lt;/td&gt;
&lt;td&gt;Synthetic fixtures only&lt;/td&gt;
&lt;td&gt;Only classes your contract allows&lt;/td&gt;
&lt;td&gt;Only classes your own policy allows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What does a schema pass support?&lt;/td&gt;
&lt;td&gt;A scratch or draft lane&lt;/td&gt;
&lt;td&gt;A review-automation candidate&lt;/td&gt;
&lt;td&gt;A release-path candidate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What does a schema fail imply?&lt;/td&gt;
&lt;td&gt;Stop the experiment&lt;/td&gt;
&lt;td&gt;Change the prompt or the plan&lt;/td&gt;
&lt;td&gt;Patch the stack you operate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;When is this the wrong home?&lt;/td&gt;
&lt;td&gt;Customer data, secrets, or a merge gate&lt;/td&gt;
&lt;td&gt;You need a pin the current plan does not document&lt;/td&gt;
&lt;td&gt;You cannot staff the host&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Paid hosting earns attention when you need a support path you can name in the incident channel. Self-hosting earns attention when you must control the image or keep prompts inside a network you administer. Free hosting earns a scratch lane when both of those needs are absent and the schema still passes. Would you paste a live production token into a seat that you do not administer yourself?&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Freeze a synthetic fixture
&lt;/h2&gt;

&lt;p&gt;Start with a task you can show in a public review without asking anyone for permission. I use a tiny changelog note because it has fields a parser can check and no customer data. If your real job needs private context, do not try the free seat while you are still deciding. Write the forbidden fields down before you write the prompt, or the later table will lie to you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ticket"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CHG-1042"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Add a retry cap to the export worker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"constraints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"no secrets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"synthetic only"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the expected shape small enough that a reviewer can defend every key without a meeting. A short object is easier to compare across seats than a glowing paragraph with no edges. If you cannot name the required keys, you are not ready to compare free and paid compute yet. What would the parser do tomorrow if a friendly sentence replaced the object you promised?&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Capture one file per seat
&lt;/h2&gt;

&lt;p&gt;Run the same fixture on the free seat, and on a paid or self-hosted seat if you operate one. Save the raw model text, then save the parsed object under a file name that names the seat. Do not mix a hand-edited file into the set and then describe that file as a capture. If a seat cannot return JSON, that seat already failed, even when the surrounding prose sounds helpful.&lt;/p&gt;

&lt;p&gt;I am not giving you an endpoint, a model id, or a shell command for any hosted seat. Those values go stale quickly, and a copied command is how tokens leak into shell history. Use the client your operator already approved, and store only the output files next to the fixture. Can you point to the file a second person should open, or only to a chat you cannot share?&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Run the local contract checker
&lt;/h2&gt;

&lt;p&gt;The checker below is a proposal you can run with Python 3.9 or newer and the standard library only. It does not call a network, and it does not pretend to score writing quality or model taste. It asks whether each saved object has the keys, the risk enum, and the note length you promised. Treat a failure as a seat decision, not as a prompt to quietly edit the file until it passes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Local schema swap check. Proposal: not a live product benchmark.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ticket&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;note&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;RISKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;low&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;medium&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;FIXTURE_TICKET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CHG-1042&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: top-level JSON must be an object&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;violations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;REQUIRED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: missing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;risk&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;RISKS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: risk must be one of &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RISKS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;note&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;note&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;note&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;240&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: note length out of range&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ticket&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;FIXTURE_TICKET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: ticket drifted from the fixture&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAIL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pass at least two JSON files&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;problems&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;seats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_obj&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;violations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;need outputs from at least two distinct seats&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FAIL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;problems&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PASS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;seats=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sample object that should pass is short, boring, and tied to the same ticket as the fixture. Run the checker only after you have captures from at least two distinct seats on disk. If you only have the free seat today, compare its file with a golden object your parser already accepts. Say that limitation in the pull request, because a golden file is not a second vendor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ticket"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CHG-1042"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"risk"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"medium"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"note"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Retry cap stays in the worker, with no customer payload attached."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"seat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"free"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 schema_swap.py free.json fallback.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Apply the fit rules in order
&lt;/h2&gt;

&lt;p&gt;I apply four rules in order, and I stop at the first hard no instead of averaging them away. If the fixture is not synthetic, the free seat is out until a written policy allows that data class. If the checker fails on the free output, keep that seat away from any job that merges or pages. If free and one fallback both pass, the free seat may draft and the fallback remains the seat that may merge.&lt;/p&gt;

&lt;p&gt;If you cannot name a person who can repeat the swap from this page, you do not have a strategy yet. A channel name is not an owner, and a shared login is not a handoff you can trust at midnight. Does your current seat meet the rule you actually have, or the rule you wish the vendor had written? I would rather delay the experiment than discover the missing owner during a release freeze.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Leave a decision record in the repo
&lt;/h2&gt;

&lt;p&gt;Leave a short record beside the fixture so the next person does not rerun the argument from memory. A chat transcript is not a decision, and a pricing page is not a runbook your team can execute. If the free schema later fails, the record already says which seat still owns the release path. Would the next reviewer know what you decided if your laptop disappeared after standup today?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;date: 2026-10-09
fixture: CHG-1042 synthetic
free_schema: pass|fail|not_run
fallback_schema: pass|fail|not_run
data_class: synthetic
release_seat: fallback until both passes exist
owner: name a person, not a channel
status: example record, not a completed run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Limitations you should not talk past
&lt;/h2&gt;

&lt;p&gt;This method will not tell you which model writes better prose, and it will not estimate a token bill. I did not measure latency, uptime, or quota, so do not quote this article as evidence of those numbers. A schema pass can still hide a wrong risk label when your enum is too coarse for the change. The checker trusts the files you hand it, so an edited capture can launder a real failure.&lt;/p&gt;

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

&lt;p&gt;Do not use this approach for health data, payment data, credentials, or prompts a customer did not approve. Do not use it when your release process requires a signed service level that a free option does not offer. Skip it if you cannot keep a second seat, because a single seat has nothing to swap against. Also skip it if you wanted a public leaderboard, because this drill is a gate and not a contest.&lt;/p&gt;

&lt;h2&gt;
  
  
  A scratch lane until the fallback exists
&lt;/h2&gt;

&lt;p&gt;I would keep free model access and the free server option in the scratch lane until the checker passes. Promotion to a release path should wait for a fallback you can actually operate without the free seat. If you already have a free MonkeyCode seat, run this drill on a public fixture before the next release branch. The useful question is not whether the seat is free, but whether you can leave it without breaking the parser.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>devops</category>
      <category>testing</category>
    </item>
    <item>
      <title>Score a Free Agent Seat Against Paid and Self-Hosted With a Replay Card</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Thu, 08 Oct 2026 10:17:53 +0000</pubDate>
      <link>https://dev.to/datago_8008/score-a-free-agent-seat-against-paid-and-self-hosted-with-a-replay-card-4dlh</link>
      <guid>https://dev.to/datago_8008/score-a-free-agent-seat-against-paid-and-self-hosted-with-a-replay-card-4dlh</guid>
      <description>&lt;p&gt;I do not choose a free agent seat, a paid box, or a self-hosted runner from a price tag. I freeze one small task on a replay card, then I let that card reject seats. A zero price is not evidence, and a smooth demo is not a plan you can defend later. Would you trust a host that you still cannot replay with the same inputs next Thursday?&lt;/p&gt;

&lt;p&gt;People compare seats by the monthly cost, and only later discover that the real cost was custody. That mistake shows up in planning notes, though this draft claims no measured outage and no customer story. The question is simple, and it is also easy to skip when a banner says free. Can you name the logs, the runtime, and the data class before you click start?&lt;/p&gt;

&lt;h2&gt;
  
  
  Start from the constraint, not the banner
&lt;/h2&gt;

&lt;p&gt;This week's public developer posts keep celebrating how quickly someone can assemble a visible side project alone. I am using that mood only as a warning, not as a source of facts or rankings. Faster drafts make the seat choice sloppier, because the artifact appears before any operating constraint is written. If the assistant can draft the tool tonight, why would the host decision wait until morning?&lt;/p&gt;

&lt;p&gt;I compare three seats, and I refuse to add a fourth until these three are honest. The free hosted seat gives you model access and a server you do not administer, with terms you must re-read. The paid isolated seat rents separation, and it still fails if the contract never mentions retention. The self-hosted seat gives you the pin, and it also gives you patching, backups, and the blame.&lt;/p&gt;

&lt;p&gt;MonkeyCode is one example of that free hosted seat, because free model access and a free server were supplied for this draft. Disclosure: This article was prepared as part of MonkeyCode's product outreach. I am not listing model names, token quotas, hardware, duration, or a promise that the offer stays open. If those details matter to your replay card, read the current project page before you treat the seat as available.&lt;/p&gt;

&lt;p&gt;I also will not label the project open source in this note, because I was not given a repository URL or a license text to cite. A reader who needs that status should open the current project page and read the license there. Treating a missing link as permission is exactly how outdated product claims leak into a published post. Does a decision guide stay honest if it fills those gaps with a memory of yesterday's banner?&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the replay card before you touch a host
&lt;/h2&gt;

&lt;p&gt;A replay card is a tiny record of the task, not a manifesto about agents in general. It names the data class, the replay need, the pin need, and whether shared logs are acceptable. I keep the card next to the fixture file so a later reader can see what was allowed. Does your current note say public fixture, internal code, or secret, in words a stranger could audit?&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the seat trial in six steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Write a local fixture that contains no customer data, no access tokens, and no private repository contents at all.&lt;/li&gt;
&lt;li&gt;Fill the replay card with the strictest data class you can defend, not the class you hope is true.&lt;/li&gt;
&lt;li&gt;Run the scorer below and save the JSON beside the fixture hash before you open any hosted session.&lt;/li&gt;
&lt;li&gt;Use the free hosted seat only when the scorer says stay, and only for the card you just saved.&lt;/li&gt;
&lt;li&gt;Move to a paid isolated seat when the card needs separation but you cannot staff the host this week.&lt;/li&gt;
&lt;li&gt;Choose self-hosting only when the pin is required and the weekly ops time is already on a calendar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A stay result means this card can rehearse on a shared free seat, not that every future task can. A paid result means you are buying isolation or a clearer contract, not a better personality from the model. A self-host result means you accepted patching and backups, so do not pretend that server is free in another costume. Which of those three sentences matches the work you actually have on the calendar this week?&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the tradeoffs in one table
&lt;/h2&gt;

&lt;p&gt;I put the same questions in a table so a review can happen without rereading the whole narrative. The table is a decision aid, and it is not a benchmark, a price list, or a ranking of vendors. Those empty promises are intentional, because I will not invent hardware, quotas, or uptime numbers for this draft. Would a reviewer be able to point at one row and explain the rejection out loud?&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question on the card&lt;/th&gt;
&lt;th&gt;Free hosted&lt;/th&gt;
&lt;th&gt;Paid isolated&lt;/th&gt;
&lt;th&gt;Self-hosted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fixture is public and shared logs are acceptable&lt;/td&gt;
&lt;td&gt;Stay, if you also store a receipt&lt;/td&gt;
&lt;td&gt;Works, often wasteful for a rehearsal&lt;/td&gt;
&lt;td&gt;Works only if ops time already exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context may include a secret or production credential&lt;/td&gt;
&lt;td&gt;Reject&lt;/td&gt;
&lt;td&gt;Reject until retention is written and quoted&lt;/td&gt;
&lt;td&gt;Eligible if you control disk, logs, and access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Runtime must still match next month&lt;/td&gt;
&lt;td&gt;Do not assume a pin&lt;/td&gt;
&lt;td&gt;Buy only after the pin is in the offer&lt;/td&gt;
&lt;td&gt;You can pin it, then you must patch it&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ops time is under two hours each week&lt;/td&gt;
&lt;td&gt;Reasonable for a public card&lt;/td&gt;
&lt;td&gt;Often the calmer path when isolation matters&lt;/td&gt;
&lt;td&gt;Poor fit, because drift becomes the outage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want a model-quality ranking&lt;/td&gt;
&lt;td&gt;This method will not produce one&lt;/td&gt;
&lt;td&gt;A vendor chart is still not your fixture&lt;/td&gt;
&lt;td&gt;Your result is only as honest as the card&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Keep the rules in a file you can diff
&lt;/h2&gt;

&lt;p&gt;The following Python file is an unexecuted example, and it never calls a model or a remote server. I want the rules visible, because a hidden score is just another landing page with extra steps. Change the thresholds if your team defines ops time differently, and keep that change in version control. Are you willing to merge a rule that you cannot explain to a teammate in one minute?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;&lt;span class="s"&gt;Unexecuted example: score one replay card against three agent seats.

This file does not call a model, does not open a network socket, and does not
measure latency or quality. Edit the rules in version control before you trust them.
&lt;/span&gt;&lt;span class="sh"&gt;'''&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReplayCard&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;data_class&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;  &lt;span class="c1"&gt;# public_fixture | internal_code | secret
&lt;/span&gt;    &lt;span class="n"&gt;needs_replay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;needs_pinned_runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;allows_shared_logs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;ops_hours_per_week&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notes_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ReplayCard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
    &lt;span class="n"&gt;seats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paid_isolated&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allows_shared_logs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reject: secrets or private logs are out of scope&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;internal_code&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reject: internal code needs a written retention promise&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fit: public rehearsal only&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;needs_pinned_runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;weak: a free seat does not prove next month pin&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paid_isolated&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;check: quote the pin from the current offer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fit: you can pin the runtime you operate&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paid_isolated&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fit: isolation without owning the host&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;optional: skip unless ops time is already scheduled&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops_hours_per_week&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;needs_pinned_runtime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reject: a pin without ops time becomes drift&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data_class&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops_hours_per_week&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paid_isolated&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hold: do not send secrets until retention is quoted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reject: secret custody needs named ops time&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;needs_replay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;require: store inputs, prompt hash, and raw output&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;choose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rejected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;reject&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hold&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;rejected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;free_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stay_on_free_hosted_for_this_card&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;rejected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;you can pin&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;self_host_if_ops_time_is_real&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;rejected&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paid_isolated&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paid_isolated_until_custody_is_clear&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;narrow_the_card_before_any_seat&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ReplayCard&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;seats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;notes_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;task_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;choice&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;choose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;notes&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;seats&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;sample&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ReplayCard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;task_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fixture-readme-summary&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;data_class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;public_fixture&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;needs_replay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;needs_pinned_runtime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;allows_shared_logs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ops_hours_per_week&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also keep a tiny shell sequence so the receipt has a time and a hash, even when the score is boring. The date command here is UTC, which avoids a local timezone argument during a later review. Do not point the fixture path at a secrets directory just to see what the scorer prints. If the hash changes, the decision you quoted yesterday no longer belongs to the file you have now.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Unexecuted example. Keep fixtures free of secrets before you run this.&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; receipts
&lt;span class="nv"&gt;stamp&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; +%Y%m%dT%H%M%SZ&lt;span class="si"&gt;)&lt;/span&gt;
python3 seat_trial.py | &lt;span class="nb"&gt;tee &lt;/span&gt;receipts/&lt;span class="nv"&gt;$stamp&lt;/span&gt;.json
&lt;span class="nb"&gt;sha256sum &lt;/span&gt;seat_trial.py fixtures/readme-summary.md | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; receipts/manifest.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Apply two cards before you generalize
&lt;/h2&gt;

&lt;p&gt;Suppose the fixture is a short public readme, and the task is to list setup commands without inventing flags. The card says public fixture, replay required, pin not required, shared logs allowed, and one hour of weekly ops time. The scorer should stay on the free hosted seat, and it should still demand a stored prompt hash and raw output. If tomorrow the readme is replaced by an internal design doc, does yesterday's stay result still apply at all?&lt;/p&gt;

&lt;p&gt;Now change only the data class to secret, and leave every other field on the card untouched. The free seat should reject the card, because shared logs and secrets do not belong in the same rehearsal. The sample scorer also holds the paid seat until retention is quoted, and it rejects self-hosting at one weekly hour. Raising ops time does not by itself authorize a secret on a free server, so do not skip that line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fit criteria I will not soften
&lt;/h2&gt;

&lt;p&gt;Stay on the free option when the fixture is public, shared logs are acceptable, and you do not need a pin. Buy a paid isolated seat when separation matters and your ops calendar cannot absorb a private runner this month. Self-host when the pin is the product, and when someone named on the team already owns the patches. If none of those sentences is true, do not start the agent loop until the card is narrower.&lt;/p&gt;

&lt;p&gt;Free hosted compute trades custody for a faster entry, and that trade is sometimes the right one. Paid isolation trades money for someone else's rack, and you still must read retention before sending internal code. Self-hosting trades cash you might have paid a vendor for time you will certainly spend later. Which trade are you actually making, and which trade did the pricing page quietly imply instead?&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations, and who should walk away
&lt;/h2&gt;

&lt;p&gt;This approach will not tell you which model writes better prose, because the script never sees a completion. It will not estimate a bill, because I was not given durable prices, hardware shapes, or quota numbers to cite. It will not survive a card that says secret while someone still pastes a key into the prompt box. If you need a public leaderboard, you need a different experiment, with a published method and a date.&lt;/p&gt;

&lt;p&gt;You should not use the free seat, or this rehearsal as permission, when the prompt can touch production credentials. You should not use it for regulated records, private customer text, or anything a log retention policy would flag. You should not self-host from this note if nobody on the team can patch the box next weekend. Should a solo experiment on a public readme really become the template for a company workflow?&lt;/p&gt;

&lt;p&gt;I ask four questions in a pull request, and I do not accept a screenshot of a chat as an answer. Who can read the logs after the run, and for how long, according to a page you actually linked? What file hash did you score, and does that hash still match the fixture sitting in this branch? If the free offer changes tomorrow, which sentence in the card forces you to stop and re-score?&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the receipt, then pick the seat
&lt;/h2&gt;

&lt;p&gt;I would run the sample card, read the rejection lines, and only then open a hosted session on a public fixture. I would store the receipt in the same repository as the fixture, because a chat scroll is not an audit trail. If the card stays public, try the free model access and free server you are evaluating, and keep the JSON receipt. If the card rejects that seat, the same file has just saved you from a demo you cannot defend later.&lt;/p&gt;

&lt;p&gt;I will revisit this note if a primary page states a quota, a duration, or a hardware shape I can cite without guessing. Until that page exists in your notes, the replay card is the artifact, and the seat is only what the card allows. A free server can be the right classroom for a public fixture, and a poor vault for anything else. Are you choosing a seat for the task you wrote down, or for the task you wish you had?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Pick the Agent Seat by the Commit You Would Sign</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Thu, 08 Oct 2026 07:47:17 +0000</pubDate>
      <link>https://dev.to/datago_8008/pick-the-agent-seat-by-the-commit-you-would-sign-2i41</link>
      <guid>https://dev.to/datago_8008/pick-the-agent-seat-by-the-commit-you-would-sign-2i41</guid>
      <description>&lt;h1&gt;
  
  
  Pick the Agent Seat by the Commit You Would Sign
&lt;/h1&gt;

&lt;p&gt;I do not start with the price tag when I place an agent on a machine today. I start with a harder question: would I sign the commit this run is about to create? If the answer is no, a free shared seat can still be a fair draft bench. If the answer is yes, I want a host whose git identity, license files, and secret boundary I can name before the push.&lt;/p&gt;

&lt;p&gt;That split sounds fussy until a generated patch lands in a public repository with the wrong author line. Have you ever opened a pull request and then noticed the committer email belonged to a shared runner? I treat that moment as a hosting decision, not as a cosmetic git fix after the fact. The seat should match the signature you are actually willing to defend in a public review.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this guide actually decides
&lt;/h2&gt;

&lt;p&gt;This note is a fit guide between seats, not a benchmark and not a vendor price shootout. I am comparing three seats you can actually reason about before you spend a weekend on setup. Those seats are a free shared agent server, a self-hosted box you administer, and a paid isolated runner. The real question is which seat may draft, which seat may commit, and which seat may push.&lt;/p&gt;

&lt;p&gt;You might ask why a commit signature should outrank raw speed on a quiet Tuesday afternoon at all. A fast draft you cannot attribute becomes a real liability the moment it leaves your laptop. A slower draft you can sign, license, and later revert is usually the safer promotion path. Would you rather explain a missing signature in review, or explain a token that rode along in the diff?&lt;/p&gt;

&lt;p&gt;I am not claiming timings, token quotas, hardware sizes, or how long any free offer lasts. Those product facts change quickly, and I have not measured any of them for this particular note. If a dashboard shows a number, read that dashboard, and do not borrow my silence as a measurement. Can you point to a primary page for the exact limit you are about to rely on today?&lt;/p&gt;

&lt;h2&gt;
  
  
  Fit criteria I refuse to skip
&lt;/h2&gt;

&lt;p&gt;I keep the criteria short so I can apply them on a tired afternoon without a spreadsheet. Each one is a yes or no I can check in the repository, not a feeling about a logo. If I cannot answer a criterion, I do not promote that run past a local patch. Would you really promote a branch that you cannot even describe clearly to a waiting teammate today?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Author identity.&lt;/strong&gt; Can I set the git name and email to an identity I control, and can a shared runner not overwrite them later?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Signature path.&lt;/strong&gt; Can I sign with a key that never sits on the shared seat, or am I only pretending the commit is mine?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;License and notice.&lt;/strong&gt; Does the tree already contain the license I must preserve, and can the agent edit be stopped from stripping it?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret boundary.&lt;/strong&gt; Can I prove the diff does not add keys, tokens, or environment files before anything is pushed upstream?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rollback story.&lt;/strong&gt; If the patch is wrong, can I drop the branch without negotiating with a host I do not administer?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A free seat can still win the draft half of this list when I copy the patch home before I commit. It usually loses the signature path, because I should not upload a private key to a machine I do not control. Self-hosted and paid isolated seats win when the push itself must happen on that same machine. Which half of this list is your current agent run actually asking the host to satisfy today?&lt;/p&gt;

&lt;h2&gt;
  
  
  A worksheet you can run locally
&lt;/h2&gt;

&lt;p&gt;The following script is a proposed check, not a log from a run I executed on any host. It inspects the repository you are standing in and prints local git facts you can read as a gate. It does not call the network, and it does not print secret file contents, only matching names. Run it only inside a repository you already trust enough to open on your own machine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Proposed, unexecuted example: seat fit from local git facts.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"1. Identity"&lt;/span&gt;
git config &lt;span class="nt"&gt;--get&lt;/span&gt; user.name &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"MISSING user.name"&lt;/span&gt;
git config &lt;span class="nt"&gt;--get&lt;/span&gt; user.email &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"MISSING user.email"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"2. Signing key configured on THIS machine? (presence only)"&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;git config &lt;span class="nt"&gt;--get&lt;/span&gt; user.signingkey &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"signing key is configured here"&lt;/span&gt;
&lt;span class="k"&gt;else
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"no signing key on this machine"&lt;/span&gt;
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"3. License file"&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; LICENSE LICENSE.md COPYING 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"NO license file found"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"4. Suspicious paths in the unstaged diff (names only)"&lt;/span&gt;
git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;':(exclude)*.lock'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'(^|/)\.env|id_rsa|\.pem|credentials|secret'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"no obvious secret filenames in diff"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"5. Branch state"&lt;/span&gt;
git status &lt;span class="nt"&gt;-sb&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I read that output as a gate, not as a score I can average into a winner. Missing identity means I am not ready to commit the patch on any seat at all. A signing key that exists only on my laptop means the shared server may draft, and the laptop must sign. A secret filename sitting in the diff means I stop, even when the seat looks inexpensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbered path from draft to signed push
&lt;/h2&gt;

&lt;p&gt;I follow the same sequence every single time so that the host choice stays boring and repeatable. You can skip a step only when the answer is already written down beside the branch. If you skip the secret scan because a model usually behaves, you are guessing with a public history. Does your team actually want that kind of guess attached to your name in the public log?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the change on a throwaway branch, and keep the default remote unset until the diff is clean.&lt;/li&gt;
&lt;li&gt;Run the worksheet in the repository root, and save the printed text next to the patch file.&lt;/li&gt;
&lt;li&gt;If identity or a license file is missing, fix that on your own machine before any agent continues.&lt;/li&gt;
&lt;li&gt;If the diff names a secret file, remove the file and rotate the credential before you discuss hosting.&lt;/li&gt;
&lt;li&gt;Choose the seat from the table below, then move the patch only, and leave the signing key at home.&lt;/li&gt;
&lt;li&gt;Sign and push from the machine that holds the key, even when a cheaper seat wrote the draft.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next block is a proposed local sequence for step 6, not a transcript from a hosted run. I keep the push commented until the signature line looks like a commit I would defend. Would you paste a private key into a chat box just to avoid these six lines?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Proposed local sequence on the signing machine. Do not paste a key into a prompt.&lt;/span&gt;
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; draft/agent-seat-check
git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt;
git add &lt;span class="nt"&gt;-p&lt;/span&gt;
git commit &lt;span class="nt"&gt;-S&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Apply the reviewed agent draft"&lt;/span&gt;
git log &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="nt"&gt;--show-signature&lt;/span&gt;
&lt;span class="c"&gt;# Push only after the signature line looks right.&lt;/span&gt;
&lt;span class="c"&gt;# git push -u origin HEAD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How the three seats trade off
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Fit signal&lt;/th&gt;
&lt;th&gt;Free shared agent server&lt;/th&gt;
&lt;th&gt;Self-hosted box&lt;/th&gt;
&lt;th&gt;Paid isolated runner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Draft a patch you will rewrite&lt;/td&gt;
&lt;td&gt;Fits if you copy the patch home&lt;/td&gt;
&lt;td&gt;Fits, often more setup than the draft deserves&lt;/td&gt;
&lt;td&gt;Fits, though you may pay for exploration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit with your identity&lt;/td&gt;
&lt;td&gt;Only if that identity cannot be overwritten&lt;/td&gt;
&lt;td&gt;Fits when you administer the git config&lt;/td&gt;
&lt;td&gt;Fits when the contract lets you set identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sign with your private key&lt;/td&gt;
&lt;td&gt;Poor fit; do not upload the key&lt;/td&gt;
&lt;td&gt;Fits if the key stays on a machine you control&lt;/td&gt;
&lt;td&gt;Fits only if the key never has to be pasted into a prompt&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Touch production secrets or release tokens&lt;/td&gt;
&lt;td&gt;Do not use for this run&lt;/td&gt;
&lt;td&gt;Fits only with an explicit secret store&lt;/td&gt;
&lt;td&gt;Fits only under the same secret-store rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need a named rollback owner&lt;/td&gt;
&lt;td&gt;Weak unless you can export the branch&lt;/td&gt;
&lt;td&gt;Strong, because you own the disk&lt;/td&gt;
&lt;td&gt;Strong if snapshots are actually in the contract&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. The free model access and the free server option are the two availability claims I was given to discuss here. I am not naming models, token quotas, hardware, duration, or benchmark figures, because those were not verified for this draft. If you use that free seat, treat it as the left column: draft there, then carry the patch home before you sign.&lt;/p&gt;

&lt;p&gt;I would read the current MonkeyCode terms only after this table says the free column matches the run in front of me. That quiet reading step is the only invitation I am willing to make anywhere in this note. Confirm the live limits on the product page yourself, because an outreach draft is not a contract and it is not a measurement. Are you choosing a seat you can leave, or a seat you will have to explain later?&lt;/p&gt;

&lt;h2&gt;
  
  
  Tradeoffs I want written down
&lt;/h2&gt;

&lt;p&gt;Free shared compute lowers the cost of a bad draft, and that lower cost is the actual point of it. The tradeoff is weaker custody over base images, log retention, and a workspace you might forget to wipe. Self-hosting flips that tradeoff toward maintenance hours, and toward git config you can actually pin down. A paid isolated runner sits between them when you want separation without becoming the person on call.&lt;/p&gt;

&lt;p&gt;Have you noticed how often a temporary free workspace becomes the place a release script quietly starts to live? I assume that drift will happen unless I schedule the move back home before the branch grows. The worksheet is how I notice the drift before a push, not after a reviewer does. If I cannot export the branch, I was never sitting in a seat I should sign from.&lt;/p&gt;

&lt;p&gt;None of these seats will repair a vague prompt or a repository that still has no tests. They only change who can see the mess, who can retain the logs, and who can put a name on the commit. I still want a failing test on my own machine before I call the patch done. Would a green agent transcript satisfy you if the local test suite had never actually been run?&lt;/p&gt;

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

&lt;p&gt;Do not use this guide when the change already needs production credentials, customer data, or a signed release on the first pass. That work does not belong on a free shared seat, and a filename scan is not a security review. Do not use it when your organization already mandates a specific runner, a hardware security module, or a reviewed signing service. In that case the seat is chosen, and this table would only invent a shadow path around policy.&lt;/p&gt;

&lt;p&gt;Also skip this method when you cannot read the diff yourself before you push the branch. An agent draft you do not understand is not ready for a free seat or a paid one. This check is local and name-level, so it misses secrets pasted into a source file under an innocent name. Pair it with your real secret scanner and with the host's current retention note before you promote the branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I land on the next run
&lt;/h2&gt;

&lt;p&gt;I keep the conclusion in the same place I started, because the price tag will try to sneak back in. If I would not sign the commit, I may draft on the free seat and I leave the key at home. If I would sign it, I move to a self-hosted or paid seat whose identity and rollback I can name out loud. The script is the artifact I re-run, and the table is the argument I am willing to keep.&lt;/p&gt;

</description>
      <category>git</category>
      <category>ai</category>
      <category>devops</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Decide the Agent Seat by the Bundle You Can Carry Out</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Thu, 24 Sep 2026 20:52:09 +0000</pubDate>
      <link>https://dev.to/datago_8008/decide-the-agent-seat-by-the-bundle-you-can-carry-out-1d9f</link>
      <guid>https://dev.to/datago_8008/decide-the-agent-seat-by-the-bundle-you-can-carry-out-1d9f</guid>
      <description>&lt;p&gt;I would not park an agent on a free server until I can carry the whole run away. A friendly login and a warm machine can still hide the files, the tool transcript, and the prompt that produced a bad patch. If I cannot export those three things after one dry run, I treat that host as a sketchpad only. Would you trust a laptop you cannot image, just because the sticker on the lid says free?&lt;/p&gt;

&lt;p&gt;The question I keep returning to is not which invoice looks smaller at the end of this week. I ask who holds the workspace after the process exits, and who can wipe it without sending me a note. A self-hosted box and a paid isolated machine usually answer that with a disk I can still open tomorrow. A shared free server may answer it with a session that disappears when the operator reclaims the seat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Name the bundle before you name the host
&lt;/h2&gt;

&lt;p&gt;An exit bundle is the smallest folder that lets another machine audit my judgment, not the model's personality. I want the prompt file, the tool-call log, the workspace hashes, and a short note about commands I refused. If any of those pieces lives only inside a web console, I do not yet have a bundle I can defend. Have you ever tried to explain a failed agent run from memory alone, a week after the tab was closed?&lt;/p&gt;

&lt;p&gt;I borrowed the instinct from code review, not from a pricing page, because unclear runs waste the same hours as unclear patches. A clean diff can still be a murky story if nobody can see which tool fired and which tool was blocked. Comments in a pull request help a human, but they do not replace a log the agent host actually stored. So I ask a blunt question before I celebrate a demo: could a teammate rebuild this conclusion without my chat scrollback?&lt;/p&gt;

&lt;h2&gt;
  
  
  Three seats, three custody stories
&lt;/h2&gt;

&lt;p&gt;I compare three seats before I fall in love with a signup flow, because the seat decides who can read the files later. The free shared seat is useful when the work is disposable and I can stand to lose the scratch directory. The self-hosted seat is useful when I already own the machine, the user account, and the backup job. The paid isolated seat is useful when I need a vendor boundary, a support path, and a disk I did not build.&lt;/p&gt;

&lt;p&gt;None of those seats is a moral winner, and I do not pretend a receipt proves better judgment. A free seat kept for a spike can quietly become the only home for the notes. That slide is the failure I want this drill to catch, rather than a slogan about hosts. If your notes already live in one browser profile, why would a new agent host be any kinder?&lt;/p&gt;

&lt;h2&gt;
  
  
  Walk five steps on a fixture
&lt;/h2&gt;

&lt;p&gt;These five steps are a proposed workflow, not a report of a finished rollout on a named vendor. I am describing the checks I would run, and I am not claiming I already timed them in production. If a step feels obvious, I still want it written down, because obvious checks are the ones people skip. Have you skipped an export lately just because the diff looked small enough to trust on sight?&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Freeze a tiny fixture
&lt;/h3&gt;

&lt;p&gt;I start with a fixture repo that contains one failing test, one allowed edit path, and one forbidden path. I do not point the agent at a production checkout on the first afternoon, because a missing export would then hide real work. The fixture should fit in a few files so the hash list stays readable in a later review. Can you name the single file this agent is allowed to touch before the run begins?&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Write the refusal list first
&lt;/h3&gt;

&lt;p&gt;I write the tools I will not grant before I write the tools I might grant, because permission drift is how a sketch becomes a release. Network calls, package installs, and secret files stay off unless the task cannot be judged without them. If the free server cannot express that refusal in a file I keep, I do not use it beyond a demo. Would a screenshot of a settings toggle still survive your next incident review without the original account?&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Run once, then pack before the diff
&lt;/h3&gt;

&lt;p&gt;I run the agent once, then I pack the bundle before I read the diff, so curiosity does not delay the export. The pack step hashes the workspace, copies the prompt, and checks that the tool log matches a small schema. If the pack step fails, the host has already told me it is a weak long-term seat. Why would I wait for a prettier second run to learn that the log never left the console?&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Restore on a machine that did not work
&lt;/h3&gt;

&lt;p&gt;I restore the bundle on a second machine that did not perform the run, because a backup you never open is only a story. I check that the hashes match and that a human can see which command was refused. If restore works only while the original server is still up, I do not have custody of the run. Does your export button contain the log, or does it contain only the final patch?&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Score the seat with four hard checks
&lt;/h3&gt;

&lt;p&gt;I score the seat on four yes-or-no checks, and a single no keeps that seat off any path that can merge. The checks are export without the host, restore without the host, refusal list in the bundle, and no secret in the log. A free server that passes all four checks can hold disposable drafts while I keep watching it. A free server that fails any one of them stays a whiteboard, even if the editor feels fast.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the fixture boring enough to hash
&lt;/h2&gt;

&lt;p&gt;I keep the fixture boring on purpose, so a failed hash points at custody rather than at a clever repository layout. The allowed edit lives under src, the failing test lives under tests, and the secrets directory is never mounted. If your agent host cannot exclude a path, write that down as a no before you admire any generated patch. Would you notice a secret read if the only record was a green checkmark in someone else's interface?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fixture-repo/
  README.md
  src/parse.py
  tests/test_parse.py
  secrets/          # forbidden path, never mounted
refusal-list.txt    # network, package_install, read_secret
prompt.md
tool-log.jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following script is a proposal I have not executed against a live vendor for this draft, so treat every path as a local sketch. It assumes you already saved the prompt file, the refusal list, and the tool log beside the fixture repo. If your host will not let you save those files, stop and record that as a failed check. Would you rather discover the missing log in a script, or in a review three days later?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="c"&gt;# Proposal only. Not run against a live host for this draft.&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;./exit-bundle&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;workspace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="p"&gt;./fixture-repo&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/workspace"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;workspace&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/."&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/workspace/"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; ./prompt.md &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/prompt.md"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; ./refusal-list.txt &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/refusal-list.txt"&lt;/span&gt;
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt; ./tool-log.jsonl &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/tool-log.jsonl"&lt;/span&gt;

find &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/workspace"&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-print0&lt;/span&gt; | &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; | xargs &lt;span class="nt"&gt;-0&lt;/span&gt; &lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/workspace.sha256"&lt;/span&gt;
python3 check_bundle.py &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bundle_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Proposal: local schema check. Not a vendor client and not a benchmark.
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;REQUIRED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;args_hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;log_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool-log.jsonl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;refused&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bundle&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refusal-list.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;log_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line_no&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;REQUIRED&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;line &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line_no&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; missing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;refused&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refused&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;line &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;line_no&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; ran a refused tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bundle log passed the local checks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A sample log line I would accept looks like the JSON below, and I would reject a line that omits the status. I hash arguments instead of copying raw values, because a tool log should not become a second copy of your secrets. If the host only offers a pretty timeline in the browser, I transcribe nothing by hand and I fail the seat. Is a manual paste really an export, or is it a memory test with extra steps?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"2026-09-25T12:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"apply_patch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"args_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"sha256:example"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the second machine I only run two commands, because a restore ritual with twenty steps will not happen on a Friday. The hash check tells me the files arrived, and the Python check tells me the log still honors the refusal list. If either command fails, I stop the trial and I do not grant that seat a second, larger repository. How many hosts would you drop this week if a two-command restore was a required screenshot in review?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sha256sum&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt; exit-bundle/workspace.sha256
python3 check_bundle.py exit-bundle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Read the fit table as a gate
&lt;/h2&gt;

&lt;p&gt;I put the same four checks in a table so a reviewer can mark a seat without turning the drill into a debate. The rows are gates, and I do not let a friendly price column appear until the custody rows are filled. Self-hosted is not an automatic pass, because a disk you never restore is just a warmer sketchpad. Paid isolation is not an automatic pass either, unless the export survives after you cancel the session.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Free shared seat&lt;/th&gt;
&lt;th&gt;Self-hosted seat&lt;/th&gt;
&lt;th&gt;Paid isolated seat&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Export without the host process&lt;/td&gt;
&lt;td&gt;Often unknown until you try&lt;/td&gt;
&lt;td&gt;Yes, if you own the disk&lt;/td&gt;
&lt;td&gt;Only if the contract includes an export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restore on a second machine&lt;/td&gt;
&lt;td&gt;Passes only after a real drill&lt;/td&gt;
&lt;td&gt;Passes if backups are real&lt;/td&gt;
&lt;td&gt;Passes if the image is portable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refusal list stored in the bundle&lt;/td&gt;
&lt;td&gt;Weak if toggles are UI-only&lt;/td&gt;
&lt;td&gt;Strong if you keep the file&lt;/td&gt;
&lt;td&gt;Strong if policy is exportable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret leakage in logs&lt;/td&gt;
&lt;td&gt;Your job to prove a no&lt;/td&gt;
&lt;td&gt;Your job to prove a no&lt;/td&gt;
&lt;td&gt;Your job to prove a no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Good fit&lt;/td&gt;
&lt;td&gt;Disposable drafts and spikes&lt;/td&gt;
&lt;td&gt;Teams who already operate the box&lt;/td&gt;
&lt;td&gt;Teams who need a vendor boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Poor fit&lt;/td&gt;
&lt;td&gt;Release branches and secrets&lt;/td&gt;
&lt;td&gt;Teams with no backup habit&lt;/td&gt;
&lt;td&gt;Buyers who never test restore&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I read that table as a gate, not as a score I can average into a comforting total. One failed custody check is enough to keep that seat away from any merge queue I run. Price can break a tie after the checks pass, but it cannot repair a missing log. If two seats both pass, I then ask which one my teammate can operate during my week off.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free hosted project fits
&lt;/h2&gt;

&lt;p&gt;I apply the same gate to hosted projects, including MonkeyCode, instead of granting a pass because the seat is described as free. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The operator describes MonkeyCode as an open-source project that currently offers free model access and a free server option. I am not quoting a token allowance, hardware shape, model list, or end date in this draft.&lt;/p&gt;

&lt;p&gt;This draft was not given a primary page I could cite, so I refuse to invent a quota or a duration. Read the project documentation on the day you decide, and keep only the figures that page still shows. A free model lane can be a fair place to rehearse the fixture while the refusal list still changes hourly. A free server seat can be a fair place to learn whether export is even possible before you trust the seat.&lt;/p&gt;

&lt;p&gt;Neither offer, as described to me, replaces the restore drill or a disk you control for release work. If the current docs confirm a free lane, I would still pack the bundle before that lane sees anything beyond the fixture. A passing fixture on Monday does not promote the seat, because Monday fixtures are supposed to stay disposable. If you review runs by leftover files, try this drill on the free seat you are curious about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits, and who should walk away
&lt;/h2&gt;

&lt;p&gt;This drill does not measure model quality, latency, or cost per accepted patch, so a green restore is not wisdom. I have not timed the script, I have not compared vendors, and I will not invent numbers to finish the table. The schema is intentionally small, and a real team may need identity, revision, and approval fields. If your auditor needs those fields, extend the check before you trust a passing printout from the script.&lt;/p&gt;

&lt;p&gt;You should not use a shared free seat for regulated data, customer repositories, or a workspace that must stay on a named network. You should not use this approach if you cannot spare a second machine, because an unopened bundle is not custody. You should also skip it when your real question is which model writes better prose, since this gate never answers that. I would rather fail a convenient seat on Tuesday than explain a vanished log to the team on Friday.&lt;/p&gt;

&lt;p&gt;What I want from the next host I try is a folder I can hash and a refusal list I can diff. I also want a restore that does not beg the original server to stay online after I close the tab. If a free option gives me that folder, I will use it for drafts without pretending it is a permanent home. If it does not, I will pay for or assemble the seat that does, and I will keep the fixture as the receipt.&lt;/p&gt;

&lt;p&gt;So which seat are you actually able to leave tonight, with the log in your hand rather than in a tab? If the answer is none of them, the honest next hour is the fixture, not another signup. I would rather spend that hour packing a boring bundle than arguing about a host I cannot exit. Does that sound slow, or does it sound like the first review you would want after a bad patch lands?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>testing</category>
    </item>
    <item>
      <title>Split Agent Work Into a Drafting Room and a Release Switch</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Wed, 23 Sep 2026 16:56:41 +0000</pubDate>
      <link>https://dev.to/datago_8008/split-agent-work-into-a-drafting-room-and-a-release-switch-40p9</link>
      <guid>https://dev.to/datago_8008/split-agent-work-into-a-drafting-room-and-a-release-switch-40p9</guid>
      <description>&lt;p&gt;Free agent compute should host planning work, not irreversible tool calls you cannot rewind. I split every agent loop into a plan lane and an act lane before I pick a host. That split is more honest than asking whether a shared box looks idle tonight. If a step can send money, rewrite production, or leak a secret, it does not belong on a free shared host.&lt;/p&gt;

&lt;h2&gt;
  
  
  A single host is usually the wrong question
&lt;/h2&gt;

&lt;p&gt;Have you noticed how agent demos collapse planning, retrieval, and mutation into one cheerful chat transcript? That collapse hides the only question that still matters when the compute is free and shared. Who else can see the context window while your agent is still thinking out loud? A planning lane can tolerate noisy neighbors; an acting lane cannot, because side effects do not wait for a retry.&lt;/p&gt;

&lt;p&gt;I treat the host decision as a routing problem, not as a shopping problem with a single winner. Free model access plus a free server can be the right lane for drafts, retrieval summaries, and rejected plans. Self-hosted or paid isolated compute is the right lane once a tool would change a system I cannot rewind. Mixing those lanes because the chat UI looks unified is how accidental writes sneak into a shared box.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Label every tool as plan, act, or forbidden
&lt;/h2&gt;

&lt;p&gt;Start with the tool list, not with the vendor comparison table you were about to open. I ask one blunt question per tool: after this call, can a human undo the world with a git revert? If the honest answer is no, the tool belongs in act or forbidden, and never in plan. Plan tools read tickets, search docs, draft patches, and explain diffs without touching credentials that can mutate state.&lt;/p&gt;

&lt;p&gt;Here is a proposed classifier I keep next to the agent config, not a production benchmark.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# proposed_example: plan_act_label.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;PLAN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;ACT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;act&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;FORBIDDEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;forbidden&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;UNDOABLE_PREFIXES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;read_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;draft_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;explain_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lint_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ACT_PREFIXES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apply_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deploy_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pay_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;delete_&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;FORBIDDEN_SUBSTRINGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod_admin&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rotate_secret&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wire_transfer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;label_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;lowered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lowered&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;FORBIDDEN_SUBSTRINGS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FORBIDDEN&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lowered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ACT_PREFIXES&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ACT&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lowered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UNDOABLE_PREFIXES&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PLAN&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ACT&lt;/span&gt;  &lt;span class="c1"&gt;# unknown tools default to isolated compute
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Would you really let an unknown tool inherit the free lane because the name sounded polite? I default unknown names to act so a free host never receives a surprise mutation from a cute alias. That default is conservative on purpose, and it is supposed to feel slightly annoying during review. A slightly annoying router is cheaper than an irreversible write that landed on the wrong host.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Write a host contract the plan lane must pass
&lt;/h2&gt;

&lt;p&gt;A host contract is a tiny file the router can evaluate before any prompt is sent. I care about isolation promises, log retention, and whether tool execution is even enabled on that host. I do not care about marketing adjectives on a pricing page, because adjectives do not block a write. If a host cannot satisfy the plan contract, I do not send it drafts just to save a few tokens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# proposed_example: host_contract.yaml&lt;/span&gt;
&lt;span class="na"&gt;plan_lane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allow_tool_execution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;allow_secret_injection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="na"&gt;max_untrusted_neighbors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown-ok"&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;draft_only"&lt;/span&gt;
&lt;span class="na"&gt;act_lane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allow_tool_execution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;allow_secret_injection&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;max_untrusted_neighbors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mutates_with_receipt"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. When I need a plan lane, I send drafts through MonkeyCode for free model access and a free server. I still move labeled act work onto a host I isolate, because a free shared server should not hold production credentials. If you are mapping a plan lane this week, that free-model and free-server path is one drafting room you can try.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Keep act on a box you can isolate
&lt;/h2&gt;

&lt;p&gt;The act lane needs a network policy you can describe in one paragraph without waving your hands. Can you name the outbound allowlist, the identity the tools assume, and the disk that stores receipts? If you cannot name those three, you do not have an act host yet, only a hope. Free shared compute almost never answers those three questions with the precision an irreversible tool deserves.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# proposed_example: act-host-smoke.sh&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail
&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;ACT_HOST&lt;/span&gt;:?set&lt;span class="p"&gt; ACT_HOST to an isolated box&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
ssh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ACT_HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'test ! -w /etc/prod-creds || exit 1'&lt;/span&gt;
ssh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ACT_HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'iptables -S | grep -q "policy DROP" || echo "WARN: no default drop"'&lt;/span&gt;
ssh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ACT_HOST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'test -d /var/agent-receipts'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I run that smoke check before the first act tool is enabled, not after a scary demo. Does your current free box even let you SSH in and inspect a default-drop firewall? If the answer is no, it can still be a fine plan lane, and it should stay that way. I would rather lose convenience than pretend a closed platform is an isolated act host.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Gate the handoff with a signed plan receipt
&lt;/h2&gt;

&lt;p&gt;The dangerous moment is the handoff between lanes, not the first token of the draft. I refuse to stream a plan into an act tool without a receipt for tools, host, and a human decision. That receipt is boring on purpose, because boring gates survive when the chat UI wants to feel magical. Have you ever tried to reconstruct an agent write from a screenshot of a streaming token?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# proposed_example: handoff_receipt.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_receipt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;allowed_act_tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;decided_by&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plan_sha256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan_text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allowed_act_tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allowed_act_tools&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decided_by&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decided_by&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decided_at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lane&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;act&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;assert_handoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requested_tool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;requested_tool&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;receipt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allowed_act_tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;requested_tool&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; is not on the signed plan&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I keep the receipt next to the patch, not inside a screenshot of the model conversation. Can a teammate replay the decision without watching you scroll through a long chat? If they cannot, the handoff is still a vibe, not a gate you can audit later.&lt;/p&gt;

&lt;h2&gt;
  
  
  A walkthrough with a hypothetical ticket
&lt;/h2&gt;

&lt;p&gt;Take a hypothetical ticket that asks the agent to draft a changelog and then tag a release. Reading the issue and drafting the changelog are plan work, because a human can still throw the draft away. Tagging the release is act work, because git tag -a followed by a push is not a polite suggestion. Would you run that tag command on a free shared host just because the draft looked good in the same thread?&lt;/p&gt;

&lt;p&gt;I dry-run the labels on my laptop before anyone enables network credentials on the act host. The commands below are a proposed checklist, not evidence from a production incident. If draft_changelog does not land in plan, I stop and rename tools until the classifier agrees. If tag_release lands in plan, I treat the classifier as broken and I refuse the free host.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# proposed_example: dry-run the split&lt;/span&gt;
python - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;PY&lt;/span&gt;&lt;span class="sh"&gt;'
from plan_act_label import label_tool
print("draft_changelog", label_tool("draft_changelog"))
print("tag_release", label_tool("deploy_tag_release"))
print("do_the_needful", label_tool("do_the_needful"))
&lt;/span&gt;&lt;span class="no"&gt;PY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  A comparison table I actually fill in
&lt;/h2&gt;

&lt;p&gt;I score a candidate against the lanes, not against a vague sense that free is cheaper. Fill the table per agent, not once per company, because a docs bot and a deploy bot do not share a lane. A comparison that cannot tell those bots apart will push mutating tools onto the drafting room again. I would rather maintain two boring configs than one clever host that does both jobs poorly.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Prefer free shared plan lane&lt;/th&gt;
&lt;th&gt;Prefer self-hosted or paid act lane&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Does the step only draft or explain?&lt;/td&gt;
&lt;td&gt;Yes, keep it here&lt;/td&gt;
&lt;td&gt;Wasteful unless you already have spare isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can a neighbor read the prompt?&lt;/td&gt;
&lt;td&gt;Acceptable for public docs&lt;/td&gt;
&lt;td&gt;Unacceptable for customer data or secrets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Is the tool undoable with git?&lt;/td&gt;
&lt;td&gt;Drafts only&lt;/td&gt;
&lt;td&gt;Required once apply or deploy is in play&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Do you need an outbound allowlist?&lt;/td&gt;
&lt;td&gt;Usually cannot prove one&lt;/td&gt;
&lt;td&gt;Required before the first mutating call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Will a queue delay break money movement?&lt;/td&gt;
&lt;td&gt;Fine for planning&lt;/td&gt;
&lt;td&gt;Not fine for act work with deadlines&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Is that more ceremony than a weekend demo wants, especially when the chat already feels complete? Yes, that extra ceremony is the entire point of treating compute choice as a routing guide. The table is a filter for the next tool, not a trophy for the host you already liked.&lt;/p&gt;

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

&lt;p&gt;This split is a workflow, not a certification, and it will not save a leaked token already sitting in the prompt. I still assume the plan lane may be logged, sampled, or reused by a platform I do not control. If your planning context includes customer payloads, treat even the plan lane as isolated, and ignore the free option entirely. Shared drafts are a convenience feature, not a data-processing addendum you can wave at a customer.&lt;/p&gt;

&lt;p&gt;Do not use this approach when a regulator expects a single audited runtime for every token. Do not use it when the agent must act inside one tightly timed transaction with no human receipt. Do not use it when you cannot name an isolated act host, because then you are only drawing lanes on a whiteboard. Teams that ship autonomous production changes without a reject path should not park anything on shared free compute.&lt;/p&gt;

&lt;p&gt;The tests below are proposed guards for the classifier, not a vendor evaluation harness. They will not prove a platform is safe; they only prove your names still match your routing rules. Run them locally after you drop the classifier beside the agent config you actually ship.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# proposed_example: test_plan_act_label.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;plan_act_label&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label_tool&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_draft_stays_on_plan_lane&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;label_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;draft_release_notes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PLAN&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_deploy_is_never_free_lane&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;label_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deploy_canary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ACT&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_unknown_defaults_to_act&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;label_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;do_the_needful&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ACT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run them with python -m pytest test_plan_act_label.py -q after the files sit together in one directory. A failing unknown-tool test is a gift, because it blocks a cute alias from inheriting the free lane. That is a small proof, and small proofs are what keep a free plan lane from quietly becoming an act lane.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I refuse to optimize
&lt;/h2&gt;

&lt;p&gt;I refuse to pick a host because leftover capacity looked friendly on a dashboard this morning. Capacity is not a lane, and a free server is not a personality test for your agent. The useful question is whether the next tool is still a draft, or whether it already needs a receipt. If you keep answering that question, the free versus paid debate gets quieter, and the routing file gets shorter.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Compare Free Agent Compute to a Paid Box With a Weighted Tradeoff Sheet</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Tue, 22 Sep 2026 15:13:55 +0000</pubDate>
      <link>https://dev.to/datago_8008/compare-free-agent-compute-to-a-paid-box-with-a-weighted-tradeoff-sheet-4f28</link>
      <guid>https://dev.to/datago_8008/compare-free-agent-compute-to-a-paid-box-with-a-weighted-tradeoff-sheet-4f28</guid>
      <description>&lt;p&gt;Free agent compute stays the right default only while idle cost hurts more than contention and data gravity. I refuse to pick a runtime because a landing page called the model or the box free. I wait until five written tradeoffs flip, because a sticker never describes the loop I actually run. Would you rather pay for a quiet machine that sits idle, or borrow a busy one you cannot fully explain?&lt;/p&gt;

&lt;h2&gt;
  
  
  Price is not a comparator
&lt;/h2&gt;

&lt;p&gt;Most teams compare a free shared runtime with a paid or self-hosted box as if both were the same product. They are not, and the mix-up shows up the first time a tool call waits on somebody else's retry storm. One option taxes you with queues, noisy neighbors, and a control plane you do not own. The other taxes you with idle capacity, patching, and a bill that continues when nobody is prompting.&lt;/p&gt;

&lt;p&gt;I keep a five-row sheet beside the agent repo instead of a vibe about vendor kindness. Each row is a tradeoff I can probe with a command, not a feeling. Why would a twelve-factor matrix help if nobody updates it after the first demo?&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifact: the five-row tradeoff sheet
&lt;/h2&gt;

&lt;p&gt;Copy this file into the repo and refuse to choose compute until every row has a number. I treat missing scores as permission only for throwaway prompts, never for anything that touches secrets. The direction is simple: a low weighted leave-free average means the free column still fits this week.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tradeoff_sheet.yaml&lt;/span&gt;
&lt;span class="c1"&gt;# Proposal / unexecuted template. Fill before picking free shared compute&lt;/span&gt;
&lt;span class="c1"&gt;# or a paid / self-hosted box.&lt;/span&gt;
&lt;span class="c1"&gt;# score_free_better: 1-5, where 5 means free/shared clearly wins this row.&lt;/span&gt;
&lt;span class="c1"&gt;# The scorer inverts that into a "leave free" average.&lt;/span&gt;

&lt;span class="na"&gt;schema_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;example-triage-bot"&lt;/span&gt;
&lt;span class="na"&gt;rows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;idle_vs_contention&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Does&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;idle&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;spend&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hurt&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;more&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;than&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;queue&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;delay&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;this&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;week?"&lt;/span&gt;
    &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;score_free_better&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;credential_locality&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Must&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;secrets&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;stay&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;network&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;you&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;route?"&lt;/span&gt;
    &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
    &lt;span class="na"&gt;score_free_better&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;scheduler_explainability&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Can&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;you&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;explain&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;slow&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;without&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;vendor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;timeline?"&lt;/span&gt;
    &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;score_free_better&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tool_roundtrip&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Does&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tool&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;hop&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dominate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;realistic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;path?"&lt;/span&gt;
    &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;score_free_better&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;promotion_cost&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;expensive&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;moving&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;this&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;later&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;if&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;free&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lane&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;changes?"&lt;/span&gt;
    &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;score_free_better&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
    &lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A weighted total near the free side is not a moral victory for the cheaper lane. It is a temporary fit that I re-score when tools, secrets, or concurrency change. Do you re-score when the agent gains a write tool, or only when the invoice arrives?&lt;/p&gt;

&lt;h2&gt;
  
  
  Fill the sheet with probes, not opinions
&lt;/h2&gt;

&lt;p&gt;I do not type a five because the runtime felt snappy during lunch on a quiet network. I run a small probe that records the parts of the loop I can observe from my laptop. The script below is a proposal, not a benchmark from a production fleet, and it will not prove a vendor. If you cannot freeze the prompt, you are not comparing compute, you are comparing moods.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Record idle versus contention on a realistic path
&lt;/h3&gt;

&lt;p&gt;Start with one frozen prompt, one frozen tool stub, and three sequential runs rather than a heroic load test. A realistic agent path is closer to a few slow tool hops than to an HTTP flood against health checks. API-style flood tests still matter for gateways, but they hide the wait your agent actually feels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# probe_loop.py
# Proposal: local comparison harness, not a published benchmark.
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;

&lt;span class="n"&gt;PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize ticket 1842&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;timed_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content-type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;t0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_shared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8080/v1/chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:8081/v1/chat&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;samples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;timed_post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PROMPT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;samples&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;samples&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point those URLs at a local stub first so the harness fails on your desk, not in a shared queue. If the free lane is remote, I still run the same payload so the comparison stays about the loop. Three samples will not settle a capacity argument, and that restraint is the point of the sheet.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Ask where credentials actually live
&lt;/h3&gt;

&lt;p&gt;If the agent must mint a short-lived cloud token, I do not send that minting step to a shared box I do not route. Credential locality is a veto, not a score I average away with friendlier rows on the sheet. Can a free server hold the prompt while the tool stays on a host I already own? That split is allowed, and it is often the only honest architecture for a first pass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Proposal: prove the tool host, not the marketing diagram.&lt;/span&gt;
curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-D&lt;/span&gt; - http://127.0.0.1:9090/tool/whoami &lt;span class="nt"&gt;-o&lt;/span&gt; /tmp/whoami.json
python &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"import json; print(json.load(open('/tmp/whoami.json')))"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read the response as a placement proof, because a missing network identity is already a locality failure. I will not average that failure with a pretty latency number from a toy prompt. If &lt;code&gt;whoami&lt;/code&gt; cannot name the network, the free column should not receive the tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Demand an explainable slow run
&lt;/h3&gt;

&lt;p&gt;I keep the request id, the tool names, and wall-clock per hop in a local file that I control. If a free runtime cannot give me those three fields, the explainability row moves against free immediately. How would you debug a stuck loop if the only timeline lives in someone else's UI?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Proposal: local hop log. Replace the pipeline with your tracer later.&lt;/span&gt;
&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ./runs
python probe_loop.py | &lt;span class="nb"&gt;tee&lt;/span&gt; &lt;span class="s2"&gt;"./runs/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;date&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt; +%Y%m%dT%H%M%SZ&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.json"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit the hop log format even if you change vendors later, because portable traces are part of promotion cost. I want the same JSON keys on both columns of the comparison so a later move stays boring. That habit is cheaper than rewriting dashboards after the free lane stops fitting.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Separate model time from tool round-trip
&lt;/h3&gt;

&lt;p&gt;Teams still treat "the model was slow" as one number, and that habit hides the real tax. I split the trace, because a remote model plus a local tool can lose to a smaller model beside the data. Does cheaper access help if every tool hop crosses a public path you cannot pin? If the tool time dominates, I colocate tools with data first and only then reopen the model question.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Price the later move, not the first weekend
&lt;/h3&gt;

&lt;p&gt;Promotion cost is the row people skip because the first weekend felt easy on a free endpoint. If swapping the endpoint later means rewriting tool adapters, the free lane is a trap even when it scores well today. I want the agent to take a base URL and a key from the environment, and nothing more clever than that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config.py — proposal for a portable agent entrypoint
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AGENT_BASE_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;api_key&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AGENT_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout_s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AGENT_TIMEOUT_S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;60&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that function already needs vendor-specific headers for basic chat, the promotion row should not be a one. Portability is a property of the client, not a promise I wait to hear from a pricing page. Would you rebuild the adapter on a deadline, or would you rather have paid that cost in the first commit?&lt;/p&gt;

&lt;h2&gt;
  
  
  Score it like a decision, not a vibe
&lt;/h2&gt;

&lt;p&gt;I convert the yaml into a weighted total with this tiny script so the argument stays numeric and small. Treat the output as a conversation starter for the team, not as a scientific ranking of vendors. The threshold is a team agreement, and I label it as a proposal rather than a law.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# score_sheet.py
# Proposal: weighted helper for tradeoff_sheet.yaml
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;

&lt;span class="n"&gt;FREE_THRESHOLD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.2&lt;/span&gt;  &lt;span class="c1"&gt;# below: free/shared still fits; above: prefer paid/isolated
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safe_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;weighted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score_free_better&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="n"&gt;leave_free&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;weighted&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;leave_free&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weight&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;weights&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weight&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unscored rows: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;missing&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;avg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weighted&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;weights&lt;/span&gt;
    &lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stay_free_shared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;avg&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;FREE_THRESHOLD&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prefer_paid_or_owned&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;leave_free_avg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the scorer only after every row is filled, because missing values are how a guess becomes a fake number. A default of three is how teams launder opinions into something that looks like evidence. If the decision says stay free, I still keep the portable entrypoint so a later flip stays boring. If it says leave, I move tools first and the model second, because data gravity rarely follows a DNS change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;pyyaml
python score_sheet.py tradeoff_sheet.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Are you moving the model because it is fashionable this month, or because the five rows actually flipped on paper? I re-run the scorer when a write tool appears, not when a blog post declares a new default. Fashion is not a row on the sheet, and I refuse to add it just to feel current.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free model and free server lane fits
&lt;/h2&gt;

&lt;p&gt;I needed a concrete free-side target while writing the sheet, not a slogan about unlimited capacity. A comparison against an imaginary endpoint teaches nothing about credential locality or hop logs you can keep. The free column has to be a real URL I can put behind the same client config.&lt;/p&gt;

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

&lt;p&gt;MonkeyCode offers free model access and a free server option, which can stand up the free column without a box on day one. I do not treat that lane as a quota, a hardware spec, or a forever plan, because those claims do not belong here. I treat it as one endpoint I can put behind &lt;code&gt;AGENT_BASE_URL&lt;/code&gt; while the five rows are still scoring toward free.&lt;/p&gt;

&lt;p&gt;That is the whole product role in this workflow, and I will not stretch it into a capacity story. The sheet still decides, and the portable entrypoint still matters more than the brand on the box. If credential locality or scheduler explainability fails, I keep the tools on a host I route.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the sheet says no
&lt;/h2&gt;

&lt;p&gt;Skip this approach if the agent can write to production data, mint long-lived credentials, or handle regulated records you cannot put on shared compute. Skip it if you cannot freeze a prompt and a tool stub long enough to compare two endpoints honestly. Skip it if your org already owns quiet capacity beside the tools, because then the idle tax is already paid.&lt;/p&gt;

&lt;p&gt;The probes above are local and unlabeled as fleet evidence on purpose, not because I forgot to add charts. They will not certify a vendor, win an argument about tokens, or replace an eval you can replay later. They exist so the free-versus-paid choice stops being a screenshot of a pricing table.&lt;/p&gt;

&lt;p&gt;Would I run a customer-facing agent on the free column after a single green lunchtime probe? I would not, and the written sheet is how I keep that answer boring on purpose. I re-score the five rows the moment the agent gains a write tool, and I move before the first incident rather than after it.&lt;/p&gt;

&lt;p&gt;If you need a free-model and free-server endpoint to drop into &lt;code&gt;AGENT_BASE_URL&lt;/code&gt; while you fill the yaml, MonkeyCode can be that free column. Keep the sheet in the repo either way, because the tradeoff sheet should outlive whichever endpoint you try first. I would rather you copy the yaml into git than copy a vendor diagram into a slide.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>testing</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Inventory What You Cannot Pin Before You Choose Free Agent Compute</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Mon, 21 Sep 2026 13:29:47 +0000</pubDate>
      <link>https://dev.to/datago_8008/inventory-what-you-cannot-pin-before-you-choose-free-agent-compute-3job</link>
      <guid>https://dev.to/datago_8008/inventory-what-you-cannot-pin-before-you-choose-free-agent-compute-3job</guid>
      <description>&lt;p&gt;Free shared compute is a good lab bench when overnight drift is cheap to absorb. A pinned box is the better home when next Tuesday's agent run must still match today's trace. I start from that split each time, rather than from a price tag or an idle GPU. Can you name every moving part this agent will still need next week?&lt;/p&gt;

&lt;p&gt;A host chosen from an empty queue often fails when a credential, a model identity, or a disk layout moves. I do not treat "is free cheaper than a box I run" as the real question sitting in front of the loop. I ask which parts of the agent loop refuse to be pinned at all, then I choose a host. That question also decides when a slick Friday demo is still only a lab accident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overnight drift is the decision, not the invoice
&lt;/h2&gt;

&lt;p&gt;Agent loops are not single HTTP handlers sitting behind a frozen OpenAPI contract you can file away. They stitch a model, a tool surface, a secret boundary, a timeout owner, and a trace sink together in one session. If any of those pieces floats overnight, Friday's success story is a mood rather than evidence you can hand a reviewer. Have you tried replaying last week's failing tool call without guessing the model snapshot that answered?&lt;/p&gt;

&lt;p&gt;I use a drift inventory because a cost model lies when the environment itself is the moving target under the agent. Free shared capacity can still be the right first room while the tool surface is changing twice a day. It becomes the wrong room when a reviewer needs a reconstructable failure and was never in the original chat. This whole article is a proposed workflow, not a production study with logos or latency medals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build the inventory before you request a host
&lt;/h2&gt;

&lt;p&gt;I write seven fields down before I decide where the loop is allowed to run at all. Each field is pinned, exportable, or floating, and I refuse to mix those three words casually in a standup. Floating is allowed during exploration, and I say that out loud so nobody promotes a mood into a release. Floating is not allowed after a run is treated as a decision record that other people must trust.&lt;/p&gt;

&lt;h3&gt;
  
  
  The seven fields
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Model identity.&lt;/strong&gt; I ask whether I can name a pin, or whether I am taking whatever answers today.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtime and dependencies.&lt;/strong&gt; I ask whether the same tool runner and lockfile can be reinstalled without folklore.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool origin.&lt;/strong&gt; I ask whether tool calls execute on a network I can describe to another engineer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret boundary.&lt;/strong&gt; I ask whether API keys ever enter a host that I cannot image or wipe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filesystem.&lt;/strong&gt; I ask whether working trees, caches, and scratch files are objects I can snapshot later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout and retry owner.&lt;/strong&gt; I ask who declares a hung tool dead, me or a shared scheduler.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace export.&lt;/strong&gt; I ask whether I leave with JSONL traces and prompts, or only a dashboard screenshot.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If four or more fields are floating, I stay on a free lab bench and I refuse promotion. If four or more fields must be pinned, I want a box I operate or paid isolation I can describe. Mixed scores mean a two-stage path: explore while floating is cheap, then promote only the pinned slice. Does that feel heavier than "just run it somewhere and see"? Agents hide real cost inside the parts you cannot even name.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run a scorecard instead of arguing in chat
&lt;/h2&gt;

&lt;p&gt;I keep the inventory in YAML so a reviewer can diff it like any other contract checked into git. The helper script below is a proposed checklist, and it does not call a vendor API or invent a benchmark. I also do not treat the integer score as a latency number or as a security control that replaces threat modeling.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# agent_env.yaml — proposed inventory, fill honestly&lt;/span&gt;
&lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;invoice-triage-loop&lt;/span&gt;
&lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;explore&lt;/span&gt;  &lt;span class="c1"&gt;# explore | promote&lt;/span&gt;
&lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;model_identity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;floating&lt;/span&gt;    &lt;span class="c1"&gt;# pinned | exportable | floating&lt;/span&gt;
  &lt;span class="na"&gt;runtime_lockfile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pinned&lt;/span&gt;
  &lt;span class="na"&gt;tool_origin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;floating&lt;/span&gt;
  &lt;span class="na"&gt;secret_boundary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;floating&lt;/span&gt;
  &lt;span class="na"&gt;filesystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;exportable&lt;/span&gt;
  &lt;span class="na"&gt;timeout_owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;floating&lt;/span&gt;
  &lt;span class="na"&gt;trace_export&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;exportable&lt;/span&gt;
&lt;span class="na"&gt;notes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provider&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tokens&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;currently&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;injected&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;by&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;shared&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;runner"&lt;/span&gt;
  &lt;span class="na"&gt;traces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;we&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;can&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;download&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;JSONL,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;raw&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sandbox&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;disk"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;drift_score.py — proposed scorecard, not measured production data.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pip install pyyaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt;

&lt;span class="n"&gt;WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pinned&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exportable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;floating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;PROMOTE_BLOCKERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secret_boundary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;floating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model_identity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;floating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;trace_export&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;floating&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;load_inventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safe_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inventory needs a fields map&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]]:&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;blockers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WEIGHTS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: unknown state &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;WEIGHTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;PROMOTE_BLOCKERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;blockers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blockers&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;recommend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blockers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;promote&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;blockers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;joined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;blockers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stay off promotion: pin &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;joined&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; before leaving the lab bench&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free shared compute is a fit while drift stays cheap&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;split the loop: explore free, pin the promote slice elsewhere&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;run the loop on a box you can pin and export&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent_env.yaml&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_inventory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blockers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stage=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;drift_score=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; (0=pinned, higher=more overnight risk)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;promote_blockers=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;blockers&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;recommend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;explore&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blockers&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


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

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;pyyaml
python3 drift_score.py agent_env.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I treat a drift score at or under four as permission to remain on free shared capacity for now. I treat any floating &lt;code&gt;secret_boundary&lt;/code&gt; as a hard promotion block, even when the rest of the card looks tidy. Would you ship a loop whose keys live on a host you cannot image after a bad run?&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free lab bench still wins the comparison
&lt;/h2&gt;

&lt;p&gt;Exploration wants cheap retries, throwaway sandboxes, and models you can try without opening a purchase order first. That is the honest job of free model access paired with a free server option during the explore stage. I use that room to fill the YAML honestly, not to pretend the YAML is already pinned for a reviewer who missed the chat.&lt;/p&gt;

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

&lt;p&gt;MonkeyCode is an open-source project with free model access and a free server option that maps onto this explore stage. I mention it because the inventory needs a lab bench, not because a free host pins production secrets for you. If most fields are still floating and the stage is still &lt;code&gt;explore&lt;/code&gt;, that lab is a rational place to generate traces you can actually export. I do not claim model names, token quotas, hardware SKUs, or how long any free tier remains available.&lt;/p&gt;

&lt;p&gt;Can you live with that uncertainty while the loop is still changing twice a day on purpose? If you can, free compute is doing exactly the job I want from an early lab. If you cannot, you already know you need a pin, and shopping for spare capacity will not create one.&lt;/p&gt;

&lt;h2&gt;
  
  
  A labeled walkthrough I have not billed as a case study
&lt;/h2&gt;

&lt;p&gt;This walkthrough is a proposed example with fake ticket names, and I am not attaching measured production timings to it. Imagine an invoice-triage agent that calls a PDF parser, a vendor HTTP API, and a local sqlite cache. During week one I let model identity float, I inject the vendor token through the shared runner, and I download JSONL after each session. The scorecard comes back high, blockers include &lt;code&gt;secret_boundary&lt;/code&gt; and &lt;code&gt;model_identity&lt;/code&gt;, and the only honest recommendation is to remain in explore.&lt;/p&gt;

&lt;p&gt;During week two I lock a requirements file, I move the vendor token into a store I operate, and I pin tool origin to a container I build. Floating fields drop on purpose, and only then do I copy the same fixtures onto isolated compute I can describe. Notice what did not need to change between those weeks: the prompts, the expected tool names, and the JSONL schema the lab already exported. The host changed because the inventory changed, not because a coupon expired or a queue looked lonely.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# proposed local pin after the lab stage — replace with your runtime&lt;/span&gt;
&lt;span class="nb"&gt;cp &lt;/span&gt;agent_env.yaml pinned_env.yaml
&lt;span class="c"&gt;# edit model_identity, secret_boundary, and tool_origin to pinned&lt;/span&gt;
python3 drift_score.py pinned_env.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the promote command still prints blockers, I do not "just try prod" to soothe a demo calendar that wants a green box. I fix the field that refused to be pinned, then I run the scorecard again before anyone changes the stage. Why would a green demo override a floating secret boundary that I already wrote down in YAML?&lt;/p&gt;

&lt;h2&gt;
  
  
  Explicit tradeoffs I put on the same card
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Free shared models and a free server&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Free shared capacity fits exploration, prompt drafts, throwaway tools, and traces that leave with me in JSONL. The tradeoff is that model identity and noisy-neighbor timing may float overnight without anyone calling a meeting. I refuse this option when someone must reconstruct a failure for a reviewer who never sat in the original session.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Self-hosted or paid isolated compute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A box I pin fits locked runtimes, secret stores I own, and tool networks I can draw on a whiteboard. The tradeoff is that I now own disk, upgrades, and the pager for hung tool calls after midnight. I refuse this option for loops that still change their tool surface twice a day and cannot sit still long enough to pin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A split path with portable fixtures&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A split path fits most agents that start messy and later need a reconstructable record instead of a chat screenshot. The tradeoff is that fixtures must stay portable, or the split quietly becomes two incompatible products with folklore in the middle. I refuse a split when the lab cannot export traces, because then the isolated box is pinning theater rather than evidence.&lt;/p&gt;

&lt;p&gt;I want fixtures to stay boring: JSONL prompts, expected tool names, and timeout budgets that survive a host change without a war story. If the lab cannot export that bundle, free compute is teaching a demo habit I do not trust on Monday. If the isolated box cannot import that bundle, I bought a pin I cannot test when the next incident shows up.&lt;/p&gt;

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

&lt;p&gt;Do not use this inventory as a substitute for threat modeling, license review, or a real secret scanner in CI. Do not use the numeric score as a performance benchmark, because the weights are conversation aids I chose in this draft. Do not run untrusted agent code on a free shared host and then point at YAML as if it were a control plane.&lt;/p&gt;

&lt;p&gt;Skip the method if your so-called agent is a stateless function with no tools, no secrets, and no session to reconstruct. A normal unit test is enough in that boring case, and the inventory would only add ceremony around a function. Skip it if you cannot tell the truth inside the YAML, because a lying inventory is worse than an empty file.&lt;/p&gt;

&lt;p&gt;I also skip free shared compute when the loop must touch production data, even when the meeting is labeled as a harmless demo for leadership. Drift is not the only risk on the table when an agent can call tools. Access is a different risk, and this scorecard does not pretend to cover production data paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monday morning steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;I write &lt;code&gt;agent_env.yaml&lt;/code&gt; before I request a host, including the stage field set to explore.&lt;/li&gt;
&lt;li&gt;I run &lt;code&gt;drift_score.py&lt;/code&gt; and I read the promote blockers out loud before anyone books a demo.&lt;/li&gt;
&lt;li&gt;I generate traces on a free lab bench only while that stage value remains explore.&lt;/li&gt;
&lt;li&gt;I export JSONL, lockfiles, and the YAML itself so the next host does not inherit folklore.&lt;/li&gt;
&lt;li&gt;I pin secrets, tool origin, and model identity on a box I control before I change the stage.&lt;/li&gt;
&lt;li&gt;I re-run the scorecard and I refuse promotion whenever any blocker is still marked floating.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Free versus self-hosted is a function of what you cannot pin, not a personality test about cloud loyalty. I would rather keep an agent in the lab for another week than promote a loop whose environment I cannot name. If you cannot name what will change overnight in your loop, you are not ready to pick a host.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>devops</category>
      <category>python</category>
    </item>
    <item>
      <title>Budget the Agent Loop Before You Choose Shared or Isolated Compute</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Sun, 20 Sep 2026 11:29:34 +0000</pubDate>
      <link>https://dev.to/datago_8008/budget-the-agent-loop-before-you-choose-shared-or-isolated-compute-2f23</link>
      <guid>https://dev.to/datago_8008/budget-the-agent-loop-before-you-choose-shared-or-isolated-compute-2f23</guid>
      <description>&lt;p&gt;The cheap lane is the wrong lane whenever a stalled model call can retrigger a write. I treat timeout budget as the first filter, not list price or leftover GPU hours. If you cannot name your p95 stall and your idempotency story, you are not choosing compute. You are gambling on retries.&lt;/p&gt;

&lt;p&gt;Have you timed the second tool call, or only the happy-path demo? Shared inference looks generous until a slow token stream collides with a client retry. I wrote this as a decision guide for that collision, not as another invoice spreadsheet. The artifact below is a proposed worksheet you can run locally with your own numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the stall, not the invoice
&lt;/h2&gt;

&lt;p&gt;Agent loops are not single HTTP calls, even when the SDK pretends they are. One user prompt can fan into planning, tool JSON, a side effect, and a second model hop. If hop two waits on hop one, tail latency stops being a quality-of-service footnote. It becomes a correctness bug.&lt;/p&gt;

&lt;p&gt;I keep seeing teams promote a playground agent because the median answer looked fine on a quiet afternoon. Did the write path survive an eight second pause? Did the webhook client retry while the first attempt was still committing? Those questions decide the host. Price does not.&lt;/p&gt;

&lt;p&gt;This article stays adjacent to the current noise about tests that no longer bound model behavior. I am not chasing a headline about models outgrowing benchmarks. I am asking a smaller, meaner question: can your loop absorb variance without double-sending money, mail, or deploys?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why agent loops punish shared inference
&lt;/h2&gt;

&lt;p&gt;Shared free inference is usually fine for read-only drafting. It gets hostile when three properties stack. First, the model call has a fat tail you do not control. Second, your client retries on timeout because that is what HTTP libraries do. Third, a tool actually mutates something outside the chat transcript.&lt;/p&gt;

&lt;p&gt;Put those together and you do not have a slow chatbot. You have an amplifier. A single stalled generation can mint two tickets, two refunds, or two &lt;code&gt;terraform apply&lt;/code&gt; runs. Would you accept that amplifier on a noisy neighbor queue you cannot drain?&lt;/p&gt;

&lt;p&gt;I score that stack before I score dollars. Isolated or self-hosted compute does not magically make models smarter. It gives you a place to set hard deadlines, pin a revision, and kill a worker without begging a shared scheduler. That is the trade I actually care about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three lanes, one timeout question
&lt;/h2&gt;

&lt;p&gt;I use three lanes only. Lane A is a free shared model plus a free shared server, useful as a scratch harness. Lane B is paid isolated inference with a contract you can page. Lane C is a box you operate, including a local runtime or a rented GPU you can ssh into. MonkeyCode sits in lane A for this worksheet because it currently offers free model access and a free server option.&lt;/p&gt;

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

&lt;p&gt;I do not treat lane A as production just because the form is empty. I treat it as a measurement bench. Can I replay a failing prompt? Can I export the trace? Can I bound the wait so a tool cannot fire twice? If the answers stay no, I refuse to promote the agent, even when the output reads fluent.&lt;/p&gt;

&lt;p&gt;Lane B and lane C buy different kinds of control, not the same kind. Isolated paid compute usually buys queue isolation and a support path. Self-hosted compute buys process death, disk, and network policy. Which control do you actually need when the model stalls? That is the comparison, not a loyalty test.&lt;/p&gt;

&lt;h2&gt;
  
  
  A numbered measurement workflow
&lt;/h2&gt;

&lt;p&gt;Run this before you bind secrets or webhooks to any lane. Label every number as an input you measured, not a vendor promise. I want the worksheet to survive if you never mention a product name again.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Draw the loop on paper, including every tool that can create, update, or charge. If a step only reads, mark it &lt;code&gt;R&lt;/code&gt;. If it writes, mark it &lt;code&gt;W&lt;/code&gt; and name the idempotency key. No key means no shared lane.&lt;/li&gt;
&lt;li&gt;Capture three timings on the same prompt: first token, full completion, and tool round trip. Record p50 and a crude p95 from at least twenty local runs. Do not invent a benchmark you did not run.&lt;/li&gt;
&lt;li&gt;Write the client timeout next to the p95. If timeout is lower than p95, you already own a retry bug. Raise the deadline or make the write idempotent before you shop for hosts.&lt;/li&gt;
&lt;li&gt;Inject a stall. Sleep in a fake tool, or drop packets with a local proxy. Watch whether the orchestrator double-fires the &lt;code&gt;W&lt;/code&gt; step. That single observation outranks any pricing page.&lt;/li&gt;
&lt;li&gt;Score the three lanes with the matrix below. Promote only when the write path stays single-shot under the stall you actually injected.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Need a command-shaped starting point for step four? Keep the stall on your laptop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 loop_budget.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--p95-ms&lt;/span&gt; 4200 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--client-timeout-ms&lt;/span&gt; 3000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--write-steps&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--idempotent&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--can-kill-worker&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--need-trace-export&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that command recommends isolation, believe the timeout math. Do not argue with a marketing page until the retry story is boring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifact: budget calculator and decision matrix
&lt;/h2&gt;

&lt;p&gt;The script is a proposal, not a load test of any vendor. Feed your measurements. It prints a lane and the rule that fired. Change the inputs when your agent changes shape.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;loop_budget.py — proposed scoring sheet, not a benchmark of any host.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoopFacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;p95_ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;client_timeout_ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;write_steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;idempotent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;can_kill_worker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;
    &lt;span class="n"&gt;need_trace_export&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;retry_overlap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LoopFacts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_timeout_ms&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;p95_ms&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_steps&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;recommend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LoopFacts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_steps&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;need_trace_export&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lane-A-shared-free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Read-only loop with no trace mandate; shared inference is a fair scratch pad.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;retry_overlap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idempotent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lane-C-self-hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Timeout sits under p95 and writes are not idempotent; you need a killable worker.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_steps&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idempotent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lane-B-isolated-paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Writes exist without keys; isolate the queue before a neighbor stall doubles a side effect.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;need_trace_export&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;can_kill_worker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lane-B-isolated-paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You need exportable traces more than process death; buy a contract you can audit.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;can_kill_worker&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;retry_overlap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lane-C-self-hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You already require worker death during overlap; keep the runtime on a box you control.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lane-A-shared-free&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Writes look idempotent and timeout covers p95; shared free compute can host the rehearsal.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--p95-ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--client-timeout-ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--write-steps&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--idempotent&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--can-kill-worker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--need-trace-export&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;facts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoopFacts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;p95_ms&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;p95_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;client_timeout_ms&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client_timeout_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;write_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write_steps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;idempotent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idempotent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;can_kill_worker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;can_kill_worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;need_trace_export&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;need_trace_export&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lane&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reason&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;recommend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;overlap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;retry_overlap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;facts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retry_overlap=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;overlap&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lane=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;lane&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reason=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;Use the matrix as a human check after the script. I still want a person to read the &lt;code&gt;W&lt;/code&gt; column. Scripts miss product language that looks read-only and is not.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal you measured&lt;/th&gt;
&lt;th&gt;Prefer shared free lane&lt;/th&gt;
&lt;th&gt;Prefer isolated paid&lt;/th&gt;
&lt;th&gt;Prefer self-hosted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tools are &lt;code&gt;R&lt;/code&gt; only&lt;/td&gt;
&lt;td&gt;Yes, as a rehearsal bench&lt;/td&gt;
&lt;td&gt;Only if you must pin a vendor SLA&lt;/td&gt;
&lt;td&gt;Rarely worth the ops load&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timeout &amp;lt; p95, writes lack keys&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Temporary, if you can pause traffic&lt;/td&gt;
&lt;td&gt;Yes, so you can kill in-flight workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need exportable traces&lt;/td&gt;
&lt;td&gt;Only if the host actually emits them&lt;/td&gt;
&lt;td&gt;Yes, when audit is the product&lt;/td&gt;
&lt;td&gt;Yes, when traces must never leave your disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets in the prompt or env&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Maybe, with scoped keys&lt;/td&gt;
&lt;td&gt;Yes, with local secret injection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You cannot name a rollback&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No — fix the agent first&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice the last row. If rollback is a shrug, no lane is honest. Compute choice cannot repair a tool that charges twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this method refuses to promise
&lt;/h2&gt;

&lt;p&gt;I am not publishing model names, token quotas, hardware SKUs, or durability claims I cannot verify. Free lanes change. Treat availability as a snapshot you re-check on the vendor's own page before you schedule a demo. This worksheet does not rank answer quality, and it does not prove that isolated compute is faster.&lt;/p&gt;

&lt;p&gt;The Python file will happily recommend lane A if you feed it optimistic timings. Garbage in stays garbage. If you skipped the stall injection, you did not run the method. You filled a form.&lt;/p&gt;

&lt;p&gt;Shared free compute also fails closed for regulated transcripts, customer secrets, and anything that must not train a neighbor's curiosity. I will not soften that. A timeout budget can be healthy and the data-handling story can still be disqualifying.&lt;/p&gt;

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

&lt;p&gt;Skip the three-lane sheet if you ship no tools and no side effects. A single-shot summarizer does not need this ceremony. Skip it if you already run a locked internal gateway with deadlines you enforce. You are past the question.&lt;/p&gt;

&lt;p&gt;Skip it if you wanted a cost-break-even spreadsheet or a blast-radius score. Those are different filters, and I am not recycling them here. This pass only asks whether a stall can duplicate a write. That is enough work for one sitting.&lt;/p&gt;

&lt;p&gt;If you still need a throwaway harness after the writes are idempotent, a free shared option such as MonkeyCode's free models and free server can host the rehearsal loop. Keep production traffic off that lane until the script and the matrix agree you can survive a stall. Then choose isolation because the retry story is settled, not because a leftover GPU looked lonely.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>agents</category>
      <category>devops</category>
    </item>
    <item>
      <title>Score the Host Before You Promote a Vibe-Coded Agent</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Sat, 19 Sep 2026 09:34:32 +0000</pubDate>
      <link>https://dev.to/datago_8008/score-the-host-before-you-promote-a-vibe-coded-agent-1jen</link>
      <guid>https://dev.to/datago_8008/score-the-host-before-you-promote-a-vibe-coded-agent-1jen</guid>
      <description>&lt;p&gt;A green chat is not a merge signal, because the host can hide the failure you actually care about. I treat vibe-coded agent work as a draft until the eval host can fail closed, not until the wording looks finished. Free shared inference is useful for that draft, and a box I control is useful when the draft pretends to be engineering. If those two hosts score the same in your notes, are you scoring the demo or the risk?&lt;/p&gt;

&lt;p&gt;This is a decision guide, not a pricing rant, and not a prompt-tuning diary. I keep seeing fluent agent traces get pasted into pull requests with no record of where they ran. The interesting question is not whether the model sounded confident. The interesting question is whether your compute choice can still prove a miss after the chat window is gone.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. I mention MonkeyCode later only as one free-model and free-server option for the draft loop, not as a substitute for the scorecard.&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure I am trying to prevent
&lt;/h2&gt;

&lt;p&gt;Vibe coding is a fast way to sketch tool calls, retries, and glue code you would not type by hand. Calling that sketch engineering is how false-green tests sneak into main. Have you ever watched an agent pass a demo because the golden answer sat in the same prompt pack as the task? That is not intelligence. That is leakage with good manners.&lt;/p&gt;

&lt;p&gt;Shared free runtimes make that leakage cheaper to produce, which is fine while you are still exploring. Isolated or paid runtimes make the same leakage more expensive, which is only worth it when a miss ships. I do not pick a host by leftover GPU time. I pick a host by whether a failed promotion can still be reconstructed tomorrow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five questions before the host gets a vote
&lt;/h2&gt;

&lt;p&gt;I score every agent spike with the same five questions, in this order, before I argue about cost. If you cannot answer them from artifacts, the chat log does not count.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Can a reviewer replay the eval suite without reading the original chat?&lt;/li&gt;
&lt;li&gt;Does the prompt pack hash differ from the eval-suite hash on disk?&lt;/li&gt;
&lt;li&gt;Are tool credentials and network egress denied unless the host is a box you control?&lt;/li&gt;
&lt;li&gt;Will a failed run leave a structured trace, or only a screenshot of a happy path?&lt;/li&gt;
&lt;li&gt;If the model changes under you, can you freeze the comparison or must you shrug?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If questions 1 and 2 fail, I stay on a free exploratory loop and I refuse to merge. If questions 3 or 4 fail, I will not put secrets, production tools, or customer data on shared compute. If question 5 fails, I treat any “it works” claim as time-boxed, even when the prose looks senior.&lt;/p&gt;

&lt;h2&gt;
  
  
  A numbered workflow I actually run
&lt;/h2&gt;

&lt;p&gt;I keep the workflow boring on purpose, because excitement is how demos skip gates. You can copy the steps without adopting my tooling, and you should label every unchecked box as unknown rather than true.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the task and the eval fixtures in two files, then refuse to paste fixtures into the system prompt.&lt;/li&gt;
&lt;li&gt;Hash both files before the first agent call, and store the hashes next to the run id.&lt;/li&gt;
&lt;li&gt;Run the draft on free shared models only if the tools are stubs and the data is synthetic.&lt;/li&gt;
&lt;li&gt;Score the host with the table below, then promote to a self-hosted or paid box when any isolation row trips.&lt;/li&gt;
&lt;li&gt;Re-run the same fixtures on the new host, and compare traces, not vibes.&lt;/li&gt;
&lt;li&gt;Merge only when a stranger can fail the suite without sitting in your original session.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Would I skip step 3 to go faster? Sometimes, when the spike is a throwaway. Would I skip step 6 because the chat felt done? That is the whole bug this article is about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Artifact: a demo-to-merge scorecard
&lt;/h2&gt;

&lt;p&gt;The following script is a proposal you can run locally. It does not benchmark models, and it does not prove production safety. It fails closed when hashes collide, when isolation is required, or when the host kind is still unknown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Demo-to-merge scorecard. Proposal: treat unknown fields as fail.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;ISOLATING_TOOLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shell&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;browser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payments&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prod_db&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secret_store&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sha256_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_bytes&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;score_run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;prompt_pack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;eval_suite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;host_kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;has_structured_trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;can_freeze_model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prompt_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sha256_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt_pack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;eval_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sha256_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eval_suite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;needs_isolation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ISOLATING_TOOLS&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;host_kind&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eval_outside_prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt_hash&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;eval_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host_declared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_shared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;paid_isolated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;isolation_matches_tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;needs_isolation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_shared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;structured_trace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;has_structured_trace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model_can_be_frozen&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;can_freeze_model&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_shared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;promote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_shared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;stay_draft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_shared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eval_outside_prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;needs_isolation&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt_hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eval_hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;eval_hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;checks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;decision&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;promote&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;promote&lt;/span&gt; &lt;span class="nf"&gt;else &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;keep_draft&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stay_draft&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fail_closed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;score_run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;prompt_pack&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt_pack.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;eval_suite&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eval_suite.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;host_kind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;free_shared&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retriever_stub&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;has_structured_trace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;can_freeze_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create two tiny fixtures so the script is reproducible on a laptop. I keep them obviously fake, because a realistic customer dump would already fail the isolation row.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'You are a summarizer. Never read eval_suite.json.\n'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; prompt_pack.txt
&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="s1"&gt;'{"cases":[{"id":"t1","expect":"ok"}]}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; eval_suite.json
python3 scorecard.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you change &lt;code&gt;tools&lt;/code&gt; to &lt;code&gt;"shell"&lt;/code&gt; and leave &lt;code&gt;host_kind&lt;/code&gt; as &lt;code&gt;free_shared&lt;/code&gt;, the decision should become &lt;code&gt;fail_closed&lt;/code&gt;. If both files contain the same bytes, it should also fail, even when the chat still looks clever. That is the point of hashing before arguing about prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tradeoffs I write down, not vibes I remember
&lt;/h2&gt;

&lt;p&gt;I use this table when a teammate wants to stay on free shared compute because the demo already “works.” Working in a chat is one column. Promoting is another column. If you cannot fill a cell, the cell is a no.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Decision axis&lt;/th&gt;
&lt;th&gt;Free shared models / free server&lt;/th&gt;
&lt;th&gt;Self-hosted or paid isolated box&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fit&lt;/td&gt;
&lt;td&gt;Synthetic data, stub tools, throwaway spikes&lt;/td&gt;
&lt;td&gt;Secrets, egress, production tools, merge candidates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Speed to first trace&lt;/td&gt;
&lt;td&gt;Usually faster to start&lt;/td&gt;
&lt;td&gt;Slower until images, queues, and IAM exist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eval honesty&lt;/td&gt;
&lt;td&gt;Easy to contaminate the prompt pack&lt;/td&gt;
&lt;td&gt;Easier to keep fixtures off the model path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Drift&lt;/td&gt;
&lt;td&gt;Model and neighbor load can move under you&lt;/td&gt;
&lt;td&gt;You can freeze runtime and often the weights&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failure evidence&lt;/td&gt;
&lt;td&gt;May be a scrollback window&lt;/td&gt;
&lt;td&gt;Can be files, metrics, and access logs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost shape&lt;/td&gt;
&lt;td&gt;Cash is low; review time is not free&lt;/td&gt;
&lt;td&gt;Cash is higher; incident cost should be lower&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wrong fit&lt;/td&gt;
&lt;td&gt;Shipping a vibe as a contract&lt;/td&gt;
&lt;td&gt;Isolating a spike that should have stayed a sketch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice that “free” only wins the cash row. Review time, incident time, and contaminated evals are still costs. Are you optimizing the invoice, or the chance that a false green reaches main?&lt;/p&gt;

&lt;p&gt;MonkeyCode is an open-source project with free model access and a free server option, which I use only for the draft side of that table. I do not treat those free options as unlimited, permanent, or equivalent to a box I own. If the scorecard returns &lt;code&gt;keep_draft&lt;/code&gt;, a free loop is enough. If it returns &lt;code&gt;fail_closed&lt;/code&gt; or you want &lt;code&gt;promote&lt;/code&gt;, move the same fixtures onto compute you can isolate.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this method refuses to claim
&lt;/h2&gt;

&lt;p&gt;This scorecard does not name models, quote throughput, or promise that any vendor will keep a free tier. It does not replace security review, license review, or load tests. Hash collision resistance here is about accidental copy-paste, not about an adversary. A structured trace can still lie if you log the wrong fields.&lt;/p&gt;

&lt;p&gt;I also do not claim that self-hosting makes vibe-coded agents honest. Isolation only preserves the evidence. You still have to write evals that the agent cannot see. If your suite is three happy-path strings, both hosts will flatter you.&lt;/p&gt;

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

&lt;p&gt;Skip this if you are pasting secrets into a shared chat to “just try something.” Skip it if your agent already drives production tools, because the draft column is already the wrong column. Skip it if you need a cost-optimization spreadsheet rather than a promotion gate. Skip it if nobody on the team will store hashes and traces; a scorecard nobody runs is fan fiction.&lt;/p&gt;

&lt;p&gt;Students and weekend spikes can stay on free shared inference for a long time, and they should. Teams that merge agent output into services should not. Which group are you in when the demo looks good at 5 p.m.?&lt;/p&gt;

&lt;h2&gt;
  
  
  A closing check I use on my own drafts
&lt;/h2&gt;

&lt;p&gt;Before I call a vibe-coded agent “done,” I ask whether a reviewer can fail it without me in the room. If the answer depends on a shared session, I keep the work on a free exploratory loop and I do not promote it. If the answer depends on tools or data I cannot expose, I move the same fixtures to isolated compute and I run the scorecard again. The host is part of the test. Pretending otherwise is how engineering gets renamed after the fact.&lt;/p&gt;

&lt;p&gt;If you want a draft-side place to run that loop, try MonkeyCode’s free model access and free server option on synthetic fixtures only, then promote with evidence instead of a fluent screenshot.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>python</category>
      <category>devops</category>
    </item>
    <item>
      <title>Choose Agent Compute by Replayable Evals, Not by Spare Capacity</title>
      <dc:creator>Riley Li</dc:creator>
      <pubDate>Fri, 18 Sep 2026 07:57:01 +0000</pubDate>
      <link>https://dev.to/datago_8008/choose-agent-compute-by-replayable-evals-not-by-spare-capacity-114a</link>
      <guid>https://dev.to/datago_8008/choose-agent-compute-by-replayable-evals-not-by-spare-capacity-114a</guid>
      <description>&lt;p&gt;I treat agent compute as a measurement problem first, and only then as a hosting or budget debate. If two runtimes cannot execute the same eval harness and emit a comparable ledger, I do not have a real choice. I have a one-way experiment between free shared capacity and a box I control, and I cannot score it later. Have you ever moved an agent onto unpaid capacity and then argued whether the model slipped or a tool call vanished?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why spare capacity is not a decision yet
&lt;/h2&gt;

&lt;p&gt;Cost spreadsheets hide the failure mode that quietly burns the most calendar time on a team. I cannot tell whether a runtime is cheaper if I cannot tell whether it still runs the same job. Self-hosted boxes give me process control, local disk, and a fingerprint I can store beside the output. Free shared options give me a lab I did not provision, which is useful only if the eval still means something.&lt;/p&gt;

&lt;p&gt;The public conversation around generated code keeps circling whether the work still counts as engineering, and I will not join that slogan fight. I care about a narrower question that I can test in an afternoon without a research budget. Can I replay a frozen task suite on two runtimes and explain the diff without guessing at hidden wrappers? If I cannot, I am not choosing compute in any honest sense, and I am only collecting anecdotes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five checks I score before I pick a runtime
&lt;/h2&gt;

&lt;p&gt;I keep the scoring boring on purpose, because boring is the only quality that stays replayable next week. Each candidate gets a yes, a no, or a not-yet against the same five checks I refuse to customize mid-argument. I do not let a price tag break a tie until those cells are filled with something I could show a teammate. If a vendor story cannot survive this worksheet, I treat it as a demo environment, not as a factory.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pin.&lt;/strong&gt; Can I freeze prompts, tools, fixtures, and expected side effects in git before anyone touches a new host?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fingerprint.&lt;/strong&gt; Can I record runtime identity, an image digest, or at least a hostname, clock, and tool versions beside every row?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replay.&lt;/strong&gt; Can I re-run the same suite after a queue delay, a host recycle, or a quiet weekend without rewriting prompts?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ledger.&lt;/strong&gt; Can I keep JSONL rows on disk I own if the free path pauses, throttles, or reroutes the next session?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diff.&lt;/strong&gt; Can a teammate read two rows and tell a real regression from timestamp noise, shuffled ids, or wrapper chatter?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the decision table I actually fill. I treat it as a proposed worksheet, not as a benchmark I already ran against a production fleet.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Box I control&lt;/th&gt;
&lt;th&gt;Free shared lab&lt;/th&gt;
&lt;th&gt;What a no means in practice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pin&lt;/td&gt;
&lt;td&gt;Yes if the repo is the only source of truth&lt;/td&gt;
&lt;td&gt;Yes only if I carry the suite with me&lt;/td&gt;
&lt;td&gt;You are demoing, not evaluating&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fingerprint&lt;/td&gt;
&lt;td&gt;Yes, digest plus hostname&lt;/td&gt;
&lt;td&gt;Often partial, sometimes missing&lt;/td&gt;
&lt;td&gt;You cannot explain a Tuesday incident&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replay&lt;/td&gt;
&lt;td&gt;Yes, until I delete the box&lt;/td&gt;
&lt;td&gt;Maybe, if the queue still admits me&lt;/td&gt;
&lt;td&gt;Last week's score is folklore&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ledger&lt;/td&gt;
&lt;td&gt;Yes, local disk I own&lt;/td&gt;
&lt;td&gt;Yes only if I copy rows off-box immediately&lt;/td&gt;
&lt;td&gt;The evidence evaporates with the session&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diff&lt;/td&gt;
&lt;td&gt;Yes, same harness both times&lt;/td&gt;
&lt;td&gt;Yes only after I normalize ids and clocks&lt;/td&gt;
&lt;td&gt;You will argue about the model instead of the trace&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Notice that the table refuses to score marketing language, idle GPU screenshots, or how generous a free tier sounded in a launch thread. I score whether tomorrow-me can replay today-me without writing fan fiction about the runtime. Would you ship a database migration without a rollback plan, then still ship a runtime migration without a ledger you can grep?&lt;/p&gt;

&lt;h2&gt;
  
  
  A workflow I can finish in one sitting
&lt;/h2&gt;

&lt;p&gt;I run this as a checklist, not as a research program, because the point is a comparable artifact. Nobody on my team is allowed to fall in love with unpaid capacity before the ledger exists. The steps are deliberately small so I cannot hide behind a two-week evaluation project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Freeze a golden set of eight to twelve tasks that already failed in interesting ways, not only the happy path that flatters every host.&lt;/li&gt;
&lt;li&gt;Hash every prompt, tool schema, and fixture so a silent file edit cannot hide inside a story about the model getting worse.&lt;/li&gt;
&lt;li&gt;Run the suite once on a box I control, even if that box is a laptop, and write JSONL onto disk that I actually own.&lt;/li&gt;
&lt;li&gt;Run the same suite on the free shared option without editing prompts, then copy the ledger off that host before I close the session.&lt;/li&gt;
&lt;li&gt;Diff hashes, exit codes, and tool-call shapes before I look at latency, because latency lies when queues stall.&lt;/li&gt;
&lt;li&gt;Label the free path as lab, factory, or reject: lab means explore, factory means keep for chores, reject means I still need isolation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I do not always need twelve tasks, but I do need enough cases that a single lucky completion cannot flatter a runtime into a strategy slide. Have you noticed how one green demo becomes next quarter's default host before anyone stores a prompt hash? That is why the ledger stays small, mean, and checked into git beside the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The artifact: a proposed replay ledger
&lt;/h2&gt;

&lt;p&gt;The script below is a proposed local harness. I am not reporting production timings, and I am not claiming a bake-off against any hosted model catalog. It writes one JSONL row per task so I can diff two runtimes with ordinary Unix tools, which is the whole scientific instrument I need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;replay_ledger.py — proposed harness, not a published benchmark.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;platform&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;GOLDEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t01_hash_prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Return only the integer 42.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expect_substr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;42&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t02_tool_shape&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Call echo with argument ping and return stdout.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expect_substr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ping&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;t03_refuse_network&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Do not open sockets. Reply with the word isolated.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expect_substr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;isolated&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sha256_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()[:&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fingerprint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;runtime_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RUNTIME_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unlabeled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;platform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;node&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cwd&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Replace this stub with your agent CLI. Keep the ledger shape stable.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;started&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# Proposed stand-in: echo the prompt so the workflow is runnable without a vendor SDK.
&lt;/span&gt;    &lt;span class="n"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;python3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;import sys; print(sys.argv[1])&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exit_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output_hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sha256_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;latency_ms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;started&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stderr_hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sha256_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;out_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LEDGER_PATH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;replay_ledger.jsonl&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;fp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fingerprint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;out_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;GOLDEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;fp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt_hash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sha256_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
            &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;passed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;expect_substr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sort_keys&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;wrote &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;out_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


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

&lt;/div&gt;



&lt;p&gt;I compile it first, then I run it twice with different &lt;code&gt;RUNTIME_ID&lt;/code&gt; values, and only then I diff the rows. If I skip the compile step, I am not measuring agents. I am measuring a syntax error I created myself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 &lt;span class="nt"&gt;-m&lt;/span&gt; py_compile replay_ledger.py
&lt;span class="nv"&gt;RUNTIME_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;box-local &lt;span class="nv"&gt;LEDGER_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ledger-local.jsonl python3 replay_ledger.py
&lt;span class="nv"&gt;RUNTIME_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;free-lab &lt;span class="nv"&gt;LEDGER_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ledger-free.jsonl python3 replay_ledger.py
python3 - &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;PY&lt;/span&gt;&lt;span class="sh"&gt;'
import json
from pathlib import Path

def load(path):
    rows = [json.loads(line) for line in Path(path).read_text().splitlines() if line]
    return {row["task_id"]: row for row in rows}

local = load("ledger-local.jsonl")
free = load("ledger-free.jsonl")
for task_id in local:
    a, b = local[task_id], free[task_id]
    print(task_id, {
        "pass_local": a["passed"],
        "pass_free": b["passed"],
        "out_match": a["output_hash"] == b["output_hash"],
        "exit_match": a["exit_code"] == b["exit_code"],
    })
&lt;/span&gt;&lt;span class="no"&gt;PY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;out_match&lt;/code&gt; is false while &lt;code&gt;prompt_hash&lt;/code&gt; is equal, I do not shrug and say the free path is just stochastic. I open the two outputs and I ask whether a tool policy, a wrapper, or a truncated context changed the job. Stochastic noise is a hypothesis I have to earn with more than one seed, not a blanket excuse for a messy ledger. Does that extra hour feel slow when a free queue is already waiting? It is still faster than a week of it worked on my shared host.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free model lab belongs in this score
&lt;/h2&gt;

&lt;p&gt;I still want a lab that I can enter without provisioning hardware first, especially when I am only trying to see whether a task suite is even worth isolating. Disclosure: This article was prepared as part of MonkeyCode's product outreach. I treat MonkeyCode as an open-source project with free model access and a free server option. Those two sit in the free shared lab column of the table above, not in a special unmeasured column. I score that column with the same ledger I would use on a laptop, a rented VM, or any other unpaid queue.&lt;/p&gt;

&lt;p&gt;I do not need a model catalog pitch to use the method, and I will not invent quotas, hardware, or bake-off numbers to dress it up. If the free path reproduces hashes and tool shapes, I keep exploration there and I stop paying for idle capacity I do not yet need. If the free path cannot fingerprint, cannot replay on Monday, or cannot let me copy JSONL off the box, I keep the factory on machines I control. Would I put a customer-facing agent on the first green lab run just because the queue was free? I would not, and I would wait until the ledger stays boring across a replay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations, and who should not use this
&lt;/h2&gt;

&lt;p&gt;This workflow is the wrong tool if you do not have any frozen tasks yet, because you will measure theater instead of regressions. It is also the wrong tool if your agent must keep secrets on disk you do not control, even when the eval looks cheap on paper. Teams that need deterministic, audited, or air-gapped runs should start on isolated hosts and should not wait for a free queue to become a compliance story after the fact.&lt;/p&gt;

&lt;p&gt;The harness above is a stub on purpose. It does not measure token quality, multi-hour jobs, GPU placement, or vendor quotas, and I will not invent those figures to look more empirical than I am. Stochastic generators can disagree without either runtime being broken, so a single mismatch is a clue I have to investigate, not a court verdict I can paste into Slack. If your golden set only contains tasks the model already likes, the ledger will flatter every host you try and teach you nothing.&lt;/p&gt;

&lt;p&gt;I also skip this ceremony for throwaway spikes that die the same afternoon, because a replay ledger earns its keep only when someone will ask next week why the agent changed. If nobody will ask, I am not choosing a runtime in any serious way. I am doodling, and doodling does not need a decision guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I decide after the rows exist
&lt;/h2&gt;

&lt;p&gt;I read the table from the bottom, because Diff is the only check a future incident review will actually care about. If Diff is a no, I do not care that the lab was free, because I cannot defend the change to a teammate who was not in the room. If Replay and Ledger are yes, and the hashes mostly match, I am willing to keep the free path as a lab and even as a low-risk factory for internal chores. If Fingerprint is a no, I keep using the lab for drafts, and I refuse to let it become the system of record for anything I will have to explain.&lt;/p&gt;

&lt;p&gt;That is the decision guide I actually want when the timeline is full of AI commentary and empty of comparable runs. Spare capacity is a rumor until the eval replays, and the ledger is the argument I can bring to a teammate without raising my voice. What would your current free queue look like if you scored it this way tonight, with hashes instead of vibes?&lt;/p&gt;

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