<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>0xE8 - Blog</title>
    <subtitle>0xE8 is a software engineering consultancy: process audits, reliability practices, AI deployment, and systems architecture.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://0xe8.com/blog/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://0xe8.com/blog/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-02-18T00:00:00+00:00</updated>
    <id>https://0xe8.com/blog/atom.xml</id>
    <entry xml:lang="en">
        <title>Cutting deploy cost by a third without adding a single dashboard</title>
        <published>2026-02-18T00:00:00+00:00</published>
        <updated>2026-02-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            Geronimo GS
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://0xe8.com/blog/cutting-deploy-cost-without-a-dashboard/"/>
        <id>https://0xe8.com/blog/cutting-deploy-cost-without-a-dashboard/</id>
        
        <content type="html" xml:base="https://0xe8.com/blog/cutting-deploy-cost-without-a-dashboard/">&lt;p&gt;A platform org of about ninety engineers came to us with a familiar complaint: releases used to take a day, now they take most of a week, and nobody could point to exactly why. Headcount had roughly doubled in eighteen months. Deploy frequency hadn&#39;t moved.&lt;/p&gt;
&lt;p&gt;We ran our usual two-week diagnostic: trace an actual change from ticket to production, write down every wait, every handoff, every manual step. Not the pipeline in the wiki — the one engineers actually route through when the wiki&#39;s version is slower than asking someone directly in Slack.&lt;/p&gt;
&lt;h2 id=&quot;what-we-expected-to-find&quot;&gt;What we expected to find&lt;/h2&gt;
&lt;p&gt;Going in, the obvious suspect was the CI pipeline itself. Slow test suites, flaky infrastructure, that kind of thing. It&#39;s usually where teams look first, because it&#39;s the part they can see.&lt;/p&gt;
&lt;h2 id=&quot;what-we-actually-found&quot;&gt;What we actually found&lt;/h2&gt;
&lt;p&gt;The pipeline was fine. Fifteen minutes, mostly test execution, nothing embarrassing. The other four days and change were almost entirely queueing: waiting for one of two people who understood a particular legacy service well enough to approve changes to it, waiting for a weekly change-advisory meeting that had quietly become mandatory for anything touching billing, waiting for a staging environment that was shared across six teams and perpetually in a broken state left by whoever used it last.&lt;/p&gt;
&lt;p&gt;None of this showed up in any dashboard, because none of it was a system anyone was measuring. It was organizational scar tissue — reasonable decisions made individually, two years&#39; worth of them, that added up to a four-day queue nobody had designed on purpose.&lt;/p&gt;
&lt;h2 id=&quot;what-we-changed&quot;&gt;What we changed&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Split the legacy-service approval bottleneck into a documented ownership boundary with a second trained approver, cutting median wait from a day and a half to under two hours.&lt;/li&gt;
&lt;li&gt;Replaced the blanket change-advisory meeting with an actual risk classification, so only the changes that needed a human review before shipping got one.&lt;/li&gt;
&lt;li&gt;Gave each team its own disposable staging environment instead of a shared one, which also — as a side effect nobody asked for — cut a class of &quot;worked on staging, broke in prod&quot; incidents to roughly zero.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;where-it-landed&quot;&gt;Where it landed&lt;/h2&gt;
&lt;p&gt;Median lead time from merge to production dropped from just under five days to a little over three. Cost per deploy — engineer-hours burned on process rather than the change itself — came down by a bit more than a third. We left the pipeline-tracing setup running so the platform team can watch the number themselves instead of taking our word for it next quarter.&lt;/p&gt;
&lt;p&gt;The fix, in the end, was mostly deleting things: a meeting, a shared environment, a single point of failure in an approval chain. That&#39;s usually where it is.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>What we actually check before an eval harness ships</title>
        <published>2025-11-04T00:00:00+00:00</published>
        <updated>2025-11-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            Agustina A
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://0xe8.com/blog/what-we-check-before-an-eval-harness-ships/"/>
        <id>https://0xe8.com/blog/what-we-check-before-an-eval-harness-ships/</id>
        
        <content type="html" xml:base="https://0xe8.com/blog/what-we-check-before-an-eval-harness-ships/">&lt;p&gt;Most eval harnesses we inherit on day one of an engagement are built to answer &quot;does this response sound plausible&quot; rather than &quot;did the model do the thing correctly.&quot; Those are different questions, and only one of them tells you whether it&#39;s safe to change the prompt, swap the model, or ship the next version.&lt;/p&gt;
