<?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: bestbee</title>
    <description>The latest articles on DEV Community by bestbee (@bestbee).</description>
    <link>https://dev.to/bestbee</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%2F4022115%2F1e3f6d82-8235-43d1-a5b6-ebda84a1f6b7.png</url>
      <title>DEV Community: bestbee</title>
      <link>https://dev.to/bestbee</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bestbee"/>
    <language>en</language>
    <item>
      <title>Should Your Platform Lead Default New Hires Onto a Free AI Lane? Use This Fit-or-Exit Card</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Wed, 23 Sep 2026 15:56:51 +0000</pubDate>
      <link>https://dev.to/bestbee/should-your-platform-lead-default-new-hires-onto-a-free-ai-lane-use-this-fit-or-exit-card-f7k</link>
      <guid>https://dev.to/bestbee/should-your-platform-lead-default-new-hires-onto-a-free-ai-lane-use-this-fit-or-exit-card-f7k</guid>
      <description>&lt;p&gt;Two new hires start Monday. Paid AI seats are still stuck in procurement. The wiki already links a free coding lane.&lt;/p&gt;

&lt;p&gt;Do you default them onto it?&lt;/p&gt;

&lt;p&gt;I would not. Not without a fit-or-exit card. Free access looks like a gift to a joiner. It often shows up later as mentor overtime and a habit the squad never voted on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The scene I keep replaying
&lt;/h2&gt;

&lt;p&gt;Composite scene, not a named-client story. Six-person squad. Two joiners. One staff engineer who already reviews too much.&lt;/p&gt;

&lt;p&gt;The joiners are not slow. They are fast in the wrong unit. Pull requests appear before they can name the invariant they touched. Mentors go quiet because the tests are green. Have you watched that happen in week one?&lt;/p&gt;

&lt;p&gt;That is not onboarding. That is a cost transfer.&lt;/p&gt;

&lt;p&gt;Here is the reversing constraint. If mentor hours are the scarce resource, a free lane that multiplies unverified diffs is more expensive than a paid seat that sits idle for two weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three placements, not two slogans
&lt;/h2&gt;

&lt;p&gt;I score three placements. I do not score "AI versus no AI."&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Free hosted lane.&lt;/strong&gt; Fastest thing you can put in a new hire's hands. Cash near zero. Your data-boundary and uptime story now belong to someone else's product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted lane.&lt;/strong&gt; Weights and logs stay inside a boundary you own. You also own the pager, the queue, and the "who restarts this" question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paid seat.&lt;/strong&gt; Procurement, vendor terms, usually clearer retention. You pay even while the joiner is still reading the runbook.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An open-source coding assistant with free model access and a free server option sits in bucket one. Sometimes it is a bridge into bucket two if you later self-host.&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 fits that first bucket: free model access, plus a free server option, which is useful when you need a bounded measurement lane before procurement moves. Useful is not the same as "make it the default." Strip the name out. The card still has to work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variable dictionary
&lt;/h2&gt;

&lt;p&gt;Write these on a whiteboard before anyone debates vendors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;B&lt;/strong&gt; — data-boundary allow. &lt;code&gt;0&lt;/code&gt; or &lt;code&gt;1&lt;/code&gt;. Security or platform owns it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M&lt;/strong&gt; — extra mentor hours spent unsticking AI output, per joiner, per week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;N&lt;/strong&gt; — share of the joiner's PRs they can narrate without the model. &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;T&lt;/strong&gt; — calendar days to the first change they own without AI as the author of record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H&lt;/strong&gt; — loaded hourly cost of a mentor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;P&lt;/strong&gt; — paid-seat monthly cost. Finance replaces the placeholder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt; — self-host monthly cost, box plus toil.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E&lt;/strong&gt; — expiry of the exception. A date, not a vibe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If &lt;strong&gt;B&lt;/strong&gt; is 0, stop. The rest of the math is entertainment.&lt;/p&gt;

&lt;p&gt;A scorecard is a conversation tool, not objective truth. If your security lead disagrees on &lt;strong&gt;B&lt;/strong&gt;, you do not average the disagreement. You halt the default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fit-or-exit card
&lt;/h2&gt;

&lt;p&gt;Four questions. Each one can kill a placement on its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Boundary: can this joiner's work leave the trust zone?
&lt;/h3&gt;

&lt;p&gt;Private source, customer records, unreleased schema: free hosted is ineligible. Public docs and secret-free internal tools: a pilot is allowed. Mixed work? Split the work. Do not split the policy.&lt;/p&gt;

&lt;p&gt;I want this in the first-week checklist. Ugly. Readable.&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;# Labeled checklist. Not a security audit.&lt;/span&gt;
rg &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"AKIA|BEGIN PRIVATE KEY|api_key|SECRET"&lt;/span&gt; &lt;span class="nt"&gt;--glob&lt;/span&gt; &lt;span class="s1"&gt;'!.git'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
echo&lt;/span&gt; &lt;span class="s2"&gt;"If this joiner's repo can trip the above, B=0 for any free hosted lane."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Policy PDFs do not catch a &lt;code&gt;.env&lt;/code&gt; in a generated commit. This does, if someone runs it.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Narration: by day 10, can they walk a diff they shipped?
&lt;/h3&gt;

&lt;p&gt;If &lt;strong&gt;N&lt;/strong&gt; stays under 0.5, the free lane is teaching speed, not the system. Paid will not fix that. Self-host will not fix that. Freeze expansion. Pair.&lt;/p&gt;

&lt;p&gt;PR template I want in the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Narration (required if an AI lane touched this PR)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Invariant I changed:
&lt;span class="p"&gt;-&lt;/span&gt; Failure I would have caused without this change:
&lt;span class="p"&gt;-&lt;/span&gt; Test that would fail if I reverted the wrong hunk:
&lt;span class="p"&gt;-&lt;/span&gt; What I did &lt;span class="ge"&gt;*not*&lt;/span&gt; let the model write:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If they cannot fill it, the PR is not late. The onboarding is.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Mentor-hour break-even: who actually pays?
&lt;/h3&gt;

&lt;p&gt;Monthly transferred cost of a "free" joiner:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;M * H * 4.3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Compare that to &lt;code&gt;P&lt;/code&gt; per paid seat, and to &lt;code&gt;S&lt;/code&gt; divided by people who actually hit the box.&lt;/p&gt;

&lt;p&gt;Worked example. Labeled assumptions. Replace every number before you quote it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two joiners.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M&lt;/strong&gt; = 3 extra mentor hours per joiner per week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H&lt;/strong&gt; = $90 loaded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;P&lt;/strong&gt; = $40 per seat per month (placeholder; use your contract).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S&lt;/strong&gt; = $400 box + 2 hours of platform toil at $90.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Free hosted cash: about $0.&lt;/p&gt;

&lt;p&gt;Transferred cost: &lt;code&gt;3 * 90 * 4.3 * 2 ≈ $2,322 / month&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Paid seats: &lt;code&gt;2 * 40 = $80&lt;/code&gt; cash. I do not assume &lt;strong&gt;M&lt;/strong&gt; falls. Measure &lt;strong&gt;M&lt;/strong&gt; either way.&lt;/p&gt;

&lt;p&gt;Self-host: &lt;code&gt;400 + 180 = $580&lt;/code&gt; total. Per-user only if six people truly share the box.&lt;/p&gt;

&lt;p&gt;See the inversion? Free can win the cash column and still tax your best reviewers. Paid can look spendy and still be cheaper than three hours of a staff engineer explaining a generated layout.&lt;/p&gt;

&lt;p&gt;Sensitivity is the whole point. If &lt;strong&gt;M&lt;/strong&gt; drops to 0.5, free hosted can be rational on money. If &lt;strong&gt;M&lt;/strong&gt; stays at 3, free hosted is a stealth cost center. Which one is your squad this month?&lt;/p&gt;

&lt;p&gt;I run it as a script so nobody hand-waves the 4.3.&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;# Worked example only. Not a benchmark. Not vendor ROI.
&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;          &lt;span class="c1"&gt;# extra mentor hours / joiner / week
&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;90.0&lt;/span&gt;         &lt;span class="c1"&gt;# loaded $ / hour
&lt;/span&gt;&lt;span class="n"&gt;joiners&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;40.0&lt;/span&gt;         &lt;span class="c1"&gt;# $ / seat / month — replace with your contract
&lt;/span&gt;&lt;span class="n"&gt;S_box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;400.0&lt;/span&gt;    &lt;span class="c1"&gt;# $ / month
&lt;/span&gt;&lt;span class="n"&gt;S_toil_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;
&lt;span class="n"&gt;users_on_box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;

&lt;span class="n"&gt;free_transfer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;4.3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;joiners&lt;/span&gt;
&lt;span class="n"&gt;paid_cash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;joiners&lt;/span&gt;
&lt;span class="n"&gt;self_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;S_box&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;S_toil_hours&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;H&lt;/span&gt;
&lt;span class="n"&gt;self_per_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self_host&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;users_on_box&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;free transferred $/mo: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;free_transfer&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="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;paid cash $/mo:        &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;paid_cash&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="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;self-host total $/mo:  &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self_host&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="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;self-host per user:    &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;self_per_user&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;m_star&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paid_cash&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;4.3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;joiners&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;break-even M* vs paid (hours/week/joiner): &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m_star&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If real &lt;strong&gt;M&lt;/strong&gt; sits above &lt;strong&gt;M&lt;/strong&gt;&lt;em&gt;, "free" is a slogan. In the placeholder above, **M&lt;/em&gt;** is tiny. That is the point. Staff-engineer time is the expensive input, not the token sticker.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Owner, expiry, exit: no owner, no lane
&lt;/h3&gt;

&lt;p&gt;I do not care how open source the stack is.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Owner:&lt;/strong&gt; a named EM or platform lead. Not "the squad."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry:&lt;/strong&gt; 30 days for a new-hire default. Not "until it feels fine."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit:&lt;/strong&gt; if &lt;strong&gt;N&lt;/strong&gt; &amp;lt; 0.5, or &lt;strong&gt;M&lt;/strong&gt; &amp;gt; &lt;strong&gt;M&lt;/strong&gt;*, or a secret hits the lane, the unsupervised default dies. Joiners keep their editors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Decision log, in the repo, not in a slide deck:&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;# decision-log/ai-onboarding-2026-09-23.yaml&lt;/span&gt;
&lt;span class="na"&gt;decision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default_new_hires_free_hosted&lt;/span&gt;
&lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platform-lead-name"&lt;/span&gt;
&lt;span class="na"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-09-23&lt;/span&gt;
&lt;span class="na"&gt;expires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-10-23&lt;/span&gt;
&lt;span class="na"&gt;B&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;M_hours_per_week&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3.0&lt;/span&gt;
&lt;span class="na"&gt;N_day10_target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;
&lt;span class="na"&gt;exit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;drops&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;N&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0.5&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;at&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;day&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;10"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;M&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;break-even&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;M*"&lt;/span&gt;
&lt;span class="na"&gt;review_after&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-10-23&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thirty days. Renew with new numbers or stop. Expiring exceptions beat evergreen "we are still piloting."&lt;/p&gt;

&lt;h2&gt;
  
  
  Day-one workflow
&lt;/h2&gt;

&lt;p&gt;I do not survey feelings. I pick one joiner, one service, one week.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Set &lt;strong&gt;B&lt;/strong&gt; with security in the room. Fifteen minutes.&lt;/li&gt;
&lt;li&gt;Put &lt;strong&gt;N&lt;/strong&gt; in the PR template. Zero extra tools.&lt;/li&gt;
&lt;li&gt;Ask the staff engineer for &lt;strong&gt;M&lt;/strong&gt;. If they say "not much" and their calendar is review, believe the calendar.&lt;/li&gt;
&lt;li&gt;Run the script with finance's &lt;strong&gt;H&lt;/strong&gt; and &lt;strong&gt;P&lt;/strong&gt;. Refuse invented ROI.&lt;/li&gt;
&lt;li&gt;Commit the YAML. Drop the expiry on the EM's calendar.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Boring on purpose. Adoption theater is expensive. Measurement is not.&lt;/p&gt;

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

&lt;p&gt;Do not default new hires onto a free hosted lane when any of these are true.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The repo can see production secrets, health data, or uncleared customer dumps.&lt;/li&gt;
&lt;li&gt;You have no spare mentor hours. A free lane without review slack is how green tests become production archaeology.&lt;/li&gt;
&lt;li&gt;You need a vendor DPA more than you need a cheap token path.&lt;/li&gt;
&lt;li&gt;You were about to treat a free server as an SRE team. It is a pilot instrument. It is not a capacity plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-host is the wrong first move when nobody can name who patches the box. Paid is the wrong first move when procurement will strand joiners for a month with no measurement plan either. Sometimes the honest answer is delayed AI. Not a free default.&lt;/p&gt;

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

&lt;p&gt;I have not run a multi-company trial of this card. The worked numbers are placeholders. Your &lt;strong&gt;H&lt;/strong&gt; and &lt;strong&gt;P&lt;/strong&gt; will move the break-even more than any model slide.&lt;/p&gt;

&lt;p&gt;Free model access and a free server option change cash timing. They do not change &lt;strong&gt;B&lt;/strong&gt;. They do not narrate the diff. They do not create an owner.&lt;/p&gt;

&lt;p&gt;Open source matters for exit: you can leave. That is real. It is not a license to skip day-10 narration.&lt;/p&gt;

&lt;p&gt;If any vendor quotes adoption percentages without your &lt;strong&gt;M&lt;/strong&gt; and &lt;strong&gt;N&lt;/strong&gt;, ignore the quote.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would reverse you?
&lt;/h2&gt;

&lt;p&gt;Forget whether the tool is likable.&lt;/p&gt;

&lt;p&gt;Which variable flips your default?&lt;/p&gt;

&lt;p&gt;If &lt;strong&gt;M&lt;/strong&gt; is really 0.4, I would let joiners start on a bounded free lane and revisit at day 30. If &lt;strong&gt;B&lt;/strong&gt; is 0, I would not. If &lt;strong&gt;N&lt;/strong&gt; is stuck at 0.2, I would spend the week pairing, not shopping seats.&lt;/p&gt;

&lt;p&gt;So. What is your &lt;strong&gt;M&lt;/strong&gt; this week, and who owns the expiry?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>management</category>
    </item>
    <item>
      <title>Should Your EM Mix a Free AI Lane With Self-Host? Use This 3-Bucket Routing Card</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Tue, 22 Sep 2026 14:14:42 +0000</pubDate>
      <link>https://dev.to/bestbee/should-your-em-mix-a-free-ai-lane-with-self-host-use-this-3-bucket-routing-card-hm4</link>
      <guid>https://dev.to/bestbee/should-your-em-mix-a-free-ai-lane-with-self-host-use-this-3-bucket-routing-card-hm4</guid>
      <description>&lt;p&gt;A $0 invoice can still be the expensive default.&lt;/p&gt;

&lt;p&gt;I keep landing in the same Monday planning room. Finance is calm. The AI line is blank. Then two seniors wait fourteen minutes on one shared free lane while a docs rewrite and a billing patch sit in the same queue. Security asks the question that should have been on the card already. Did customer code leave the boundary because we treated “free” as “fine for everything”?&lt;/p&gt;

&lt;p&gt;That is not a model problem. It is a mix problem.&lt;/p&gt;

&lt;p&gt;Most teams still run a binary. Keep the free lane, or stand up something private. Binary feels clean. It also dumps three jobs into one pipe. Commodity text. Boundary code. Deadline bursts. They do not share a cost unit, and they do not share a failure mode.&lt;/p&gt;

&lt;p&gt;So here is the card I want an EM to fill. Not buy-or-don't. Which work stays on a free hosted lane, which work must stay in-boundary, and which work needs reserved capacity — with an owner and an expiry date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure, and where a free lane actually fits
&lt;/h2&gt;

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

&lt;p&gt;I am not crowning a stack. I am trying to stop a blank invoice from posing as a strategy. If you need a free hosted option for the commodity bucket, MonkeyCode is an open-source project that currently offers free model access and a free server option. I am not treating any posted quota, box size, or duration as durable. Check the project on the day you write the policy.&lt;/p&gt;

&lt;p&gt;Strip that name out and the routing card still has to work. That is the bar.&lt;/p&gt;

&lt;h2&gt;
  
  
  The constraint that reverses “just use free”
&lt;/h2&gt;

&lt;p&gt;Zero dollars is a price. It is not a capacity plan.&lt;/p&gt;

&lt;p&gt;Shared free capacity has a queue. Self-hosted capacity has an ops tax. Reserved capacity has a sticker. Your job is to put work on the lane whose failure mode you can live with. Not the lane whose invoice is quiet.&lt;/p&gt;

&lt;p&gt;Ask it this way. If the free lane vanished for ten days, which PRs would you still ship by hand, which PRs would you pause, and which PRs should never have been on that lane at all?&lt;/p&gt;

&lt;p&gt;If that takes a meeting, you do not have a mix. You have a habit.&lt;/p&gt;

&lt;p&gt;Look at the incentives, because they will write the mix if you do not. Finance is paid to keep the line at zero. Security is paid to assume nothing left the building. You are paid to show throughput. Seniors are paid to stop waiting behind docs. An unwritten default lets finance win the meeting and security lose the incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variable definitions — write these first
&lt;/h2&gt;

&lt;p&gt;A scorecard is a conversation tool, not objective truth. Fill the variables before you score a vendor.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Queue minutes (Q):&lt;/strong&gt; wall-clock wait from “I submitted” to “the lane started useful work,” sampled over a week, not a lucky hour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;People stacked (P):&lt;/strong&gt; how many engineers are blocked on that wait. Idle seniors are not free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fully loaded rate (R):&lt;/strong&gt; your finance number per engineer-hour, including benefits. Not a blog number.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ops hours (H):&lt;/strong&gt; platform hours per week to keep a private lane alive: upgrades, auth, disks, “why is it 500.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ops rate (S):&lt;/strong&gt; fully loaded cost of the person who actually gets paged.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boundary (B):&lt;/strong&gt; can this diff include customer code, secrets, or production config? Yes or no. No maybes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blast radius (Z):&lt;/strong&gt; if the model is wrong, is the miss a typo in docs or a payment path?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry (E):&lt;/strong&gt; the date the mix dies unless a named human renews it. No open-ended exceptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Queue tax for a bucket, dollars per week:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;queue_tax = (Q / 60) * P * PRs_per_week * R&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ops tax:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ops_tax = H * S&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Reserved sticker is whatever finance is actually billed for that burst lane. Do not convert it into seats. Seats hide contention.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 3-bucket routing card
&lt;/h2&gt;

&lt;p&gt;Put every recurring work type into one bucket. If a type fits two, it goes to the stricter one. Argue the row, not the brand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bucket A — commodity, public-shaped
&lt;/h3&gt;

&lt;p&gt;Think internal docs, test scaffolding on fake data, changelog drafts, “explain this open module.”&lt;/p&gt;

&lt;p&gt;Fit: B is no. Z is low. Q can get ugly before the dollar tax beats a private box.&lt;/p&gt;

&lt;p&gt;Default lane: free hosted.&lt;/p&gt;

&lt;p&gt;Exit: if a commodity PR starts carrying production config, it is no longer commodity. Move it the same day. “Just this once” is how Bucket B leaks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bucket B — boundary or high blast radius
&lt;/h3&gt;

&lt;p&gt;Think billing, auth, migrations, customer payloads, anything you would page on.&lt;/p&gt;

&lt;p&gt;Fit: B is yes, or Z is high. Cost is not the decider. The boundary is.&lt;/p&gt;

&lt;p&gt;Default lane: self-hosted in-boundary, or no AI on that path.&lt;/p&gt;

&lt;p&gt;Exit: if you cannot staff H, you do not self-host. You restrict the work. A free shared lane is not a compliance control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bucket C — deadline bursts
&lt;/h3&gt;

&lt;p&gt;Think a freeze window, an incident patch, a launch week when three squads collide on one pipe.&lt;/p&gt;

&lt;p&gt;Fit: Q times P spikes, even if B is no.&lt;/p&gt;

&lt;p&gt;Default lane: reserved capacity, or a hard cap on who may touch the free lane during the window.&lt;/p&gt;

&lt;p&gt;Exit: the freeze ends, the reserved lane expires. Burst is not a lifestyle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example (labeled hypothetical)
&lt;/h2&gt;

&lt;p&gt;This is a filled card, not a customer case. Do not quote it as evidence. Squad of eight. Planning week of 2026-09-22. Rates are placeholders so you can replace them.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bucket&lt;/th&gt;
&lt;th&gt;PRs/week&lt;/th&gt;
&lt;th&gt;Q (min)&lt;/th&gt;
&lt;th&gt;P&lt;/th&gt;
&lt;th&gt;R&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;Z&lt;/th&gt;
&lt;th&gt;Weekly queue tax&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;A docs/tools&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;td&gt;$120&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;$160&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B billing/auth&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;1.5&lt;/td&gt;
&lt;td&gt;$120&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;high&lt;/td&gt;
&lt;td&gt;$96, plus an unacceptable boundary miss&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C launch burst&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;3.0&lt;/td&gt;
&lt;td&gt;$120&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;med&lt;/td&gt;
&lt;td&gt;$648&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Self-host ops: H = 5 hours/week, S = $160, so ops_tax = $800.&lt;/p&gt;

&lt;p&gt;Read it slowly.&lt;/p&gt;

&lt;p&gt;Bucket A is cheap to leave on free. The tax is real and still smaller than standing up a private box for docs. Bucket B should never have been on the shared free lane, even though its queue tax looks small. The failure mode is not money. Bucket C is where the blank invoice lies. Three people waiting eighteen minutes, six times a week, is already most of a private lane’s ops tax — and that is before review time.&lt;/p&gt;

&lt;p&gt;Break-even for moving only Bucket C off free: if &lt;code&gt;queue_tax_C&lt;/code&gt; stays above the reserved sticker (or above the share of ops_tax you would actually staff for C) for three weeks, C leaves the free lane. If Q drops to four minutes, C can return. The mix is allowed to move. The card is not.&lt;/p&gt;

&lt;p&gt;Sensitivity, same sheet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If R is $80, C’s tax falls to $432. Free looks better. The boundary rule for B does not move.&lt;/li&gt;
&lt;li&gt;If Q for C is 4 minutes, tax falls to $144. Do not self-host for pride.&lt;/li&gt;
&lt;li&gt;If H is 12 hours because nobody automated upgrades, self-host loses even when Q is ugly. Buy reserved, or cut AI off that path.&lt;/li&gt;
&lt;li&gt;If B flips to yes on a “docs” PR, the whole row jumps to Bucket B. Cost stops mattering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which variable would reverse your call this month? Q, H, or B? Pick one. Write it under the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run the numbers. Do not argue the vibe.
&lt;/h2&gt;

