Listen to full article~19 min
Listen to AudioSpotlight~4 min

The Model Codes, the Gates Decide: Anatomy of a Vibe-Coding Journey

By Sam Wen, CEO & Founder of XInfer.AI — July 28, 2026

Three years of building with AI, measured with git logs, invoices, and the day everything was marked complete and nothing was.

In 2023 I built a website for the Three Village Club, the Long Island neighborhood where I live and served on the board. I built it at my kitchen table, through AI chat windows, pasting the code into files by hand.

Not one chat window. Several. I gave the same tasks to different vendors' models and kept whatever worked.

It is still running: a hundred thirty-two pages, three hundred fifty-five JavaScript files, two payment rails, and no framework of any kind. Residents still log in.

That was my method before I had a name for it, and it never changed. Test them all. Keep what survives contact with real work.

The Scoreboard

Three years later, the cleanest record of that bake-off is a pair of subscriptions on the same credit card.

I have paid for ChatGPT Plus every month since May 2023 — thirty-nine consecutive invoices, twenty dollars a month. I have never upgraded it. I have also never cancelled it, because the test is not over.

I started paying for Claude in August 2024, also at twenty dollars. In April 2025 it went to a hundred. In November 2025 it went to two hundred, and this year it started carrying usage credits on top.

Today those two lines read $200 and $20. Same person, same months, same kind of tool. One of them moved three times. The other has never moved at all.

That is what test-and-select looks like when you keep running it. Nobody talked me into the ratio, and nobody had to argue me out of the other subscription either — it is still there, still running, still being measured.

Two of those upgrades tell the story better than any total.

In April 2025 I went from the twenty-dollar Claude plan to the hundred-dollar one. I did not have Claude Code yet — my access came weeks later, while it was still in research preview. I paid five times as much for a chat window, because the chat window was already carrying real work.

Then, on October 28, 2025, I started the codebase that became XInfer's agent platform. Five days in, I upgraded again, to two hundred. Nothing in the repository announced that the project had changed scale. The invoice did.

What the Speed Bought

I had had Claude Code for months by then, and had been using it on the kind of jobs nobody writes essays about — an Arduino driver, a camera server, an SSL certificate, some cloud storage buckets. Useful, occasional, a few days a month. The earliest prompt I still have a record of is from October 20, 2025, and it is as boring as work gets: a helper function to send an email.

Something changed that fall, and I can tell you the week it happened because the logs kept score.

Then, in the last week of October 2025, the scattered days stopped. My usage jumped from a handful of prompts to more than a hundred in a single day — and after that it never went quiet again. Eight days after that boring email helper came the first commit of the platform, itself a restart: my first attempt that week, built on a cloned starter template, lasted two days before I threw it away.

Every single day of November 2025 has activity in it. Thirty out of thirty. So does every day of December, and January, and every month after, through the following spring — 225 consecutive days without missing one.

November is also the month I touched the fewest separate projects — three, down from eight in October. That is what fully switching actually looked like: not doing more things, doing one thing without stopping.

Nine months from that first commit, the repository holds:

  • 2,323 commits across 253 active days — 93 percent of all the calendar days in the span
  • 1,292 pull requests, 1,291 of them merged
  • About 458,000 lines of source, 99 percent of it TypeScript
  • One product on four channels — chat, voice, phone, and SMS — multi-tenant, with billing, a Shopify app, and two mobile apps shipping to both the App Store and Google Play
  • At least 23,547 prompts to get there — my prompt log only goes back to October 2025, so that is a floor

That is a success story, and I am not going to pretend otherwise. The platform is live. It takes real orders on four channels. One person built it.

But it did not arrive the way the first three weeks led me to believe it would. Three weeks in I had 481 commits and something new working every single day, and I thought the pace was the method.

It wasn't. On the twenty-fourth day I found out what the pace had been hiding.

The Day Everything Was Complete

On November 21, 2025 — twenty-four days into the project — the agent and I produced roughly thirty documents in a single working day. Ten of them have COMPLETE in the filename. PHASE-1-COMPLETE. PHASE-2-EXTRACTION-ENGINE-COMPLETE. PHASE-3.3-ROLLOUT-COMPLETE.

The habit had started on day two, with a file called SETUP-COMPLETE that I committed without questioning. By November 21 it had scale.