&lt;p&gt;Before we trust an eval harness enough to gate a deploy on it, we run it through the same four checks every time.&lt;/p&gt;
&lt;h2 id=&quot;1-does-it-fail-on-cases-you-know-are-wrong&quot;&gt;1. Does it fail on cases you know are wrong?&lt;/h2&gt;
&lt;p&gt;The single most common problem: an eval set with no negative examples. If every case in the suite is a real, correctly-handled request, a harness that always returns a fixed canned answer can still score close to 100%. We seed at least a third of the set with inputs we know should fail — ambiguous requests, adversarial phrasing, cases the current model already gets wrong — specifically to confirm the scoring function can tell the difference.&lt;/p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #F8F8F2; background-color: #282A36;&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color: #50FA7B;&quot;&gt; score&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span style=&quot;color: #FFB86C;font-style: italic;&quot;&gt;response&lt;/span&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color: #8BE9FD;font-style: italic;&quot;&gt; str&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span style=&quot;color: #FFB86C;font-style: italic;&quot;&gt; expected&lt;/span&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt;:&lt;/span&gt;&lt;span&gt; Expectation)&lt;/span&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt; -&amp;gt;&lt;/span&gt;&lt;span style=&quot;color: #8BE9FD;font-style: italic;&quot;&gt; float&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; expected.must_contain&lt;/span&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt; and&lt;/span&gt;&lt;span&gt; expected.must_contain&lt;/span&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt; not in&lt;/span&gt;&lt;span&gt; response:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #BD93F9;&quot;&gt; 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt;    if&lt;/span&gt;&lt;span&gt; expected.must_refuse&lt;/span&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt; and not&lt;/span&gt;&lt;span&gt; looks_like_refusal(response):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color: #BD93F9;&quot;&gt; 0.0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #FF79C6;&quot;&gt;    return&lt;/span&gt;&lt;span&gt; semantic_similarity(response, expected.reference)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A surprising amount of &quot;eval harness&quot; code we see is just the last line of that function — pure semantic similarity against a reference answer, with no hard failure conditions above it. That catches drift in tone. It does not catch a model confidently returning the wrong account balance.&lt;/p&gt;
&lt;h2 id=&quot;2-is-the-eval-set-actually-yours&quot;&gt;2. Is the eval set actually yours?&lt;/h2&gt;
&lt;p&gt;Generic benchmarks tell you how a model performs on the internet&#39;s idea of your problem. They don&#39;t tell you how it performs on your actual traffic, which has its own weird distribution of edge cases: the customer who pastes in a support ticket instead of a question, the request in a language your prompt wasn&#39;t tuned for, the input that&#39;s technically valid JSON but structurally nonsense. We build the eval set from real logged requests — sanitized, but real — every time.&lt;/p&gt;
&lt;h2 id=&quot;3-does-a-regression-in-the-eval-mean-a-regression-for-users&quot;&gt;3. Does a regression in the eval mean a regression for users?&lt;/h2&gt;
&lt;p&gt;We run this one backwards: take a change everyone agrees made things worse — a prompt edit that was rolled back, a model downgrade that got reverted — and confirm the eval score actually drops when we replay it. If the harness doesn&#39;t notice a change that the team already knows was bad, it isn&#39;t measuring the thing that matters, no matter how good the pass rate looks.&lt;/p&gt;
&lt;h2 id=&quot;4-who-looks-at-the-failures&quot;&gt;4. Who looks at the failures?&lt;/h2&gt;
&lt;p&gt;An eval harness that reports a number to a dashboard nobody opens isn&#39;t a safety mechanism, it&#39;s a decoration. Before we sign off on one, there&#39;s a named person whose job includes reading the failing cases after every run, not just the aggregate score. Usually that turns up a category of failure the eval set doesn&#39;t cover yet, which goes back into check 2.&lt;/p&gt;
&lt;p&gt;None of this is exotic. It&#39;s the same instinct as a good test suite: assert on outcomes, not vibes, and make sure something fails when it&#39;s supposed to. The harness that survives all four checks is the one we&#39;re willing to gate a production deploy on. Most of what we&#39;re handed on day one survives one or two.&lt;/p&gt;
</content>
        
    </entry>
</feed>