&lt;p&gt;Label this as unexecuted example code. Point it at your samples, not at a vendor dashboard.&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;# Hypothetical worksheet. Not a benchmark. Not a product result.
&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;Bucket&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="n"&gt;prs_per_week&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;queue_min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;people_stacked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;engineer_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;boundary&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;blast_high&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;queue_tax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Bucket&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;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prs_per_week&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;people_stacked&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queue_min&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;60.0&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;hours&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engineer_rate&lt;/span&gt;

&lt;span class="n"&gt;buckets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Bucket&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_commodity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&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="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B_boundary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Bucket&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_burst&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&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="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;ops_tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;160&lt;/span&gt;  &lt;span class="c1"&gt;# H * S
&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;buckets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;queue_tax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boundary&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blast_high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;self_host_or_none&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;tax&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ops_tax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reserved_or_self_host&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;route&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_hosted&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="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;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; tax=$&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;tax&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;7.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  route=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;route&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;ops_tax=$&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ops_tax&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="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;Want a queue sample you actually own? Pull wait from your logs. Adjust the pattern. This is a sketch.&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 only. Replace the file and field with your lane's logs.&lt;/span&gt;
&lt;span class="c"&gt;# Do not pretend a missing log is a zero wait.&lt;/span&gt;

&lt;span class="nb"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'
  /queue_wait_ms/ {
    n++
    sum += $2
  }
  END {
    if (n &amp;lt; 20) {
      print "not enough samples; do not route on this"
      exit 2
    }
    print n, "samples, avg_min=", sum / n / 60000
  }
'&lt;/span&gt; /var/log/ai-lane/queue.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you do not have logs, you do not have Q. You have folklore. Folklore always says the free lane is fine.&lt;/p&gt;

&lt;p&gt;Need a rough split of work types before you fill PRs/week? Use your own tree. This is not a quality metric. It is a mix input.&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: last week's path hits, not a productivity score.&lt;/span&gt;
git log &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'2026-09-15'&lt;/span&gt; &lt;span class="nt"&gt;--name-only&lt;/span&gt; &lt;span class="nt"&gt;--pretty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;format: |
  &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'^(docs|internal|billing|auth)/'&lt;/span&gt; |
  &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s#/.*##'&lt;/span&gt; |
  &lt;span class="nb"&gt;sort&lt;/span&gt; | &lt;span class="nb"&gt;uniq&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tiny routing policy beats a wiki paragraph. Expire it.&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;# Proposal: commit next to the architecture decision record.&lt;/span&gt;
&lt;span class="c1"&gt;# Owner: platform EM. Expires: 2026-10-22.&lt;/span&gt;

&lt;span class="na"&gt;mix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platform-em"&lt;/span&gt;
  &lt;span class="na"&gt;expires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-10-22"&lt;/span&gt;
  &lt;span class="na"&gt;review_channel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;#ai-mix"&lt;/span&gt;

&lt;span class="na"&gt;buckets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;commodity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;examples&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;docs"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;internal-tools"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fake-data-tests"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;lane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;free_hosted&lt;/span&gt;
    &lt;span class="na"&gt;boundary&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;boundary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;examples&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;billing"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auth"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;migrations"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer-payloads"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;lane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;self_hosted_or_none&lt;/span&gt;
    &lt;span class="na"&gt;boundary&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;burst&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;examples&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;launch-week"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;incident-window"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;lane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reserved&lt;/span&gt;
    &lt;span class="na"&gt;expire_with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&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;freeze&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;calendar"&lt;/span&gt;

&lt;span class="na"&gt;hard_gates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;customer&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;code&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;shared&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="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mix&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;named&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;owner"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;open-ended&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;burst&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;exceptions"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hard gates, owner, expiry, exit
&lt;/h2&gt;

&lt;p&gt;Gates are yes/no. Scores are for debate.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Boundary gate.&lt;/strong&gt; If B is yes, the free shared lane is illegal for that work. Do not average it with queue tax.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sample gate.&lt;/strong&gt; If you have fewer than 20 wait samples in a week, you may pilot. You may not declare the mix “working.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owner gate.&lt;/strong&gt; One named human renews the YAML. A rotation is fine. “The platform team” is not a name.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry gate.&lt;/strong&gt; Thirty days, then the exception archives. Burst lanes die with the freeze, not with “we will revisit.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit gate.&lt;/strong&gt; To leave a bucket on free, queue tax must stay below the next alternative for three weeks, and B stays no. To leave self-host, H must stay staffed. If H disappears, AI on Bucket B disappears with it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Archive rule: when you change a route, keep the old YAML in git. Future-you will ask why billing ever sat on the free lane. Show them the date, not a Slack myth.&lt;/p&gt;

&lt;p&gt;Pilot rule: run the card for one planning cycle on two work types only. Commodity plus one boundary path. If you cannot keep the YAML honest for that, you will not keep it honest for a company-wide rollout.&lt;/p&gt;

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

&lt;p&gt;Do not run a three-bucket mix if you are a two-person shop with no customer data and no queue. You will spend more hours on the card than on the product. Stay on a free lane and write a one-line boundary rule.&lt;/p&gt;

&lt;p&gt;Do not self-host because the invoice is $0 and that feels suspicious. Idle ops hours are a real cost. If nobody can own H, you are buying a second incident surface.&lt;/p&gt;

&lt;p&gt;Do not use this if legal already mandated a private cluster. The mix collapsed to Bucket B. Fill the YAML anyway so people stop sneaking commodity work onto the expensive box.&lt;/p&gt;

&lt;p&gt;And do not treat my placeholder rates as your rates. If R and S are guesses, the table is theater.&lt;/p&gt;

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

&lt;p&gt;This card ignores model quality. A free lane that is empty and wrong is still wrong. It ignores token stickers on purpose. Stickers do not capture stacked seniors. It ignores hiring effects. If juniors only ship from a lane nobody can review, you have a different problem, and a routing table will not save you.&lt;/p&gt;

&lt;p&gt;I also cannot certify any vendor’s uptime, quota, or hardware from this chair. Free hosted options change. That is why expiry exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question that actually matters
&lt;/h2&gt;

&lt;p&gt;Would you still keep docs and billing on the same free lane if Q for bursts doubled next week?&lt;/p&gt;

&lt;p&gt;If yes, your binding constraint is not money. It is probably H, or a boundary rule you have not written down.&lt;/p&gt;

&lt;p&gt;If no, write the three buckets this afternoon. Put an expiry on the YAML. Name an owner. Then decide whether the commodity bucket rides a free hosted option.&lt;/p&gt;

&lt;p&gt;Which variable would reverse your mix this month — queue minutes, ops hours, or the boundary flag? Write that variable under the table before you change a lane.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>management</category>
    </item>
    <item>
      <title>Price Free AI Capacity With Incident-Adjacent Share, Not Seat Count</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Mon, 21 Sep 2026 12:15:52 +0000</pubDate>
      <link>https://dev.to/bestbee/price-free-ai-capacity-with-incident-adjacent-share-not-seat-count-g9d</link>
      <guid>https://dev.to/bestbee/price-free-ai-capacity-with-incident-adjacent-share-not-seat-count-g9d</guid>
      <description>&lt;p&gt;Seat count called it free. In this labeled scene, 4 of 11 merged AI-assisted diffs last week touched a production path.&lt;/p&gt;

&lt;p&gt;That share is the number I want on the table. Not the token sticker. Not the seat. Once that share climbs, a free coding lane stops being a cheap experiment. It becomes an unpriced exception sitting on the incident path.&lt;/p&gt;

&lt;p&gt;Can your squad still defend that exception next Friday?&lt;/p&gt;

&lt;h2&gt;
  
  
  The scene that should reverse the call
&lt;/h2&gt;

&lt;p&gt;Labeled example, not a customer claim: a 12-person platform squad, public APIs in production, a free AI coding lane still on because nobody opened a purchase order.&lt;/p&gt;

&lt;p&gt;Friday, 4:40 p.m. On-call opens a 400-line diff. Tests are green. The author cannot narrate why the retry budget changed. The box that generated half the patch has no owner and no SLA.&lt;/p&gt;

&lt;p&gt;Would you keep that lane as a standing default? Or would you put a clock on it?&lt;/p&gt;

&lt;p&gt;I keep putting clocks on it. Seat count does not move incidents. Incident-adjacent share does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seat count is the wrong proxy
&lt;/h2&gt;

&lt;p&gt;Seats are easy to count. They do not tell you where prompts live, which paths diffs touch, who pays in review hours, or what breaks when the lane disappears mid-freeze.&lt;/p&gt;

&lt;p&gt;A free model and a free server can be the right &lt;em&gt;exception&lt;/em&gt;. They are a poor &lt;em&gt;standing budget line&lt;/em&gt; once the work is incident-adjacent.&lt;/p&gt;

&lt;p&gt;This ledger is a conversation tool. It is not objective truth. Move one threshold and the call can flip. That is the point. Write the reverse number before you argue about vendors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variable definitions
&lt;/h2&gt;

&lt;p&gt;Five fields. Fill them weekly. Expire the card.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Incident-adjacent share&lt;/td&gt;
&lt;td&gt;AI-assisted PRs that touch a production path / all merged AI-assisted PRs, trailing 14 days&lt;/td&gt;
&lt;td&gt;EM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fattest prompt class this week&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;public&lt;/code&gt; / &lt;code&gt;internal&lt;/code&gt; / &lt;code&gt;restricted&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Security + EM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Net review hours&lt;/td&gt;
&lt;td&gt;Reviewer hours on AI diffs minus hours you honestly think authors would have spent without the lane&lt;/td&gt;
&lt;td&gt;Review lead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Blocked hours if the lane is gone&lt;/td&gt;
&lt;td&gt;Hours of change-freeze or incident work that cannot proceed&lt;/td&gt;
&lt;td&gt;On-call&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Exception expiry&lt;/td&gt;
&lt;td&gt;A calendar date, never "until it feels fine"&lt;/td&gt;
&lt;td&gt;EM&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Starting gates I use as conversation numbers, not laws:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;D = restricted&lt;/code&gt; → a shared free lane is the wrong fit. Stop. Do not convert later as a workaround.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;S &amp;gt;= 0.30&lt;/code&gt; → the lane is on the incident path. Convert or kill. Do not quiet-keep.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;N &amp;gt; 0&lt;/code&gt; → review is costing more than the lane returns. Do not upgrade. Kill or retrain.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;B &amp;gt;= 4&lt;/code&gt; and there is no SLA → free shared capacity is the wrong fit for that window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which of those four would reverse &lt;em&gt;your&lt;/em&gt; call if I moved it?&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4-clock ledger
&lt;/h2&gt;

&lt;p&gt;Four clocks. Each one is &lt;code&gt;GREEN&lt;/code&gt; (keep the exception), &lt;code&gt;AMBER&lt;/code&gt; (shorten &lt;code&gt;E&lt;/code&gt;), or &lt;code&gt;RED&lt;/code&gt; (convert or kill).&lt;/p&gt;

&lt;h3&gt;
  
  
  Clock 1 — Data
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;GREEN&lt;/code&gt; if every prompt this week is &lt;code&gt;public&lt;/code&gt;. &lt;code&gt;AMBER&lt;/code&gt; if anything is &lt;code&gt;internal&lt;/code&gt;. &lt;code&gt;RED&lt;/code&gt; if anything is &lt;code&gt;restricted&lt;/code&gt; or you cannot classify it.&lt;/p&gt;

&lt;p&gt;Cannot classify is not &lt;code&gt;AMBER&lt;/code&gt;. It is &lt;code&gt;RED&lt;/code&gt;. Ambiguity is how exceptions become standing lines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clock 2 — Path
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;S&lt;/code&gt; is the clock. Production path means: auth, payments, data stores, deploy tooling, on-call runbooks, or anything that pages a human.&lt;/p&gt;

&lt;p&gt;Proposed measurement, unexecuted. Tag PRs. Then count.&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, not a run I am claiming.&lt;/span&gt;
&lt;span class="c"&gt;# Requires: gh auth, labels ai-assisted and prod-path on merged PRs.&lt;/span&gt;

&lt;span class="nv"&gt;SINCE&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; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'14 days ago'&lt;/span&gt; +%Y-%m-%dT%H:%M:%SZ&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;AI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;list &lt;span class="nt"&gt;--state&lt;/span&gt; merged &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"merged:&amp;gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SINCE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; label:ai-assisted"&lt;/span&gt; &lt;span class="nt"&gt;--limit&lt;/span&gt; 200 &lt;span class="nt"&gt;--json&lt;/span&gt; number &lt;span class="nt"&gt;--jq&lt;/span&gt; &lt;span class="s1"&gt;'length'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;PROD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gh &lt;span class="nb"&gt;pr &lt;/span&gt;list &lt;span class="nt"&gt;--state&lt;/span&gt; merged &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"merged:&amp;gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SINCE&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; label:ai-assisted label:prod-path"&lt;/span&gt; &lt;span class="nt"&gt;--limit&lt;/span&gt; 200 &lt;span class="nt"&gt;--json&lt;/span&gt; number &lt;span class="nt"&gt;--jq&lt;/span&gt; &lt;span class="s1"&gt;'length'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

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 os
ai = int(os.environ.get("AI", "0") or 0)
prod = int(os.environ.get("PROD", "0") or 0)
s = (prod / ai) if ai else None
print({"ai": ai, "prod": prod, "S": None if s is None else round(s, 2)})
&lt;/span&gt;&lt;span class="no"&gt;PY
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Export &lt;code&gt;AI&lt;/code&gt; and &lt;code&gt;PROD&lt;/code&gt; from those &lt;code&gt;gh&lt;/code&gt; calls, or paste the counts. If you cannot label, you cannot compute &lt;code&gt;S&lt;/code&gt;. Then Clock 2 is &lt;code&gt;RED&lt;/code&gt; until you can.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GREEN&lt;/code&gt; if &lt;code&gt;S &amp;lt; 0.15&lt;/code&gt;. &lt;code&gt;AMBER&lt;/code&gt; if &lt;code&gt;0.15 &amp;lt;= S &amp;lt; 0.30&lt;/code&gt;. &lt;code&gt;RED&lt;/code&gt; if &lt;code&gt;S &amp;gt;= 0.30&lt;/code&gt; or unlabeled.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clock 3 — Review net
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;N&lt;/code&gt; is messy. Say that out loud. Still write a number.&lt;/p&gt;

&lt;p&gt;I treat &lt;code&gt;N&lt;/code&gt; as &lt;code&gt;reviewer_hours_on_ai_diffs - avoided_author_hours&lt;/code&gt;. Both sides are estimates. Label them &lt;code&gt;est&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GREEN&lt;/code&gt; if &lt;code&gt;N &amp;lt;= -2&lt;/code&gt; (the lane returns at least two hours). &lt;code&gt;AMBER&lt;/code&gt; if &lt;code&gt;-2 &amp;lt; N &amp;lt;= 0&lt;/code&gt;. &lt;code&gt;RED&lt;/code&gt; if &lt;code&gt;N &amp;gt; 0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Do not convert a &lt;code&gt;RED&lt;/code&gt; review clock into a paid seat. Paying does not fix a workflow that reviewers already cannot narrate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Clock 4 — Uptime / blast
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;B&lt;/code&gt; is "hours we cannot move if this lane is dark during a freeze or a page."&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GREEN&lt;/code&gt; if &lt;code&gt;B &amp;lt; 1&lt;/code&gt;. &lt;code&gt;AMBER&lt;/code&gt; if &lt;code&gt;1 &amp;lt;= B &amp;lt; 4&lt;/code&gt;. &lt;code&gt;RED&lt;/code&gt; if &lt;code&gt;B &amp;gt;= 4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A free server with no named owner is not &lt;code&gt;GREEN&lt;/code&gt; just because it answered yesterday. Yesterday is not an SLA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Policy file the squad can argue with
&lt;/h2&gt;

&lt;p&gt;Hang this next to the CODEOWNERS file. If it is not in the repo, it is not a policy.&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;# exception-clock.yml — conversation tool, not a control plane&lt;/span&gt;
&lt;span class="na"&gt;exception&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform-em&lt;/span&gt;
  &lt;span class="na"&gt;expires_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-10-05&lt;/span&gt;
  &lt;span class="na"&gt;lane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;free-shared&lt;/span&gt;
&lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.36&lt;/span&gt;          &lt;span class="c1"&gt;# 4 / 11 in the filled example below&lt;/span&gt;
  &lt;span class="na"&gt;D&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;internal&lt;/span&gt;
  &lt;span class="na"&gt;N_hours&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3.5&lt;/span&gt;     &lt;span class="c1"&gt;# est; review heavier than avoided author time&lt;/span&gt;
  &lt;span class="na"&gt;B_hours&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
&lt;span class="na"&gt;gates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;S_red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.30&lt;/span&gt;
  &lt;span class="na"&gt;N_red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.0&lt;/span&gt;
  &lt;span class="na"&gt;B_red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4.0&lt;/span&gt;
  &lt;span class="na"&gt;D_red&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;restricted&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;unknown&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;exit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;kill_if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S above gate two trailing windows&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;D upgrades to restricted&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;author cannot narrate a prod-path diff during a page&lt;/span&gt;
  &lt;span class="na"&gt;convert_if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;S red and D is internal and N is green or amber&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;B red and the squad still wants the lane&lt;/span&gt;
  &lt;span class="na"&gt;keep_exception_if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;no clock red&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;owner named&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;expires_on in the future&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scorer you can run locally
&lt;/h2&gt;

&lt;p&gt;Proposed script. Not a benchmark. Not production telemetry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;

&lt;span class="n"&gt;GATES&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;S_red&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;N_red&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.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;B_red&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;D_RED&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;restricted&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;unknown&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;clock_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&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;d&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;D_RED&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;RED&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;d&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="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;AMBER&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;d&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="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;GREEN&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;RED&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;clock_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;GATES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S_red&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;RED&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;s&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.15&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;AMBER&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;GREEN&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;clock_review&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;GATES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;N_red&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;RED&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;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AMBER&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;GREEN&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;clock_blast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;GATES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B_red&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;RED&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;b&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="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;AMBER&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;GREEN&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;decide&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;clocks&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;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;clock_data&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;D&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;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;clock_path&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;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;review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;clock_review&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;N&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;blast&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;clock_blast&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;B&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;reds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;clocks&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;v&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;RED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;expired&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromisoformat&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;E&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;today&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;expired&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;data&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;reds&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;review&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;reds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KILL&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;reds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CONVERT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# path or blast red, data/review not blocking
&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;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KEEP_EXCEPTION&lt;/span&gt;&lt;span class="sh"&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;clocks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clocks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;example&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;S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;D&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;internal&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;N&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;E&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;2026-10-05&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;decide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On that filled row the path clock is &lt;code&gt;RED&lt;/code&gt;, review is &lt;code&gt;RED&lt;/code&gt;, blast is &lt;code&gt;RED&lt;/code&gt;, data is &lt;code&gt;AMBER&lt;/code&gt;. Action: &lt;code&gt;KILL&lt;/code&gt;. Paying does not repair a positive &lt;code&gt;N&lt;/code&gt;. Self-hosting does not repair an author who cannot narrate the diff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Filled example, then sensitivity
&lt;/h2&gt;

&lt;p&gt;All numbers below are illustrative. They are not a measured customer result and not a model benchmark.&lt;/p&gt;

&lt;p&gt;Squad P, 12 people, platform APIs. Trailing 14 days: 11 AI-assisted merges, 4 tagged &lt;code&gt;prod-path&lt;/code&gt;. &lt;code&gt;S = 0.36&lt;/code&gt;. &lt;code&gt;D = internal&lt;/code&gt;. &lt;code&gt;N = +3.5&lt;/code&gt; hours. &lt;code&gt;B = 6&lt;/code&gt; hours on the Friday deploy train. &lt;code&gt;E = 2026-10-05&lt;/code&gt;. Owner: the platform EM.&lt;/p&gt;

&lt;p&gt;Call: kill the standing free lane, or shrink it to non-prod paths with a new expiry. Do not convert first. Conversion is for a lane that is already net-negative on &lt;code&gt;N&lt;/code&gt; and still needed on the path.&lt;/p&gt;

&lt;p&gt;Now flip three knobs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;S&lt;/code&gt; drops to &lt;code&gt;2/11 ≈ 0.18&lt;/code&gt;, &lt;code&gt;N&lt;/code&gt; flips to &lt;code&gt;-4&lt;/code&gt;, and &lt;code&gt;B&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt; → clocks land &lt;code&gt;AMBER&lt;/code&gt; / &lt;code&gt;AMBER&lt;/code&gt; / &lt;code&gt;GREEN&lt;/code&gt; / &lt;code&gt;AMBER&lt;/code&gt;. Action: &lt;code&gt;KEEP_EXCEPTION&lt;/code&gt; until &lt;code&gt;E&lt;/code&gt;. Re-score on the expiry date, not in Slack.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;S&lt;/code&gt; stays &lt;code&gt;0.36&lt;/code&gt; but &lt;code&gt;N&lt;/code&gt; flips to &lt;code&gt;-5&lt;/code&gt; and &lt;code&gt;D&lt;/code&gt; stays &lt;code&gt;internal&lt;/code&gt; → review is no longer the blocker. Path and blast still &lt;code&gt;RED&lt;/code&gt;. Action: &lt;code&gt;CONVERT&lt;/code&gt; if the squad still wants the lane on prod paths.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;D&lt;/code&gt; becomes &lt;code&gt;restricted&lt;/code&gt; → &lt;code&gt;KILL&lt;/code&gt; on any other combination. Do not bargain with Clock 1.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Break-even on &lt;code&gt;S&lt;/code&gt;: I start the conversion talk at &lt;code&gt;0.30&lt;/code&gt;. If your on-call density is low and prod-path means "touches a helm chart once a quarter," your reverse number might be &lt;code&gt;0.50&lt;/code&gt;. Write it. If you will not write a reverse number, you are not using a gate. You are using a mood.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free vs paid vs self-host: fit, not vibes
&lt;/h2&gt;

