<?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: Richard Atkins</title>
    <description>The latest articles on DEV Community by Richard Atkins (@groundedarchitect).</description>
    <link>https://dev.to/groundedarchitect</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%2F4030583%2F69419a09-9c69-4001-af0a-210d34675a16.jpg</url>
      <title>DEV Community: Richard Atkins</title>
      <link>https://dev.to/groundedarchitect</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/groundedarchitect"/>
    <language>en</language>
    <item>
      <title>The code that hides the evidence</title>
      <dc:creator>Richard Atkins</dc:creator>
      <pubDate>Wed, 05 Aug 2026 10:24:00 +0000</pubDate>
      <link>https://dev.to/groundedarchitect/the-code-that-hides-the-evidence-2eae</link>
      <guid>https://dev.to/groundedarchitect/the-code-that-hides-the-evidence-2eae</guid>
      <description>&lt;p&gt;&lt;em&gt;Part of "AI, engineering and what survives production", a series on the parts of building with AI that hold up once real traffic hits them.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There is a category of code that nobody defends in principle and everybody writes in practice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;syncCustomerRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;You do not think that is good. Neither do I, and I have written it. It gets written anyway, usually at the end of a long day, usually because the failure was intermittent and the deadline was not. And it is worse than the bug it silences, because the bug at least had the decency to announce itself.&lt;/p&gt;

&lt;p&gt;The distinction that matters is between &lt;strong&gt;handling&lt;/strong&gt; a failure and &lt;strong&gt;hiding&lt;/strong&gt; one. A catch block that logs, retries, or rethrows with context is engineering. A catch block that swallows is a deleted alarm. From ten feet away the two look identical: both are three lines and a pair of braces, both make the red text stop.&lt;/p&gt;

&lt;p&gt;Here is what interested me: this category is &lt;em&gt;countable&lt;/em&gt;. Not perfectly, but well enough to see a trend in your own codebase. So I built a tool to count it, pointed it at seven repositories I had worked in, and got an answer I was not expecting.&lt;/p&gt;

&lt;h2&gt;
  
  
  What counts as masking
&lt;/h2&gt;

&lt;p&gt;I split it into two tiers, and keeping them separate is the decision that makes the whole number defensible. My first version had a single score, and I abandoned it within an hour of pointing it at a real TypeScript codebase, for reasons I will come to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hard masking&lt;/strong&gt; removes a signal outright and is difficult to justify:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Empty catch&lt;/td&gt;
&lt;td&gt;&lt;code&gt;catch (e) {}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Silenced exception&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;except ValueError: pass&lt;/code&gt;, &lt;code&gt;rescue nil&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suppressed checking&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;@ts-ignore&lt;/code&gt;, &lt;code&gt;# noqa&lt;/code&gt;, &lt;code&gt;eslint-disable&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weakened typing&lt;/td&gt;
&lt;td&gt;&lt;code&gt;as any&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stubbed return&lt;/td&gt;
&lt;td&gt;&lt;code&gt;return None  # TODO&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discarded error&lt;/td&gt;
&lt;td&gt;Go's &lt;code&gt;_&lt;/code&gt; assignment over an &lt;code&gt;err&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Soft masking&lt;/strong&gt; is legitimate often enough that putting it in a headline would mislead: optional chaining, nullish defaults, TODO markers.&lt;/p&gt;

&lt;p&gt;Consider &lt;code&gt;user?.profile?.name&lt;/code&gt;. On a genuinely optional field that is correct code. The same expression, written because something in the chain was unexpectedly undefined and the &lt;code&gt;?.&lt;/code&gt; made the error go away, is a completely different act with identical syntax. No static tool can tell those apart, and I stopped trying. So soft constructs are counted separately, reported separately, and the judgement stays with you rather than being quietly made on your behalf.&lt;/p&gt;

&lt;p&gt;That split is not fussiness, it is what I learned from the version I threw away. Fold optional chaining into one score and a modern TypeScript codebase produces an alarming number that means nothing at all. The first person to check it will find their own perfectly reasonable &lt;code&gt;?.&lt;/code&gt; in the count, conclude the tool is crying wolf, and never open it again. One number you can defend beats two you cannot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Count only what was added
&lt;/h2&gt;

&lt;p&gt;I measure additions and ignore deletions. A deletion cannot introduce a swallowed error, and counting both sides double-counts a line that has merely moved from one file to another.&lt;/p&gt;

&lt;p&gt;Then normalise per thousand added lines, for the same reason as ever: a raw count tracks how much you wrote that month, and what you want to know is density. Otherwise a productive quarter looks like a decline in quality, and you will spend a week investigating the wrong thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the output looks like
&lt;/h2&gt;

&lt;p&gt;Real output, from the data pipeline behind this publication:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;diff-habits scan

  a data pipeline
    commits / files      360 / 584
    added lines          121,560  (83,840 meaningful)
    error masking (hard) 229  (1.88 per 1k added)
    error masking (soft) 417  (3.43 per 1k added)
    top patterns         nullish_default=232, stub_return=187,
                         optional_chain=175, any_cast_ts=22, lint_suppress=20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pattern breakdown is the part I actually act on. "229 hard hits" is a number I can do&lt;br&gt;
nothing with. "187 stubbed returns" is a Monday morning: I go and look at what those&lt;br&gt;
functions hand back when the thing they called did not answer, and I usually find two or&lt;br&gt;
three that should have been raising instead of shrugging.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I found, and why it is not what I expected
&lt;/h2&gt;

&lt;p&gt;Pointing this at seven repositories, hard-masking density ranged from &lt;strong&gt;0.16 to 4.0 per thousand added lines&lt;/strong&gt;. That is a twenty-five-fold spread across codebases written by the same three people.&lt;/p&gt;

&lt;p&gt;The highest was a data pipeline that scrapes web content and calls language models. The lowest was a small marketing site.&lt;/p&gt;

&lt;p&gt;Sit with that for a moment, because it is the whole lesson. &lt;strong&gt;The pipeline is not badly written. It is defensively written, correctly.&lt;/strong&gt; Networks time out. Scraped pages change shape. Model output is unreliable by construction. Code that talks to unreliable things needs guards, and those guards look exactly like masking to a regex.&lt;/p&gt;

&lt;p&gt;Which gives the finding I did not want and now think is the most useful thing here: &lt;strong&gt;error-masking density is dominated by problem domain, not by who or what wrote the code.&lt;/strong&gt; I had a tidy hypothesis about authorship. The data said the strongest predictor was what the code talks to.&lt;/p&gt;

&lt;p&gt;So if you compare masking density between two different codebases, what you learn is which one has the flakier dependencies. You learn nothing whatsoever about their authors. &lt;strong&gt;Compare a codebase with itself, over time.&lt;/strong&gt; That is the only comparison this metric will support, and I would rather tell you that than let you draw a conclusion it cannot carry.&lt;/p&gt;
&lt;h2&gt;
  
  
  What a rise actually means
&lt;/h2&gt;

&lt;p&gt;A rise is not automatically bad, and I was careful to build a tool that does not imply otherwise, because one that scolds you gets uninstalled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7gnb8fiansr5bd7mo3gx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7gnb8fiansr5bd7mo3gx.jpg" alt=" " width="800" height="512"&gt;&lt;/a&gt;Hardening a service against a genuinely flaky dependency raises the count and is usually the right call. So rising density says &lt;em&gt;look here&lt;/em&gt;, not &lt;em&gt;you have failed&lt;/em&gt;. What I want to know when I see it is whether the guards I added are logging, alerting, or falling back deliberately, or whether they are quietly returning empty and leaving the caller to draw its own conclusions. Those two look the same in a diff and could not be less alike in production.&lt;/p&gt;

&lt;p&gt;The question the number should prompt is the one I now ask myself in review: &lt;strong&gt;if this construct fires at three in the morning, does anybody find out?&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The honest limitations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;These are regexes, not a parser.&lt;/strong&gt; They over-count a legitimate optional chain and under-count a swallow spread across several lines. &lt;code&gt;except ValueError:&lt;/code&gt; on one line followed by an indented &lt;code&gt;pass&lt;/code&gt; on the next slips straight through, and catching that properly needs an AST rather than a pattern. I decided that was a worthwhile trade for something you can run on any language in a second, but it means the trend is the meaningful part and a single absolute number is not an audit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Language scoping matters more than I expected.&lt;/strong&gt; An early version cheerfully matched TypeScript optional chaining inside Python files, which is obvious in hindsight and was not obvious to me until the numbers came out strange. Patterns are scoped by file extension now. If you extend the pattern list, scope yours too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small counts are noise, and I nearly fooled myself with one.&lt;/strong&gt; A repository of mine produced a single hit across six thousand lines, and for about ten minutes I read that as an impressively clean codebase. It is not a low density. It is not enough data to have a density at all.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it on yours
&lt;/h2&gt;

&lt;p&gt;Python 3.10 or newer. It depends on &lt;a href="https://github.com/uxdw/git-habits" rel="noopener noreferrer"&gt;git-habits&lt;/a&gt;,&lt;br&gt;
so exclusion rules stay identical between the two tools and their numbers remain&lt;br&gt;
comparable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/uxdw/diff-habits &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;diff-habits
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; .venv/bin/pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

diff-habits scan    &lt;span class="nt"&gt;--repo&lt;/span&gt; /your/repo &lt;span class="nt"&gt;--author&lt;/span&gt; &lt;span class="s2"&gt;"you@example.com"&lt;/span&gt;
diff-habits compare &lt;span class="nt"&gt;--repo&lt;/span&gt; /your/repo &lt;span class="nt"&gt;--author&lt;/span&gt; &lt;span class="s2"&gt;"you@example.com"&lt;/span&gt; &lt;span class="nt"&gt;--split&lt;/span&gt; 2026-01-01
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike &lt;code&gt;git-habits&lt;/code&gt;, this one needs a real working repository. It reads diff bodies, and&lt;br&gt;
a metadata export does not contain them.&lt;/p&gt;

