<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged software-testing</title>
<link>https://coderlegion.com/tag/software-testing</link>
<description>Powered by Question2Answer</description>
<item>
<title>The Verification Bottleneck in AI-Generated Software</title>
<link>https://coderlegion.com/26528/the-verification-bottleneck-in-ai-generated-software</link>
<description>&lt;p&gt;&lt;em&gt;AI can generate code faster than ever. That doesn't mean we're shipping correct software faster.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Recently, I asked a coding agent to build a password reset flow. It produced the route, the token handling, the email integration, and the UI in about five minutes.&lt;/p&gt;
&lt;p&gt;The implementation had a bug. The reset link worked more than once. Use it to set a new password, then open the same link again, and it still worked.&lt;/p&gt;
&lt;p&gt;The feature request hadn't explicitly said that a reset link should be single use. It wasn't in the feature request, because it's the kind of thing that goes without saying right up until the moment it doesn't. Every path a person would click through by hand worked perfectly. A code review might have caught it. A demo would not have.&lt;/p&gt;
&lt;p&gt;That gap is what I want to talk about.&lt;/p&gt;
&lt;h2&gt;Code generation is no longer the expensive part&lt;/h2&gt;
&lt;p&gt;Traditional software development has an obvious constraint: humans have to write the software. We think about the requirement, design the implementation, write the code, run it, discover that it doesn't work, debug it, and repeat until we're sufficiently convinced.&lt;/p&gt;
&lt;p&gt;AI coding agents compress parts of that loop dramatically. The agent can often produce an implementation faster than I can thoroughly review what it generated, which creates an inversion. For a long time, writing code was expensive and checking it was comparatively cheap. What happens when writing becomes cheap?&lt;/p&gt;
&lt;p&gt;Verification becomes proportionally more valuable.&lt;/p&gt;
&lt;p&gt;Suppose an agent implements a feature in five minutes, but determining whether the implementation is correct requires another 45 minutes of manual testing and code review. We haven't created a five-minute development process. We've created a 50-minute development process with a very fast implementation stage.&lt;/p&gt;
&lt;p&gt;And the verification half is harder than it used to be, because you're now auditing code you didn't write.&lt;/p&gt;
&lt;p&gt;Generating more code doesn't solve that. We need a better feedback loop.&lt;/p&gt;
&lt;h2&gt;The specification is becoming the durable artifact&lt;/h2&gt;
&lt;p&gt;Here's the shift I think matters most, and it goes well beyond testing.&lt;/p&gt;
&lt;p&gt;If an agent can rewrite a component cheaply, we become less attached to any particular implementation. Implementations are becoming disposable. Six months from now the routes change, the framework changes, the DOM changes, the internal architecture changes.&lt;/p&gt;
&lt;p&gt;The user requirement doesn't:&lt;/p&gt;
&lt;blockquote&gt;&lt;div&gt;
  A user who resets their password must subsequently be able to authenticate with the new password, must no longer be able to authenticate with the old one, and must not be able to reuse the reset link.