&lt;p&gt;Same five variables. Three homes. Pick with the clocks, not with a catalog page.&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;Keep a free shared lane as an exception&lt;/th&gt;
&lt;th&gt;Convert to a paid lane&lt;/th&gt;
&lt;th&gt;Self-host&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;public, maybe internal with a short &lt;code&gt;E&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;internal, vendor DPA you actually read&lt;/td&gt;
&lt;td&gt;restricted, or you already cannot leave the boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;under your red gate&lt;/td&gt;
&lt;td&gt;at or above the gate, and you still want AI on those paths&lt;/td&gt;
&lt;td&gt;at or above the gate, and blast must stay inside your network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;must be green or you kill, you do not buy&lt;/td&gt;
&lt;td&gt;green or amber, with a named review ritual&lt;/td&gt;
&lt;td&gt;same; hosting does not teach narration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;under 4 hours, owner named&lt;/td&gt;
&lt;td&gt;you are buying an SLA, so write the SLA hours into &lt;code&gt;B&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;you are buying ops load; add on-call hours into &lt;code&gt;N&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;14–28 days, written&lt;/td&gt;
&lt;td&gt;standing line with a quarterly kill review&lt;/td&gt;
&lt;td&gt;standing line with a capacity review&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Free is not cheaper. Price the exception in review hours and blocked hours. Paid is not safer. It is a different invoice plus whatever SLA you actually negotiate. Self-host is not automatically the grown-up move. It is the move when &lt;code&gt;D&lt;/code&gt; or &lt;code&gt;B&lt;/code&gt; cannot leave your boundary, and you already know who gets paged when the box dies.&lt;/p&gt;

&lt;p&gt;Hard rule I use: never convert a &lt;code&gt;KILL&lt;/code&gt; review clock into spend. Spend hides the mismatch. It does not close it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free-model, free-server option actually belongs
&lt;/h2&gt;

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

&lt;p&gt;If the honest call is &lt;code&gt;KEEP_EXCEPTION&lt;/code&gt;, you still need a lane that does not wait on a purchase order while the clocks run. An open-source coding assistant with free model access and a free server option is useful &lt;em&gt;as the exception under test&lt;/em&gt;. MonkeyCode is one such project. I would still hang &lt;code&gt;exception-clock.yml&lt;/code&gt; on the repo. I would still refuse restricted prompts. I would still expire &lt;code&gt;E&lt;/code&gt;. I would not treat the free server as an SLA.&lt;/p&gt;

&lt;p&gt;That is the whole product-shaped sentence. The ledger still decides.&lt;/p&gt;

&lt;h2&gt;
  
  
  Owner, expiry, exit, archive
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Owner.&lt;/strong&gt; The EM or platform lead who can kill the lane without a committee. If kill needs three directors, you do not have an exception. You have a zombie.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry.&lt;/strong&gt; 14 or 28 days, written in the YAML. No silent renewals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit.&lt;/strong&gt; Two trailing windows with &lt;code&gt;S&lt;/code&gt; above gate, or &lt;code&gt;D&lt;/code&gt; upgrades, or &lt;code&gt;N&lt;/code&gt; stays positive, or one page where the author cannot narrate a prod-path diff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Archive.&lt;/strong&gt; If you convert, keep the ledger and reset &lt;code&gt;E&lt;/code&gt; to the next quarter. If you kill, write one paragraph on why so the next squad does not reopen "but it's free" as a strategy.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Do not run this ledger if you have no production path, no merge labels, and no on-call. Individuals tinkering on throwaway branches do not need four clocks. Orgs that already banned AI on prod paths do not need a conversion talk. Security reviews are not replaced by a Python dict. If your real constraint is a legal hold, stop scoring and call counsel.&lt;/p&gt;

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

&lt;p&gt;&lt;code&gt;N&lt;/code&gt; is mushy. &lt;code&gt;S&lt;/code&gt; is only as good as your &lt;code&gt;prod-path&lt;/code&gt; label. The &lt;code&gt;0.30&lt;/code&gt; gate is a conversation number I can defend in a staff meeting, not a measured industry constant. I am not sourcing model names, token quotas, hardware, uptime, or permanence I cannot point at. A free server can vanish. That fact is why Clock 4 exists.&lt;/p&gt;

&lt;p&gt;The scorer will happily emit &lt;code&gt;KEEP_EXCEPTION&lt;/code&gt; if you feed it wishful inputs. Garbage &lt;code&gt;N&lt;/code&gt; in, confident action out. Treat the printout as minutes for a fight, not as proof.&lt;/p&gt;

&lt;p&gt;If I moved &lt;code&gt;S&lt;/code&gt; from &lt;code&gt;0.30&lt;/code&gt; to &lt;code&gt;0.50&lt;/code&gt;, would you keep the free lane as a standing default? If the answer changes, write your reverse number before the next Friday 4:40. That number, not the seat count, is the decision.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Should Your EM Graduate Off a Free AI Coding Lane? Use This 5-Gate Switching Card</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Sun, 20 Sep 2026 10:27:19 +0000</pubDate>
      <link>https://dev.to/bestbee/should-your-em-graduate-off-a-free-ai-coding-lane-use-this-5-gate-switching-card-oh4</link>
      <guid>https://dev.to/bestbee/should-your-em-graduate-off-a-free-ai-coding-lane-use-this-5-gate-switching-card-oh4</guid>
      <description>&lt;p&gt;If you cannot point to a kill date, you are not piloting a free AI coding lane. You are running a shadow default.&lt;/p&gt;

&lt;p&gt;Picture a capacity review, not a model bake-off. Finance froze headcount. Platform dropped a self-host doc in the shared drive. The squad already pastes stack traces into whichever chatbot loaded first this morning. Sound familiar?&lt;/p&gt;

&lt;p&gt;I do not start with which model is smarter. I start with which constraint would reverse the choice this quarter. Would you still keep the free lane if the kill date were next Friday?&lt;/p&gt;

&lt;h2&gt;
  
  
  This meeting is about switching cost
&lt;/h2&gt;

&lt;p&gt;Seat licenses feel precise. They are not.&lt;/p&gt;

&lt;p&gt;A paid seat you can turn off is often cheaper than a "free" lane nobody is allowed to kill. Self-hosting feels like control. It is also an idle bill: someone patches, watches the box, and answers "is it up?" at 6pm.&lt;/p&gt;

&lt;p&gt;I use a 5-gate switching card. It is a conversation tool, not objective truth. If your team cannot argue with the inputs, do not trust the output.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 5 gates
&lt;/h2&gt;

&lt;p&gt;I score three destinations with the same five questions: keep a sanctioned free lane, buy a vendor lane, or self-host.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Boundary.&lt;/strong&gt; Do prompts ever include non-public code, secrets, or customer data?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idle.&lt;/strong&gt; What do you pay when nobody is typing?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switch.&lt;/strong&gt; How many hours to leave without losing working context?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skill-retention.&lt;/strong&gt; Can the squad still ship if the lane dies on Friday?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Owner-expiry.&lt;/strong&gt; Named owner, calendar kill date, written exit?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If gate 1 fails for a hosted free lane, I stop. Cash does not get a vote.&lt;/p&gt;

&lt;h3&gt;
  
  
  Variable definitions
&lt;/h3&gt;

&lt;p&gt;Replace every number. The names are the method.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;B&lt;/code&gt; — boundary class: &lt;code&gt;public_only&lt;/code&gt;, &lt;code&gt;internal_ok&lt;/code&gt;, or &lt;code&gt;customer_data&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;H_idle&lt;/code&gt; — hours per week to keep a self-hosted lane healthy at zero use&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;C_hour&lt;/code&gt; — loaded cost of the person who does that idle work&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;P_seat&lt;/code&gt; — monthly vendor seat quote you actually have in writing&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;N&lt;/code&gt; — people who would get a seat&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;H_switch&lt;/code&gt; — hours to migrate prompts, policies, and "how we do this here"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;S&lt;/code&gt; — 1 if a named teammate can narrate and land a typical change with the lane offline&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;O&lt;/code&gt; — 1 if there is a named owner&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;E&lt;/code&gt; — 1 if expiry sits on a real calendar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Monthly idle drag of self-host, in cash terms:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;IDLE = H_idle * C_hour * 4.3&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Monthly paid cash:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PAID = P_seat * N&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I do not convert skill-retention into a fake ROI. I treat &lt;code&gt;S = 0&lt;/code&gt; as a hard stop on expanding any lane, free or not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Copy-paste policy, then a scorer
&lt;/h2&gt;

&lt;p&gt;Write the exception down before anyone pastes a repo. YAML is enough. Put it next to the other platform policies, not in a chat thread.&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;# ai_lane_exception.yaml — worked example, not a standard&lt;/span&gt;
&lt;span class="na"&gt;ai_coding_lane&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;exception&lt;/span&gt;
  &lt;span class="na"&gt;destination_candidates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sanctioned_free&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;vendor_paid&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;self_hosted&lt;/span&gt;
  &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platform-em"&lt;/span&gt;
  &lt;span class="na"&gt;expires_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-10-18"&lt;/span&gt;
  &lt;span class="na"&gt;boundary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;public_only&lt;/span&gt;
  &lt;span class="na"&gt;idle&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;max_hours_per_week&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;pager&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;platform-em"&lt;/span&gt;
  &lt;span class="na"&gt;exit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;revoke_keys&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;archive_prompts&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;freeze_new_repos&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;kill_triggers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;customer_data_in_prompt&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;owner_vacant_7d&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;expiry_with_no_renewal_note&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the numbers in the open, on a laptop, in the review. No dashboard required.&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;# switching_card.py
# Labeled example. Conversation tool, not a truth machine.
&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;Inputs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;boundary&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_only | internal_ok | customer_data
&lt;/span&gt;    &lt;span class="n"&gt;h_idle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;          &lt;span class="c1"&gt;# hours/week to keep self-host healthy at zero use
&lt;/span&gt;    &lt;span class="n"&gt;c_hour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;          &lt;span class="c1"&gt;# loaded $/hour for that work
&lt;/span&gt;    &lt;span class="n"&gt;p_seat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;          &lt;span class="c1"&gt;# monthly vendor quote — replace with yours
&lt;/span&gt;    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;                 &lt;span class="c1"&gt;# seats
&lt;/span&gt;    &lt;span class="n"&gt;h_switch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;        &lt;span class="c1"&gt;# hours to leave the current lane
&lt;/span&gt;    &lt;span class="n"&gt;skill_ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;         &lt;span class="c1"&gt;# can ship if the lane dies Friday
&lt;/span&gt;    &lt;span class="n"&gt;owner&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;expiry&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;hard_stops&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inputs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;stops&lt;/span&gt; &lt;span class="o"&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="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skill_ok&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;stops&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;skill-retention: do not expand any lane&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="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;stops&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;no owner: do not start or keep a lane&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="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expiry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;stops&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;no kill date: this is a shadow default&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;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boundary&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;stops&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;customer data: hosted free lane is out&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;stops&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inputs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;idle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h_idle&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_hour&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;4.3&lt;/span&gt;
    &lt;span class="n"&gt;paid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;p_seat&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;n&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;self_host_idle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;idle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vendor_paid&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;paid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;switch_hours&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h_switch&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;suggest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Inputs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;stops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hard_stops&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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;stops&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;stops&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;stops&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&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_switch_yet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;monthly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Heuristic, not a law. Move the 0.6 if your ops reality is different.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boundary&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_only&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;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;h_switch&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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;call&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;keep_sanctioned_free_as_exception&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;math&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&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_host_idle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vendor_paid&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="mf"&gt;0.6&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;boundary&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_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;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;call&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_host&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;math&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="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;call&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;vendor_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;math&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="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;example&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inputs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;boundary&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_only&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;h_idle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;6.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;c_hour&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;95.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;p_seat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;40.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# ILLUSTRATIVE — paste your quote
&lt;/span&gt;        &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;h_switch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;12.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;skill_ok&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;owner&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;expiry&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;hard_stops&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example&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;monthly&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example&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;suggest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 switching_card.py
&lt;span class="c"&gt;# then put expires_on on a calendar the owner actually sees&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you cannot run that in five minutes, you do not have inputs. You have opinions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example (composite, not a client)
&lt;/h2&gt;

&lt;p&gt;Eight engineers. B2B product. The monorepo holds customer code. Finance wants "the free thing." Platform wants a box in the VPC. The squad wants whatever answers first.&lt;/p&gt;

&lt;p&gt;I fill the card in the room:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value on the whiteboard&lt;/th&gt;
&lt;th&gt;Why it is not a vibe&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;customer_data&lt;/code&gt; for the monorepo, &lt;code&gt;public_only&lt;/code&gt; for a sample sandbox&lt;/td&gt;
&lt;td&gt;Mixed boundaries are two lanes, not one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;H_idle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;6 hours/week&lt;/td&gt;
&lt;td&gt;Patch, queue, "is it up?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C_hour&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$95 loaded&lt;/td&gt;
&lt;td&gt;Staff-engineer time, not a cloud list price&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;P_seat&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;$40&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Illustrative.&lt;/strong&gt; Replace with the quote in your inbox&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;N&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;People who would actually get seats&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;H_switch&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;Prompt library, review rules, onboarding doc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;S&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;unknown until a Friday drill&lt;/td&gt;
&lt;td&gt;I do not assume yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;O&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;platform EM&lt;/td&gt;
&lt;td&gt;If this is blank, stop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2026-10-18&lt;/td&gt;
&lt;td&gt;Four weeks, then renew or kill&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do the arithmetic.&lt;/p&gt;

&lt;p&gt;Self-host idle ≈ 6 × 95 × 4.3 = &lt;strong&gt;$2,451 / month&lt;/strong&gt; before any model bill. Vendor cash ≈ 40 × 8 = &lt;strong&gt;$320 / month&lt;/strong&gt; at the illustrative rate. The free hosted lane is $0 cash. It is also out for the monorepo under gate 1, because &lt;code&gt;B = customer_data&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the real choice is not "free vs paid vs self-host" as a slogan. It is a &lt;code&gt;public_only&lt;/code&gt; sandbox on a sanctioned free lane, and a different destination for the monorepo. Would you still self-host if idle is six hours a week and paid seats are a few hundred dollars? I would not. Not this quarter.&lt;/p&gt;

&lt;p&gt;Change one input. If they already operate a box and &lt;code&gt;H_idle&lt;/code&gt; drops to 1, idle ≈ $408. Self-host starts to talk. That is the point of sensitivity. One field should be allowed to reverse you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hard gates, owner, expiry, exit
&lt;/h2&gt;

&lt;p&gt;I write these as rules, not culture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard gates&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customer data or secrets in prompts → hosted free lane is out. No exception by enthusiasm.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;S = 0&lt;/code&gt; after a Friday drill → freeze expansion on every lane.&lt;/li&gt;
&lt;li&gt;Vacant owner for 7 days → revoke.&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;expires_on&lt;/code&gt; → do not start.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Owner.&lt;/strong&gt; One human. Not "platform." A calendar they look at.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expiry.&lt;/strong&gt; A date. Renewal needs a written note: which field changed, and which destination you are switching to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exit.&lt;/strong&gt; Revoke keys. Archive prompts. Freeze new repos. Say out loud what you will forget — that is the switching cost you underpriced last time.&lt;/p&gt;

&lt;p&gt;A scorecard that cannot kill the lane is a poster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a sandbox free lane actually fits
&lt;/h2&gt;

&lt;p&gt;I want a place to practice the card on sample code before anyone touches the monorepo. That is a different job from production coding.&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. I treat that combination as exception infrastructure: public or synthetic repos, a named owner, a kill date. It is one way to keep the sandbox off the customer boundary while you learn whether &lt;code&gt;S&lt;/code&gt; is even true. It is not a reason to skip gate 1.&lt;/p&gt;

&lt;p&gt;If the sandbox cannot expire, it is not a sandbox.&lt;/p&gt;

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

&lt;p&gt;Skip the card if you are shopping for a model leaderboard. Skip it if you need a permanent free production agent. Skip it if you cannot instrument idle hours, even roughly.&lt;/p&gt;

&lt;p&gt;Regulated shops with a written data-residency rule already know gate 1. Do not dilute that rule with a spreadsheet. Tiny teams of two who share one laptop may not need three destinations. Name an owner and a date anyway. The meeting is still the same meeting.&lt;/p&gt;

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

&lt;p&gt;I did not benchmark models. I did not measure your token bill. The $40 seat and $95 hour are labeled placeholders, not market facts.&lt;/p&gt;

&lt;p&gt;The heuristic that self-host "wins" below 60% of paid cash is an argument starter. Move it. If your ops hours are unpaid heroics, &lt;code&gt;C_hour&lt;/code&gt; is a lie and the card will flatter self-hosting. This article will rot if you treat the worked numbers as research.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would reverse you?
&lt;/h2&gt;

&lt;p&gt;I end reviews with one question. Not "would you buy." Not "is free good."&lt;/p&gt;

&lt;p&gt;Which single field — boundary, idle hours, switching hours, skill-retention, or expiry — would reverse your destination this quarter?&lt;/p&gt;

&lt;p&gt;If you cannot name it, you are not deciding. You are hoping the shadow default holds.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>career</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Should Your Squad Keep a Free AI Lane When Green Tests Stop Meaning Done? Use This False-Done Gate</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Sat, 19 Sep 2026 08:46:38 +0000</pubDate>
      <link>https://dev.to/bestbee/should-your-squad-keep-a-free-ai-lane-when-green-tests-stop-meaning-done-use-this-false-done-gate-3cpl</link>
      <guid>https://dev.to/bestbee/should-your-squad-keep-a-free-ai-lane-when-green-tests-stop-meaning-done-use-this-false-done-gate-3cpl</guid>
      <description>&lt;p&gt;Nine of the last twelve AI-touched pull requests on the board were green. Two of them still shipped a path no test executed. That ratio can reverse a spend decision faster than any token invoice.&lt;/p&gt;

&lt;p&gt;I'm treating this as a composite squad, not a war story. If your numbers differ, the card still works. Would you keep the free lane, isolate the sensitive work, or exit generation on that surface entirely?&lt;/p&gt;

&lt;p&gt;Most teams start in the wrong meeting. They argue free versus paid, or free versus self-hosted, before they can say what "done" meant last week. I don't. I want a field that can fail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The standup that should have been a stop
&lt;/h2&gt;

&lt;p&gt;Picture Tuesday. A service owner pastes a diff that reads complete. CI is green. The reviewer asks one question: which test hits the new branch?&lt;/p&gt;

&lt;p&gt;Silence. Then a follow-up commit. Then another. The original PR was not unfinished in the Git sense. It was unfinished in the evidence sense. That is the leak I score.&lt;/p&gt;

&lt;p&gt;Throughput looked fine. Review comments looked polite. The team still could not reproduce the claim without the author in the room. If that is your week, buying a bigger lane will not fix it. It will only make false-done cheaper.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stop pricing the lane before you define false-done
&lt;/h2&gt;

&lt;p&gt;A free coding lane is a capacity choice. It is also a governance choice. Mixing those two debates is how platform leads buy isolation they did not need, or keep a shared lane they cannot defend.&lt;/p&gt;

&lt;p&gt;I use four outcomes, not two:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep&lt;/strong&gt; the free lane for that surface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Split&lt;/strong&gt;: free for scratch, isolated for anything with data, secrets, or production blast radius.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit&lt;/strong&gt; generation on that surface until evidence holds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Park&lt;/strong&gt; the decision with an expiry, not a vibe.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Paid and self-hosted sit inside Split or Exit. They are not a personality. They are a response to a gate you can fail.&lt;/p&gt;

&lt;p&gt;This scorecard is a conversation tool, not objective truth. If nobody on the squad can name the variable that would reverse Keep, you are not deciding. You are decorating a preference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the variables before anyone scores
&lt;/h2&gt;

&lt;p&gt;I will not score a lane with undefined nouns. Write these on the wiki first.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;False-done rate (FDR).&lt;/strong&gt; Share of AI-touched PRs in the sample that merged or were marked ready, then needed a follow-up because a generated path was untested, unreproducible, or unexplained. Count the PR, not the commit spam.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evidence lag (EL).&lt;/strong&gt; Hours from "looks done" until a &lt;em&gt;named&lt;/em&gt; owner can reproduce the claim without the author. If the owner is "the team," EL is infinite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boundedness (B).&lt;/strong&gt; Share of generated branches, handlers, or jobs that a test, a recorded manual reproduction, or a failing fixture actually hits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation need (I).&lt;/strong&gt; Binary for the surface: does policy forbid prompts, code, or tool output on a shared free server? If yes, Keep is already illegal. Do not score taste.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switch cost (SC).&lt;/strong&gt; Hours to stand up an isolated lane (vendor or self-host) &lt;em&gt;and&lt;/em&gt; move the evidence template with it. Exclude catalogue shopping. Include review, secrets, and rollback notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sample window (W).&lt;/strong&gt; Consecutive calendar days, not "busy week." I default to 14. Shorter windows lie. Longer windows hide the fire.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tag AI-touched PRs in the description or a label. If you cannot tag them, you cannot compute FDR. That is a process bug, not a model bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4-gate false-done card
&lt;/h2&gt;

&lt;p&gt;Copy this. Fill it in a doc, not in Slack.&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;# false-done-gate.v1.yaml&lt;/span&gt;
&lt;span class="c1"&gt;# Conversation tool. Not a procurement score.&lt;/span&gt;
&lt;span class="na"&gt;surface&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-webhooks&lt;/span&gt;  &lt;span class="c1"&gt;# one surface per card&lt;/span&gt;
&lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;em-payments&lt;/span&gt;          &lt;span class="c1"&gt;# named human, not a rotation&lt;/span&gt;
&lt;span class="na"&gt;window_days&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;14&lt;/span&gt;
&lt;span class="na"&gt;expiry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-10-17&lt;/span&gt;          &lt;span class="c1"&gt;# 28 days from decision, not "next quarter"&lt;/span&gt;
&lt;span class="na"&gt;sample&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ai_touched_prs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;
  &lt;span class="na"&gt;false_done_prs&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;fdr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.167&lt;/span&gt;                &lt;span class="c1"&gt;# 2 / 12&lt;/span&gt;
  &lt;span class="na"&gt;evidence_lag_hours_p50&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6&lt;/span&gt;
  &lt;span class="na"&gt;boundedness&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.75&lt;/span&gt;         &lt;span class="c1"&gt;# 9 / 12 had a hit on the new path&lt;/span&gt;
  &lt;span class="na"&gt;isolation_need&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;     &lt;span class="c1"&gt;# policy check, not preference&lt;/span&gt;
  &lt;span class="na"&gt;switch_cost_hours&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16&lt;/span&gt;
&lt;span class="na"&gt;gates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;fdr_max&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.20&lt;/span&gt;             &lt;span class="c1"&gt;# fail closed if FDR &amp;gt; 20%&lt;/span&gt;
  &lt;span class="na"&gt;el_max_hours&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;           &lt;span class="c1"&gt;# fail if p50 evidence lag &amp;gt; 8h&lt;/span&gt;
  &lt;span class="na"&gt;boundedness_min&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.70&lt;/span&gt;     &lt;span class="c1"&gt;# fail if &amp;lt; 70% of generated paths are hit&lt;/span&gt;
  &lt;span class="na"&gt;isolation_must_pass&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;outcome&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;keep&lt;/span&gt;               &lt;span class="c1"&gt;# keep | split | exit | park&lt;/span&gt;