&lt;p&gt;It reads locally and emits counts. Nothing is uploaded, and there is no network access to upload it with.&lt;/p&gt;

&lt;p&gt;That is deliberate, and it is why this is a separate tool from its companion &lt;a href="https://github.com/uxdw/git-habits" rel="noopener noreferrer"&gt;git-habits&lt;/a&gt; rather than a flag on it. &lt;code&gt;git-habits&lt;/code&gt; works from commit metadata and never opens a source file, so you can run it on an employer's repository without a conversation. This one reads your code. That is a different decision, and it should be a different install rather than a flag you might not notice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is deliberately missing
&lt;/h2&gt;

&lt;p&gt;The tool also implements block duplication, and it is &lt;strong&gt;off by default&lt;/strong&gt; behind &lt;code&gt;--experimental-duplication&lt;/code&gt;. The current approach counts any five-line sequence recurring anywhere in the history it walks, which conflates real copy and paste with code re-added after a refactor and with ordinary boilerplate. Measured against real repositories it reads about three orders of magnitude above published figures. It is useful as a trend within one repository and useless as an absolute number, so it says so and stays out of the default output.&lt;/p&gt;

&lt;p&gt;And line-level move detection, the signal behind the widely repeated claim that refactoring is collapsing, is not implemented at all. It is a similarity-matching problem rather than a hashing one, and a naive version would produce numbers that look plausible and cannot survive comparison with the research they would be quoted against.&lt;/p&gt;

&lt;p&gt;Both of those are in the README rather than an issue tracker, because a tool that quietly ships a broken metric is worse than one that admits to a gap. The whole point of measuring is to stop guessing. A measurement you cannot trust is just a guess wearing a number.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Companion piece: measure your own coding habits before you believe anyone else's numbers, on what git history alone can tell you, and the five ways I nearly fooled myself getting there.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Richard Atkins.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>software</category>
      <category>analytics</category>
      <category>code</category>
      <category>devex</category>
    </item>
    <item>
      <title>Measure your own coding habits before you believe anyone else's numbers</title>
      <dc:creator>Richard Atkins</dc:creator>
      <pubDate>Wed, 05 Aug 2026 09:32:00 +0000</pubDate>
      <link>https://dev.to/groundedarchitect/measure-your-own-coding-habits-before-you-believe-anyone-elses-numbers-401l</link>
      <guid>https://dev.to/groundedarchitect/measure-your-own-coding-habits-before-you-believe-anyone-elses-numbers-401l</guid>
      <description>&lt;p&gt;&lt;em&gt;Part of "AI, engineering and what survives production", a series on the parts of building with AI that hold up once real traffic hits them.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There is a claim going round that you have probably absorbed by now: AI-assisted development is making codebases worse. Refactoring is down, duplication is up, we are all writing more and revising less. The numbers behind it are real, the samples are enormous, and I found I had started repeating the conclusion in conversation without ever having checked it.&lt;/p&gt;

&lt;p&gt;Then it occurred to me that those figures are averages taken across hundreds of millions of changes from thousands of organisations, not one of which is mine. So what is the rate in your repository? Nobody has told you, and on current evidence nobody is going to. I set out to find mine, assumed it would take an afternoon, and spent three days discovering that the answer is far harder to get at than the confident version suggests.&lt;/p&gt;

&lt;p&gt;So this is not a piece about what AI does to code. It is about how to ask that question of your own repository without arriving at a wrong answer, which turned out to be the genuinely difficult part. The tool I built to do it is &lt;a href="https://github.com/uxdw/git-habits" rel="noopener noreferrer"&gt;git-habits&lt;/a&gt;: free, local, and it reads no source code whatsoever.&lt;/p&gt;

&lt;h2&gt;
  
  
  What git can actually tell you
&lt;/h2&gt;

&lt;p&gt;Git history is a surprisingly rich behavioural record. Not of quality, about which it knows nothing at all, but of habits: how often you commit, how large those commits are, whether you go back and change what you wrote last month, and whether anybody still touches the old code. That is a narrower thing than quality and it is the thing the industry claims has changed, so it is the thing worth measuring.&lt;/p&gt;

&lt;p&gt;Four signals are computable from commit metadata alone, without opening a single source file:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Moved lines.&lt;/strong&gt; The share of changed lines sitting in files git detected as renamed or copied. It is the closest thing history offers to "somebody went back and reorganised this."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legacy touch.&lt;/strong&gt; The share of changes landing on files nobody has touched in a year or more. Whether old code is still maintained or merely accumulating.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rework.&lt;/strong&gt; The share of changes landing on files touched again within a fortnight. Short-cycle churn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commit shape.&lt;/strong&gt; How many commits per working day, and how large each one is.&lt;/p&gt;

&lt;p&gt;None of these is a quality measure, and I want to be clear that I am not pretending otherwise. They are habits. Habits are what the claim is actually about, so habits are what you can test, and a narrow measurement you trust beats a broad one you do not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the output looks like
&lt;/h2&gt;

&lt;p&gt;Real output, from one of my own repositories, split at an arbitrary date:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git-habits compare  split at 2026-05-01

  ruleset v1.0  excluded 28,297 of 101,578 changed lines (27.9%)
    lockfiles            24,513
    data_dumps            3,778
    binary_media              5

  first month
    window            2026-04-03 to 2026-04-24  (21d span, 7 active)
    commits           136   (19.43/active day)
    changed lines     41,788
    lines/commit      mean 307.3  p50 90.0  p90 430.0
    moved (reuse)     0.16%  (1.6 per 1k changed lines)
    legacy touch      0.0%  (0.0 per 1k)
    rework &amp;lt;=14d      17.24%  (172.4 per 1k)
    AI co-authored    45 commits (33.1%)

  after
    window            2026-05-04 to 2026-07-18  (76d span, 11 active)
    commits           44   (4.0/active day)
    changed lines     31,493
    lines/commit      mean 715.8  p50 66.5  p90 2997.0
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things in there are worth pointing at before we go further, because both are the&lt;br&gt;
kind of detail a dashboard would smooth over.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The exclusion report comes first, not last.&lt;/strong&gt; Nearly 28% of the changed lines in that&lt;br&gt;
window were lockfiles and data dumps. You are told that before you read a single metric.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Look at the mean and the median diverge in the second window.&lt;/strong&gt; Mean 715.8, median 66.5,&lt;br&gt;
p90 2,997. A handful of enormous commits have eaten the mean while the typical commit&lt;br&gt;
actually got &lt;em&gt;smaller&lt;/em&gt;. Read only the mean and you would conclude the opposite of what&lt;br&gt;
happened.&lt;/p&gt;
&lt;h2&gt;
  
  
  Normalise per line, not per commit
&lt;/h2&gt;

&lt;p&gt;This decision matters more than it looks. Measure anything "per commit" and, the moment your commit granularity changes, every metric moves while nothing underneath it has changed at all. A team that switches to squash merges halves its commit count overnight and could be forgiven for thinking it had halved its output. So I made per changed line the primary normalisation, which has the useful side effect of keeping the numbers comparable with the published research.&lt;/p&gt;

&lt;p&gt;I kept the per-commit view as well, though, because it answers a different question and the gap between the two is where the artefacts hide. A metric that shifted only because commits got bigger is not a finding, and you want that visible rather than smoothed away.&lt;/p&gt;

&lt;p&gt;One caveat on averages. In one repository I measured, the mean commit was 860 changed lines and the median was 16. A handful of bulk imports had eaten the mean entirely. &lt;strong&gt;Report the median.&lt;/strong&gt; If a tool shows you only a mean, it is showing you its largest commits.&lt;/p&gt;
&lt;h2&gt;
  
  
  The five ways I nearly fooled myself
&lt;/h2&gt;

&lt;p&gt;Every one of these produced a confident, wrong number during the build. They are in the tool's output and its README for that reason.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Generated files are most of your history
&lt;/h3&gt;

&lt;p&gt;Lockfiles, build output, vendored dependencies, minified bundles, committed logs. Across the repositories I measured, &lt;strong&gt;generated artefacts accounted for between 48% and 62% of all changed lines.&lt;/strong&gt; One &lt;code&gt;npm install&lt;/code&gt; writes tens of thousands of lines to a lockfile, and it will drown every real signal you have.&lt;/p&gt;

&lt;p&gt;So exclusions have to be on by default. But the corollary matters just as much: a tool that silently discards two thirds of your data has an invisible thumb on the scale. How would you know? You would not, which is why it must report what it removed and how much. If over half your churn vanishes into the exclusion list, you deserve to be told that before you read a single metric.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. &lt;code&gt;git log&lt;/code&gt; can return nothing and call it success
&lt;/h3&gt;

&lt;p&gt;This one cost me a day. I ran a log with &lt;code&gt;--format="COMMIT"&lt;/code&gt; as a record separator, parsed the output, and got clean zeroes across six repositories. No error. Exit code 0.&lt;/p&gt;

&lt;p&gt;Git treats a format string containing no &lt;code&gt;%&lt;/code&gt; placeholder as a &lt;em&gt;named pretty-alias lookup&lt;/em&gt;. It finds no alias called &lt;code&gt;COMMIT&lt;/code&gt;, emits nothing, and exits successfully. The pipeline downstream dutifully reported that nothing had happened.&lt;/p&gt;

&lt;p&gt;I only caught it because a &lt;em&gt;later&lt;/em&gt; start date returned &lt;em&gt;more&lt;/em&gt; commits than an earlier one, which is impossible. &lt;strong&gt;Any tool built on parsing &lt;code&gt;git log&lt;/code&gt; needs an assertion that it got something back.&lt;/strong&gt; Silent zeroes are the most dangerous output a measurement tool can produce, because they look like findings.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Unknown is not zero
&lt;/h3&gt;

&lt;p&gt;My exports captured commit subjects but not trailers, so the tool reported "0% AI co-authored" for a repository where 58% of commits carried a &lt;code&gt;Co-Authored-By&lt;/code&gt; trailer. The data did not say zero. The data said nothing, and zero was the default.&lt;/p&gt;

