<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[SkillPilot]]></title><description><![CDATA[SkillPilot]]></description><link>https://skillpilotapp.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>SkillPilot</title><link>https://skillpilotapp.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 12 Sep 2026 00:53:49 GMT</lastBuildDate><atom:link href="https://skillpilotapp.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[I shipped a paid product with Claude Code. 1,805 green tests didn't catch the bug that mattered.]]></title><description><![CDATA[I built SkillPilot over about three weeks with Claude
Code, a set of workflow skills, and a lot of arguing. It is a real product: two
Next.js apps on Cloudflare Workers, Supabase for auth and entitlem]]></description><link>https://skillpilotapp.hashnode.dev/i-shipped-a-paid-product-with-claude-code-1-805-green-tests-didn-t-catch-the-bug-that-mattered</link><guid isPermaLink="true">https://skillpilotapp.hashnode.dev/i-shipped-a-paid-product-with-claude-code-1-805-green-tests-didn-t-catch-the-bug-that-mattered</guid><category><![CDATA[AI]]></category><category><![CDATA[Testing]]></category><category><![CDATA[webdev]]></category><category><![CDATA[showdev]]></category><dc:creator><![CDATA[Carlos Infantes]]></dc:creator><pubDate>Tue, 01 Sep 2026 15:48:13 GMT</pubDate><content:encoded><![CDATA[<p>I built <a href="https://skillpilot.app">SkillPilot</a> over about three weeks with Claude
Code, a set of workflow skills, and a lot of arguing. It is a real product: two
Next.js apps on Cloudflare Workers, Supabase for auth and entitlements, Stripe as
merchant of record, 24 sellable items, real money.</p>
<p>This is what I actually learned, including the parts that make agentic coding
look worse than the marketing does.</p>
<h2>The initial build is genuinely fast, and the token bill is brutal</h2>
<p>The first 80% arrived at a speed I have not seen before. Schema, auth, content
pipeline, checkout, webhook, entitlements — days, not weeks.</p>
<p>The cost is not subtle. Long agentic sessions burn tokens at a rate that will
surprise you if you are used to autocomplete. A single deep session on the
payments layer cost more than a month of my previous tooling. That is a real
number in a real budget, and nobody's demo mentions it.</p>
<p><strong>It is worth it for the initial build and it stops being worth it for small
changes.</strong> Knowing which of the two you are in is most of the skill.</p>
<h2>It rewards knowing exactly what you want</h2>
<p>The single biggest predictor of a good session was how precisely I could state
the outcome before starting.</p>
<p>"Add coupons" produced something plausible and wrong. "A coupon is either a gift
that writes an enrolment directly, or a discount that forwards to a Stripe
promotion code and is only consumed once the webhook confirms payment — and a
gift must never go through the gateway, because a 100%-off Checkout Session
settles to <code>no_payment_required</code> and our webhook only accepts <code>paid</code>" produced
something I shipped.</p>
<p>The second version is not a longer prompt. It is a design decision I had already
made. The model was fast at <em>building</em> it and would not have <em>chosen</em> it.</p>
<p>Which brings me to the uncomfortable part.</p>
<h2>It does not replace engineering experience</h2>
<p>Not yet, and not close. Three examples from this codebase, all of which needed
someone who has been burned before:</p>
<p><strong>The write order in the payment webhook.</strong> Purchase first, enrolment second. A
crash between them leaves someone who paid without access — recoverable by hand.
The other order leaves access granted with no accounting record, which is not.
Nothing in the prompt implies that ordering; you have to have thought about which
failure you would rather explain to a customer.</p>
<p><strong>The gift coupon's opposite order.</strong> For a gift, the redemption is written
<em>before</em> the enrolment — the reverse of the purchase path — because there the
redemption is what rations the access. Write the enrolment first and you hand out
the gift, then discover it was not available. I only found this because a
security review made me ask why the two paths differed.</p>
<p><strong>A database function instead of application code.</strong> Checking a coupon's limit
and recording the redemption has to be one atomic step. Read the count in the
worker, decide, then write, and a code posted to a forum hands out as many
enrolments as requests arrive in between. A forum link <em>is</em> a burst of concurrent
requests. Verified: 40 simultaneous redemptions against a cap of 10 grant exactly
10.</p>
<p>An agent will happily write the racy version. It reads fine.</p>
<h2>AI interfaces are weak until you give them something concrete</h2>
<p>Every UI I got with a generic prompt looked like every other AI-generated UI:
rounded cards, gradient buttons, an emoji, and no point of view.</p>
<p>What changed it was two things.</p>
<p><strong>A design skill in the loop</strong> — an actual document describing type scale,
spacing, colour roles and when to use which chart form, rather than "make it look
good".</p>
<p><strong>Concrete references.</strong> "Take the density and restraint of Linear's marketing
site" moved the output further in one prompt than a paragraph of adjectives ever
did. Naming a real product you both can look at replaces a lot of hand-waving.</p>
<p>With those two, I got a usable design on roughly the first attempt instead of the
fifth. Not finished — usable. Then a few rounds of "this section is 12 screens
deep on mobile, fix the hierarchy" got it the rest of the way.</p>
<p>That refinement loop is where the last 20% lives, and it is slower and less fun
than the first 80%.</p>
<h2>And then the part that actually matters</h2>
<p>Here is the thing I would tell anyone shipping something agentic-built and taking
money for it.</p>
<p><strong>On the day I made the first real purchase, the suite was green. <code>tsc</code> was
clean. The checkout had been dead in production for days.</strong></p>
<p>1,805 unit tests. 103 test files against 306 source files. All passing. Three
bugs, and <strong>not one of them could have appeared in a unit test</strong>:</p>
<ul>
<li><strong>A Content-Security-Policy header killed the payment.</strong> <code>form-action</code> governs
the redirect to Stripe, and ours did not allow it. "Continue to payment" did
nothing, in every Chromium browser. No error, no exception, no failing test.</li>
<li><strong>The dashboard gave away the whole pack</strong> to anyone who bought a single
course, because the access check matched on pack and ignored the course.</li>
<li><strong>One of four purchase screens quoted the wrong price</strong>, because it rendered
before the coupon was validated.</li>
</ul>
<p>I found all three by buying my own product with a real card.</p>
<p>And then it happened again. Weeks later I discovered analytics had been silently
dead: the tracker loaded from one domain and sent events to another, and the CSP
allowed only the first. Script loads, <code>window.umami</code> exists, page perfect,
dashboard empty — which reads as "no traffic", which is exactly what a new site
expects to see. Same class of bug. Second time.</p>
<p>The lesson is not "write more unit tests". It is that <strong>a certain kind of bug
lives entirely outside the unit</strong>: browser policy, a real session, a real
redirect, a real payment, a real card. The only thing that catches them is
exercising the actual path in the actual browser against the actual production
config.</p>
<p>So: end-to-end tests, and more of them than feels reasonable. Not because the
agent writes bad code — the code was fine — but because agentic development moves
fast enough that you accumulate integration surface faster than your intuition
about it.</p>
<h2>What I would tell myself three weeks ago</h2>
<ul>
<li><strong>Decide the hard things yourself.</strong> Failure modes, data ownership, what
happens when the money and the access disagree. The agent builds; it does not
choose.</li>
<li><strong>Budget for tokens like a line item.</strong> Expensive up front, then taper.</li>
<li><strong>Give the design system real references.</strong> Name a site.</li>
<li><strong>Test the browser, not the function.</strong> Your suite being green is evidence
about your functions, and almost none about your product.</li>
</ul>
<p>The productivity gain is real and large. It is not "no engineers needed". It is
closer to: the typing stopped being the bottleneck, and every decision I was
already bad at is now the whole job.</p>
<hr />
<p><em>I run <a href="https://skillpilot.app">SkillPilot</a> — researched tech career roadmaps
where every salary figure cites its source and the date it was retrieved. The
roadmaps are free.</em></p>
]]></content:encoded></item></channel></rss>