&lt;span class="na"&gt;exit_criteria&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FDR&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0.20&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;any&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;completed&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;window"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;EL&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;p50&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;8h&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;two&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;windows"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;isolation_need&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;flips&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;span class="na"&gt;reversal_question&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Which&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;single&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;field,&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;it&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;flipped,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;would&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;kill&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Keep?"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hard reading order. Do not average the fields.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Isolation gate.&lt;/strong&gt; If &lt;code&gt;I&lt;/code&gt; is true, Keep is forbidden. Split or Exit. Stop scoring FDR as a way to smuggle a policy exception.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FDR gate.&lt;/strong&gt; If FDR is above your max, you do not have a capacity problem. You have an evidence problem. Exit generation on that surface, or Split so the messy work cannot hide in the same queue as production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boundedness + lag gate.&lt;/strong&gt; If B is below the floor &lt;em&gt;or&lt;/em&gt; EL blows the cap, Keep only if the owner can name a two-week fix. Otherwise Park with expiry.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switch-cost gate.&lt;/strong&gt; Buy or self-host only when gates 1–3 already demand isolation &lt;em&gt;and&lt;/em&gt; SC is lower than the evidence debt you are already paying. Evidence debt, roughly: &lt;code&gt;false_done_prs * (EL hours + re-review hours)&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Would a cheaper token price reverse Exit? It should not. Price does not create a test hit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example, then I break it
&lt;/h2&gt;

&lt;p&gt;Illustrative numbers. Not a benchmark. Not a customer.&lt;/p&gt;

&lt;p&gt;A payments-webhooks squad, 14-day window, 12 AI-touched PRs, 2 false-done. FDR = 16.7%. Evidence lag p50 = 6 hours. Boundedness = 75%. Isolation need = false. Switch cost to an isolated lane = 16 hours. Re-review on each false-done ≈ 3 hours.&lt;/p&gt;

&lt;p&gt;Evidence debt in the window: &lt;code&gt;2 * (6 + 3) = 18 hours&lt;/code&gt;. Switch cost is 16 hours. Close, right? Not yet. Isolation need is false, FDR is under 20%, lag is under 8, boundedness is over 70%. &lt;strong&gt;Keep.&lt;/strong&gt; The 16-hour migrate would buy a feeling, not a gate.&lt;/p&gt;

&lt;p&gt;Now flip one field. Same squad, isolation need becomes true because webhook payloads include customer identifiers that cannot sit on a shared free server. Outcome is &lt;strong&gt;Split&lt;/strong&gt; on the same afternoon. FDR did not move. Policy did.&lt;/p&gt;

&lt;p&gt;Flip a different field. Isolation stays false, but false-done PRs are 4 of 12. FDR = 33%. Evidence debt: &lt;code&gt;4 * 9 = 36 hours&lt;/code&gt;. &lt;strong&gt;Exit&lt;/strong&gt; generation on that surface until boundedness recovers. Do not "upgrade" the lane so people can miss tests faster.&lt;/p&gt;

&lt;p&gt;Sensitivity I actually walk:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Knob you change&lt;/th&gt;
&lt;th&gt;Keep still holds?&lt;/th&gt;
&lt;th&gt;What I ask next&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FDR 17% → 25%&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Which paths were unhit? Exit or Split, not spend.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EL 6h → 12h&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Name an owner. If you cannot, Park.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B 75% → 60%&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Add reproduction notes before any vendor talk.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;I false → true&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Split today. Free scratch can remain.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SC 16h → 40h&lt;/td&gt;
&lt;td&gt;Yes, if I is false&lt;/td&gt;
&lt;td&gt;Do not migrate to soothe anxiety.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;W 14d → 5d&lt;/td&gt;
&lt;td&gt;Invalid&lt;/td&gt;
&lt;td&gt;Refuse the card. Sample is too short.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If FDR is the field that reverses you, you were never in a build-versus-buy meeting. You were in a test-design meeting wearing a procurement hat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commands to count false-done without inventing dashboards
&lt;/h2&gt;

&lt;p&gt;I want the sample in git, not in memory. Label this as a method you can copy. It is not production telemetry, and it will lie if you skip labels.&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;# Last 14 days of merged PRs that someone tagged as AI-touched.&lt;/span&gt;
&lt;span class="c"&gt;# Requires GitHub CLI. Adjust the label to whatever you actually use.&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;list &lt;span class="nt"&gt;--state&lt;/span&gt; merged &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"label:ai-touched merged:&amp;gt;=2026-09-05"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--json&lt;/span&gt; number,title,mergedAt,url,labels &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/ai-prs.json

&lt;span class="c"&gt;# Follow-up commits on the same paths in 72h often signal false-done.&lt;/span&gt;
&lt;span class="c"&gt;# This is a heuristic. Read the PR. Do not let the script merge for you.&lt;/span&gt;
git log &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'14 days ago'&lt;/span&gt; &lt;span class="nt"&gt;--pretty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;format:&lt;span class="s1"&gt;'%h %ad %s'&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;short &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s1"&gt;'*.py'&lt;/span&gt; &lt;span class="s1"&gt;'*.ts'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tiny scorer you can run after you classify each PR by hand. Classification is the work. The script only refuses a missing denominator.&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;# proposal: score a window you already classified
# fdr = false_done / ai_touched; fail closed on empty sample
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;false_done_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ai_touched&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;false_done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&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;ai_touched&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;empty sample; do not score&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;false_done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;false_done&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ai_touched&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;false_done must sit inside ai_touched&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;false_done&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;ai_touched&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fdr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fdr_max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.20&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="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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fdr&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;fdr_max&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;pass&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;__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;fdr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;false_done_rate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ai_touched&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;false_done&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fdr&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;fdr&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;gate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fdr&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you will not classify PRs by hand for two weeks, do not run a free lane at production blast radius. You cannot see FDR. You are guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  A PR template that makes boundedness visible
&lt;/h2&gt;

&lt;p&gt;I want the evidence in the PR, not in a hallway. Paste this under the diff.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Evidence (AI-touched)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Generated paths listed (file + function / job name)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Test or fixture that hits each path, &lt;span class="ge"&gt;*or*&lt;/span&gt; a recorded reproduction
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Named owner who can re-run that claim without the author
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Data / secrets in the prompt: none | redacted | blocked (isolation)
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Follow-up PR expected? no | yes, ticket id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the checklist is empty and CI is green, that is a false-done candidate. Green is not done. Green is "the tests you already had did not scream."&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free model lane still earns Keep
&lt;/h2&gt;

&lt;p&gt;Some squads need a scratch lane to &lt;em&gt;measure&lt;/em&gt; FDR before they pay for isolation. That is a real job. It is not a brand preference.&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 coding tool with free model access and a free server option. I treat those as availability facts, not as a bake-off. I will not invent model names, quotas, hardware, or permanence. If a free shared server cannot hold your prompts, Isolation need is already true. The product does not get a vote.&lt;/p&gt;

&lt;p&gt;Use a free lane when all of this is true:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolation need is false for that surface.&lt;/li&gt;
&lt;li&gt;You will tag AI-touched PRs and run the 14-day window.&lt;/li&gt;
&lt;li&gt;The owner can fail Keep.&lt;/li&gt;
&lt;li&gt;Scratch work and production work are not one queue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want a place to run the card without buying capacity first, that free model access and free server option are one way to do the measurement. The card still owns the decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Owner, expiry, exit
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Owner.&lt;/strong&gt; Engineering manager or platform lead for the surface. Not "AI champions." Champions do not revoke lanes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry.&lt;/strong&gt; 28 days, written on the YAML. If the card is not re-scored, the lane Parks. Park is not Keep with worse lighting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit.&lt;/strong&gt; Any completed window with FDR above max, EL above cap for two windows, or Isolation need flipping to true. Exit means generation stops on that surface until boundedness recovers. It does not mean a angry all-hands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Archive.&lt;/strong&gt; Keep the YAML. Future you will try to remember why you Split. Future you is a liar.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Do not run a free shared lane, including a free server, if legal already forbids prompts or code leaving your boundary. Do not use this card to launder that exception.&lt;/p&gt;

&lt;p&gt;Do not use it if you refuse to label AI-touched PRs. The math needs a denominator.&lt;/p&gt;

&lt;p&gt;Do not use it as a model beauty contest. There are no latency tables here on purpose. If your question is "which weights are hottest this week," you are in a different article.&lt;/p&gt;

&lt;p&gt;Do not use it for a two-person hobby repo with no reviewer. FDR collapses into self-grade. Be honest and skip the theater.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations, said plainly
&lt;/h2&gt;

&lt;p&gt;FDR depends on how strict you are when you classify follow-ups. Two reviewers will disagree on the edge. Write the rule: unhit path, unreproducible claim, or missing owner. Not "I did not like the style."&lt;/p&gt;

&lt;p&gt;A 14-day window can miss a rare surface. A 90-day window can hide a bad week under a good month. If the blast radius is high, shorten the &lt;em&gt;decision&lt;/em&gt; loop, not the sample until it flatters you.&lt;/p&gt;

&lt;p&gt;Switch cost is local. My 16-hour example is illustrative. Your procurement, your SSO, your secret broker. Fill the number. Do not borrow mine.&lt;/p&gt;

&lt;p&gt;Free lanes change. Availability is not a contract I can sign for you. Re-score when the lane you measured is not the lane you have.&lt;/p&gt;

&lt;p&gt;And tests can be as outdated as the generation they fail to bound. If AI output routinely steps around the assertions you still worship, FDR will look fine while production will not. Boundedness is about hitting the new path, not collecting more of the old green.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question that actually closes the meeting
&lt;/h2&gt;

&lt;p&gt;I do not care whether you "believe in" a free lane. Belief does not reverse.&lt;/p&gt;

&lt;p&gt;Which field on your card, if it flipped this week, would kill Keep: FDR, evidence lag, boundedness, or isolation need? If you cannot name it, you are not choosing. You are hoping the next green build means done. It might not.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>career</category>
    </item>
    <item>
      <title>Should Your Squad Keep a Free AI Lane When Nobody Can Narrate the Diff? Use This Ownership Half-Life Gate</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Fri, 18 Sep 2026 06:51:32 +0000</pubDate>
      <link>https://dev.to/bestbee/should-your-squad-keep-a-free-ai-lane-when-nobody-can-narrate-the-diff-use-this-ownership-342l</link>
      <guid>https://dev.to/bestbee/should-your-squad-keep-a-free-ai-lane-when-nobody-can-narrate-the-diff-use-this-ownership-342l</guid>
      <description>&lt;p&gt;The standup looked calm. Then I asked the only question that matters for a free AI coding lane.&lt;/p&gt;

&lt;p&gt;"Can you narrate this diff without the chat log?"&lt;/p&gt;

&lt;p&gt;Nobody could. Twelve minutes to generate. Forty minutes of shrugs. If that ratio holds, the free server is already more expensive than a quieter paid lane. Would you keep it anyway?&lt;/p&gt;

&lt;p&gt;This is a composite from platform reviews, not a customer case. I still use it because the constraint is real. Generation got cheap. Ownership did not.&lt;/p&gt;

&lt;h2&gt;
  
  
  The decision this gate is for
&lt;/h2&gt;

&lt;p&gt;You are not choosing a mascot. You are choosing one of four moves for a squad that already touches a free AI coding path:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep&lt;/strong&gt; the free hosted models and free server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move&lt;/strong&gt; to self-hosted or paid, but only if ownership actually improves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pilot&lt;/strong&gt; a tighter lane with an expiry date.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop&lt;/strong&gt; the lane and return the work to human-owned slices.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The 2026 argument around "vibe coding" keeps collapsing into a culture war. I care about a narrower product question. When does unowned generation become a P&amp;amp;L leak?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why free-server uptime is the wrong unit
&lt;/h2&gt;

&lt;p&gt;Uptime is a vanity metric here. A box that is "always on" can still ship diffs that die in review, or land and then cannot be explained on a Sev-2 call.&lt;/p&gt;

&lt;p&gt;Ask yourself: if the author left tomorrow, how many days until the squad can still reconstruct &lt;em&gt;why&lt;/em&gt; the change exists?&lt;/p&gt;

&lt;p&gt;I call that &lt;strong&gt;ownership half-life&lt;/strong&gt;. It is a conversation tool, not a law of physics. Treat every number below as a proposal you should replace with your own logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variable definitions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;G&lt;/strong&gt; — generation minutes for a change, from first prompt to a mergeable diff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E&lt;/strong&gt; — explanation minutes: time for the author to teach the change to a teammate who was not in the session, with the chat log closed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;H&lt;/strong&gt; — ownership half-life in days: how long until a typical teammate can no longer reconstruct intent without the original thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;R&lt;/strong&gt; — rehearsal success: &lt;code&gt;1&lt;/code&gt; if the author can re-derive the change from the ticket and the diff alone, else &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B&lt;/strong&gt; — blast radius: count of production services or data classes the diff can break.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;X&lt;/strong&gt; — unexplained-diff budget remaining this sprint.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Derived:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explanation ratio&lt;/strong&gt; &lt;code&gt;Q = E / G&lt;/code&gt;. If &lt;code&gt;Q &amp;gt; 1&lt;/code&gt;, generation is not the bottleneck. Teaching is.&lt;/li&gt;
&lt;li&gt;There is no magic weighted score. Hard gates beat averages that hide one ugly PR.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The ownership half-life gate
&lt;/h2&gt;

&lt;p&gt;Run this on &lt;strong&gt;five merged PRs&lt;/strong&gt;, not on a demo. If you only sample the pretty one, you already decided to keep the lane.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Keep the free lane&lt;/th&gt;
&lt;th&gt;Move, split, or stop&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Q = E/G&lt;/td&gt;
&lt;td&gt;Q ≤ 1.5 on at least 4/5 PRs&lt;/td&gt;
&lt;td&gt;Q &amp;gt; 1.5 on 2+ PRs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;Rehearsal succeeds on 4/5&lt;/td&gt;
&lt;td&gt;Two failures in five&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;H&lt;/td&gt;
&lt;td&gt;Half-life ≥ 10 calendar days&lt;/td&gt;
&lt;td&gt;Half-life &amp;lt; one sprint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B&lt;/td&gt;
&lt;td&gt;B ≤ 1, or B ≥ 2 only with a written owner&lt;/td&gt;
&lt;td&gt;B ≥ 2 with no named owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;td&gt;Unexplained diffs still inside budget&lt;/td&gt;
&lt;td&gt;Budget already spent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If any hard gate fails, you do not "optimize prompts." You change the lane. Paid and self-hosted options only win if they change Q, R, or H. Faster tokens that raise Q are a loss.&lt;/p&gt;

&lt;p&gt;Which threshold would reverse &lt;em&gt;your&lt;/em&gt; call? If you cannot name it, you are shopping, not deciding.&lt;/p&gt;

&lt;h2&gt;
  
  
  A filled example (labeled, not measured in your shop)
&lt;/h2&gt;

&lt;p&gt;Squad: four backend engineers, two-week sprint, one shared free coding server for non-prod work. I filled the rows so we can argue about thresholds, not vibes.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PR&lt;/th&gt;
&lt;th&gt;G (min)&lt;/th&gt;
&lt;th&gt;E (min)&lt;/th&gt;
&lt;th&gt;Q&lt;/th&gt;
&lt;th&gt;R&lt;/th&gt;
&lt;th&gt;B&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;auth retry&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;0.78&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Ticket was clear&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cache stampede&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;td&gt;3.44&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Author could not re-derive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSV export&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;0.55&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Fine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;feature flag default&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;td&gt;4.00&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;"The model suggested it"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;log sampling&lt;/td&gt;
&lt;td&gt;15&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;1.07&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Borderline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two PRs already fail Q and R. Blast radius is 2 with no extra owner. I would &lt;strong&gt;freeze&lt;/strong&gt; the free lane for anything that can touch auth, cache, or flags. I would &lt;strong&gt;keep&lt;/strong&gt; it for export and logging only if X still has room.&lt;/p&gt;

&lt;p&gt;That is the opposite of a seat-based upgrade. You might stay on free models and a free server for low-B work. You might still buy or self-host a governed lane for high-B work. Or you stop generation on high-B work entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sensitivity, not a vendor story
&lt;/h3&gt;

&lt;p&gt;If E on the cache PR drops from 31 to 12 because the author wrote a 15-line narrative in the PR body, Q falls under 1.5 and R may flip to 1. The same free server suddenly passes. The product change was documentation discipline, not a new contract.&lt;/p&gt;

&lt;p&gt;If E stays high even after a narrative template, the lane is the problem. Exit. Do not add more headroom.&lt;/p&gt;

&lt;p&gt;Break-even in this model is not dollars per seat. It is the Q at which explanation time eats the generation "win." For the cache row, any G under 9 still loses while E sits at 31. You cannot prompt your way out of a teaching bottleneck you refuse to measure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free vs self-hosted vs paid vs stop
&lt;/h2&gt;

&lt;p&gt;Compare moves against ownership, not against brochure speed.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Move&lt;/th&gt;
&lt;th&gt;Can win when&lt;/th&gt;
&lt;th&gt;Loses when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Keep free models + free server&lt;/td&gt;
&lt;td&gt;Q stays ≤ 1.5, R is boring, B is 1, you need a pilot without procurement&lt;/td&gt;
&lt;td&gt;You use "it's free" to skip a named owner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-host&lt;/td&gt;
&lt;td&gt;You have operators, and persistent context or policy actually raises H&lt;/td&gt;
&lt;td&gt;You only lift G, so Q gets worse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paid / governed&lt;/td&gt;
&lt;td&gt;Audit, tenancy, or review hooks you will operate, with a bet on Q or H&lt;/td&gt;
&lt;td&gt;You buy status after two ugly PRs and never re-measure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stop&lt;/td&gt;
&lt;td&gt;High-B diffs fail rehearsal twice&lt;/td&gt;
&lt;td&gt;You stop everything, including B = 1 chores the squad can already narrate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Self-hosted is not morally serious. Paid is not automatically safer. Both are more expensive ways to hide the same leak if authors still cannot close the chat log and teach the diff.&lt;/p&gt;

&lt;p&gt;One question for a buyer's call: will this option change H, or only G?&lt;/p&gt;

&lt;h2&gt;
  
  
  How I would instrument this in a week
&lt;/h2&gt;

&lt;p&gt;Do not wait for a platform program. Steal five PRs and a spreadsheet.&lt;/p&gt;

&lt;p&gt;Proposed log schema. Unexecuted example, not a production collector:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pr_id,merged_at,g_min,e_min,rehearsal,blast_radius,chat_log_used,owner,expiry
auth-retry,2026-09-18,18,14,1,1,0,em-backend,2026-10-02
cache-stampede,2026-09-18,9,31,0,2,1,em-backend,2026-10-02
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tiny checker you can run locally after the fifth PR. Proposal only. Replace the thresholds before you argue with finance.&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;# proposal: ownership_gate.py
&lt;/span&gt;&lt;span class="n"&gt;prs&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;auth&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;g&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&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;b&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="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;cache&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;g&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&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;b&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="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;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;g&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&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;b&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="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;flag&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;g&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&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;b&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="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;logs&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;g&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&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;b&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="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;Q_MAX&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;
&lt;span class="n"&gt;fail_q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;e&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;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;g&lt;/span&gt;&lt;span class="sh"&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="n"&gt;Q_MAX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fail_r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;r&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;fail_b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;prs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;b&lt;/span&gt;&lt;span class="sh"&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="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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q_failures=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fail_q&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; rehearsal_failures=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fail_r&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; high_blast=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;fail_b&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;fail_q&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;fail_r&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GATE: freeze or split the lane&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="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;GATE: keep, expiry 14 days&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;Put the human check in the PR template, not in a wiki nobody opens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Ownership check&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Chat log closed while explaining to a reviewer
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Rehearsal: I can re-derive this from the ticket
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Blast radius and named owner
&lt;span class="p"&gt;-&lt;/span&gt; [ ] If Q &amp;gt; 1.5, this class of change does not use the free lane next time
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you cannot get authors to close the chat log during explanation, you do not have a measurement problem. You have an incentive problem. The free lane is rewarding speed theater.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free model path belongs in this gate
&lt;/h2&gt;

&lt;p&gt;I only reach for a zero-cost coding environment when I need to &lt;strong&gt;price the measurement&lt;/strong&gt;, not when I need to declare a platform winner.&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 that currently offers free model access and a free server option. I am not attaching model names, token ceilings, hardware SKUs, or uptime promises here. Those claims go stale, and I will not invent them. Use whatever is on the project page the day you run the gate.&lt;/p&gt;

&lt;p&gt;The fit is narrow. A free server is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need a &lt;strong&gt;pilot&lt;/strong&gt; with an expiry, not a permanent estate.&lt;/li&gt;
&lt;li&gt;You want authors to log G and E without a procurement cycle.&lt;/li&gt;
&lt;li&gt;The work is low blast radius, so a failed rehearsal is cheap.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is the wrong default when you already fail Q or R on production-shaped diffs, when you need audit or tenancy the free lane does not claim to give you, or when "it's free" is how the squad avoids naming an owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hard gates, owner, expiry, exit
&lt;/h2&gt;

&lt;p&gt;Copy these into the decision record. If you skip owner and expiry, you did not decide. You postponed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard gates (any fail = no keep for high-B work)&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Two or more of five sampled PRs with Q &amp;gt; 1.5.&lt;/li&gt;
&lt;li&gt;Two rehearsal failures.&lt;/li&gt;
&lt;li&gt;Any B ≥ 2 change with no named human owner overnight.&lt;/li&gt;
&lt;li&gt;Unexplained-diff budget X already spent.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Owner:&lt;/strong&gt; the engineering manager of the squad, not the vendor champion. Platform can advise. They do not hold the pager narrative.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expiry:&lt;/strong&gt; 14 days after the fifth sampled PR, or the next sprint boundary, whichever is sooner. No silent renewals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exit criteria&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split the lane: free path for B = 1 chores; governed or human-only for the rest.&lt;/li&gt;
&lt;li&gt;Move to self-hosted or paid only with a written bet that Q or H will improve, reviewed at expiry.&lt;/li&gt;
&lt;li&gt;Stop generation on the failing class of diffs. Tickets go back to smaller human slices.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Archive the five-PR table. If you cannot find it next month, the gate never happened.&lt;/p&gt;

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

&lt;p&gt;Skip the gate if you are a solo hobbyist with no reviewer and no incident channel. You are not hiding cost from a squad.&lt;/p&gt;

&lt;p&gt;Skip it if your team already forbids AI on anything that can page. You already made the call.&lt;/p&gt;

&lt;p&gt;Skip it if you will not close the chat log during explanation. The numbers will be fan fiction.&lt;/p&gt;

&lt;p&gt;This is a poor tool for ranking vendors. It will not tell you a free open-source path is "better" than a paid IDE. It will tell you whether &lt;em&gt;your&lt;/em&gt; free lane is producing unowned work.&lt;/p&gt;

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