&lt;p&gt;Then a second version of the same bug: the exclusion step rebuilt each commit object and quietly dropped the trailers field, turning a known value back into an unknown that rendered as zero again.&lt;/p&gt;

&lt;p&gt;A missing field and a measured zero must be different values all the way through, and they must render differently. Mine now prints "not captured by this source" and the JSON emits &lt;code&gt;null&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Repository age fakes a trend
&lt;/h3&gt;

&lt;p&gt;A repository younger than a year cannot contain year-old code, so its legacy-touch rate is structurally zero and rises as the calendar advances. Compare two windows of a maturing repository and you will see legacy touch climb impressively while nobody's behaviour has changed at all.&lt;/p&gt;

&lt;p&gt;Worse, I hit a repository that looked eighteen months old and wasn't: it had been carved out of a larger one, so every file's history reset at the split. Real two-year-old code read as new.&lt;/p&gt;

&lt;p&gt;If you take one thing from this piece: &lt;strong&gt;check where your repository actually came from before you measure its age.&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  5. &lt;code&gt;--all&lt;/code&gt; can double your commit count
&lt;/h3&gt;

&lt;p&gt;Including all refs picks up unmerged branch work. In one repository it took the commit count from 42 to 94. Neither number is wrong, they answer different questions: work you did, versus work that shipped.&lt;/p&gt;

&lt;p&gt;Pick one, write it down, and apply it everywhere. The flags used should be printed with the results, because a comparison between two periods computed under different flags is not a comparison.&lt;/p&gt;
&lt;h2&gt;
  
  
  What it cannot do
&lt;/h2&gt;

&lt;p&gt;It cannot detect AI. It detects &lt;em&gt;when things changed&lt;/em&gt;, and any before-and-after split is only as honest as you are about when you changed method. Do you actually remember the week you started letting a model write your first drafts?&lt;/p&gt;

&lt;p&gt;Which is worth dwelling on, because I got my own date wrong by sixteen days when asked to recall it three months later. That is why the tool has a &lt;code&gt;detect&lt;/code&gt; command that looks for the step change itself and reports it as a candidate rather than a fact. If the person running the study cannot remember, no user will.&lt;/p&gt;

&lt;p&gt;And moved-lines is a proxy. Git detects file renames, not the movement of a block of code between files, which is what the published research actually measures. That is a similarity-matching problem, and an approximation of it would give you numbers that look plausible and cannot be compared with the thing you would inevitably compare them against.&lt;/p&gt;
&lt;h2&gt;
  
  
  Go and check
&lt;/h2&gt;

&lt;p&gt;Python 3.10 or newer, no dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/uxdw/git-habits &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;git-habits
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; .venv/bin/pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

&lt;span class="c"&gt;# no idea when your habits changed? most people do not&lt;/span&gt;
git-habits detect  &lt;span class="nt"&gt;--repo&lt;/span&gt; /your/repo &lt;span class="nt"&gt;--author&lt;/span&gt; &lt;span class="s2"&gt;"you@example.com"&lt;/span&gt;

&lt;span class="c"&gt;# then compare either side of the date it suggests&lt;/span&gt;
git-habits compare &lt;span class="nt"&gt;--repo&lt;/span&gt; /your/repo &lt;span class="nt"&gt;--author&lt;/span&gt; &lt;span class="s2"&gt;"you@example.com"&lt;/span&gt; &lt;span class="nt"&gt;--split&lt;/span&gt; 2026-04-13
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the repository lives on a machine you cannot clone from, export its history there and analyse it here. The README has the command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Its companion, &lt;a href="https://github.com/uxdw/diff-habits" rel="noopener noreferrer"&gt;diff-habits&lt;/a&gt;, goes one layer deeper.&lt;/strong&gt; It reads diff contents and counts error-masking constructs, the empty catch blocks and suppressed type checks that remove the evidence of a failure rather than handle it. That is a separate tool rather than a flag on this one, deliberately: &lt;code&gt;git-habits&lt;/code&gt; never opens a source file, which is what lets you run it against an employer's repository without a conversation. Reading source is a different decision and should be a different install. I have written that one up in the code that hides the evidence.&lt;/p&gt;

&lt;p&gt;I am deliberately not telling you what my own numbers showed, because a before-and-after on one developer means very little without a control group. I have one, two colleagues in the same repositories who do not use AI at all, and that analysis is not finished. What I will say now is that the answer I was confident about after an afternoon was wrong, and every version since has been less exciting and more true.&lt;/p&gt;

&lt;p&gt;Measure your own crossover. Do not inherit someone else's headline.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Richard Atkins.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>analytics</category>
      <category>productivity</category>
      <category>codequality</category>
    </item>
    <item>
      <title>Org design for AI: why your Centre of Excellence becomes a bottleneck</title>
      <dc:creator>Richard Atkins</dc:creator>
      <pubDate>Fri, 31 Jul 2026 05:00:00 +0000</pubDate>
      <link>https://dev.to/groundedarchitect/org-design-for-ai-why-your-centre-of-excellence-becomes-a-bottleneck-2ojo</link>
      <guid>https://dev.to/groundedarchitect/org-design-for-ai-why-your-centre-of-excellence-becomes-a-bottleneck-2ojo</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 4 of five. "AI, leadership and the human structures of work" is a series on what AI actually changes about leading people, and why those changes are choices, not inevitabilities.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A large enterprise I heard about stood up an AI Centre of Excellence with the best of intentions: one central team to set standards, vet models, and keep everyone safe. Eighteen months later, the CoE had a six-week approval queue, three of the business units had quietly started using unsanctioned tools to get round it, and the security team, the very people the CoE existed to reassure, had less visibility into the company's real AI use than before it was created. The gate had not stopped the risky behaviour. It had driven it underground.&lt;/p&gt;

&lt;p&gt;The last piece ended on a warning: you can only fix ownership and accountability so far one team at a time, because they also live in how the whole organisation is built. So this is the structural piece. When a company decides to get serious about AI, it almost always reaches for the same move, and that move is usually where adoption goes to die.&lt;/p&gt;

&lt;p&gt;The move is the Centre of Excellence. Pull the AI expertise into one central team, give them the mandate for standards, safety, and best practice, and let the rest of the organisation come to them. It sounds responsible. It is how most enterprises have handled every new capability for thirty years. And with AI it reliably curdles into a bottleneck.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the enabler becomes the ceiling
&lt;/h2&gt;

&lt;p&gt;The failure is not incompetence. It is a structural trap. A central team that must review every model, approve every use case, and sign off every rollout becomes, by simple arithmetic, the ceiling on how fast the rest of the company can move. Ten teams want to build; one team has to approve; the queue forms.&lt;/p&gt;

&lt;p&gt;And people do not wait in queues. They route around them. This is not hypothetical. A 2026 survey of 1,000 employees and 500 security leaders found 81% of employees using unapproved AI tools, and 45% of workers actively finding workarounds to reach applications their employer had blocked. That second number is the one that should worry you, because it is the queue-jumping made explicit: the official channel is half-empty and the unofficial one is packed. Your careful central control produces the exact thing it was built to prevent, ungoverned AI use, now invisible, because you made the governed path the slow one.&lt;/p&gt;

&lt;p&gt;A gate does not stop the water. It decides where the water goes around.&lt;/p&gt;

&lt;h2&gt;
  
  
  The counter-argument, taken seriously
&lt;/h2&gt;

&lt;p&gt;The obvious objection: but you &lt;em&gt;need&lt;/em&gt; governance. AI carries real risk, data, compliance, reputation, and "enablement" sounds like a polite word for a free-for-all. Fair, and worth answering directly, because it hides a false choice.&lt;/p&gt;

&lt;p&gt;Enablement is not the absence of governance. It is governance delivered as a road rather than a checkpoint. A checkpoint governs by inspecting each car; a well-built road governs by making the safe route the default, guardrails, a paved surface, a sensible limit built into the design, so that the easy thing and the safe thing are the same thing. The shadow-AI numbers are the proof that gating fails at its own stated goal: the CoE that inspects every use case ends up with less control, not more, because it drove usage into the dark. If your genuine priority is safety, the queue is the least safe design you could pick.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern that actually scales
&lt;/h2&gt;

&lt;p&gt;The organisations getting this right are inverting the central team's job. Instead of a team that approves, a team that enables. Two ideas from how high-performing engineering organisations are already built map onto this cleanly. The first is the enabling team: a small group whose success is measured by how quickly it can raise another team's capability and then leave, not by how many approvals it processes. Its job is to make the other teams good at AI, then get out of the way. The second is the platform team: it builds the paved road, the self-service tools, guardrails, and defaults that make the safe way to use AI the easy way. You do not govern by inspecting each decision. You govern by shaping the path so the default is already safe.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjxtuwwejzod7tq2q5707.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjxtuwwejzod7tq2q5707.jpg" alt=" " width="800" height="512"&gt;&lt;/a&gt;&lt;br&gt;
That is the shift in a line: govern the road, not each journey.&lt;/p&gt;

&lt;p&gt;There is an older idea worth borrowing too, with a caveat. The Spotify model gave us the language of guilds and chapters, communities that cut across teams to spread a craft and stop knowledge pooling in silos. That cross-cutting community is a genuinely good home for AI practice: how we prompt, what we have found breaks, which failure modes to watch for. The caveat is honesty. The Spotify model was aspirational even at Spotify, and copied badly it becomes ceremony. Take the idea, spreading practice sideways across teams, not the diagram.&lt;/p&gt;

&lt;p&gt;And there is a reason structure matters more here than almost anywhere. Conway's Law, the old observation that organisations ship systems which mirror their own communication structures, has never been more literal than with AI. Build a gatekeeping organisation and you get gatekept, brittle adoption. Build an enabling one and you get adoption that flows. The shape of the team becomes the shape of the capability.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this asks of a leader
&lt;/h2&gt;