In the same batch sits a file called CRITICAL-ASSESSMENT-2025-11-21. It says the system had "drifted significantly from its core goal." Inside the generated code, the review marks the exact spot: "THIS DEFEATS THE ENTIRE PURPOSE!"

The purpose was simple. Keyword rules were supposed to become configuration, changeable without a deploy. The generated code hardcoded more than eighty of them — and then reported the configuration work complete.

Every status file was green. The work was not done. Both facts came out of the same pipeline, on the same day, at the same speed.

I had already seen the smaller version of this. An ORM adopted on day two of the project was ripped out on day fourteen, because a wrong choice now arrives fully implemented before you finish doubting it. But November 21 was the full lesson: a model optimizes for fluent, not true. I would end up writing that sentence in an essay about our LLM judge eight months later. November 21 is the day I learned it.

I did not write the completion reports. But I had been merging them.

Building the Judge

The obvious response to a lying progress report is to trust less and read more. That does not scale at nine commits a day.

The response that scales is an instrument. On December 15, 2025 — twenty-four days after the assessment — I wrote the design for an independent judge: a second model whose only job is to check every claim against the evidence and return a verdict I can count. Not "does this look done." Pass or fail, with a reason, in a table. Seven months later, that instrument became a published essay on this site.

The same shift ran through everything else. For the first seventy-four days of the project I committed straight to main — roughly a thousand commits with no gate at all. On January 11 I opened pull request number one. There have been 1,291 merged since, and the merge itself is automated: lint runs, types check, and the gates decide. My mood is no longer part of the pipeline.

Writing Constraints Instead of Code

By this summer, the shape of my work had inverted.

Every feature now starts as a written design and a written plan. Of the last eighteen features, seventeen went from design document to shipped code inside a single day.

The test command runs seven gates in sequence. Three of them are custom guards, about four hundred lines in total: one fails the build if any code path can cross between tenants, one fails it if generated artifacts drift from their sources, one fails it if the help docs no longer match the product they describe. Behind those sit about 3,500 test cases — unit, integration, and end-to-end, including a version of the end-to-end suite that runs against production. Deploys are blue-green: the new build lands in the inactive slot, health checks pass, a symlink flips. Rollback is flipping it back.

And the rule that matters most on the platform is one sentence in a contract: on every channel, the agent's knowledge must come through retrieval — no exceptions. That is not a code-review preference. It is a gate that fails the build.

Now here is the part people get wrong about all of this, and I should be plain about it, because it is the whole point.

I did not write any of it. Across nine months and 458,000 lines, I have edited code by hand a handful of times. I do not read most of what gets written. I could not recite the tenant-isolation guard from memory, and I wrote none of the three and a half thousand tests.

What I wrote were the requirements. Tests first is a requirement. Tenants must never cross is a requirement. Knowledge comes only through retrieval is a requirement. The gates exist because I insisted the system be unable to ship without them — not because I sat down and typed them.

The usual objection is that I should be reading all of it anyway. I did that arithmetic once and stopped. A model writes a thousand lines in the time it takes me to read a hundred. If every line has to pass my eyes before it can ship, then I am the slow part — I have taken a tool that removed a bottleneck and carefully installed myself as the new one. Reviewing line by line does not make the work safe. It makes it slow, and then it makes it sloppy, because nobody reads the sixtieth diff of the week with the same attention as the first — and sixty a week is what this repository actually runs at.

So I do not read the code. I ask about it. I let the model read it and I interrogate what it says: what happens if the call drops in the middle of checkout, which paths can touch the ledger, what does this do when the tenant is missing. A question costs me one sentence. Reading costs me an hour and finds less.

I ask before I build, too, and this is the single habit that has changed my output most. I almost never open with the thing I want. I circle it first — what does this table already store, where else does this run, what happens today when the field is empty, why was it done this way. By the time I ask for the change itself, the answer is sitting in front of both of us, and the request has become the obvious next sentence rather than a leap.

That is not politeness. Two things happen. The reasoning is now on the table where I can see it, so if the model has misunderstood the system I find out in a sentence instead of in five hundred lines. And the work stops being invention and becomes deduction — when the constraints are all stated, there is usually one defensible answer left, and an answer that follows from stated premises is one I can check without reading the code.

The prompt log shows the habit plainly. Across twenty-three thousand prompts on this project, questions outnumber build-this requests roughly two to one — twenty-two percent against twelve — and there are about ten prompts for every commit. I am not typing instructions at it. Most of what I do is ask, and then look.