&lt;p&gt;Half-life is a judgment, not a stopwatch. Two reviewers will disagree on whether a narrative counts. That disagreement is data.&lt;/p&gt;

&lt;p&gt;Five PRs is a small n. It is enough to freeze a lane. It is not enough to publish a benchmark.&lt;/p&gt;

&lt;p&gt;I have not run these exact rows in your shop. The table is a filled example so you can argue with the thresholds instead of the mood in Slack.&lt;/p&gt;

&lt;p&gt;Essays this month keep asking whether models outgrew our tests, or whether we started calling autocomplete "engineering." I will not launder secondary recaps as proof. The operational test is still local: can the author narrate the diff?&lt;/p&gt;

&lt;p&gt;If the answer is no, the cheapest tokens you will ever get are still too expensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would reverse it?
&lt;/h2&gt;

&lt;p&gt;If your Q stays under 1.0 and rehearsal is boringly successful, keep the free lane. Do not upgrade for status.&lt;/p&gt;

&lt;p&gt;If Q is ugly but a 12-line PR narrative flips R to 1, fix the template before you buy anything.&lt;/p&gt;

&lt;p&gt;If high-B work keeps failing rehearsal even after you add narrative and a named owner, freeze that class. Then, and only then, compare a governed or self-hosted option against stopping.&lt;/p&gt;

&lt;p&gt;I would rather a squad keep a free server for the work they can still explain than buy a louder lane they cannot.&lt;/p&gt;

&lt;p&gt;So: which variable would reverse your keep-or-kill call this sprint — Q, R, H, or B? If you cannot pick one, you are not ready to spend, and you are not ready to keep the free lane on trust.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>career</category>
    </item>
    <item>
      <title>Should Your Squad Expand AI Capacity When Reviewers Go Quiet? Use This Question-Rate Gate</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Thu, 17 Sep 2026 04:56:44 +0000</pubDate>
      <link>https://dev.to/bestbee/should-your-squad-expand-ai-capacity-when-reviewers-go-quiet-use-this-question-rate-gate-44h5</link>
      <guid>https://dev.to/bestbee/should-your-squad-expand-ai-capacity-when-reviewers-go-quiet-use-this-question-rate-gate-44h5</guid>
      <description>&lt;p&gt;Eleven of twenty-four AI-assisted pull requests merged last week with zero review comments. Median time-to-approve: nine minutes. Tests green. That number should reverse a buy. It should also reverse a self-host.&lt;/p&gt;

&lt;p&gt;Why would you add capacity to a lane that already stopped being engineering?&lt;/p&gt;

&lt;p&gt;Picture Tuesday standup. Maya, an EM on a payments squad, is proud. Cycle time dropped. Then a rollback lands at 4 p.m. because an AI-authored retry loop double-charged a webhook. Nobody in review asked how idempotency worked. The tool was not the failure. The silent approve was.&lt;/p&gt;

&lt;p&gt;Names here are composite. The numbers below are a worked example, not a customer case. I still use this filter because the incentive is the same every time: a free or paid lane that makes diffs look finished will get expanded for the wrong reason.&lt;/p&gt;

&lt;h2&gt;
  
  
  The unit is question rate, not cycle time
&lt;/h2&gt;

&lt;p&gt;Cycle time is a bad proxy. It moves in the same direction as both real engineering and pretend engineering. Question rate does not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question rate&lt;/strong&gt; is review comments plus blocking questions per AI-assisted PR, counted after the first bot noise is stripped. &lt;strong&gt;Silent-approve rate&lt;/strong&gt; is the share of those PRs merged with zero human comments and a sub-15-minute approve. If those two signals invert while cycle time “improves,” you do not have an adoption win. You have a trust unit going to zero.&lt;/p&gt;

&lt;p&gt;Would you buy more seats for a queue nobody interrogates? I would not. Would you stand up a GPU box for the same queue? Also no.&lt;/p&gt;

&lt;p&gt;This gate is a conversation tool. It is not objective truth. Game it and it will lie. Use it anyway, because token stickers and seat counts lie faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four options, one bottleneck
&lt;/h2&gt;

&lt;p&gt;You are not choosing a model brand. You are choosing blast radius.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep a bounded free lane.&lt;/strong&gt; Capacity stays small on purpose. You measure trust before you spend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buy a paid lane.&lt;/strong&gt; You pay for context, SLA, or vendor features. You also scale whatever habit you already have.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-host.&lt;/strong&gt; You pay in ops time for data control. Same habit risk. Different invoice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop or shrink.&lt;/strong&gt; The lane is producing silent approves plus rollbacks. Extra capacity is malpractice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A free model-access path and a free server option only matter in option 1. They are a blast-radius cap, not a trophy. If your reviewers already went quiet, paid and self-hosted are the same mistake with better hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Variable definitions
&lt;/h2&gt;

&lt;p&gt;Write these on a wiki page before you argue in Slack.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AI_PR_WEEK&lt;/code&gt;: PRs in the last 7 days labeled AI-assisted by the author or your bot.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Q&lt;/code&gt;: human review comments + blocking questions on those PRs. Strip linter bots.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;QR = Q / AI_PR_WEEK&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;QR_HUMAN&lt;/code&gt;: same ratio on PRs with no AI label, same week.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;QR_RATIO = QR / QR_HUMAN&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SA&lt;/code&gt;: silent approves. Zero human comments, merge under 15 minutes, tests green.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SA_RATE = SA / AI_PR_WEEK&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RB_H&lt;/code&gt;: hours spent rolling back or hotfixing AI-assisted changes in the last 30 days. Include the meeting.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TEST_DELTA&lt;/code&gt;: new or changed tests per AI-assisted PR. 0.0 means the model wrote product code and nobody added proof.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXPLAIN_OWNER&lt;/code&gt;: named human who can defend the change without re-reading the model transcript.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cannot fill those fields from git and review data, you do not have a buy/self-host decision. You have a vibe.&lt;/p&gt;

&lt;h2&gt;
  
  
  A 30-minute ledger, labeled unexecuted
&lt;/h2&gt;

&lt;p&gt;Do not trust memory. Export one week.&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. Adjust labels to match your process.&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;list &lt;span class="nt"&gt;--state&lt;/span&gt; merged &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"merged:&amp;gt;=2026-09-10"&lt;/span&gt; &lt;span class="nt"&gt;--limit&lt;/span&gt; 50 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--json&lt;/span&gt; number,title,author,mergedAt,reviews,comments,labels &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/pr-week.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then score it. This script is a proposal, not a benchmark I ran on your repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Unexecuted example: question-rate ledger from a simplified CSV.
# columns: pr, ai, human_comments, merge_minutes, rollback_hours, tests_changed
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;

&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&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;ai_review_week.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="n"&gt;ai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ai&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;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;human&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ai&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;0&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;mean_comments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;group&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;sum&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;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;human_comments&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;max&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;group&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;qr_ai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mean_comments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;qr_human&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mean_comments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;human&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ai&lt;/span&gt; &lt;span class="k"&gt;if&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;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;human_comments&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="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&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;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;merge_minutes&lt;/span&gt;&lt;span class="sh"&gt;"&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;15&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;rb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&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;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rollback_hours&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;td&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&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;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tests_changed&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;max&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;ai&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="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;ai_pr_week&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;ai&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;qr&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;qr_ai&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;qr_ratio&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;qr_ai&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;qr_human&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;qr_human&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sa_rate&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;sa&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ai&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ai&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rb_h&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;rb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test_delta&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;td&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;QR_RATIO&lt;/code&gt; is missing because you never labeled AI PRs, stop. Label for two weeks. Then decide. Expanding first is how you buy a mess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example: Northwind payments, 8 engineers
&lt;/h2&gt;