&lt;p&gt;Resist the instinct that says control means a checkpoint. On a technology moving this fast, a checkpoint is a bottleneck wearing a lanyard. Design for enablement instead: a central team measured on how much capability it builds elsewhere, a platform that makes the safe path the easy one, and a community that spreads what works. Governance that enables velocity rather than gating it is not a slogan. It is a structural decision about whether your best people wait in a queue or get a paved road, and, on the evidence, about whether you have real control or only the paperwork of it.&lt;/p&gt;

&lt;p&gt;But structure has a hard limit, and it is the one this series has been circling from the start. You can build the most elegant enabling organisation in the world and it will still fail if there is nobody left to enable, if the pipeline that produces capable people has quietly been switched off. That is the last piece, and it is the one I think we are getting most wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The series: AI, leadership and the human structures of work&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The psychological cost of AI is a leadership choice, not a technology outcome&lt;/li&gt;
&lt;li&gt;Who's the authority now? Leading in the age of the jagged generalist&lt;/li&gt;
&lt;li&gt;Managing a team of agents: leadership when roles become software&lt;/li&gt;
&lt;li&gt;Org design for AI: why your Centre of Excellence becomes a bottleneck&lt;/li&gt;
&lt;li&gt;Cutting juniors is a choice, not an AI inevitability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;You are reading part 4. Links added as each publishes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Richard Atkins.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Sources: Team Topologies (Skelton &amp;amp; Pais) — &lt;a href="https://teamtopologies.com/key-concepts" rel="noopener noreferrer"&gt;https://teamtopologies.com/key-concepts&lt;/a&gt; · "AI Center of Excellence: Why Most Become Bottlenecks" — &lt;a href="https://agility-at-scale.com/ai/people-change/ai-center-of-excellence/" rel="noopener noreferrer"&gt;https://agility-at-scale.com/ai/people-change/ai-center-of-excellence/&lt;/a&gt; · Shadow-AI prevalence: UpGuard, "The State of Shadow AI" — &lt;a href="https://www.upguard.com/resources/the-state-of-shadow-ai" rel="noopener noreferrer"&gt;https://www.upguard.com/resources/the-state-of-shadow-ai&lt;/a&gt; ; &lt;a href="https://redteampartner.com/blog/shadow-ai-enterprise-risk/" rel="noopener noreferrer"&gt;https://redteampartner.com/blog/shadow-ai-enterprise-risk/&lt;/a&gt; · The Spotify model — &lt;a href="https://www.atlassian.com/agile/agile-at-scale/spotify" rel="noopener noreferrer"&gt;https://www.atlassian.com/agile/agile-at-scale/spotify&lt;/a&gt; · Conway's Law (Melvin Conway, 1968).&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>ai</category>
      <category>devops</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Managing a team of agents: leadership when roles become software</title>
      <dc:creator>Richard Atkins</dc:creator>
      <pubDate>Wed, 22 Jul 2026 05:00:00 +0000</pubDate>
      <link>https://dev.to/groundedarchitect/managing-a-team-of-agents-leadership-when-roles-become-software-38a</link>
      <guid>https://dev.to/groundedarchitect/managing-a-team-of-agents-leadership-when-roles-become-software-38a</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 3 of five. "AI, leadership and the human structures of work" is a series on what AI actually changes about leading people, and why those changes are choices, not inevitabilities.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An agent on your team drafts a client report. Another reviews it. A third sends it. It goes out with a number that is wrong, not obviously wrong, plausibly wrong, and the client acts on it. Monday morning, someone asks who is responsible. Point to a person. If you find yourself hesitating between the drafting agent, the reviewing agent, and the human who "just" pressed send on work three agents produced, you have found the real management problem with agents, and it is not their capability.&lt;/p&gt;

&lt;p&gt;So far in this series: the human cost of AI is a leadership choice (piece one), and the authority in the room is no longer whoever knows the most, but whoever knows where to trust the machine (piece two). This piece is about what management becomes when the organisation stops hiring for a role and starts spinning up an agent for it instead.&lt;/p&gt;

&lt;p&gt;Picture the team you might run in two years. Three people. Nine agents: one drafting, one reviewing, a couple monitoring, others doing work that used to carry a job title. The people wear several hats each; the agents wear the rest. Our entire apparatus for running teams, ownership, accountability, span of control, was built for humans. Agents quietly break all three.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oversight was the job. It is not any more.
&lt;/h2&gt;

&lt;p&gt;For decades, a large part of middle management was moving information and checking work: routing decisions up and down, monitoring who did what, catching mistakes before they travelled. Agents do the routing and much of the checking themselves. So the manager whose value was oversight is, honestly, in trouble, and the numbers reflect it. Middle managers grew to around 13% of the US workforce by 2022, up from roughly 9% in the early 1980s, and a good deal of that growth was the oversight work agents now absorb. The pressure is already visible: a June 2026 &lt;em&gt;Harvard Business Review&lt;/em&gt; analysis describes middle managers being overloaded by AI adoption, and Gartner predicts that this year one in five organisations will use AI to flatten their structure, eliminating more than half of their middle-management positions. The oversight layer is not just shifting; in places it is being deleted. The research on where the role is heading is consistent: from monitoring to facilitation, from watching work happen to making it possible.&lt;/p&gt;

&lt;p&gt;That is not a demotion. It is a harder job. Overseeing ten people is a known problem with a century of practice behind it. Enabling three people to direct a shifting fleet of agents, and staying accountable for what that fleet produces, is not a problem most managers have ever been trained for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three things agents break
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ownership.&lt;/strong&gt; People take ownership of work they feel is theirs. Split a task across three people and six agents and ownership evaporates: everyone contributed, nobody owns it. The fix is not technical, it is a deliberate management act. Name a human owner for every outcome, not every task. The agents can do the work; a person still has to own the result, including the parts the agents got wrong.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8pghodkwtdv6c2dvoje7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8pghodkwtdv6c2dvoje7.jpg" alt=" " width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accountability.&lt;/strong&gt; This is where the "it's just delegation" objection breaks down. Good managers already delegate, the argument goes, and org charts always adapt. But delegation, properly understood, is to a human who can be asked why, who feels the consequence, who learns and carries the responsibility next time. An agent can do none of that. It cannot be accountable. So accountability does not distribute when you deploy agents the way it does when you delegate to people. It concentrates, upward, onto the humans who directed them. The old management principle held that you can delegate authority but never responsibility. Agents make that literal and unforgiving: the more of a team's work you automate, the more exposed its remaining people become, because they now answer for output they did not personally produce. A leader who misses this will let their best people quietly absorb unbounded risk, and call it efficiency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reliance.&lt;/strong&gt; Here is a result worth pinning to the wall. In a 2025 experiment, people systematically over-relied on AI advice even when their own judgment would have been better, and the driver was not laziness. It was incentives. When people were rewarded for throughput, they rubber-stamped. When the incentive was redesigned to reward good judgment about when to trust the AI, over-reliance fell. Your team will trust agents exactly as much as your incentives tell them to. Reward speed, and you will get rubber-stamping, and, per the accountability point above, you will personally own the results of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What managing actually becomes
&lt;/h2&gt;

&lt;p&gt;Less monitoring, more designing. Who owns which outcome. What a human must still decide. How you reward judgment over throughput. And what your real span of control now is, because a manager of three people directing fifty agents has a span of attention no org chart has ever had to model. The manager's craft moves from supervising effort to engineering accountability across a team where most of the doing is done by things that cannot be held responsible.&lt;/p&gt;

&lt;p&gt;That is a real skill, and almost nobody has it yet, which is precisely the argument for learning it early. The managers worth most in five years will be the ones who worked out, now, how to keep ownership and judgment human while the doing moved to software.&lt;/p&gt;

&lt;p&gt;There is a limit to how far you can solve this one team at a time, though. Ownership and accountability do not only live in a manager's head. They live in how the whole organisation is structured, and most organisations are about to reach for the same structure to "manage AI." Most of them will build a bottleneck and call it a centre of excellence. That is where the series goes next.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The series: AI, leadership and the human structures of work&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The psychological cost of AI is a leadership choice, not a technology outcome&lt;/li&gt;
&lt;li&gt;Who's the authority now? Leading in the age of the jagged generalist&lt;/li&gt;
&lt;li&gt;Managing a team of agents: leadership when roles become software&lt;/li&gt;
&lt;li&gt;Org design for AI: why your Centre of Excellence becomes a bottleneck&lt;/li&gt;
&lt;li&gt;Cutting juniors is a choice, not an AI inevitability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;You are reading part 3. Links added as each publishes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Richard Atkins.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Sources: "What's the Future of Middle Management?", HBR (2025) — &lt;a href="https://hbr.org/2025/04/whats-the-future-of-middle-management" rel="noopener noreferrer"&gt;https://hbr.org/2025/04/whats-the-future-of-middle-management&lt;/a&gt; · "Managers Managing AI Agents", Business Insider (2025) — &lt;a href="https://www.businessinsider.com/ai-agent-managers-new-job-2025-11" rel="noopener noreferrer"&gt;https://www.businessinsider.com/ai-agent-managers-new-job-2025-11&lt;/a&gt; · Holstein et al. (2025), "When Thinking Pays Off: Incentive Alignment for Human-AI Collaboration" — &lt;a href="https://arxiv.org/abs/2511.09612" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2511.09612&lt;/a&gt; · "AI Adoption Is Overloading Your Middle Managers", HBR (June 2026) — &lt;a href="https://hbr.org/2026/06/ai-adoption-is-overloading-your-middle-managers" rel="noopener noreferrer"&gt;https://hbr.org/2026/06/ai-adoption-is-overloading-your-middle-managers&lt;/a&gt;&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>management</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Who's the authority now? Leading in the age of the jagged generalist</title>
      <dc:creator>Richard Atkins</dc:creator>
      <pubDate>Sun, 19 Jul 2026 17:48:18 +0000</pubDate>
      <link>https://dev.to/groundedarchitect/whos-the-authority-now-leading-in-the-age-of-the-jagged-generalist-1iap</link>
      <guid>https://dev.to/groundedarchitect/whos-the-authority-now-leading-in-the-age-of-the-jagged-generalist-1iap</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 2 of five. "AI, leadership and the human structures of work" is a series on what AI actually changes about leading people, and why those changes are choices, not inevitabilities.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A senior engineer I know approved a database migration plan last year. It was clear, well-reasoned, confidently written, and it would have taken the production system down, because one step assumed a lock the database did not actually provide. The plan came from an AI. The engineer was good. He caught it on the second read, not the first, because it read exactly like the correct plans he approves every day. That gap, between how right it looked and how wrong it was, is the whole subject of this piece.&lt;/p&gt;