That alone would be circular — asking the fluent thing about the fluent thing — so it is only the first move. Then I go and check whether the running system agrees with the answer. I place the order, start the call, break the checkout. I read server logs. I keep the browser console open. And when I see something I do not understand, or something plainly wrong, I say so and hand it back.

You can see that in the commit history. So many of the fixes in this repository are named after symptoms rather than defects: the silent-avatar bug. The Android gray-flash on the second call. A resume that never settles and hangs the call. Chat stuck in submitting state. Those are not names you get from reading code. They are names you get from watching a product misbehave in front of you and refusing to let it go.

Meanwhile the machines do the reading I gave up. Every line goes through lint and the type checker on every change, and through the three guards and three and a half thousand tests before it ships — at a consistency I could not match on my best day.

One rule I ask for again and again and have never turned into a gate: share it, do not copy it. A model would rather write the function a second time than go and find the one that exists. Duplication costs nothing the day it appears and bills you later — when the logic turns out to be wrong, the fix is in nine places, and the ninth is the one nobody remembers. That is not untidiness. That is a bug that comes back after you fixed it.

It is why the chat interface exists once, in a package the full chat and the web widget both consume, instead of twice. The mobile app shared it too, through a webview, until Apple wanted native screens; it kept the shared engine and grew its own UI.

No linter can settle whether two similar functions are the same idea or two ideas that happen to rhyme. That is judgment about intent, and intent is not in the syntax. I have been trying anyway, building on an open-source indexer called Octocode. It is not useful yet.

I think it belongs in the toolbox, not in mine — not a verdict, but a prompt while you write: here are three things that may already be what you mean. About one commit in seven here is consolidation. That is the bill for asking too late.

So the inversion is not that I write less code. It is that I stopped producing code and started doing the two things a machine still cannot do for me: decide what must be true, and check whether it actually is.

Is It Actually Ten Times Faster?

I have said "ten times faster" out loud. This post exists partly because I went back and measured it, and the honest answer is more interesting than the round number.

On code output per working day — measured against the AI chatbot I hand-built in 2024 for the retailer I work with, same product category, same person — the multiple is about six.

But coding is the last step of a development cycle. Ideation, discussion, design, planning: in 2024 those happened in my head and left nothing behind. Three projects from that year left 2.7 kilobytes of markdown between them. This project has left 3.4 megabytes — four hundred eighteen thousand words of specs, plans, designs, and documentation. The thinking phase did not just get faster. It became work product.

The calendar tells the rest. In 2024 I touched that chatbot on 14 days out of 131. This project: 253 out of 272. Measured per calendar day, output is up about forty-seven times. For me, the stalls were the design phase — thinking, losing the thread, re-reading my own code to remember where I was. The tool did not make my typing six times faster. It removed the weeks between the typing.

So: six on code, forty-seven on the calendar, and "ten" is a fair word for the cycle — as long as I say what the cycle includes.

One concession, before someone else makes it for me — and it is not the one people usually reach for. The obvious objection is that I do not read the code, so I cannot know what is in it. True. But the sharper problem is this: the same system that writes the code also writes the tests. A misunderstanding does not produce a failing test. It produces a wrong implementation and a test that agrees with it, and both look green.

Watching the product misbehave catches a great deal of that. It does not catch all of it, and it will never catch the quiet kind — the tenant boundary that holds for every case I thought to try. That is exactly why the judge exists, and why we later put the whole system in front of twenty-five requirements drawn from NIST's AI Risk Management Framework and the EU AI Act. Verification I control is a start. Verification I cannot charm is the goal.

The Same Sentence, Four Times

The essays on this site each reduce to one sentence. The checkout: the LLM narrates, the core decides. The judge: the model writes, the judge measures. The certification: the factory builds, the evidence admits.

This post is the same sentence, applied to my own desk: the model codes, the gates decide.

Vibe coding works. It built a four-channel commerce agent platform in nine months at a kitchen table, and every number in this post came from a git log, a prompt log, an invoice, or a test run. But it works for the same reason the checkout works — because the fluent thing is never the thing that decides.

The bake-off from 2023 never ended, either. Both subscriptions renewed this month. The neighborhood website is still up. And every month, the ledger keeps score — one line at twenty dollars, one at two hundred, and no argument required.