&lt;p&gt;Hypothetical week. I am not claiming this is a real team.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Human PRs&lt;/th&gt;
&lt;th&gt;AI-assisted PRs&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Count&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mean human comments (&lt;code&gt;QR&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;1.80&lt;/td&gt;
&lt;td&gt;0.42&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silent approves&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SA_RATE&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10%&lt;/td&gt;
&lt;td&gt;46%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;TEST_DELTA&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1.4&lt;/td&gt;
&lt;td&gt;0.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;RB_H&lt;/code&gt; (30-day, AI only)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;QR_RATIO = 0.42 / 1.80 = 0.23&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Maya’s cycle time looks great. The ledger does not. Eleven silent approves is not “the model got better.” It is reviewers treating green CI as a personality.&lt;/p&gt;

&lt;p&gt;Decision under this gate: &lt;strong&gt;do not expand&lt;/strong&gt;. Do not buy. Do not self-host for “more speed.” Keep a bounded free lane only if you still need the tool for drafts, and freeze it to files the squad already owns. If &lt;code&gt;RB_H&lt;/code&gt; stays above the rollback gate below, shrink further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hard gates (any one fails → no expand)
&lt;/h2&gt;

&lt;p&gt;These are stop signs, not vibes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;SA_RATE&lt;/code&gt; &amp;gt; 30%&lt;/strong&gt; on AI-assisted PRs. Reviewers went quiet. Extra capacity scales silence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;QR_RATIO&lt;/code&gt; &amp;lt; 0.35&lt;/strong&gt;. AI diffs get less than about one-third the interrogation of human diffs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;RB_H&lt;/code&gt; &amp;gt; 8 hours / 30 days&lt;/strong&gt;. The lane is already costing review-adjacent labor you will not see on a token invoice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;TEST_DELTA&lt;/code&gt; &amp;lt; 0.5&lt;/strong&gt;. The model is writing product code without proof. Buying context will not grow a test habit you refused to require.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No &lt;code&gt;EXPLAIN_OWNER&lt;/code&gt;&lt;/strong&gt;. If the author cannot defend the change without the chat log, it is not a PR. It is a paste.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If gate 1 and gate 3 both fire, the call is &lt;strong&gt;stop or shrink&lt;/strong&gt;, not “try a better model.” A better model with the same review policy is a faster webhook double-charge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sensitivity: which number reverses the call?
&lt;/h2&gt;

&lt;p&gt;Hold Northwind constant and move one field.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;SA_RATE&lt;/code&gt; drops from 46% to 18% and &lt;code&gt;QR_RATIO&lt;/code&gt; rises to 0.70, &lt;strong&gt;buy becomes discussable&lt;/strong&gt; — but only if the bottleneck is context or vendor workflow, not GPU envy.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;RB_H&lt;/code&gt; falls from 14 to 3 and &lt;code&gt;TEST_DELTA&lt;/code&gt; hits 1.0, &lt;strong&gt;self-host becomes discussable&lt;/strong&gt; — but only if data residency or air-gap is a real constraint, not a status purchase.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;AI_PR_WEEK&lt;/code&gt; doubles while &lt;code&gt;QR&lt;/code&gt; stays at 0.42, &lt;strong&gt;the decision gets worse&lt;/strong&gt;. Volume is not evidence.&lt;/li&gt;
&lt;li&gt;If human &lt;code&gt;QR&lt;/code&gt; also collapses to 0.42, you do not have an AI problem. You have a review-culture problem. No lane, free or paid, will save you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ask the squad this out loud: &lt;strong&gt;which single threshold would reverse your expand vote?&lt;/strong&gt; If nobody can name one, you are shopping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Free vs paid vs self-host under a quiet review queue
&lt;/h2&gt;

&lt;p&gt;Fit is not “which model is smart.” Fit is whether capacity is the constraint.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;If this is true&lt;/th&gt;
&lt;th&gt;Keep bounded free&lt;/th&gt;
&lt;th&gt;Buy&lt;/th&gt;
&lt;th&gt;Self-host&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reviewers still ask hard questions&lt;/td&gt;
&lt;td&gt;Maybe&lt;/td&gt;
&lt;td&gt;Maybe&lt;/td&gt;
&lt;td&gt;Maybe&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;SA_RATE&lt;/code&gt; already &amp;gt; 30%&lt;/td&gt;
&lt;td&gt;Cap, don’t market it&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Context across repos is the actual bottleneck&lt;/td&gt;
&lt;td&gt;Weak fit&lt;/td&gt;
&lt;td&gt;Stronger fit&lt;/td&gt;
&lt;td&gt;Only if you will staff the box&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data cannot leave the building&lt;/td&gt;
&lt;td&gt;Weak fit&lt;/td&gt;
&lt;td&gt;Usually no&lt;/td&gt;
&lt;td&gt;Only after trust gates pass&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You cannot name an &lt;code&gt;EXPLAIN_OWNER&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Shrink&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You want a trophy for “AI adoption”&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&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. MonkeyCode is an open-source project with free model access and a free server option. I am not using that as a bake-off win. I am using it as an example of a &lt;strong&gt;bounded lane&lt;/strong&gt;: useful while you run the ledger, dangerous if you treat free capacity as a reason to skip gates. The article still works if you never touch that project. Substitute any free lane you already have.&lt;/p&gt;

&lt;p&gt;Paid and self-hosted fail the same way free fails. They fail faster when the invoice or the rack implies you must “get value.” Incentives leak into review. Quiet reviewers plus a larger context window is how pretend-engineering gets a budget line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Owner, expiry, archive
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Owner:&lt;/strong&gt; the EM plus one staff reviewer who is not the vendor champion. The champion can collect data. They cannot grade their own expansion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry:&lt;/strong&gt; 14 days for the first ledger, 30 days after that. An expired exception is a no.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit:&lt;/strong&gt; if gate 1 and gate 3 both fire in a window, disable AI labels from merge, or cut the lane back to draft-only on non-production paths. Write the rollback in the same doc as the adoption note.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Archive rule:&lt;/strong&gt; keep the CSV. Do not keep screenshots of cycle-time dashboards as proof.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Put the expiry on a calendar. Verbal “we’ll watch it” is how silent approves become culture.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Teams with no review data and no will to label AI PRs. You cannot price trust from anecdotes.&lt;/li&gt;
&lt;li&gt;Security or compliance work that needs a legal review of any tool, free or not. A decision card is not a SOC report.&lt;/li&gt;
&lt;li&gt;Solo hackers optimizing for learning speed. Question rate is a team unit.&lt;/li&gt;
&lt;li&gt;Anyone hunting a promotional build-versus-buy conclusion. If you already picked a vendor, this ledger will feel hostile. Good.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Small, boring diffs can be silent and still correct. A 4-line typo fix should not inflate &lt;code&gt;SA_RATE&lt;/code&gt; the way a 400-line retry loop should. Split trivial PRs out, or you will punish good hygiene.&lt;/p&gt;

&lt;p&gt;Comment count can be gamed. “LGTM” is not a question. Count blocking questions if your tool allows it. If it does not, sample 10 PRs by hand once a week. Hand samples beat vanity metrics.&lt;/p&gt;

&lt;p&gt;I have not run these commands on your repository. There is no benchmark hiding in this post. There is a policy you can fill, argue with, and expire.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question that actually matters
&lt;/h2&gt;

&lt;p&gt;Not “would you try the tool?” Not “is free cheaper than a rack?”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If silent-approve rate stayed at 46%, what extra capacity would you still purchase?&lt;/strong&gt; If the answer is none, keep the lane bounded or kill it. If the answer is “we’d buy anyway because leadership wants AI,” you do not have a model problem. You have a P&amp;amp;L that is rewarding pretend work.&lt;/p&gt;

&lt;p&gt;Run the ledger on last week’s merges. Fill &lt;code&gt;QR_RATIO&lt;/code&gt;, &lt;code&gt;SA_RATE&lt;/code&gt;, and &lt;code&gt;RB_H&lt;/code&gt;. Then pick keep-bounded, buy, self-host, or stop. If you need a cap while you measure, a free-model plus free-server lane is one way to keep capacity from becoming the decision. The gate still comes first.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>career</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Should a Platform Lead Self-Host an AI Coding Lane or Keep a Free One? Use This 6-Field Fit Card</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Wed, 16 Sep 2026 03:13:45 +0000</pubDate>
      <link>https://dev.to/bestbee/should-a-platform-lead-self-host-an-ai-coding-lane-or-keep-a-free-one-use-this-6-field-fit-card-3248</link>
      <guid>https://dev.to/bestbee/should-a-platform-lead-self-host-an-ai-coding-lane-or-keep-a-free-one-use-this-6-field-fit-card-3248</guid>
      <description>&lt;p&gt;Monday, 9:40 a.m. An AI-assisted change is already in production. The invoice is still zero. The on-call thread is not.&lt;/p&gt;

&lt;p&gt;Can you replay the exact lane that wrote the diff? If the answer is a shrug, the “free” column is already charging you — just not on a card statement. This piece is a fit card for that moment. It is not a vendor bake-off, and it is not a claim that any one runtime is “better at coding.”&lt;/p&gt;

&lt;p&gt;I treat the numbers below as a labeled hypothetical. Fill your own. A scorecard is a conversation tool, not objective truth. Which single threshold would reverse &lt;em&gt;your&lt;/em&gt; keep-free decision?&lt;/p&gt;

&lt;h2&gt;
  
  
  The constraint that can flip the call
&lt;/h2&gt;

&lt;p&gt;A free hosted lane is cheap until three things collide: you cannot pin the model and runtime, review happens &lt;em&gt;beside&lt;/em&gt; the PR instead of in it, and people hide usage so the lane stays free. Self-hosting is expensive until those three things are the job.&lt;/p&gt;

&lt;p&gt;Paid SaaS sits in the middle only if the contract actually buys pin, boundary, and an exit. Seat stickers do not buy those. Neither do token stickers.&lt;/p&gt;

&lt;p&gt;So the question is not “is free good?” It is: &lt;strong&gt;where should this squad’s coding lane live for the next 45 days — free hosted, paid hosted, or self-hosted — given replay, data, incentives, and exit?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Define the variables before you score
&lt;/h2&gt;

&lt;p&gt;Write these on a wiki page. If a field has no owner, it is not a field. It is a vibe.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Owner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Can we re-run the same model + runtime + prompt pack against the same SHA?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;yes&lt;/code&gt; / &lt;code&gt;partial&lt;/code&gt; / &lt;code&gt;no&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What leaves the building, and is that allowed in writing?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ok&lt;/code&gt; / &lt;code&gt;exception&lt;/code&gt; / &lt;code&gt;blocked&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Does the lane sit in the PR path, or in a side chat that reviewers never see?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;in-band&lt;/code&gt; / &lt;code&gt;side&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;EM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;I&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Are people hiding prompts, pasting secrets, or dual-running a shadow tool?&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;clean&lt;/code&gt; / &lt;code&gt;leak&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;EM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;H&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extra human hours the lane creates: review, rollback, incident archaeology&lt;/td&gt;
&lt;td&gt;hours / week&lt;/td&gt;
&lt;td&gt;EM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;X&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hours to leave: export, re-onboard, rewrite rules, kill the exception&lt;/td&gt;
&lt;td&gt;hours&lt;/td&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C_h&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fully loaded cost of an engineering hour&lt;/td&gt;
&lt;td&gt;currency / hour&lt;/td&gt;
&lt;td&gt;Finance partner&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C_run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invoice or infra for the lane itself&lt;/td&gt;
&lt;td&gt;currency / 45 days&lt;/td&gt;
&lt;td&gt;Platform&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;H&lt;/code&gt; is the expensive number. &lt;code&gt;C_run&lt;/code&gt; is the loud one. Do not let the loud one win by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three columns, not two slogans
&lt;/h2&gt;

&lt;p&gt;Score the same squad three ways. Do not skip a column because it feels unfashionable.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep a free hosted lane.&lt;/strong&gt; Invoice near zero. You accept whatever pin, quota, and region the operator gives you this month.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buy a hosted lane.&lt;/strong&gt; You are paying for a contract: pin, logs, DPA language, support, and a kill switch you can actually pull.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-host.&lt;/strong&gt; You buy replay and boundary with owner hours. The GPU bill is not the whole bill.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some teams park column 1 on a product that currently offers free model access and a free server option. Disclosure: This article was prepared as part of MonkeyCode's product outreach. I am not treating those offers as permanent, unlimited, named-model, or benchmarked. They are a perishable input to column 1. If they change next week, the card should still work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hard gates (these are not scores)
&lt;/h2&gt;

&lt;p&gt;If any gate fails, stop scoring and pick the column that clears the gate. Scores do not override law, paging, or a lying incentive.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pin gate.&lt;/strong&gt; The next Sev-2 needs a model id, runtime id, and prompt-pack hash on the PR. If the lane cannot emit those, column 1 is closed for that repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Boundary gate.&lt;/strong&gt; Customer data, secrets, or production configs cannot ride a lane with no written exception. &lt;code&gt;B = blocked&lt;/code&gt; kills hosted-free for that surface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incentive gate.&lt;/strong&gt; If people dual-run a shadow tool to “protect” the free lane, you do not have adoption. You have a leak. Freeze expansion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In-band gate.&lt;/strong&gt; If reviewers cannot see the prompt, the file list, and the rejection path in the PR, &lt;code&gt;W = side&lt;/code&gt;. Side channels do not get to touch auth, payments, or migrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Who should not use this card? A solo hobby repo with no pager and no customer data. You do not need a six-field ledger to autocomplete a side project. Also skip it if nobody will own &lt;code&gt;R&lt;/code&gt; and &lt;code&gt;X&lt;/code&gt;. An orphaned self-host is just a future incident with extra YAML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example (hypothetical, 8-person squad)
&lt;/h2&gt;

&lt;p&gt;Assume &lt;code&gt;C_h = 95&lt;/code&gt; currency units per hour. Forty-five day window. One platform owner at 0.25 FTE on the lane. No invented vendor list prices — &lt;code&gt;C_run&lt;/code&gt; is what &lt;em&gt;you&lt;/em&gt; were quoted or what your cloud bill actually did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Column 1, free hosted&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;R = no&lt;/code&gt; (no pin you control)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;B = exception&lt;/code&gt; (public tickets only; prod configs banned)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;W = side&lt;/code&gt; for two engineers who live in chat&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I = leak&lt;/code&gt; starting in week three (paste of a staging URL)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;H = 5.5&lt;/code&gt; extra review/archaeology hours per week&lt;/li&gt;
&lt;li&gt;&lt;code&gt;C_run = 0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X = 6&lt;/code&gt; hours to leave&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Loaded 45-day human cost: &lt;code&gt;5.5 * 6.4 weeks * 95 ≈ 3,344&lt;/code&gt;. Exit is cheap. Replay is not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Column 2, paid hosted&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;R = partial&lt;/code&gt; (vendor pin, not your binary)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;B = ok&lt;/code&gt; on the paper you actually signed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;W = in-band&lt;/code&gt; after you force the PR check&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I = clean&lt;/code&gt; if the paid seat is the only blessed path&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;H = 2.0&lt;/code&gt; hours / week&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;C_run =&lt;/code&gt; your quote&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X = 20&lt;/code&gt; hours if the export is clumsy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Human cost: &lt;code&gt;2.0 * 6.4 * 95 ≈ 1,216&lt;/code&gt; plus &lt;code&gt;C_run&lt;/code&gt; plus a slower exit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Column 3, self-host&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;R = yes&lt;/code&gt; if you freeze image digest + model artifact + prompt pack&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;B = ok&lt;/code&gt; on your network&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;W = in-band&lt;/code&gt; only if you build the PR check; the box does not do that for you&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;I = leak&lt;/code&gt; if the server is up and the workflow is annoying&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;H = 1.5&lt;/code&gt; hours / week once the workflow exists, &lt;strong&gt;plus&lt;/strong&gt; 0.25 FTE owner (&lt;code&gt;0.25 * 36 hours * 95 ≈ 855&lt;/code&gt; in 45 days)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;C_run =&lt;/code&gt; power, box, storage, backups — your bill, not a blog benchmark&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;X = 40&lt;/code&gt; hours if you are the only person who knows the runbook&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-host wins on pin and boundary. It loses if the owner is fictional.&lt;/p&gt;

&lt;p&gt;Would you still keep column 1 if &lt;code&gt;H&lt;/code&gt; is 5.5 and &lt;code&gt;R&lt;/code&gt; is no? Only if this squad never pages, never handles customer data, and you have already scheduled the expiry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sensitivity: the one slider that reverses the call
&lt;/h2&gt;

&lt;p&gt;Hold everything else still. Move one variable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;H&lt;/code&gt; drops under ~2 hours/week because the free lane is in-band and boring, column 1 can survive a 45-day exception. The invoice was never the point.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;R&lt;/code&gt; stays &lt;code&gt;no&lt;/code&gt; and you have had one unreplayable incident, column 1 is done for that repo. Do not “try one more sprint.”&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;C_run&lt;/code&gt; for paid hosted exceeds the &lt;code&gt;H&lt;/code&gt; savings, you are buying a brand, not a pin. Demand the pin in writing or stop.&lt;/li&gt;
&lt;li&gt;If self-host &lt;code&gt;X&lt;/code&gt; is 40 hours and the owner takes leave, you do not have a platform. You have a pet.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Break-even against staying free, in words: &lt;strong&gt;column 2 or 3 is cheaper when &lt;code&gt;(H_free - H_alt) * weeks * C_h + incident_risk_you_will_actually_write_down &amp;gt; C_run_alt + owner_hours_alt * C_h + (X_alt - X_free) amortized&lt;/code&gt;.&lt;/strong&gt; If you will not write the incident risk down, set it to zero and admit you are gambling.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 6-field fit card (copy this)
&lt;/h2&gt;

&lt;p&gt;Score each field 0, 1, or 2. Higher means “this column fits this squad for 45 days.” Cap any column at 0 if a hard gate failed.&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;# fit-card.45d.yaml — conversation tool, not truth&lt;/span&gt;
&lt;span class="na"&gt;squad&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;payments-api-8&lt;/span&gt;
&lt;span class="na"&gt;window_days&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;45&lt;/span&gt;
&lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform-lead&lt;/span&gt;
&lt;span class="na"&gt;expiry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-10-31&lt;/span&gt;
&lt;span class="na"&gt;hard_gates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pin&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fail-closed&lt;/span&gt;
  &lt;span class="na"&gt;boundary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fail-closed&lt;/span&gt;
  &lt;span class="na"&gt;incentive_leak&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;freeze-expansion&lt;/span&gt;
  &lt;span class="na"&gt;in_band_for_sensitive_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
&lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;free_hosted&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;R&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;   &lt;span class="c1"&gt;# no pin we control&lt;/span&gt;
    &lt;span class="na"&gt;B&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;   &lt;span class="c1"&gt;# exception, public tickets only&lt;/span&gt;
    &lt;span class="na"&gt;W&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;   &lt;span class="c1"&gt;# side chat still exists&lt;/span&gt;
    &lt;span class="na"&gt;I&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;   &lt;span class="c1"&gt;# leak observed&lt;/span&gt;
    &lt;span class="na"&gt;H&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;   &lt;span class="c1"&gt;# 5.5h/week extra&lt;/span&gt;
    &lt;span class="na"&gt;X&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;   &lt;span class="c1"&gt;# cheap to leave&lt;/span&gt;
  &lt;span class="na"&gt;paid_hosted&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;R&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;B&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;W&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;I&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;H&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;X&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;self_host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;R&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;B&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;W&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;   &lt;span class="c1"&gt;# only if the PR check ships&lt;/span&gt;
    &lt;span class="na"&gt;I&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;H&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;X&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;   &lt;span class="c1"&gt;# expensive pet risk&lt;/span&gt;
&lt;span class="na"&gt;gates_failed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;free_hosted&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pin&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;incentive_leak&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;recommendation&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Do&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;expand&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;free_hosted.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Pick&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;paid_hosted&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;self_host&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;after&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;pin&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;evidenced."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run a dumb scorer so the meeting cannot hide in adjectives:&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;# fit_card.py — labeled example, not a benchmark
&lt;/span&gt;&lt;span class="n"&gt;COLUMNS&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;R&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;B&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;W&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;I&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;H&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;X&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="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="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;R&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;B&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;W&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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;I&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;H&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;X&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;self_host&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;R&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;W&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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;I&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;H&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;X&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="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;GATES_FAILED&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;pin&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;incentive_leak&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
&lt;span class="n"&gt;WEIGHT&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;R&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B&lt;/span&gt;&lt;span class="sh"&gt;"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;W&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="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;I&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;H&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;  &lt;span class="c1"&gt;# pin/boundary dominate
&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;scores&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;COLUMNS&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;GATES_FAILED&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="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="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;: GATE FAIL &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;GATES_FAILED&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="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; -&amp;gt; 0 (do not rank)&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;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WEIGHT&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&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;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;WEIGHT&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="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;: weighted &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; / &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WEIGHT&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That script will print a zero for the free column. Good. The meeting should argue the &lt;em&gt;inputs&lt;/em&gt;, not the printout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make replay a merge rule, not a slide
&lt;/h2&gt;

&lt;p&gt;If you cannot pin, you cannot choose column 1 for a paged repo. Put the evidence on the PR. Something this boring:&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;# required labels on every AI-touched PR (policy, not a product pitch)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"lane=&lt;/span&gt;&lt;span class="nv"&gt;$LANE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"model_id=&lt;/span&gt;&lt;span class="nv"&gt;$MODEL_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;          &lt;span class="c"&gt;# empty =&amp;gt; fail closed&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"runtime_digest=&lt;/span&gt;&lt;span class="nv"&gt;$DIGEST&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;      &lt;span class="c"&gt;# empty =&amp;gt; fail closed&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"prompt_pack=&lt;/span&gt;&lt;span class="nv"&gt;$PACK_SHA&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"files=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git diff &lt;span class="nt"&gt;--name-only&lt;/span&gt; origin/main&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Empty &lt;code&gt;model_id&lt;/code&gt; is a failed pin gate. Do not negotiate it in Slack after the page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Owner, expiry, exit
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Owner:&lt;/strong&gt; the platform lead who can turn the lane off. Not “the squad.” Not “AI champions.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry:&lt;/strong&gt; 45 days, on a calendar invite, with the six fields filled again. Exceptions expire. They do not mellow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit criteria for column 1:&lt;/strong&gt; pin gate fail, one unreplayable incident, &lt;code&gt;I = leak&lt;/code&gt;, or &lt;code&gt;H&lt;/code&gt; still above the number you wrote down on day 0.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit criteria for column 3:&lt;/strong&gt; owner drops below 0.15 FTE, backups untested, or &lt;code&gt;W&lt;/code&gt; slides back to side chat.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Archive rule:&lt;/strong&gt; keep the YAML, the PR labels, and the incident note. Delete the exception ticket so it cannot be copy-pasted as policy.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;This card will not tell you which model writes prettier React. It will not rank vendors. It will not invent an ROI from tokens. It under-weights rare, huge incidents unless you write that risk as a number you are willing to defend. It over-weights process if your company never pages.&lt;/p&gt;

&lt;p&gt;Do not use it to justify a self-host vanity cluster. Do not use it to keep a free lane alive after a leak because the invoice is flattering.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would reverse it?
&lt;/h2&gt;

&lt;p&gt;I would keep a free hosted lane for 45 days if &lt;code&gt;R&lt;/code&gt; becomes &lt;code&gt;partial&lt;/code&gt; or better, &lt;code&gt;W&lt;/code&gt; is in-band, &lt;code&gt;I&lt;/code&gt; stays clean, and &lt;code&gt;H&lt;/code&gt; is under two hours a week on a non-sensitive repo. I would self-host the day &lt;code&gt;B&lt;/code&gt; is blocked and we still need a lane. I would pay the day pin and logs are in the contract and owner hours for self-host would exceed the quote.&lt;/p&gt;

&lt;p&gt;Your turn. Which variable — &lt;code&gt;R&lt;/code&gt;, &lt;code&gt;H&lt;/code&gt;, or &lt;code&gt;I&lt;/code&gt; — would reverse the column you are defending this week? Write that number next to an expiry date. Then run the card again before the exception quietly becomes the architecture.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>career</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Should Your Team Stay on a Free AI Coding Tier? Run This Three-Lane Break-Even Model First</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Tue, 15 Sep 2026 03:04:34 +0000</pubDate>
      <link>https://dev.to/bestbee/should-your-team-stay-on-a-free-ai-coding-tier-run-this-three-lane-break-even-model-first-211o</link>
      <guid>https://dev.to/bestbee/should-your-team-stay-on-a-free-ai-coding-tier-run-this-three-lane-break-even-model-first-211o</guid>
      <description>&lt;h2&gt;
  
  
  The capability fight is over. The invoice fight hasn't started.
&lt;/h2&gt;

&lt;p&gt;Two DEV posts landed within three days of each other this month. On 10 September 2026, one asked whether AI is already better at coding than most software developers, and collected 213 reactions and 181 comments (&lt;a href="https://dev.to/sylwia-lask/ai-is-already-better-at-coding-than-most-software-developers-4hno"&gt;link&lt;/a&gt;). On 8 September, "Most 'AI Agents' Are Just If-Statements in a Trench Coat" gathered 105 reactions and 125 comments (&lt;a href="https://dev.to/james_anderson_h/most-ai-agents-are-just-if-statements-in-a-trench-coat-3960"&gt;link&lt;/a&gt;). Then, on 13 September, a third thread argued the problem is not vibe coding but calling it engineering (&lt;a href="https://dev.to/georgekobaidze/vibe-coding-isnt-the-problem-calling-it-engineering-is-lm1"&gt;link&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;All three are good reads. None of them answers the question that actually reaches a budget review: &lt;strong&gt;which lane should your team pay for, and at what volume does the answer flip?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So let me do the unglamorous part. Here is the model I use to compare a free hosted tier, a self-hosted box, and a metered paid API — plus a script you can run before your next planning meeting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three lanes, one unit
&lt;/h2&gt;

&lt;p&gt;Every team I talk to evaluates these three options on sticker price. That's the first mistake.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lane A — free hosted access.&lt;/strong&gt; Someone else's servers, someone else's terms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lane B — self-hosted.&lt;/strong&gt; Hardware you own or rent, on your network, with your uptime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lane C — metered paid API.&lt;/strong&gt; You pay per unit of consumption and control nothing about capacity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Seats lie. Price per million tokens lies harder, because tokens are usually a rounding error next to the line item nobody counts: human review time.&lt;/p&gt;

&lt;p&gt;So pick a unit that survives contact with your P&amp;amp;L.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Unit: fully loaded cost per accepted change.&lt;/strong&gt; An accepted change is an AI-assisted change that passes review and is still in the codebase two weeks later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why two weeks? Because a change reverted on day three was never a win, and rollback labor is real labor. If you cannot measure survival yet, use "merged and not reverted in 14 days" as a first proxy — but write down that it is a proxy, not a measurement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Lane A refers to in this article
&lt;/h2&gt;

&lt;p&gt;The operator-supplied claims I am working from: &lt;strong&gt;MonkeyCode&lt;/strong&gt; is an open-source project that offers free model access and a free server option, and the operator advertises 10M free tokens for people evaluating it.&lt;/p&gt;

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

&lt;p&gt;I have not independently verified the current quota, the model list, the server specification, or the expiry date. Free allocations change, and that is not a scandal — it is a fact you should plan around. Treat Lane A below as "free until the operator says otherwise" and attach a real expiry date to your own assumption before you build a quarter on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The eight inputs you actually need
&lt;/h2&gt;

&lt;p&gt;Most cost models fail because they use four inputs and infer the rest. Use these eight, and label the source of each one.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Attempts per month.&lt;/strong&gt; Every AI-assisted change that reached review, including the ones you threw away.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept rate per lane.&lt;/strong&gt; Accepted changes ÷ attempts. This differs per lane and people usually assume it doesn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review minutes per attempt, per lane.&lt;/strong&gt; Your reviewer reads differently when the tool differs. Measure it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Loaded hourly cost of the reviewer.&lt;/strong&gt; Salary plus overhead, not salary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variable cost per attempt.&lt;/strong&gt; Tokens, API calls, power draw.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed monthly cost.&lt;/strong&gt; Reserved capacity, amortized hardware, licenses — things you pay for whether you use them or not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ops hours per month.&lt;/strong&gt; Upgrades, key rotation, incidents, model swaps, backup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost per hour of whoever owns the infrastructure.&lt;/strong&gt; If nobody owns it, that is Lane B's hidden failure mode.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Inputs 3 and 5 are the ones people guess. Pull 30 recent pull requests and time the reviews with a stopwatch. It takes an afternoon and it will change your conclusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  A script you can run in twenty minutes
&lt;/h2&gt;

&lt;p&gt;The script below is a &lt;strong&gt;proposal, not a measured result&lt;/strong&gt;. I have not attached a run log, and every number in &lt;code&gt;LANES&lt;/code&gt; is an assumption you are expected to overwrite with your own invoice and calendar data.&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;Compare three AI coding lanes on cost per accepted change.

STATUS: proposal. Every number in LANES is an ASSUMPTION.
Usage:
    python3 lane_breakeven.py --attempts 900 --loaded-hourly 78 --ops-hourly 95
&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;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="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;Lane&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="n"&gt;fixed_monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;       &lt;span class="c1"&gt;# paid whether you use it or not
&lt;/span&gt;    &lt;span class="n"&gt;per_attempt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;         &lt;span class="c1"&gt;# tokens, API calls, power, per attempt
&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;float&lt;/span&gt;      &lt;span class="c1"&gt;# human review per attempt
&lt;/span&gt;    &lt;span class="n"&gt;ops_hours_monthly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;   &lt;span class="c1"&gt;# upgrades, incidents, key rotation
&lt;/span&gt;    &lt;span class="n"&gt;accept_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;         &lt;span class="c1"&gt;# fraction of attempts that survive review
&lt;/span&gt;

&lt;span class="n"&gt;LANES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Lane&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 free hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="mf"&gt;0.00&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;24.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.58&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Lane&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B self-hosted&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1450.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.02&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;27.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;9.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.57&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Lane&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 paid metered&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="mf"&gt;0.41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;23.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.61&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;cost_per_accepted&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;attempts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;loaded_hourly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ops_hourly&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;accepted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attempts&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;accept_rate&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;accepted&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&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;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;inf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attempts&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;per_attempt&lt;/span&gt;
    &lt;span class="n"&gt;review&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;attempts&lt;/span&gt; &lt;span class="o"&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;review_minutes&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;60.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;loaded_hourly&lt;/span&gt;
    &lt;span class="n"&gt;ops&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;ops_hours_monthly&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ops_hourly&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;lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixed_monthly&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;review&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;ops&lt;/span&gt;
    &lt;span class="k"&gt;return&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;accepted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;self_host_breakeven&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self_lane&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paid_lane&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ops_hourly&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Attempts/month where self-hosting ties the metered lane.

    Review cost is treated as lane-independent, which holds only when
    accept_rate and review_minutes match. Change the inputs rather than
    trusting this number if they don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;fixed_gap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self_lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixed_monthly&lt;/span&gt;
                 &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;self_lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops_hours_monthly&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ops_hourly&lt;/span&gt;
                 &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;paid_lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fixed_monthly&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;per_attempt_gap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;paid_lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;per_attempt&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;self_lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;per_attempt&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;per_attempt_gap&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixed_gap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;per_attempt_gap&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;p&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;p&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;--attempts&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;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;900.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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;--loaded-hourly&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;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;78.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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;--ops-hourly&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;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;95.0&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;p&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="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;attempts/month=&lt;/span&gt;&lt;span class="si"&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;attempts&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;  loaded=$&lt;/span&gt;&lt;span class="si"&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;loaded_hourly&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/h&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="si"&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="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total/mo&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;accepted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;per accepted&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14&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;for&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;LANES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;per&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="nf"&gt;cost_per_accepted&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;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempts&lt;/span&gt;&lt;span class="p"&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;loaded_hourly&lt;/span&gt;&lt;span class="p"&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;ops_hourly&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;accepted&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;attempts&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;accept_rate&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="si"&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;name&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;16&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="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;accepted&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mf"&gt;10.0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;per&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;self_host_breakeven&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LANES&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;LANES&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="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ops_hourly&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;be&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="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;self-host ties the metered lane at any volume for these inputs&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="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;self-host ties the metered lane at ~&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; attempts/month &lt;/span&gt;&lt;span class="sh"&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;(~&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; per engineer at 5 engineers)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;minute_cost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&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;attempts&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;60.0&lt;/span&gt;&lt;span class="p"&gt;)&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;loaded_hourly&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;one extra review minute per attempt costs ~$&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;minute_cost&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/month&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;h2&gt;
  
  
  A filled example (hypothetical, fully specified)
&lt;/h2&gt;

&lt;p&gt;Picture a five-engineer squad. 900 attempts a month, $78 loaded hourly, $95 hourly for the one person who owns infrastructure. Lane A has no fixed cost and no metered cost because it is free today. Lane B carries a $1,450/month amortized hardware and power line, plus nine ops hours. Lane C meters at $0.41 per attempt plus one ops hour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 lane_breakeven.py &lt;span class="nt"&gt;--attempts&lt;/span&gt; 900 &lt;span class="nt"&gt;--loaded-hourly&lt;/span&gt; 78 &lt;span class="nt"&gt;--ops-hourly&lt;/span&gt; 95
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These outputs are arithmetic from the assumptions above — not measurements of any product.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;attempts/month=900  loaded=$78/h
lane                 total/mo  accepted  per accepted
A free hosted          28,080       522         53.79
B self-hosted          33,913       513         66.11
C paid metered         27,374       549         49.86

self-host ties the metered lane at ~5,910 attempts/month (~1,182 per engineer at 5 engineers)
one extra review minute per attempt costs ~$1,170/month
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the shape of that table. The entire metered token bill for Lane C is $369/month. The review line for the same lane is $26,910/month. The model choice is roughly 1.4% of the total.&lt;/p&gt;

&lt;p&gt;That is the finding most teams miss while they argue about which model is smarter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sensitivity: three variables, three different answers
&lt;/h2&gt;

&lt;p&gt;A single point estimate is not a decision. Move these three and watch the ranking change.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Review minutes.&lt;/strong&gt; Here, one extra minute per attempt costs about $1,170/month. Lane B's review is four minutes slower than Lane C's, which is worth roughly $4,680/month — more than three times Lane B's entire hardware line. That single assumption decides the answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept rate.&lt;/strong&gt; Drop Lane C's accept rate from 0.61 to 0.55 and its cost per accepted change moves from $49.86 to about $55.30, which makes the free lane the cheapest option again. Accept rate is not a detail; it is a ranking variable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ops hours.&lt;/strong&gt; Self-hosting only ties the metered lane at roughly 5,910 attempts/month for these inputs. Cut ops to two hours and hardware to $700 and the crossover falls to about 2,282 attempts — still around 456 attempts per engineer per month.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if Lane A quietly throttles or queues, adding three minutes of waiting per attempt costs about $3,510/month. "Free" becomes the second-most-expensive lane without anyone changing a price.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fit criteria: five questions, one table
&lt;/h2&gt;

&lt;p&gt;Answer these before you pick a lane. The scorecard is a conversation tool, not objective truth — its job is to surface disagreement, not to settle it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Can your source code leave your network at all? If no, Lane A and Lane C are disqualified and the real choice is Lane B versus not adopting.&lt;/li&gt;
&lt;li&gt;Does one named person spend at least four hours a week owning infrastructure? If no, do not choose Lane B.&lt;/li&gt;
&lt;li&gt;What is your attempts per month? Below ~1,500, fixed costs dominate and self-hosting almost never amortizes.&lt;/li&gt;
&lt;li&gt;How spiky is demand? Steady load favors self-hosting; bursty load favors metered billing.&lt;/li&gt;
&lt;li&gt;How much review headroom do you have? The model shows review dominates, so adding a lane without adding review capacity just relocates the queue.&lt;/li&gt;
&lt;/ol&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 hosted&lt;/th&gt;
&lt;th&gt;Self-hosted&lt;/th&gt;
&lt;th&gt;Paid metered&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Code can leave your network&lt;/td&gt;
&lt;td&gt;no → disqualified&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;no → disqualified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Named infra owner ≥4h/week&lt;/td&gt;
&lt;td&gt;not needed&lt;/td&gt;
&lt;td&gt;required&lt;/td&gt;
&lt;td&gt;not needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Attempts per month&lt;/td&gt;
&lt;td&gt;low to mid&lt;/td&gt;
&lt;td&gt;high enough to amortize&lt;/td&gt;
&lt;td&gt;any, but cap the spend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Demand shape&lt;/td&gt;
&lt;td&gt;steady, low stakes&lt;/td&gt;
&lt;td&gt;steady, sensitive data&lt;/td&gt;
&lt;td&gt;spiky bursts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost of leaving&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;td&gt;high, hardware is sunk&lt;/td&gt;
&lt;td&gt;low&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Hard gates, an owner, an expiry
&lt;/h2&gt;

&lt;p&gt;A model without an enforcement clause is a slide. Write these down.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lane A gate:&lt;/strong&gt; re-approve every 30 days. Free allocations change; a decision made against today's terms should expire with them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lane B gate:&lt;/strong&gt; kill it if ops hours exceed your stated ceiling for two consecutive months. Name the owner and the ceiling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lane C gate:&lt;/strong&gt; alert at 80% of the monthly cap, and require a second approval above it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry:&lt;/strong&gt; every lane decision expires in 90 days or when any input moves more than 25%. Whichever comes first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit criteria:&lt;/strong&gt; if review minutes per accepted change rise 25% for two consecutive weeks, stop adding seats or lanes and fix the review path first.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One owner per lane. An expiry date. A written exit condition. That is the whole governance cost.&lt;/p&gt;

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

&lt;p&gt;The model above ignores switching costs, quality differences beyond accept rate, and queueing delays when a hosted tier throttles. It treats review cost as lane-independent in the crossover formula, which is wrong whenever review minutes actually differ — and in the example, they do.&lt;/p&gt;

&lt;p&gt;Skip this approach if you are a solo developer with fewer than 50 attempts a month; noise will dominate every number and you will spend more time modeling than coding. Skip it if your code cannot leave your network and you have no infra owner — your answer is "none of these lanes," and that is a legitimate answer. And do not build a roadmap on a free allocation you have not dated.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would ask you
&lt;/h2&gt;

&lt;p&gt;Before you switch lanes, answer one question: &lt;strong&gt;which variable would have to move — review minutes, attempts per month, or ops hours — before your current lane stops being the right choice?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the honest answer is "review minutes," then the cheapest experiment is a bounded pilot on a free lane, because you are not testing the model. You are testing one number with a stopwatch. MonkeyCode's free model access and free server option exist for exactly that kind of bounded test, and the operator's terms — including the advertised 10M free tokens — are theirs to set and worth reading before you plan a quarter around them.&lt;/p&gt;

&lt;p&gt;Measure the review minutes first. Everything else is cheaper than guessing wrong about those.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Price AI Coding Lanes With Rollback Hours, Not Token Stickers</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Sun, 13 Sep 2026 19:10:20 +0000</pubDate>
      <link>https://dev.to/bestbee/price-ai-coding-lanes-with-rollback-hours-not-token-stickers-44la</link>
      <guid>https://dev.to/bestbee/price-ai-coding-lanes-with-rollback-hours-not-token-stickers-44la</guid>
      <description>&lt;p&gt;A platform lead told a room the AI coding bill was zero. Then someone opened the revert log. Fourteen reverts in eleven working days. That is not a free path. That is an unpriced one.&lt;/p&gt;

&lt;p&gt;I keep seeing the same inversion. Finance scores seats and token stickers. Incident review scores hours you cannot get back. Which unit should actually assign the work?&lt;/p&gt;

&lt;p&gt;This is a routing guide, not a vendor sermon. I will price three lanes with one equation, fill a labeled example, and show which variable flips the call. The scorecard is a conversation tool. It is not objective truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bad proxy hiding in the standup
&lt;/h2&gt;

&lt;p&gt;Teams still ask, "Is the model free?" That question is incomplete. Free of invoice is not free of review, revert, or context setup.&lt;/p&gt;

&lt;p&gt;A token sticker also lies in the other direction. A paid seat can look expensive while it quietly deletes two rollback hours a week. Self-host can look virtuous while it burns a platform engineer on GPU babysitting that never shows up on the AI budget line.&lt;/p&gt;

&lt;p&gt;So I stopped asking which tool is cheaper. I ask which &lt;em&gt;workstream&lt;/em&gt; belongs on which lane.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three lanes, one workstream at a time
&lt;/h2&gt;

&lt;p&gt;Do not make a team-wide license call. Route tickets.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free lane:&lt;/strong&gt; zero invoice, shared or hosted-for-you runtime, weakest guarantee that the path will still look the same next quarter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paid lane:&lt;/strong&gt; invoice you can forecast, vendor on the hook for uptime and policy knobs, still not your metal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-host lane:&lt;/strong&gt; you own the runtime, the logs, and the failure. You also own the idle capacity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A changelog draft and an authz middleware change should not share a lane just because they share a repo. Why would they?&lt;/p&gt;

&lt;h2&gt;
  
  
  Variable definitions
&lt;/h2&gt;

&lt;p&gt;Write these on the top of the sheet before anyone argues about brands.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symbol&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;R&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Fully loaded cost of one rollback hour (author + reviewer + wait)&lt;/td&gt;
&lt;td&gt;currency / hour&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;H&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extra rollback hours this workstream is expected to create per week on that lane&lt;/td&gt;
&lt;td&gt;hours / week&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;I&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invoice for that lane, allocated to this workstream&lt;/td&gt;
&lt;td&gt;currency / week&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Amortized context and policy setup (rules, allowlists, eval fixtures)&lt;/td&gt;
&lt;td&gt;currency / week&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;G&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Governance drag (legal, security, procurement) that actually fires&lt;/td&gt;
&lt;td&gt;currency / week&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;K&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hard kill switch. If true, cost math does not get a vote&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Weekly lane cost:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LaneCost = I + R * H + C + G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;K&lt;/code&gt; is true, you do not pick the cheapest number. You leave the lane. Secrets, production-adjacent writes without an owner, and unauditable training-data questions are &lt;code&gt;K&lt;/code&gt; events in most orgs I advise. Your legal team may add more. They should write them down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rollback-hour router
&lt;/h2&gt;

&lt;p&gt;I score each workstream against all three lanes. Lowest &lt;code&gt;LaneCost&lt;/code&gt; wins &lt;em&gt;unless&lt;/em&gt; a kill switch fires.&lt;/p&gt;

&lt;p&gt;Copy this YAML and fill it in the staff meeting, not after the vendor demo.&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;# proposal: conversation tool, not a benchmark&lt;/span&gt;
&lt;span class="na"&gt;workstream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;billing-api-tests&lt;/span&gt;
&lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform-lead&lt;/span&gt;
&lt;span class="na"&gt;expires_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-10-14&lt;/span&gt;
&lt;span class="na"&gt;r_rollback_hour&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;180&lt;/span&gt;   &lt;span class="c1"&gt;# labeled assumption, fully loaded&lt;/span&gt;
&lt;span class="na"&gt;lanes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;free&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;I&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;H&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3.5&lt;/span&gt;
    &lt;span class="na"&gt;C&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;
    &lt;span class="na"&gt;G&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;K&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;paid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;I&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;220&lt;/span&gt;
    &lt;span class="na"&gt;H&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.2&lt;/span&gt;
    &lt;span class="na"&gt;C&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;
    &lt;span class="na"&gt;G&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
    &lt;span class="na"&gt;K&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;self_host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;I&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;    &lt;span class="c1"&gt;# allocated idle capacity, not cash if already owned&lt;/span&gt;
    &lt;span class="na"&gt;H&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.0&lt;/span&gt;
    &lt;span class="na"&gt;C&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;70&lt;/span&gt;
    &lt;span class="na"&gt;G&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;
    &lt;span class="na"&gt;K&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;exit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;freeze_free_if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;H_free&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2.0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;2&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;consecutive&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;weeks"&lt;/span&gt;
  &lt;span class="na"&gt;rescore_after_tickets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the arithmetic so the argument has a denominator.&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;# unlabeled brands on purpose. plug in your numbers.
&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;Lane&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="n"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;extra_rollback_h&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;governance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;kill&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;R&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;180.0&lt;/span&gt;  &lt;span class="c1"&gt;# labeled assumption: $/rollback-hour
&lt;/span&gt;
&lt;span class="n"&gt;lanes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nc"&gt;Lane&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&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="mf"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;40&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="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nc"&gt;Lane&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&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;220&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&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="nc"&gt;Lane&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_host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;70&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;15&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;lane&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;lanes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;cost&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;invoice&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;R&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;extra_rollback_h&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;setup&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;governance&lt;/span&gt;
    &lt;span class="n"&gt;status&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&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;lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kill&lt;/span&gt; &lt;span class="k"&gt;else&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;cost&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="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="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;lane&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; LaneCost=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected print for the labeled example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;free       LaneCost=670
paid       LaneCost=491
self_host  LaneCost=355
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Self-host wins &lt;em&gt;on this sheet&lt;/em&gt;. Change &lt;code&gt;R&lt;/code&gt; or &lt;code&gt;H&lt;/code&gt; and it may not. That is the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  A filled squad example (labeled, not a customer claim)
&lt;/h2&gt;

&lt;p&gt;Take an eight-person platform squad. Three workstreams. I am not citing a named company. These are working numbers so you can disagree with a digit instead of a vibe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Assumptions I want challenged:&lt;/strong&gt; &lt;code&gt;R = $180&lt;/code&gt;. Reviewer time is in the number. Calendar time waiting on a broken deploy is not, unless you add it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Release notes and internal runbooks.&lt;/strong&gt; &lt;code&gt;H_free = 0.3&lt;/code&gt;, &lt;code&gt;I_free = 0&lt;/code&gt;, &lt;code&gt;K = false&lt;/code&gt;. Free lane cost ≈ &lt;code&gt;$54 + setup&lt;/code&gt;. Paid cannot win unless setup on free is chaotic. Keep it free. Put a human on the merge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Billing API tests that touch fixtures, not secrets.&lt;/strong&gt; &lt;code&gt;H_free = 3.5&lt;/code&gt;, &lt;code&gt;H_paid = 1.2&lt;/code&gt;, &lt;code&gt;I_paid = $220 / week&lt;/code&gt; allocated. From the script above, paid beats free (&lt;code&gt;491&lt;/code&gt; vs &lt;code&gt;670&lt;/code&gt;). Self-host beats both &lt;em&gt;if&lt;/em&gt; you already have idle capacity. If you do not, set &lt;code&gt;I_self_host&lt;/code&gt; to the real weekly carry and re-run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authz middleware.&lt;/strong&gt; &lt;code&gt;K = true&lt;/code&gt; on any path you cannot log, restrict, or turn off. Cost math is commentary. Self-host or a paid tenant with a written data path. Not a shared free box.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice what I did not do. I did not average the three workstreams into one "AI ROI." Averages hide the kill switch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sensitivity: which number reverses you?
&lt;/h2&gt;

&lt;p&gt;Hold everything else still and move one lever.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lever&lt;/th&gt;
&lt;th&gt;Direction&lt;/th&gt;
&lt;th&gt;What flips&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;R&lt;/code&gt; falls from 180 to 50&lt;/td&gt;
&lt;td&gt;rollback is cheap&lt;/td&gt;
&lt;td&gt;billing tests fall back to free (&lt;code&gt;0 + 50*3.5 + 40 = 215&lt;/code&gt; vs paid &lt;code&gt;220 + 50*1.2 + 55 = 335&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;H_free&lt;/code&gt; falls from 3.5 to 1.0&lt;/td&gt;
&lt;td&gt;reviewers actually catch the mess&lt;/td&gt;
&lt;td&gt;free wins on billing tests even at &lt;code&gt;R = 180&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;I_paid&lt;/code&gt; jumps because you allocated the whole invoice to one squad&lt;/td&gt;
&lt;td&gt;paid looks toxic&lt;/td&gt;
&lt;td&gt;you are doing allocation theater; split &lt;code&gt;I&lt;/code&gt; by tickets, not by pride&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Idle GPUs already exist&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;I_self_host&lt;/code&gt; near zero&lt;/td&gt;
&lt;td&gt;self-host wins more often, until on-call hours leak into &lt;code&gt;C&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Legal says prompts leave the tenant&lt;/td&gt;
&lt;td&gt;&lt;code&gt;K = true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;free lane dies regardless of &lt;code&gt;LaneCost&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If no lever can reverse you, you are not running a model. You are defending a purchase.&lt;/p&gt;

&lt;p&gt;Crude telemetry helps you stop guessing &lt;code&gt;H&lt;/code&gt;. This is a proxy, not science.&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;# last 14 days, revert-shaped commits on one service&lt;/span&gt;
git log &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"14 days ago"&lt;/span&gt; &lt;span class="nt"&gt;--grep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"revert"&lt;/span&gt; &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; services/billing-api | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;

&lt;span class="c"&gt;# optional: minutes between bad merge and revert, if your messages are disciplined&lt;/span&gt;
git log &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"14 days ago"&lt;/span&gt; &lt;span class="nt"&gt;--grep&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"revert"&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"%ct %s"&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; services/billing-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Count is not hours. Multiply by your median revert duration from the incident doc, then divide by two weeks. If you do not have that median, you are not ready to claim the free lane is "working."&lt;/p&gt;

&lt;h2&gt;
  
  
  Hard gates, owner, expiry, exit
&lt;/h2&gt;

&lt;p&gt;Gates that skip the equation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Secrets or customer PII in prompt, repo context, or traces.&lt;/strong&gt; No free shared runtime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production-adjacent write tools without a named blast-radius owner.&lt;/strong&gt; No lane at all until the owner exists.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No merge human.&lt;/strong&gt; If the path can open a PR, a person still ships it. Automation without a neck is not a lane. It is a leak.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Owner:&lt;/strong&gt; the platform lead who can freeze a lane without a steering committee. If that person does not exist, you do not have a router. You have a Slack poll.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expiry:&lt;/strong&gt; 30 days or 20 tickets, whichever comes first. Write the date in the YAML. An expired score with last quarter's &lt;code&gt;H&lt;/code&gt; is fan fiction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exit:&lt;/strong&gt; freeze the free lane for that workstream when &lt;code&gt;H_free&lt;/code&gt; beats your break-even for two consecutive weeks, or when a &lt;code&gt;K&lt;/code&gt; event fires once. Unfreezing needs a new sheet, not a vibe that "the model got better."&lt;/p&gt;

&lt;p&gt;Break-even extra rollback hours for free versus paid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;H_free_break_even = H_paid + (I_paid + C_paid + G_paid - C_free - G_free) / R
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Plug the labeled billing-test numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;H_free_break_even = 1.2 + (220 + 25 + 30 - 40 - 0) / 180
                  = 1.2 + 235 / 180
                  = 2.51 hours/week
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If free is adding more than ~2.5 rollback hours a week on that stream, the sticker price of zero has already lost. That threshold moves the moment &lt;code&gt;R&lt;/code&gt; moves. Put the formula next to the YAML so people argue the input, not the brand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free model path still belongs
&lt;/h2&gt;

&lt;p&gt;I do not route every spike to a credit card. Internal docs, throwaway probes, and new-hire sandboxes often lose when you force a paid tenant before anyone knows whether the workflow sticks.&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 pair maps to the free lane in this router: useful when &lt;code&gt;K&lt;/code&gt; is false and &lt;code&gt;H&lt;/code&gt; is still a guess. It does not map to authz middleware, and I will not pretend a free runtime is a production owner. If you try it, score the workstream in the YAML first. Then look at revert hours, not at whether the chat felt fast.&lt;/p&gt;

&lt;p&gt;A free server also fails a different way than a free chat box. Someone still has to patch it, restrict network egress, and decide who can paste logs into the prompt. If that someone is "whoever found the link," &lt;code&gt;C&lt;/code&gt; and &lt;code&gt;G&lt;/code&gt; are lying on your sheet.&lt;/p&gt;

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

&lt;p&gt;Skip it if you are a solo hobbyist. Your &lt;code&gt;R&lt;/code&gt; is weekend mood, not payroll.&lt;/p&gt;

&lt;p&gt;Skip it if a regulator or a customer contract already names the runtime. The equation will only decorate a decision you are not allowed to make.&lt;/p&gt;

&lt;p&gt;Skip it if you cannot name a median revert duration. You would be stuffing &lt;code&gt;H&lt;/code&gt; with optimism. That is how "free" paths become silent headcount taxes.&lt;/p&gt;

&lt;p&gt;And skip any scorecard that outputs a single company-wide winner. Workstreams do not consent to that average.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would challenge on your sheet
&lt;/h2&gt;

&lt;p&gt;Would a 30-point drop in &lt;code&gt;R&lt;/code&gt; send billing tests back to free? If yes, your paid lane is a rollback hedge, not a quality religion. Price it that way.&lt;/p&gt;

&lt;p&gt;Would one &lt;code&gt;K&lt;/code&gt; event — a secret in a prompt, a prod write with no owner — wipe the free lane even when &lt;code&gt;LaneCost&lt;/code&gt; looks pretty? It should.&lt;/p&gt;

&lt;p&gt;I want the argument on those two questions. Not on whether the token sticker was zero.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>career</category>
    </item>
    <item>
      <title>Should a Squad Graduate a Free Coding Path When Review Time Inverts? Use This 5-Field Gate</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Sat, 12 Sep 2026 17:04:00 +0000</pubDate>
      <link>https://dev.to/bestbee/should-a-squad-graduate-a-free-coding-path-when-review-time-inverts-use-this-5-field-gate-43io</link>
      <guid>https://dev.to/bestbee/should-a-squad-graduate-a-free-coding-path-when-review-time-inverts-use-this-5-field-gate-43io</guid>
      <description>&lt;p&gt;Forty extra review minutes can erase a zero invoice. I keep seeing that inversion in platform reviews, and it almost never shows up on a pricing page.&lt;/p&gt;

&lt;p&gt;Last quarter I sat with an EM who was proud the coding path had no bill. The review queue was two days deep. Agent-shaped PRs were landing faster. Humans were not. So I asked the only question that can reverse a “keep it, it’s free” call: what happens if review minutes per merged change stay inverted for two more sprints?&lt;/p&gt;

&lt;p&gt;This is not a buy-the-tool essay. It is a graduation gate. Free hosted models and a free server can be a rational row in the table. They can also become a shadow platform with no owner, no expiry, and a switch cost you will hate later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong unit is still “free”
&lt;/h2&gt;

&lt;p&gt;Invoice line is a terrible proxy for coding-path cost. A zero invoice hides three cash-like drains: extra review minutes, dual-workflow tax, and the day you must move.&lt;/p&gt;

&lt;p&gt;Paid seats can be the wrong unit too. Self-hosting can be the wrong unit if you price hardware and ignore the human who now owns uptime. I want one question on the whiteboard: &lt;strong&gt;should this squad keep, graduate, or kill the free coding path?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keep means the free path stays default for a named scope. Graduate means you move that scope to paid or self-hosted on a date. Kill means you archive the path and write down what you will not do again. Which of those three is actually on your calendar today?&lt;/p&gt;

&lt;h2&gt;
  
  
  Define five fields before anyone argues
&lt;/h2&gt;

&lt;p&gt;Treat this scorecard as a conversation tool, not objective truth. Fill it with your numbers. If a field is blank, you do not have a decision. You have a vibe.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Definition&lt;/th&gt;
&lt;th&gt;Unit&lt;/th&gt;
&lt;th&gt;Who measures&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Review-minute inversion (RMI)&lt;/td&gt;
&lt;td&gt;Extra human review minutes per merged PR vs the squad’s baseline for similar diffs&lt;/td&gt;
&lt;td&gt;minutes / merged PR&lt;/td&gt;
&lt;td&gt;EM + a rotating reviewer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secret surface (SS)&lt;/td&gt;
&lt;td&gt;Whether prompts, repo context, or secrets leave the team’s control boundary&lt;/td&gt;
&lt;td&gt;inside / mixed / leaves&lt;/td&gt;
&lt;td&gt;Security + platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switch cost (SC)&lt;/td&gt;
&lt;td&gt;Calendar days to move the same workflow to paid or self-hosted without freezing shipping&lt;/td&gt;
&lt;td&gt;days&lt;/td&gt;
&lt;td&gt;Tech lead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dual-path tax (DPT)&lt;/td&gt;
&lt;td&gt;Hours per week lost to two coding paths, two prompt styles, two “how we do agents” docs&lt;/td&gt;
&lt;td&gt;hours / week&lt;/td&gt;
&lt;td&gt;EM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Owner + expiry (OE)&lt;/td&gt;
&lt;td&gt;Named human plus a date when keep/graduate/kill is re-decided&lt;/td&gt;
&lt;td&gt;name + ISO date&lt;/td&gt;
&lt;td&gt;Director or platform lead&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Hard rule: if OE is empty, the path is not free. It is unowned infrastructure.&lt;/p&gt;

&lt;p&gt;I score keep vs graduate vs kill with gates, not with a weighted average that pretends precision. Averages hide a single red gate. You already know that from incident reviews. Why would a coding path be different?&lt;/p&gt;

&lt;h2&gt;
  
  
  Proposed measurement, not a benchmark
&lt;/h2&gt;

&lt;p&gt;Do not invent velocity theater. Pull a small, boring sample. Thirty merged PRs. Two weeks. Label the method as a proposal until you actually run it.&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 measurement — run on YOUR repo; this is not a result set.&lt;/span&gt;
&lt;span class="c"&gt;# Baseline: human-authored PRs. Treatment: PRs that used the free coding path.&lt;/span&gt;
gh &lt;span class="nb"&gt;pr &lt;/span&gt;list &lt;span class="nt"&gt;--state&lt;/span&gt; merged &lt;span class="nt"&gt;--limit&lt;/span&gt; 30 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--json&lt;/span&gt; number,title,author,createdAt,mergedAt,reviews,labels &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /tmp/pr-sample.json

&lt;span class="c"&gt;# Then tag each row in a sheet: baseline | free_path&lt;/span&gt;
&lt;span class="c"&gt;# RMI = median(review_minutes_free) - median(review_minutes_baseline)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review minutes are not “time to first comment.” Use time from ready-for-review to first approving review, minus known blockers. If you cannot get that from your tool, sit with two reviewers for one standup and reconstruct ten PRs. Ugly beats fake precision.&lt;/p&gt;

&lt;p&gt;A tiny ledger keeps the argument honest:&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;# decision_record.yaml — proposal, unexecuted&lt;/span&gt;
&lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;graduate_free_coding_path&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;squad_orion_service_repo&lt;/span&gt;
&lt;span class="na"&gt;baseline_window&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-08-25/2026-09-12&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;rmi_minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;          &lt;span class="c1"&gt;# fill from sample&lt;/span&gt;
  &lt;span class="na"&gt;secret_surface&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mixed&lt;/span&gt;      &lt;span class="c1"&gt;# inside | mixed | leaves&lt;/span&gt;
  &lt;span class="na"&gt;switch_cost_days&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;       &lt;span class="c1"&gt;# paid vs self-host may differ; pick the real alternative&lt;/span&gt;
  &lt;span class="na"&gt;dual_path_tax_hours&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;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&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;Chen,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;EM"&lt;/span&gt;
  &lt;span class="na"&gt;expiry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2026-10-10"&lt;/span&gt;
&lt;span class="na"&gt;gates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;secrets_must_stay_inside&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;named_owner_required&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;rmi_kill_threshold_minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;
  &lt;span class="na"&gt;rmi_streak_sprints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;rmi_minutes&lt;/code&gt; stays null, stop the meeting. You are bargaining about a feeling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hypothetical: Squad Orion, not a case study
&lt;/h2&gt;

&lt;p&gt;I am not claiming this squad exists. I am filling the tool so you can see the arithmetic. Copy the structure. Replace every number.&lt;/p&gt;

&lt;p&gt;Squad Orion: eight engineers, one service repo, one “no invoice” coding path for boilerplate and tests. Baseline review for a similar PR: 25 minutes. Free-path PRs: 70 minutes, because the diffs are wide, the tests are shallow, and reviewers do not trust the agent loop. RMI = 45. Secret surface = mixed (prompts leave the laptop, secrets are supposed to stay). Switch cost to a paid path = 6 days of policy and seat work. Switch cost to self-host = 18 days including on-call. Dual-path tax = 4 hours/week of “which path did you use?” Slack. Owner exists. Expiry is blank.&lt;/p&gt;

&lt;p&gt;What does the gate say?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;OE fails.&lt;/strong&gt; No expiry means keep-by-inertia. That is a stop, not a keep.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RMI is 45 against a 40-minute kill line.&lt;/strong&gt; One sprint is a smell. Two sprints is a graduation trigger.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SS is mixed.&lt;/strong&gt; If the next SOC questionnaire asks where repo context went, “it was free” is not an answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SC is the real comparison.&lt;/strong&gt; Six days to a paid path vs eighteen to self-host. Free vs paid is not the same decision as free vs self-host. Write both.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Weekly human cost of the inversion, labeled as arithmetic on the hypothetical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;12 merged free-path PRs / week × 45 extra minutes = 9 hours of senior review.&lt;/li&gt;
&lt;li&gt;Plus 4 hours of dual-path tax = 13 hours / week.&lt;/li&gt;
&lt;li&gt;At a fully loaded $120/hour (your finance number, not mine), that is $1,560 / week of “free.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Would you still call it free if the invoice arrived as review load? I wouldn’t. Not past expiry. Not with mixed secret surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sensitivity: which number flips you?
&lt;/h2&gt;

&lt;p&gt;Hold every field still and move one. That is the whole point of a gate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If RMI drops to 12 minutes after you ban agent loops from auth and migrations, keep can survive — &lt;strong&gt;with an expiry&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If RMI stays at 45 for two sprints, graduate the default path even if the invoice is still zero.&lt;/li&gt;
&lt;li&gt;If SS becomes “leaves” for a regulated repo, free hosted is out regardless of RMI. That is a hard gate, not a score.&lt;/li&gt;
&lt;li&gt;If SC to paid is 6 days and SC to self-host is 18, do not let a hardware enthusiast skip the cheaper graduation. Self-host is a product choice, not a moral one.&lt;/li&gt;
&lt;li&gt;If DPT hits 8 hours/week, you already have two platforms. Pick one default. The second path becomes an expiring exception, not a culture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Break-even on the hypothetical: extra review minutes × PRs per week = the “free” surplus. At 12 PRs/week, a 40-minute RMI is 8 hours. If your paid alternative’s true add-on (seats, admin, extra process) is less than those 8 hours, graduation wins on P&amp;amp;L even before secrets. If the paid add-on is 15 hours/week of ceremony, keep the free path and fix the review protocol instead. See how fast the answer moves? That is why a single vendor narrative is useless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where a free hosted row belongs
&lt;/h2&gt;

&lt;p&gt;You still need a concrete row for “stay on a free hosted path.” Empty rows get filled by whoever is loudest.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode is an open-source project that currently offers free model access and a free server option. I am using those two availability claims as operator-supplied inputs to the table — not as a TCO conclusion, a benchmark, or a promise about models, quotas, hardware, or how long the offer lasts.&lt;/p&gt;

&lt;p&gt;Put that row next to “paid hosted” and “self-host.” Then run SS and SC. A free hosted path is a fit when secret surface can stay inside policy, RMI is measured, a named owner exists, and expiry is on a calendar. It is a poor fit when the squad is already using the path as default infra for anything that can page production.&lt;/p&gt;

&lt;p&gt;If you want a free hosted row to score against your own review sample, try MonkeyCode and then fill RMI from &lt;em&gt;your&lt;/em&gt; last thirty PRs — not from a landing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hard gates, owner, expiry, exit
&lt;/h2&gt;

&lt;p&gt;Gates are binary. Miss one and you do not “average it out.”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep is allowed only if all of these are true:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Named owner on the decision record.&lt;/li&gt;
&lt;li&gt;Expiry ≤ 45 days from today (pick your number; write it).&lt;/li&gt;
&lt;li&gt;SS is inside, or mixed with a written exception that names the repos that are in and out.&lt;/li&gt;
&lt;li&gt;RMI is below your kill line, or above it for at most one sprint with a dated fix.&lt;/li&gt;
&lt;li&gt;Default path is scoped (for example: tests and docs, not auth).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Graduate when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RMI ≥ kill line for two consecutive sprints, or&lt;/li&gt;
&lt;li&gt;DPT ≥ 6 hours/week, or&lt;/li&gt;
&lt;li&gt;a paid path’s switch cost is lower than the next two sprints of inverted review.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Kill when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SS is “leaves” on a repo that cannot leave, or&lt;/li&gt;
&lt;li&gt;no owner will put their name on OE, or&lt;/li&gt;
&lt;li&gt;the path is the only way anyone knows how to change the service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Exit criteria should be boring. Archive the prompts. Close the free-path default in the team README. Move the exception list to a gist or an internal RFC with an expiry. Say out loud what happens to in-flight agent sessions on the expiry date. If you cannot describe the Tuesday after expiry, you do not have an exit. You have hope.&lt;/p&gt;

&lt;p&gt;Owner is not “platform.” Owner is a person who can stop the path. Expiry is not “when we know more.” Expiry is an ISO date that creates a meeting even if nobody wants it.&lt;/p&gt;

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

&lt;p&gt;Skip this gate if you do not merge through review. There is no RMI without a reviewer. Also skip it if legal already forbids any hosted prompt path; you already have the answer, and a scorecard would be theater.&lt;/p&gt;

&lt;p&gt;Do not use a free hosted path as a stealth self-host delay for teams that need an on-call owner tomorrow. Do not use self-host as a purity move when your actual pain is review protocol. And do not run this as a founder-only spreadsheet while the EM who eats the queue is out of the room. The queue is the P&amp;amp;L.&lt;/p&gt;

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

&lt;p&gt;This model ignores model quality as a single number because I will not invent win rates. Quality shows up as RMI and as rollback rate. If you have a rollback delta, add a sixth field. If you do not, do not fake one.&lt;/p&gt;

&lt;p&gt;The 40-minute kill line is a conversation starter. Finance might want dollars. Security might want a binary SS and nothing else. Good. Bring them into the same document. The failure mode I care about is a squad that keeps a free path because the invoice is quiet while seniors drown in wide diffs.&lt;/p&gt;

&lt;p&gt;I also cannot tell you that free model access or a free server will still be there on your expiry date. Price switch cost as if the row can vanish. That is just TCO hygiene.&lt;/p&gt;

&lt;p&gt;So here is the question I actually want back: &lt;strong&gt;which field would reverse your keep — RMI, secret surface, or switch cost — and what number did you write next to it?&lt;/strong&gt; If you cannot name the number, you are not deciding. You are hoping the invoice stays zero long enough that the queue feels like someone else’s problem.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>opensource</category>
      <category>career</category>
    </item>
    <item>
      <title>Should a Squad Promote a Free Coding Path to Shared Context? Use This 4-Gate Test</title>
      <dc:creator>bestbee</dc:creator>
      <pubDate>Fri, 11 Sep 2026 14:59:58 +0000</pubDate>
      <link>https://dev.to/bestbee/should-a-squad-promote-a-free-coding-path-to-shared-context-use-this-4-gate-test-41o</link>
      <guid>https://dev.to/bestbee/should-a-squad-promote-a-free-coding-path-to-shared-context-use-this-4-gate-test-41o</guid>
      <description>&lt;p&gt;I still start these reviews the same way. Not with a model leaderboard. With the merge queue.&lt;/p&gt;

&lt;p&gt;A twelve-person squad can mint more unreviewed AI answers in one week than staff engineers can reconcile in a month. That ratio can reverse a “make the free path the default” decision overnight. A viral thread claiming AI already codes better than most developers does not pay the review tax. You do.&lt;/p&gt;

&lt;p&gt;Picture Tuesday standup. The EM drops a screenshot. Three people solved the same auth-boundary question in three private chats. Three answers. Three slightly different error contracts. Zero shared constraints in the repo. Cheap generation. Expensive divergence. Sound familiar?&lt;/p&gt;

&lt;h2&gt;
  
  
  The wrong question
&lt;/h2&gt;

&lt;p&gt;“Is the model good enough?” is a product-marketing question. It is not an adoption question.&lt;/p&gt;

&lt;p&gt;The adoption question is uglier. Should this free coding path stay a &lt;strong&gt;personal scratchpad&lt;/strong&gt;, or should you promote it into &lt;strong&gt;shared context&lt;/strong&gt; the team is allowed to trust?&lt;/p&gt;

&lt;p&gt;Those are different products wearing the same chat UI. Mix them up and you get shadow standards, unowned incidents, and a prompt folklore nobody can exit.&lt;/p&gt;

&lt;p&gt;I use four gates. They are a conversation tool, not objective truth. If one variable below would flip your call, write it down before anyone “standardizes” a server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scratchpad vs shared context
&lt;/h2&gt;

&lt;p&gt;A scratchpad is private, disposable, and easy to abandon. A shared context path is a workflow. It has owners, reuse, and a blast radius when it is wrong.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;What you are actually buying&lt;/th&gt;
&lt;th&gt;Failure mode&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Personal scratchpad&lt;/td&gt;
&lt;td&gt;Speed on a single task&lt;/td&gt;
&lt;td&gt;Divergent patterns, duplicated wrong answers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared context&lt;/td&gt;
&lt;td&gt;Reused constraints, fewer repeated questions&lt;/td&gt;
&lt;td&gt;Unowned “the agent said so” merges&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Paid team workspace&lt;/td&gt;
&lt;td&gt;Vendor workflow, seats, support path&lt;/td&gt;
&lt;td&gt;Seat proxies hiding unused licenses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Self-host&lt;/td&gt;
&lt;td&gt;Control of data path and teardown&lt;/td&gt;
&lt;td&gt;You inherited an internal SaaS&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Free model access and a free server option sit in the first two rows until you &lt;strong&gt;promote&lt;/strong&gt; them. Promotion is the decision. Not the signup.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach. MonkeyCode is one open-source coding product that currently offers free model access and a free server option. I am not treating those as a quality ranking, a quota promise, or a permanent SKU. I am treating them as a cheap way to run the gates below before you pay, self-host, or freeze a standard.&lt;/p&gt;

&lt;p&gt;Would you promote a wiki that nobody edits? Then do not promote a chat log either.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 4-gate ownership test
&lt;/h2&gt;

&lt;p&gt;Define the variables first. Then score. Then argue.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Context reuse rate (CRR).&lt;/strong&gt; Share of AI answers that get pasted, linked, or encoded into repo artifacts another human can find in 90 seconds. Unit: percent of AI-touched tasks in a 14-day window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review hours per AI-touched merged PR (RH-PR).&lt;/strong&gt; Staff time spent on first review plus re-review, including “please undo the clever bit.” Unit: hours / merged PR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Named revert authority (NRA).&lt;/strong&gt; One human who can revoke the path, revert the pattern, and say no without a committee. Unit: named role, not a Slack channel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Folklore exit days (FED).&lt;/strong&gt; Calendar days to recapture prompts, rules, and “we always do it this way” into files in git if the free path vanishes. Unit: days.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Score each gate 0, 1, or 2. Total 0–8. This is not a personality test. It is a promotion test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scoring rubric
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;CRR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0: reuse under 15%. Private chats die in the thread.&lt;/li&gt;
&lt;li&gt;1: 15–40%. A few snippets land in PRs, still not searchable.&lt;/li&gt;
&lt;li&gt;2: over 40%. Constraints live in repo docs, fixtures, or policy files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;RH-PR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0: review hours &lt;strong&gt;up&lt;/strong&gt; more than 25% vs the prior 14 days on comparable PRs.&lt;/li&gt;
&lt;li&gt;1: flat within ±25%.&lt;/li&gt;
&lt;li&gt;2: down more than 25%, with the same review bar. No silent rubber-stamping.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NRA&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0: “the team” owns it. Nobody can kill it on Friday.&lt;/li&gt;
&lt;li&gt;1: an EM owns it, but only after a sync.&lt;/li&gt;
&lt;li&gt;2: a named owner can revoke access the same day, in writing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;FED&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0: exit would take more than 14 days or depends on one person’s head.&lt;/li&gt;
&lt;li&gt;1: 8–14 days, with a documented prompt dump.&lt;/li&gt;
&lt;li&gt;2: 7 days or fewer, because rules already live in the repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hard promotion rule I use: &lt;strong&gt;do not promote to shared context unless CRR ≥ 1, NRA = 2, and total ≥ 5.&lt;/strong&gt; A pretty model demo cannot override a missing owner. Should it?&lt;/p&gt;

&lt;h2&gt;
  
  
  Filled example (hypothetical squad, labeled as such)
&lt;/h2&gt;

&lt;p&gt;Squad Helios. 12 engineers. 14-day window. Labeled &lt;strong&gt;unmeasured proposal&lt;/strong&gt;, not a customer case.&lt;/p&gt;

&lt;p&gt;They want to promote a free coding server from “try it” to “how we answer architecture questions.”&lt;/p&gt;

&lt;p&gt;Observed in the worksheet (hypothetical):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;40 AI-touched tasks&lt;/li&gt;
&lt;li&gt;8 produced a repo artifact another person reused → CRR = 20% → score &lt;strong&gt;1&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Mean RH-PR moved from 1.6h to 2.1h → +31% → score &lt;strong&gt;0&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Owner is “platform, kind of” → NRA score &lt;strong&gt;0&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Prompts live in four Notion pages and one engineer’s local snippets → FED ≈ 15 days → score &lt;strong&gt;0&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total: &lt;strong&gt;1 / 8&lt;/strong&gt;. Keep it a scratchpad. Do not put it on the onboarding doc. Do not imply the answers are team canon.&lt;/p&gt;

&lt;p&gt;Same squad, different 14 days, after they force one rule: every reused answer must land in &lt;code&gt;/docs/ai-constraints/&lt;/code&gt; or it does not count as shared.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CRR 45% → &lt;strong&gt;2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;RH-PR 1.4h vs 1.6h baseline → &lt;strong&gt;2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Staff engineer Maya is revert authority, written in the README → &lt;strong&gt;2&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Constraints already in git, FED = 3 days → &lt;strong&gt;2&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total: &lt;strong&gt;8 / 8&lt;/strong&gt;. Now you may &lt;em&gt;discuss&lt;/em&gt; promotion. You still set an expiry. A scorecard is not a marriage certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sensitivity that should change your mind
&lt;/h2&gt;

&lt;p&gt;Hold three variables still. Move one.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Lever you change&lt;/th&gt;
&lt;th&gt;If it moves this way&lt;/th&gt;
&lt;th&gt;Decision flip&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CRR&lt;/td&gt;
&lt;td&gt;Falls under 15%&lt;/td&gt;
&lt;td&gt;Demote to personal scratchpad&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RH-PR&lt;/td&gt;
&lt;td&gt;Rises over 25%&lt;/td&gt;
&lt;td&gt;Freeze promotion, inspect review bar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NRA&lt;/td&gt;
&lt;td&gt;Owner goes on PTO with no deputy&lt;/td&gt;
&lt;td&gt;Suspend shared use the same day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FED&lt;/td&gt;
&lt;td&gt;Exit estimate exceeds 14 days&lt;/td&gt;
&lt;td&gt;Stop writing new shared prompts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Incident&lt;/td&gt;
&lt;td&gt;One production miss tied to an unreviewed answer&lt;/td&gt;
&lt;td&gt;Exit the shared path; scratchpad may remain&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Break-even I actually argue about: &lt;strong&gt;hours saved in repeated questions versus hours added in review.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Weekly question load &lt;code&gt;Q&lt;/code&gt;. Minutes saved per reused answer &lt;code&gt;S&lt;/code&gt;. Reuse rate &lt;code&gt;CRR&lt;/code&gt;. Extra review minutes per AI-touched PR &lt;code&gt;R&lt;/code&gt;. AI-touched PRs per week &lt;code&gt;P&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Net hours ≈ &lt;code&gt;(Q * CRR * S) / 60 - (P * R) / 60&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If net hours go negative, the free path is a cost center even when the invoice is zero. Invoice-zero is not P&amp;amp;L-zero. You knew that, right?&lt;/p&gt;

&lt;p&gt;Worked numbers for Helios, still hypothetical: &lt;code&gt;Q = 30&lt;/code&gt;, &lt;code&gt;S = 12&lt;/code&gt;, &lt;code&gt;CRR = 0.20&lt;/code&gt;, &lt;code&gt;P = 10&lt;/code&gt;, &lt;code&gt;R = 30&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Net ≈ &lt;code&gt;(30 * 0.20 * 12)/60 - (10 * 30)/60&lt;/code&gt; = &lt;code&gt;1.2 - 5.0&lt;/code&gt; = &lt;strong&gt;-3.8 hours/week&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That is the whole case against promotion. Not model quality. Not a tweet. Review tax larger than reuse.&lt;/p&gt;

&lt;p&gt;Raise CRR to 0.50 and drop &lt;code&gt;R&lt;/code&gt; to 10 minutes because constraints are in git: net ≈ &lt;code&gt;(30 * 0.50 * 12)/60 - (10 * 10)/60&lt;/code&gt; = &lt;code&gt;3.0 - 1.7&lt;/code&gt; = &lt;strong&gt;+1.3 hours/week&lt;/strong&gt;. Only then is shared context even in the conversation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Measurement you can run without a vendor dashboard
&lt;/h2&gt;

&lt;p&gt;Label this as &lt;strong&gt;unexecuted template&lt;/strong&gt;. Do not pretend it is telemetry you already have.&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;# Last 14 days of merged PRs, titles only. Adjust the date.&lt;/span&gt;
git log &lt;span class="nt"&gt;--merges&lt;/span&gt; &lt;span class="nt"&gt;--since&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'2026-08-28'&lt;/span&gt; &lt;span class="nt"&gt;--pretty&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;format:&lt;span class="s1"&gt;'%h %ad %s'&lt;/span&gt; &lt;span class="nt"&gt;--date&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;short
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep a boring CSV. If it is not boring, people will stop filling it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;date,task_id,ai_touched,reused_in_repo,review_hours,merged,owner
2026-09-01,PAY-118,yes,yes,1.2,yes,maya
2026-09-02,PAY-121,yes,no,2.4,yes,lee
2026-09-03,PAY-126,no,no,0.8,yes,maya
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Proposed scorer. Hypothetical. Run it on your sheet, not on my claims.&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;# proposal only: score promotion gates from a local csv
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;statistics&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt;

&lt;span class="n"&gt;BASELINE_RH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.6&lt;/span&gt;  &lt;span class="c1"&gt;# hours; set from YOUR prior window
&lt;/span&gt;
&lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&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;ai_context_gate.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="n"&gt;ai&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ai_touched&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;yes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;crr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reused_in_repo&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;yes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ai&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;max&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;ai&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;rh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mean&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;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;review_hours&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;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;ai&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;ai&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;BASELINE_RH&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bucket_crr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&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;2&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.40&lt;/span&gt; &lt;span class="k"&gt;else&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;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt; &lt;span class="k"&gt;else&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;bucket_rh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;base&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;delta&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.25&lt;/span&gt; &lt;span class="k"&gt;else&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;crr&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;crr&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;crr_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bucket_crr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crr&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rh_pr&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;rh&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;rh_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;bucket_rh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BASELINE_RH&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NRA and FED still need a human. Scripts do not name owners. Scripts do not recapture folklore. If your “owner” is a distribution list, you already scored a zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hard gates, owner, expiry, exit
&lt;/h2&gt;

&lt;p&gt;Write these in the same README you were about to stuff with tool cheerleading.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Owner:&lt;/strong&gt; one staff engineer or EM. Deputy named. Not “platform.”&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiry:&lt;/strong&gt; 14 days after promotion, auto-demote unless the four scores are re-recorded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stop gates:&lt;/strong&gt; CRR &amp;lt; 15%, RH-PR +25%, missing owner, or one production incident tied to an unreviewed answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit:&lt;/strong&gt; prompts and constraints already in git, or FED work starts the day you promote, not the day the free server hiccups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-goals:&lt;/strong&gt; do not use seats, token headlines, or “it feels faster” as proxies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cannot name the exit, you are not buying leverage. You are buying a habit.&lt;/p&gt;

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

&lt;p&gt;Use a free-model, free-server path when you are still in &lt;strong&gt;measurement mode&lt;/strong&gt;. You need enough usage to fill the CSV. You do not yet need a seat contract or a self-hosted internal SaaS.&lt;/p&gt;

&lt;p&gt;Stay on personal scratchpad if CRR is low and RH-PR is rising. That is most squads in week one. It is not a moral failure. It is a workflow mismatch.&lt;/p&gt;

&lt;p&gt;Consider paid or self-host only after promotion passes twice in a row. Paid does not fix missing ownership. Self-host does not fix a review bar you were afraid to keep. Build-versus-buy is downstream of this test. Reverse that order and you will decorate a bad habit with invoices or with YAML.&lt;/p&gt;

&lt;p&gt;MonkeyCode is a reasonable place to run the first 14-day measurement if a free model path plus a free server is what you need to get the worksheet. Run the gates first. If the score stays a 1, do not “standardize” anything. Just close the tab.&lt;/p&gt;

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

&lt;p&gt;Do not promote a third-party free server into shared context if you cannot put that code or that prompt traffic on someone else’s machine. Regulated data, unpaid legal review, or “we will anonymize later” is a stop, not a yellow flag.&lt;/p&gt;

&lt;p&gt;Do not use the scorecard if you will treat a 6 as a mandate. It is a conversation tool. Two senior engineers can weight RH-PR differently. Good. Put the disagreement on the page.&lt;/p&gt;

&lt;p&gt;Do not use it to launder a quality claim. I am not saying any model is better than your developers. I am saying unowned generation does not become knowledge because the chat was fluent.&lt;/p&gt;

&lt;p&gt;Skip the whole promotion idea if the squad already has a working design-review ritual and AI is only used for local boilerplate. You do not need a shared context program to rename variables.&lt;/p&gt;

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

&lt;p&gt;I did not benchmark models. I did not invent a quota, a GPU SKU, or a durability promise. Token headlines change behavior; they are still a bad unit for this decision. Review hours and reuse are slower to collect and harder to fake. That is the point.&lt;/p&gt;

&lt;p&gt;Fourteen days is an arbitrary window. If your merge cadence is weekly, extend the window or you will overfit two PRs. If your cadence is many merges per day, 14 days may hide a bad week. Say the window out loud.&lt;/p&gt;

&lt;p&gt;And if the only artifact you can produce is a vibe, you are not ready to promote. You are ready to keep a scratchpad.&lt;/p&gt;

&lt;p&gt;So which variable would reverse &lt;strong&gt;your&lt;/strong&gt; call? CRR, RH-PR, the named owner, or the exit clock? If you cannot pick one, you are not deciding. You are hoping the free path stays free and the review queue stays quiet. Hope is not a gate.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>career</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