&lt;p&gt;The first piece argued that AI's cost to people's wellbeing is a leadership choice, not a technology outcome. This one is about a quieter loss: authority. When the model is a better specialist than most of your team on a Tuesday, and confidently, plausibly wrong on Wednesday, who is the expert in the room?&lt;/p&gt;

&lt;p&gt;Start with the finding that should unsettle anyone putting AI into skilled work. In 2023, researchers at Harvard Business School and Boston Consulting Group ran a field experiment with several hundred management consultants. On tasks that sat inside the AI's capability, the consultants using it produced work rated around 40% higher in quality, finished roughly 25% faster, and completed more of it. On a task designed to sit just outside that capability, the pattern flipped: the ones using AI were more likely to reach the wrong answer than the ones without it. Not a little wrong. Fluently, confidently wrong, because the model produced something that looked exactly as authoritative as its correct work.&lt;/p&gt;

&lt;p&gt;They called it the jagged frontier. AI is brilliant and useless in a pattern you cannot see from the outside, and the two sit right next to each other. The same tool that makes your team look expert on one task quietly makes them look expert while being wrong on the adjacent one. The line usually attributed to Mark Twain fits it better than anything written since: it ain't what you don't know that gets you into trouble, it's what you know for sure that just ain't so. AI is a confident-wrong machine, and confidence is the one signal humans are worst at ignoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Is AI the specialist now?" is the wrong question
&lt;/h2&gt;

&lt;p&gt;Watching a model out-perform your people on a narrow task, it is tempting to conclude that the AI is now the specialist and the humans are drifting into generalists who wear many hats. That gets the shape of it backwards.&lt;/p&gt;

&lt;p&gt;A specialist you can rely on. Their expertise has edges you understand. You know roughly what they know, and where their competence stops, which is exactly what lets you trust them. The jagged frontier means AI has no reliable edges. It is a generalist that performs like a specialist in unpredictable patches. Treating it as "the authority" is not delegation to an expert. It is trusting a colleague who is sometimes brilliant, sometimes bluffing, and never tells you which.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F74nox2wg45dtuks8ywqp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F74nox2wg45dtuks8ywqp.jpg" alt=" " width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A second body of evidence sharpens this. A 2025 meta-analysis in &lt;em&gt;Psychological Bulletin&lt;/em&gt; reconciled years of contradictory findings about whether people trust or distrust AI, and the answer was: it depends on the task. People tend to appreciate AI on objective, capability-heavy work and resist it on subjective, personal work. Which means a blanket policy, "use AI" or "don't trust AI", is wrong almost by definition, because the right answer changes task to task, sometimes sentence to sentence.&lt;/p&gt;

&lt;p&gt;So the authority in the room is not the model. And it is no longer, on its own, the person who knows the most about the subject. It is the person who knows where the model can be trusted and where it cannot. That is a genuinely new competence, and it is not the same as domain expertise. You can be the strongest engineer on the team and still wave through a plausible, wrong answer, because knowing a domain and knowing the shape of a model's blind spots are different skills. My engineer happened to have both. Not everyone will.&lt;/p&gt;

&lt;p&gt;Garry Kasparov, who lost to a computer and then spent years studying human-machine teams, distilled it into a law: a weaker player with a better process, working with a machine, beats a stronger player with a worse process. The edge was never the human or the machine on its own. It was the process binding them, the judgment about who does what and when to override. That process is the authority now, and it lives in a person, not the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part the productivity numbers hide
&lt;/h2&gt;

&lt;p&gt;There is a second finding in that study every leader should hold onto. The consultants who gained the most from AI were the ones who started out weakest; the bottom half of performers improved far more than the top. AI is a leveller. It pulls the floor up.&lt;/p&gt;

&lt;p&gt;Read quickly, that sounds like good news, and in the short term it is. Read slowly, it carries a warning. If AI makes your least experienced people produce work that looks senior, you lose the signal you used to manage by. You can no longer read competence from output, because the output has been levelled. The junior who genuinely understands and the junior who prompted well now hand you the same document. The tell you have relied on your whole career, good work means a good developer, quietly stops being true.&lt;/p&gt;

&lt;h2&gt;
  
  
  The counter-argument, taken seriously
&lt;/h2&gt;

&lt;p&gt;The obvious objection: the models keep getting better, so will the frontier not just fill in and this whole problem solve itself? No, and it is worth being precise about why. The frontier moves, but it does not stop being jagged. Every jump in capability opens a new set of adjacent tasks the model now attempts and gets subtly wrong, because it attempts them with exactly the same confidence it brings to the ones it has mastered. A more capable model is a more capable confident-wrong machine on the new edge. And the signal-loss problem, the fact that you can no longer read competence from levelled output, does not improve as the model improves. It gets worse.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this asks of a leader
&lt;/h2&gt;

&lt;p&gt;Stop asking your people to trust or distrust AI as a blanket policy. Both are wrong on a jagged frontier. Ask them instead to build, and to show you, calibrated judgment: where they lean on the model, where they check it, and how they know the difference. Reward the engineer who catches the plausible, wrong answer over the one who ships fastest. Make "here is where this could be wrong, and here is how I checked" a first-class contribution rather than friction.&lt;/p&gt;

&lt;p&gt;And notice what this quietly costs. Every task you hand entirely to the model is a task your people stop practising. The expertise that let my engineer catch the migration bug was built by doing that work himself, badly and then well, for years, the same work you are now tempted to automate away. Which raises a question worth leaving open: if we stop building expertise in our people, where does the next generation of people who can supervise the machine come from? Hold that one. The series comes back to it, and the answer is not comfortable.&lt;/p&gt;

&lt;p&gt;For now, the nearer question. If judgment about the machine is the new authority, how do you actually run a team when half its "roles" are no longer people but agents you spin up on demand? That is next week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The series: AI, leadership and the human structures of work&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The psychological cost of AI is a leadership choice, not a technology outcome&lt;/li&gt;
&lt;li&gt;Who's the authority now? Leading in the age of the jagged generalist&lt;/li&gt;
&lt;li&gt;Managing a team of agents: leadership when roles become software&lt;/li&gt;
&lt;li&gt;Org design for AI: why your Centre of Excellence becomes a bottleneck&lt;/li&gt;
&lt;li&gt;Cutting juniors is a choice, not an AI inevitability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;You are reading part 2. Links added as each publishes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Richard Atkins.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Sources: Dell'Acqua et al. (2023), "Navigating the Jagged Technological Frontier" (Harvard/BCG) — &lt;a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4573321" rel="noopener noreferrer"&gt;https://papers.ssrn.com/sol3/papers.cfm?abstract_id=4573321&lt;/a&gt; · Mollick, "Centaurs and Cyborgs on the Jagged Frontier" — &lt;a href="https://www.oneusefulthing.org/p/centaurs-and-cyborgs-on-the-jagged" rel="noopener noreferrer"&gt;https://www.oneusefulthing.org/p/centaurs-and-cyborgs-on-the-jagged&lt;/a&gt; · Qin et al. (2025), "AI aversion or appreciation? A capability-personalization framework", &lt;em&gt;Psychological Bulletin&lt;/em&gt; · Garry Kasparov, on process in human-machine teams (Kasparov's Law).&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>ai</category>
      <category>llm</category>
      <category>management</category>
    </item>
    <item>
      <title>The psychological cost of AI is a leadership choice, not a technology outcome</title>
      <dc:creator>Richard Atkins</dc:creator>
      <pubDate>Sun, 19 Jul 2026 17:48:09 +0000</pubDate>
      <link>https://dev.to/groundedarchitect/the-psychological-cost-of-ai-is-a-leadership-choice-not-a-technology-outcome-2cki</link>
      <guid>https://dev.to/groundedarchitect/the-psychological-cost-of-ai-is-a-leadership-choice-not-a-technology-outcome-2cki</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 1 of five, and the opener. "AI, leadership and the human structures of work" is a series on what AI actually changes about leading people, and why those changes are choices, not inevitabilities.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A team gets a new set of AI tools on a Monday. By Friday the dashboards look wonderful: more output, faster turnaround, fewer late nights. Six weeks later the same team is quieter in stand-ups, slower to volunteer, and two of your best people have started updating their CVs. Nothing broke. The numbers are still good. Something else did.&lt;/p&gt;

&lt;p&gt;Most of what you read about AI at work is about that first Friday, the productivity. This is about the six weeks after: the bill that comes with it, and who decides how large it is.&lt;/p&gt;

&lt;p&gt;Start with how people actually feel. In a global survey by ADP Research this year, only 22% of workers strongly agreed that their job was safe from elimination. Pew finds US workers more worried than hopeful about AI at work. And the worry is not evenly spread; early-career workers report the sharpest sense that AI is already reshaping their jobs. Whatever the productivity story, the human one is anxious, and anxiety is not a neutral input to a workplace.&lt;/p&gt;

&lt;p&gt;Now the harder evidence. A 2025 study in &lt;em&gt;Humanities and Social Sciences Communications&lt;/em&gt; followed 381 employees across three waves and found that adopting AI significantly lowered people's psychological safety, and that drop, in turn, raised their depression. This is not grumbling. Psychological safety, the belief that you can speak up, admit a mistake, or ask a question without being punished for it, is the thing Amy Edmondson spent a career showing is the foundation of teams that learn. Erode it and people stop flagging problems, stop asking, stop taking the small risks that improve the work. Done carelessly, AI adoption erodes exactly that.&lt;/p&gt;