&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;In an era of inexpensive code generation, the thing worth maintaining is increasingly the specification rather than the implementation. Which means it's worth writing the specification first, deliberately, as an artifact in its own right rather than as documentation of something already built.&lt;/p&gt;
&lt;h2&gt;Start with behavior, not implementation&lt;/h2&gt;
&lt;p&gt;I tested this with a &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/kenwalger/spec-first-verification&quot;&gt;small web application&lt;/a&gt;, &lt;a rel=&quot;nofollow&quot; href=&quot;https://claude.com/product/claude-code&quot;&gt;Claude Code&lt;/a&gt;, and &lt;a rel=&quot;nofollow&quot; href=&quot;https://testrigor.com/&quot;&gt;testRigor&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The application was deliberately ordinary: authentication, user accounts, login behavior, the kind of functionality in countless business applications. I wasn't interested in whether an agent could produce something visually impressive. I wanted to answer a different question. Can we define expected behavior first, let an agent implement it, and use independent end to end verification to determine whether the agent actually succeeded?&lt;/p&gt;
&lt;p&gt;Consider the password reset feature. The implementation involves a route, form handling, token generation, validation, password hashing, database updates, session behavior, error handling, and UI changes. An agent generates all of it quickly.&lt;/p&gt;
&lt;p&gt;None of those implementation details are what the user cares about. The user cares whether they can request a reset, receive the email, set a new password, log in with it, and whether the old password and the used link both stop working.&lt;/p&gt;
&lt;p&gt;Those are observable outcomes. That makes them a useful boundary between what we asked the agent to build and what the agent actually built.&lt;/p&gt;
&lt;h2&gt;Executable specifications&lt;/h2&gt;
&lt;p&gt;This is where testRigor became interesting to me.&lt;/p&gt;
&lt;p&gt;testRigor expresses tests as English-like behavioral instructions rather than requiring the test author to work primarily in selectors and automation code. A test describes what a user does and what they expect to see.&lt;/p&gt;
&lt;p&gt;That creates an opportunity when combined with AI-assisted development, because the behavioral test can function as an executable specification.&lt;/p&gt;
&lt;p&gt;Instead of telling an agent to &quot;add password reset,&quot; we provide a behavioral contract. The application must email a reset link. The link must lead to a form. The new password must work afterward. The link must not work a second time.&lt;/p&gt;
&lt;p&gt;Now there are two artifacts with two responsibilities. The coding agent is responsible for figuring out how to implement the behavior. The behavioral test is responsible for determining whether the behavior exists.&lt;/p&gt;
&lt;p&gt;That separation is the point.&lt;/p&gt;
&lt;h2&gt;Don't let the student grade the exam&lt;/h2&gt;
&lt;p&gt;AI coding tools are increasingly capable of generating their own tests, and that's useful. I use it. But there's a problem when the same system interprets the requirement, creates the implementation, creates the test for that implementation, and then announces that everything passes.&lt;/p&gt;
&lt;p&gt;The system can make the same mistaken assumption in multiple places. If the agent misunderstands the requirement, it produces code consistent with that misunderstanding and tests that validate the same misunderstanding.&lt;/p&gt;
&lt;p&gt;Everything is green, and everything is also wrong.&lt;/p&gt;
&lt;p&gt;This is exactly what happened with the reset link. An agent asked to write its own tests for the feature it just built would have tested the happy path, because the happy path is what it understood the requirement to be. It would have passed.&lt;/p&gt;
&lt;p&gt;The single use check existed only because a specification written before the code asked a question the feature request never raised. That's the whole value: not that the test is in English, but that it was written by someone thinking about the requirement rather than about the implementation.&lt;/p&gt;
&lt;p&gt;Independent behavioral verification asks a different question:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Regardless of how you implemented this, does the software exhibit the behavior we specified?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That's closer to the question a user actually cares about.&lt;/p&gt;
&lt;h2&gt;Closing the loop&lt;/h2&gt;
&lt;p&gt;The part of this that interests me most isn't the testing tool. It's the feedback loop.&lt;/p&gt;
&lt;p&gt;Once an end to end test produces a deterministic pass or failure, that result becomes input to the coding agent. The agent implements the feature, the behavioral test runs, and if the test fails, the failure returns to the agent. The agent examines the implementation, makes another change, and verification runs again.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.kenwalger.com/blog/wp-content/uploads/2026/09/mermaid-diagram-2026-09-08-140833.png&quot; alt=&quot;Flowchart showing an AI-assisted software development loop. A behavioral contract is passed to an AI coding agent, which produces an implementation. Behavioral end-to-end verification checks whether expected behavior is present. Passing behavior becomes verified behavior, while failure evidence is returned to the coding agent for another implementation attempt.&quot;&gt;&lt;/p&gt;
&lt;p&gt;In my case the full cycle ran three times. Red against the baseline, because the feature didn't exist yet. Red again after generation, on the reused link. Green after the failure text went back to the agent as context. About twenty minutes of wall clock end to end, most of it unattended.&lt;/p&gt;
&lt;p&gt;The failure text mattered more than I expected. It wasn't a stack trace. It was a step in the behavior, in plain English, that didn't happen. That's readable by a person and readable by an agent, which is what let the loop close without me translating between them.&lt;/p&gt;
&lt;p&gt;The agent now has something more useful than &quot;try again.&quot; It has evidence that a specific expected behavior was not observed.&lt;/p&gt;
&lt;p&gt;&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/QCAUyFKlhhQ&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;allowfullscreen&quot;&gt;&lt;br&gt;
&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://youtu.be/QCAUyFKlhhQ&quot;&gt;Spec-First Verification for AI-Generated Code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The video is rough around the edges, which is probably appropriate for an experiment. The interesting part isn't production quality. It's watching the loop operate.&lt;/p&gt;
&lt;h2&gt;Generation and authority are different jobs&lt;/h2&gt;
&lt;p&gt;This reinforced something I've been thinking about more broadly in AI system design. Probabilistic systems are extraordinarily useful for proposing things: generate this implementation, interpret this requirement, suggest a fix, explain this failure, determine which files probably need to change.&lt;/p&gt;
&lt;p&gt;But there are places where I want something else to have authority. Did the build succeed? Did the API return the expected response? Does the database contain the expected state? Can the user complete the specified workflow? Did the test pass?&lt;/p&gt;
&lt;p&gt;Those questions can be answered deterministically, which gives a useful architectural separation:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI proposes. Deterministic systems verify.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It doesn't eliminate mistakes. A badly written test verifies the wrong thing. An incomplete specification leaves important behavior uncovered. A test environment can differ from production. Verification itself needs engineering.&lt;/p&gt;
&lt;p&gt;But separating generation from verification means we stop treating the model's confidence as evidence that the implementation is correct.&lt;/p&gt;
&lt;h2&gt;Behavioral tests aren't magic&lt;/h2&gt;
&lt;p&gt;Working with an English-like testing system reinforced another lesson: plain English does not mean no learning required.&lt;/p&gt;
&lt;p&gt;Tools still have semantics. You need to understand how the system identifies elements, interprets instructions, manages state, handles authentication, and responds when the application doesn't behave as expected. There were several moments where I had to learn testRigor's particular vocabulary before a seemingly obvious instruction did what I expected. My spec assumed the application would land on a login form after a successful reset. It didn't. That's a gap in my specification, not a bug in the application, and finding it took a run I hadn't budgeted for.&lt;/p&gt;
&lt;p&gt;That isn't a flaw unique to testRigor. Abstractions don't eliminate complexity. They move it.&lt;/p&gt;
&lt;p&gt;SQL didn't eliminate the need to understand databases. High level languages didn't eliminate the need to understand software. Natural language testing doesn't eliminate the need to understand testing.&lt;/p&gt;
&lt;p&gt;What changes is who can express the behavior, and how tightly that behavior is coupled to implementation details. That part is genuinely interesting.&lt;/p&gt;
&lt;h2&gt;What we should be optimizing&lt;/h2&gt;
&lt;p&gt;Much of the excitement around AI-assisted development has focused on productivity. How much faster can developers write code? How many tasks can an agent complete? How many tokens did it use?&lt;/p&gt;
&lt;p&gt;Those metrics aren't useless, but they aren't the outcome. Software exists to behave correctly enough to solve a problem.&lt;/p&gt;
&lt;p&gt;If an agent generates 10,000 lines in ten minutes and we spend the rest of the day figuring out whether any of it works, those lines aren't evidence of productivity. They're inventory awaiting inspection.&lt;/p&gt;
&lt;p&gt;The metric worth tracking is correct functionality delivered per unit of time. That includes generation, but it also includes verification. As generation approaches zero marginal effort, the second half is where the remaining cost lives.&lt;/p&gt;
&lt;p&gt;Coding agents are going to get better. They'll generate larger changes, operate longer without supervision, understand more complex repositories, and handle more of the implementation process autonomously. That makes verification more important, not less. Greater autonomy without independent evaluation doesn't produce a better development system. It produces a faster source of unverified output.&lt;/p&gt;
&lt;p&gt;The opportunity is to build verification into the architecture rather than bolting it on afterward. The specification defines the destination. The coding agent proposes a route. Verification tells us whether we actually arrived.&lt;/p&gt;
&lt;p&gt;Not generating code faster. Shipping working software faster.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/26528/the-verification-bottleneck-in-ai-generated-software</guid>
<pubDate>Wed, 09 Sep 2026 14:39:00 +0000</pubDate>
</item>
<item>
<title>The Divergence Problem: Why Your Proxy Ages Faster Than You Think</title>
<link>https://coderlegion.com/21530/the-divergence-problem-why-your-proxy-ages-faster-than-you-think</link>
<description>&lt;p&gt;You know that moment when your test suite goes green but the feature is clearly broken? Multiply that by an entire field, stretch it over decades, and you've got what dendroclimatologists call &lt;em&gt;the divergence problem&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id=&quot;the-benchmark-that-quietly-expired&quot;&gt;The benchmark that quietly expired&lt;/h3&gt;
&lt;p&gt;HumanEval — 164 hand-written Python problems from 2021 — became &lt;em&gt;the&lt;/em&gt; benchmark for LLM coding ability. For three years, pass@1 scores tracked real capability improvements. Then frontier models started hitting 90%+ and the benchmark was quietly dropped from comparisons.&lt;/p&gt;
&lt;p&gt;How much of that 90% was real?&lt;/p&gt;
&lt;p&gt;Bradbury and More (2024) built HumanEval-T — same problems, different enough to prevent memorization. Every model dropped 5 to 14 percentage points. Qwen-2.5-Coder now explicitly decontaminates against HumanEval using 10-gram collision detection. A major lab admitting in their training pipeline that the benchmark was compromised.&lt;/p&gt;
&lt;p&gt;The proxy expired. Nobody printed the warranty.&lt;/p&gt;
&lt;h3 id=&quot;this-is-actually-a-thousand-year-old-problem&quot;&gt;This is actually a thousand-year-old problem&lt;/h3&gt;
&lt;p&gt;For a thousand years, tree rings at far-northern latitudes tracked temperature faithfully. Wider rings meant warmer summers. Dendroclimatologists built entire climate reconstructions on this relationship — centuries of temperature data, cited by the IPCC.&lt;/p&gt;
&lt;p&gt;Then around 1960, the trees stopped matching the thermometers. Ring widths diverged downward while temperatures went up. Nobody noticed for 35 years.&lt;/p&gt;
&lt;p&gt;The field has six plausible explanations. None definitively rules out the others. D'Arrigo's 2008 review laid them all out: drought stress, global dimming, UV-B damage, snowmelt timing shifts, survivorship bias in sample selection, and statistical artifacts. The forensics are permanently messy — because when a proxy fails, multiple causal pathways break at once.&lt;/p&gt;
&lt;h3 id=&quot;the-pattern-shows-up-in-ai-evaluation-too&quot;&gt;The pattern shows up in AI evaluation too&lt;/h3&gt;
&lt;p&gt;GPT-4 passed theory-of-mind tests (the Sally-Anne false-belief task) at 75%. Looked like emergent reasoning.&lt;/p&gt;
&lt;p&gt;Then Ullman (2023) changed one thing: made the container transparent instead of opaque. GPT-3.5 dropped to 6%. SCALPEL (2024) found GPT-4 at 20.35% on the variant.&lt;/p&gt;
&lt;p&gt;Here's the kicker: add one explicit line saying the character &quot;recognizes&quot; the contents, and GPT-4 jumped back to 89.64%.&lt;/p&gt;
&lt;p&gt;The capability existed. The proxy just lost the ability to measure it.&lt;/p&gt;
&lt;h3 id=&quot;the-five-phase-warranty&quot;&gt;The five-phase warranty&lt;/h3&gt;
&lt;p&gt;Every proxy failure follows the same arc:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Calibration&lt;/strong&gt; — proxy tracks reality&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reliance&lt;/strong&gt; — you build systems on it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Silent divergence&lt;/strong&gt; — proxy quietly decouples&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hindsight discovery&lt;/strong&gt; — a second instrument reveals the gap&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overdetermined forensics&lt;/strong&gt; — multiple explanations, none clean&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;what-you-can-actually-do&quot;&gt;What you can actually do&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Rotate your benchmarks.&lt;/strong&gt; LiveCodeBench (ICLR 2025) uses rolling monthly updates so models can't train on the test set. If your internal benchmark hasn't changed in two years, treat that as a yellow flag.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Treat stability as suspicious.&lt;/strong&gt; A metric that hasn't moved could be saturated, gamed, or decoupled. Stable ≠ reliable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don't scale your way out.&lt;/strong&gt; Pan et al. (2022) showed larger models get higher proxy rewards but &lt;em&gt;lower&lt;/em&gt; true rewards. More optimization against a broken proxy makes the problem worse.&lt;/p&gt;
&lt;p&gt;Every metric you rely on — test coverage, sprint velocity, interview rubrics, code review approval rates — was calibrated under conditions that will not hold forever. The trees kept faith for a thousand years. When they stopped, nobody heard it happen.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;Sources: D'Arrigo et al. (2008); Bradbury &amp;amp; More (2024), arXiv:2412.01526; Pi et al. (2024), arXiv:2406.14737; Kosinski (2024), PNAS; Ullman (2023); Pan et al. (2022); LiveCodeBench (ICLR 2025); &quot;Dead rats, dopamine, performance metrics, and peacock tails,&quot; BBS (2023).&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;The essay's prescription: build a second instrument.&lt;/strong&gt; &lt;a rel=&quot;nofollow&quot; href=&quot;https://vibeagentmaking.com/verify/&quot;&gt;Chain of Consciousness&lt;/a&gt; applies this to agent systems — every action anchored to a verifiable external record, so your audit trail doesn't depend on the agent's own self-report. &lt;code&gt;pip install chain-of-consciousness&lt;/code&gt;&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/21530/the-divergence-problem-why-your-proxy-ages-faster-than-you-think</guid>
<pubDate>Mon, 29 Jun 2026 02:13:16 +0000</pubDate>
</item>
</channel>
</rss>