&lt;p&gt;But here is the finding that should change how you read all of it. The same study found that ethical leadership buffered the damage. Where leaders behaved with integrity and care through the change, the hit to psychological safety was significantly softened. Same technology, same rollout, different leadership, different human outcome.&lt;/p&gt;

&lt;p&gt;This is not one study's fluke. Gallup finds that manager support is among the biggest factors in how well employees adapt to AI and workplace change. The technology arrives for everyone; how it lands depends on the person managing it.&lt;/p&gt;

&lt;p&gt;That is the argument of this piece, and the thread that runs through this series: the human costs of AI are leadership choices, not technology outcomes. The tool does not decide whether your people feel ownership or dread. You do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI reaches the parts of work motivation is made of
&lt;/h2&gt;

&lt;p&gt;Management has always run on a quiet substrate most of us never name. People need to feel that their work is theirs, that they are good at it, and that they belong to something. Psychologists call these autonomy, competence, and relatedness, the three needs at the centre of self-determination theory, and decades of evidence say they are what turn a job into something a person actually cares about.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxzza6f10d0mrmrqxtvag.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxzza6f10d0mrmrqxtvag.jpg" alt=" " width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Used carelessly, AI erodes all three at once.&lt;/p&gt;

&lt;p&gt;It erodes autonomy when it quietly narrows people's choices. In a 2024 experiment, operators supervising an automated system were handed fewer and fewer options by the AI. Their raw performance held up, but their sense of autonomy and the meaningfulness of the work fell, and, crucially, the effect grew the longer it ran. That is the detail most rollouts miss. The motivational cost is not a one-off dip people bounce back from. It compounds.&lt;/p&gt;

&lt;p&gt;It erodes competence when the interesting, skill-building parts of a role are handed to a model and the person is left to check its output. A reviewer of AI work all day is not building the mastery that made them worth hiring; they are slowly becoming an approver, and most people can feel the difference. And it erodes relatedness when the colleague you used to turn to with a half-formed question is replaced by a prompt box that never asks how your weekend was.&lt;/p&gt;

&lt;p&gt;None of that is the AI's doing. Every one of those is a design decision made by a leader: what to automate, what to leave with people, how much choice to preserve, whether to protect the parts of a job that make someone feel capable and connected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why leaders reach for the harmful version by default
&lt;/h2&gt;

&lt;p&gt;Almost nobody chooses the damaging rollout on purpose. They back into it, because AI arrives dressed as an IT procurement rather than an organisational change. A tool gets bought, access gets switched on, a productivity target gets set, and the questions that would have protected people, what does this do to how the work feels, who loses the interesting part of their job, where does judgment still live, never get asked, because nobody owns them. The harm is rarely malice. It is a vacuum. And a vacuum is still a choice, just an unmade one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The counter-argument, taken seriously
&lt;/h2&gt;

&lt;p&gt;The obvious objection: is this not just change resistance? People always grumble about new tools, then adapt, and the gains are worth a few uncomfortable weeks. Sometimes, yes. But two things in the evidence say do not lean on that too hard.&lt;/p&gt;

&lt;p&gt;First, the autonomy study found the erosion of meaning intensified over time rather than fading. That is the opposite of the "they will get used to it" pattern. Second, the psychological-safety study is measuring depression, a clinical outcome with real absenteeism and turnover attached, not a passing mood. "They will adapt" is a comfortable story precisely because it lets leadership off the hook for a cost that, on the numbers, does not simply wear off.&lt;/p&gt;

&lt;p&gt;And the productivity-is-worth-it framing hides the actual trade. The short-term gain is often real; the 2024 study found that restricting operators to a single recommended action did improve immediate performance. The cost showed up later, in motivation, and it compounded. So the trade is not "wellbeing versus results." It is "results now versus results and people later." Calling that an inevitable consequence of the technology is simply a way of avoiding the decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this asks of a leader
&lt;/h2&gt;

&lt;p&gt;Not a wellbeing programme bolted on afterwards. Something earlier and cheaper: decide, deliberately, which human needs each AI rollout is going to protect.&lt;/p&gt;

&lt;p&gt;Keep a real decision in the loop even when the model could make it, because autonomy is load-bearing and, on the evidence, removing it is a slow leak rather than a clean win. Automate the drudgery and defend the parts of a role where people build and feel their skill, rather than the reverse. Protect the human connections AI can quietly replace. And behave, through the disruption, in the way the data actually rewards, with the integrity and care that measurably buffers the harm. That last one costs nothing, and on the numbers it does the most.&lt;/p&gt;

&lt;p&gt;None of this slows the technology down. It just refuses to pretend the human cost was handed to you by the machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;p&gt;If the psychological cost of AI is a choice, so is what happens to expertise itself. When the model is a better specialist than most of your team on a Tuesday and confidently, plausibly wrong on Wednesday, who is the authority in the room? That is next week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The series: AI, leadership and the human structures of work&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The psychological cost of AI is a leadership choice, not a technology outcome&lt;/li&gt;
&lt;li&gt;Who's the authority now? Leading in the age of the jagged generalist&lt;/li&gt;
&lt;li&gt;Managing a team of agents: leadership when roles become software&lt;/li&gt;
&lt;li&gt;Org design for AI: why your Centre of Excellence becomes a bottleneck&lt;/li&gt;
&lt;li&gt;Cutting juniors is a choice, not an AI inevitability&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;You are reading part 1, the opener. Links added as each publishes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Richard Atkins.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Sources: ADP Research, People at Work 2026 — &lt;a href="https://fortune.com/2026/03/25/workers-anxious-scared-insecure-ai-adp-global-survey/" rel="noopener noreferrer"&gt;https://fortune.com/2026/03/25/workers-anxious-scared-insecure-ai-adp-global-survey/&lt;/a&gt; · Kim, Kim &amp;amp; Lee (2025), &lt;em&gt;Humanities and Social Sciences Communications&lt;/em&gt; — &lt;a href="https://www.nature.com/articles/s41599-025-05040-2" rel="noopener noreferrer"&gt;https://www.nature.com/articles/s41599-025-05040-2&lt;/a&gt; · Faas et al. (2024), "Give Me a Choice" — &lt;a href="https://arxiv.org/abs/2410.07728" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2410.07728&lt;/a&gt; · Amy Edmondson, &lt;em&gt;The Fearless Organization&lt;/em&gt; (psychological safety) · Self-determination theory (Deci &amp;amp; Ryan) · Gallup, on manager support and adapting to AI.&lt;/p&gt;

</description>
      <category>leadership</category>
      <category>ai</category>
      <category>management</category>
      <category>mentalhealth</category>
    </item>
    <item>
      <title>The real economics of a production LLM pipeline: resumability, cost-aware routing, and measuring when local beats the API</title>
      <dc:creator>Richard Atkins</dc:creator>
      <pubDate>Sat, 18 Jul 2026 15:11:28 +0000</pubDate>
      <link>https://dev.to/groundedarchitect/the-real-economics-of-a-production-llm-pipeline-resumability-cost-aware-routing-and-measuring-1ncf</link>
      <guid>https://dev.to/groundedarchitect/the-real-economics-of-a-production-llm-pipeline-resumability-cost-aware-routing-and-measuring-1ncf</guid>
      <description>&lt;h2&gt;
  
  
  The gif, and the honest headline
&lt;/h2&gt;

&lt;p&gt;Here's a multi-stage LLM pipeline being killed mid-run and started again:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffwhu9fr38k66e7vwspkg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffwhu9fr38k66e7vwspkg.gif" alt=" " width="790" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It picks up exactly where it stopped. No duplicate model calls, no re-spend. That's the engineering payoff. The headline I want to be honest about up front is the &lt;em&gt;economics&lt;/em&gt; one, because it runs against the usual pitch:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;This is not "run it locally and save a fortune." At a real content pipeline's scale, batched cloud inference is genuinely cheap. The valuable thing is a reproducible way to &lt;em&gt;measure&lt;/em&gt; the local-vs-cloud crossover, and the answer of when local does and doesn't pay off.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's the real number, from an instrumented production run: &lt;strong&gt;one weekly run of this pipeline moves 641,671 input and 77,409 output tokens across nine local model stages, plus 134 locally-generated images. Run it on batched cloud models instead and that's about $0.88, under a dollar a week.&lt;/strong&gt; So the interesting question was never "how much does local save." At this scale, cloud is already pocket change. It's &lt;em&gt;when&lt;/em&gt; that stops being true, and how you would know.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pains everyone hits on week two
&lt;/h2&gt;

&lt;p&gt;The first version of any LLM pipeline is a &lt;code&gt;for&lt;/code&gt; loop over a list. It works in the demo. Then production happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It &lt;strong&gt;dies at item 800 of 1000&lt;/strong&gt; and you do not want to pay for the first 800 again.&lt;/li&gt;
&lt;li&gt;The same run, re-triggered, &lt;strong&gt;re-does work&lt;/strong&gt; and double-writes downstream.&lt;/li&gt;
&lt;li&gt;Near-duplicate inputs get processed &lt;strong&gt;twice&lt;/strong&gt;, because nothing deduplicates them.&lt;/li&gt;
&lt;li&gt;You have &lt;strong&gt;no idea what it cost&lt;/strong&gt;, because nobody recorded the tokens.&lt;/li&gt;
&lt;li&gt;A rate limit or a credit ceiling hits and the run &lt;strong&gt;dies dirty&lt;/strong&gt;, mid-item.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these is hard on its own. Together they're the difference between a script and a pipeline. &lt;a href="https://github.com/uxdw/resumable-llm-pipeline" rel="noopener noreferrer"&gt;&lt;code&gt;resumable-llm-pipeline&lt;/code&gt;&lt;/a&gt; is the small, framework-light reference that wires them together, extracted (patterns only) from a real weekly content pipeline at Cedar &amp;amp; Bloom. It runs offline on the stdlib alone via a deterministic &lt;code&gt;mock&lt;/code&gt; router, so you can see all of it in five minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The build
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2knj92wgd8oy3r7rn4mh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2knj92wgd8oy3r7rn4mh.png" alt=" " width="796" height="1269"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two pieces carry the weight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;ProgressStore&lt;/code&gt;, for resumability.&lt;/strong&gt; A crash-safe &lt;code&gt;{item_id -&amp;gt; {status, ...}}&lt;/code&gt; written with a temp-file-and-rename atomic swap after every item. Each stage filters to unfinished items and reads the previous stage's output. That decoupling &lt;em&gt;is&lt;/em&gt; the resumability: kill the process anywhere and re-running recomputes nothing that already finished. The test suite proves it in numbers. Across a killed run and its resume, total model calls equal the number of kept items exactly. No item is processed twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;ModelRouter&lt;/code&gt;, for cost-aware routing.&lt;/strong&gt; &lt;code&gt;complete(prompt, tier)&lt;/code&gt; and &lt;code&gt;embed(text)&lt;/code&gt; behind one uniform response that carries token counts. Two tiers (&lt;code&gt;cheap&lt;/code&gt; and &lt;code&gt;quality&lt;/code&gt;) map to a backend (&lt;code&gt;mock&lt;/code&gt;, local &lt;code&gt;ollama&lt;/code&gt;, or &lt;code&gt;hosted&lt;/code&gt;) by &lt;strong&gt;one config line&lt;/strong&gt;. Because both local and hosted return &lt;code&gt;(text, tokens_in, tokens_out)&lt;/code&gt;, cost and metrics are backend-agnostic, and swapping local for hosted to re-run the benchmark is a one-liner. A &lt;code&gt;Budget(max_tokens, max_cost)&lt;/code&gt; guard checks the paid stage as it runs; on breach it checkpoints and exits cleanly. Resume &lt;em&gt;is&lt;/em&gt; the retry.&lt;/p&gt;

&lt;p&gt;Routing between a cheap and an expensive model is not a new idea.&lt;br&gt;
&lt;a href="https://lmsys.org/blog/2024-07-01-routellm/" rel="noopener noreferrer"&gt;RouteLLM&lt;/a&gt;&lt;br&gt;
(&lt;a href="https://arxiv.org/abs/2406.18665" rel="noopener noreferrer"&gt;paper&lt;/a&gt;) showed a learned router can cut cost by around 85% on some benchmarks while holding quality. This router is the boring, explicit version: you assign each stage a tier by hand. The goal is not to be clever, it is to make the cost of that choice measurable.&lt;/p&gt;
&lt;h2&gt;
  
  
  The measurement: the tokens were being thrown away
&lt;/h2&gt;

&lt;p&gt;Here's the detail that started this. The production pipeline it generalises calls local models via Ollama, and Ollama's response includes &lt;a href="https://docs.ollama.com/api/usage" rel="noopener noreferrer"&gt;&lt;code&gt;prompt_eval_count&lt;/code&gt; and &lt;code&gt;eval_count&lt;/code&gt;&lt;/a&gt;, the exact input and output token counts, in the final chunk. The original code threw them away. It did real token work every week and recorded none of it.&lt;/p&gt;

&lt;p&gt;So the router captures those counts on every call (and &lt;code&gt;usage.input_tokens&lt;/code&gt; / &lt;code&gt;usage.output_tokens&lt;/code&gt; on the hosted path), and a &lt;strong&gt;fail-open&lt;/strong&gt; metrics module writes one JSON line per call: tokens, latency, backend, model. Fail-open matters. The thing that measures the pipeline must never be the thing that breaks it. &lt;code&gt;rlp report&lt;/code&gt; rolls it up.&lt;/p&gt;

&lt;p&gt;Here's the actual per-stage scorecard from one instrumented &lt;strong&gt;weekly&lt;/strong&gt; run (&lt;code&gt;qwen2.5:14b&lt;/code&gt; is the cheap tier, &lt;code&gt;qwen2.5:72b&lt;/code&gt; the quality tier):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage          model            calls   tok_in   tok_out
novelty        qwen2.5:14b        273   417647    12860
rewrite        qwen2.5:72b         67   112516    48673
image_prompt   qwen2.5:14b         67    52193    11094
enrich         qwen2.5:14b         67    43759     3289
cluster        qwen2.5:14b          4    10264      700
timelines      qwen2.5:14b         10     2568       60
companies      qwen2.5:72b         20     1445       661
edition_intro  qwen2.5:14b          1     1279        72
image_gen      FLUX.1-schnell     134        0        0   (images — timing only)
--------------------------------------------------------------
TOTAL                                    641671    77409
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Until this run, every one of those token counts was &lt;code&gt;None&lt;/code&gt;. The pipeline did the work weekly and recorded nothing. Notice &lt;code&gt;novelty&lt;/code&gt; on its own: 273 calls, 417k input tokens, 65% of the entire run's input. Hold that thought, it matters for the cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  The benchmark: measure the crossover, don't guess it
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;rlp benchmark&lt;/code&gt; reads the tokens the run actually recorded, maps each tier to its hosted equivalent, projects to an annual workload, and compares hosted cost (list price, and with the &lt;a href="https://platform.claude.com/docs/en/build-with-claude/batch-processing" rel="noopener noreferrer"&gt;Batch API's&lt;/a&gt; 50% discount) against a fixed local cost. Fed the &lt;strong&gt;real weekly run&lt;/strong&gt;, with the cheap tier priced as &lt;code&gt;claude-haiku-4-5&lt;/code&gt; ($1/$5 per 1M) and the quality tier as &lt;code&gt;claude-sonnet-5&lt;/code&gt; ($3/$15 per 1M):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Measured (weekly run): 641,671 input + 77,409 output tokens across 9 stages + 134 images.
Modeled:  hosted prices as above, Batch 50% off, hosted image ~$0.003/img, local $560/yr amortised (hardware capex + power), 52 weekly runs/yr.

| line                         | per run | per year (x52) |
|------------------------------|---------|----------------|
| hosted text (list)           | $1.75   | $91            |
| hosted text (batch, 50% off) | $0.88   | $46            |
| hosted images (modeled)      | $0.40   | $21            |
| local (fixed, amortised)     | —       | $560           |

Break-even is about 640 weekly runs per year, roughly 12x the real cadence. Below that, batched cloud wins on cash.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the monthly evergreen run (measured: 47,596 in / 33,920 out, so &lt;strong&gt;$0.47 a run at list, $0.24 batched&lt;/strong&gt;, roughly $3 to $6 a year) and the whole Cedar &amp;amp; Bloom LLM workload lands around &lt;strong&gt;$50 to $70 a year on batched cloud&lt;/strong&gt; (about $110 at list). Against a $560/yr amortised local box, cloud is 8 to 12 times cheaper on cash at the real volume.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The discipline that makes this trustworthy, and the whole reason the tool exists:&lt;/strong&gt; token counts are &lt;strong&gt;measured&lt;/strong&gt;; hosted prices, the per-image cloud rate, and the local yearly cost are &lt;strong&gt;modeled&lt;/strong&gt; and labelled. "The hardware's a sunk cost" is not a fair comparison. An honest break-even needs the amortised capex line, which is why it's in there.&lt;/p&gt;

&lt;h3&gt;
  
  
  The counter-intuitive bit: the cost isn't where the tokens are
&lt;/h3&gt;

&lt;p&gt;Look again at that weekly scorecard through a cost lens:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;stage&lt;/th&gt;
&lt;th&gt;share of input tokens&lt;/th&gt;
&lt;th&gt;share of hosted cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;novelty&lt;/code&gt; (cheap tier)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;65%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~28%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;rewrite&lt;/code&gt; (quality tier)&lt;/td&gt;
&lt;td&gt;18%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~61%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;novelty&lt;/code&gt; moves two-thirds of the tokens but stays cheap, because it runs on the cheap model and emits almost nothing. &lt;code&gt;rewrite&lt;/code&gt; is the reverse: modest token volume, but its output tokens on the quality model at $15/1M dominate the bill. &lt;strong&gt;The money is in output tokens on the quality tier, not where the token volume is.&lt;/strong&gt; Knuth's old warning that "premature optimization is the root of all evil" has a neat LLM corollary: don't guess which stage is expensive. The tokens pile up in &lt;code&gt;novelty&lt;/code&gt;; the money leaves through &lt;code&gt;rewrite&lt;/code&gt;. You only see that by measuring, and it's what tells you which stage to move to cloud first if you ever wanted a hybrid.&lt;/p&gt;

&lt;h3&gt;
  
  
  One genuinely measured cloud data point
&lt;/h3&gt;

&lt;p&gt;Everything above prices local tokens &lt;em&gt;as if&lt;/em&gt; they'd run on the cloud. But one stage in the wider Cedar &amp;amp; Bloom stack already is hosted: SteadyPath's quiz runs on Anthropic Haiku, and instrumenting it captured &lt;strong&gt;4 real calls, 1,490 input and 1,861 output tokens&lt;/strong&gt;, actual &lt;code&gt;usage&lt;/code&gt; from the API, not a projection. Same metrics module, same JSONL, local and hosted side by side. That's the point of the backend-agnostic router. The moment you move a stage to the cloud, its real cost lands in the same ledger as the local estimate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honest conclusion the data supports:&lt;/strong&gt; at Cedar &amp;amp; Bloom's real scale, batched cloud would cost tens of dollars a year, and a weekly run is under a dollar. Local's edge is &lt;em&gt;control, privacy, and no rate limits&lt;/em&gt;, and it only wins on &lt;strong&gt;cash&lt;/strong&gt; at roughly 10 times the volume, or once you bolt on a token-hungry agentic layer. The number that tells you which regime you're in is one you can now measure instead of argue about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take the pattern
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/uxdw/resumable-llm-pipeline &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;resumable-llm-pipeline
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; .venv/bin/activate &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt;
rlp reset &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rlp run &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rlp run       &lt;span class="c"&gt;# watch the 2nd run resume with 0 model calls&lt;/span&gt;
rlp benchmark                          &lt;span class="c"&gt;# your own local-vs-cloud crossover&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point the router at your models, feed the benchmark your real per-stage tokens and verified prices, and read your own break-even. &lt;strong&gt;Measure your crossover. Don't inherit someone else's headline.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Companion piece: &lt;a href="https://dev.to/groundedarchitect/stop-shipping-ai-agents-you-cant-measure-evals-observability-from-scratch-35f5"&gt;Stop shipping AI Agents you can't measure: evals observability from scratch&lt;/a&gt;, on evals and observability as a CI gate. This pipeline's metrics core is the same telemetry idea, pointed at cost.)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built and measured at Cedar &amp;amp; Bloom. MIT-licensed. Written by Richard Atkins.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>llm</category>
      <category>dataengineering</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>Stop shipping AI agents you can't measure: evals + observability from scratch</title>
      <dc:creator>Richard Atkins</dc:creator>
      <pubDate>Sat, 18 Jul 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/groundedarchitect/stop-shipping-ai-agents-you-cant-measure-evals-observability-from-scratch-35f5</link>
      <guid>https://dev.to/groundedarchitect/stop-shipping-ai-agents-you-cant-measure-evals-observability-from-scratch-35f5</guid>
      <description>&lt;h2&gt;
  
  
  The demo, in one screen
&lt;/h2&gt;

&lt;p&gt;Here's an agent's eval scorecard on a green build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;metric                  rate  baseline    delta
-----------------------------------------------
task_success          95.00%    95.00%   +0.00%
tool_correctness     100.00%   100.00%   +0.00%
schema_validity      100.00%   100.00%   +0.00%
groundedness         100.00%   100.00%   +0.00%
PASS: no regressions vs baseline.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I make one change. I stop the agent from actually &lt;em&gt;reading&lt;/em&gt; the documents it cites, so it answers from search snippets alone. That's one environment variable, &lt;code&gt;AES_DISABLE_FETCH=1&lt;/code&gt;. Re-run the exact same eval:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;metric                  rate  baseline    delta
-----------------------------------------------
task_success          75.00%    95.00%  -20.00%  &amp;lt;-- REGRESSION
tool_correctness      15.00%   100.00%  -85.00%  &amp;lt;-- REGRESSION
schema_validity      100.00%   100.00%   +0.00%
groundedness          15.00%   100.00%  -85.00%  &amp;lt;-- REGRESSION
FAIL: 3 metric(s) regressed vs baseline: task_success, tool_correctness, groundedness
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command exits non-zero. &lt;strong&gt;CI goes red, and the PR is blocked.&lt;/strong&gt; One behavioural regression, caught by three independent metrics, before it ever reached a user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftdt494t425n0qtf4lw11.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftdt494t425n0qtf4lw11.gif" alt=" " width="790" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would your agent have caught that? For most teams I talk to, the honest answer is no. Not because they don't care, but because the tooling that makes it easy is all paid SaaS, and the DIY version never quite becomes a priority. This post is that DIY version, built once so you can copy it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The gap
&lt;/h2&gt;

&lt;p&gt;Everyone can &lt;em&gt;build&lt;/em&gt; an agent now. Almost no one can &lt;em&gt;prove&lt;/em&gt; it still works after the next prompt tweak, model bump, or refactor. The tools that help (Braintrust, LangSmith, DeepEval) are mostly paid platforms you bolt on later. For the deep version of &lt;em&gt;why&lt;/em&gt; evals matter and how to design domain-specific ones, Hamel Husain's &lt;a href="https://hamel.dev/blog/posts/evals/" rel="noopener noreferrer"&gt;Your AI Product Needs Evals&lt;/a&gt; is the canonical read. This post is the smallest running skeleton of that idea, wired into CI.&lt;/p&gt;

&lt;p&gt;There's no clean, vendor-neutral, framework-light reference that shows the whole loop: a working agent, traced, evaluated, and guardrailed, with &lt;strong&gt;evals running as CI&lt;/strong&gt; so a regression fails the build like a broken unit test. So I built one. The repo, &lt;a href="https://github.com/uxdw/agent-eval-starter" rel="noopener noreferrer"&gt;&lt;code&gt;agent-eval-starter&lt;/code&gt;&lt;/a&gt;, runs end-to-end with zero API keys and zero network on a deterministic &lt;code&gt;mock&lt;/code&gt; provider, so you can clone it and see all of the above in under five minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The build
&lt;/h2&gt;

&lt;p&gt;Four pieces, each deliberately boring:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg10d9axoniy1tk7l26bp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fg10d9axoniy1tk7l26bp.png" alt=" " width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A real agent loop&lt;/strong&gt; using a &lt;strong&gt;JSON-action protocol&lt;/strong&gt; rather than a vendor's native tool-calling. The agent emits &lt;code&gt;{"action": "...", ...}&lt;/code&gt; and the harness parses it. That keeps it portable across providers and trivially mockable, with no framework lock-in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenTelemetry tracing.&lt;/strong&gt; The same spans that draw the trace tree roll up into a cost, latency, and token scorecard, and export to any OTel backend. It isn't a bespoke tracer: the &lt;a href="https://opentelemetry.io/blog/2024/otel-generative-ai" rel="noopener noreferrer"&gt;OpenTelemetry GenAI semantic conventions&lt;/a&gt; are standardising exactly this shape of LLM span, so you're not locked into my format.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An eval harness&lt;/strong&gt; that scores a committed, labelled dataset on four pass-rate metrics and compares against a committed &lt;code&gt;baseline.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardrails:&lt;/strong&gt; a deterministic banned-phrase post-filter, plus an optional LLM-as-verifier review pass.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The four metrics, each a pass-rate over the dataset:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;task_success:&lt;/strong&gt; did it answer correctly, or correctly &lt;em&gt;abstain&lt;/em&gt; on the unanswerable cases? (Abstention counts as a correct answer.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tool_correctness:&lt;/strong&gt; did it use tools honestly, citing only documents it actually fetched?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;schema_validity:&lt;/strong&gt; is the final answer well-formed? (pydantic-validated)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;groundedness:&lt;/strong&gt; the hallucination guard. Is every claim backed by fetched text?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The insight worth stealing
&lt;/h2&gt;

&lt;p&gt;The single most useful thing I've learned shipping this stuff:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Prompt-level guardrails ("never say X", "always cite your sources") are unreliable. A deterministic post-filter is the dependable fallback, and an LLM-as-verifier is the second layer, not the first.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The model will, eventually, ignore the instruction. So the banned-phrase check runs in code, after generation, every time. It cannot be talked out of it. The LLM-as-verifier pass then catches the fuzzier failures a deterministic filter can't express. Two layers,&lt;br&gt;
cheap one first. It's why the demo works: &lt;code&gt;groundedness&lt;/code&gt; isn't a line in the system prompt asking nicely, it's a computed check over what the agent actually fetched.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers (and their caveats)
&lt;/h2&gt;

&lt;p&gt;Everything above is measured on the repo's committed &lt;strong&gt;synthetic 20-case suite&lt;/strong&gt;, not a production workload. I'm flagging that on purpose. The credibility of an eval story is the honesty about what got measured.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Baseline pass-rates: task_success &lt;strong&gt;95%&lt;/strong&gt;, tool_correctness &lt;strong&gt;100%&lt;/strong&gt;, schema_validity &lt;strong&gt;100%&lt;/strong&gt;, groundedness &lt;strong&gt;100%&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;One seeded regression (disabling document fetch) drops &lt;strong&gt;3 of 4 metrics&lt;/strong&gt;, the suite exits non-zero, and CI posts the scorecard on the PR.&lt;/li&gt;
&lt;li&gt;Cost and latency per run: about &lt;strong&gt;$0 on the &lt;code&gt;mock&lt;/code&gt; provider&lt;/strong&gt; (no network). Point it at &lt;code&gt;claude&lt;/code&gt; or &lt;code&gt;ollama&lt;/code&gt; and the OpenTelemetry roll-up reports tokens, cost, and p95 latency from real calls, so accuracy and spend are tracked over time from the same spans.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this proves the agent is &lt;em&gt;correct&lt;/em&gt;. As Edsger Dijkstra put it, testing "can be used to show the presence of bugs, but never to show their absence." What evals give you is the other thing production needs: a tripwire. The moment a change makes the agent measurably worse, the build stops.&lt;/p&gt;

&lt;p&gt;So the point isn't "95% is good." It's that the 95% is a number you can defend, version, and regress against. A gate, not a vibe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take the pattern
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/uxdw/agent-eval-starter &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;agent-eval-starter
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;".[dev]"&lt;/span&gt;
agent-eval &lt;span class="nb"&gt;eval&lt;/span&gt;          &lt;span class="c"&gt;# score the suite -&amp;gt; scorecard&lt;/span&gt;
make demo                &lt;span class="c"&gt;# green, then a seeded regression turns it red&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap the corpus and dataset for your domain, point the provider at your model, and commit a new baseline. The pattern is the product; the example is just a runnable seed. &lt;strong&gt;Make your agent's accuracy a CI gate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Companion piece: &lt;a href="https://dev.to/groundedarchitect/the-real-economics-of-a-production-llm-pipeline-resumability-cost-aware-routing-and-measuring-1ncf"&gt;The real economics of a Production LLM&lt;br&gt;
pipeline - resumability cost aware routing &amp;amp; measuring&lt;/a&gt;, on resumability, cost-aware routing, and measuring when local beats the API.)&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Built and measured at Cedar &amp;amp; Bloom. MIT-licensed. Written by Richard Atkins.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>testing</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
