I have seen the same sentence ruin more AI-built products than any model bug: "It works on my machine."
The sentence is usually true. The app opens locally. The button clicks. The agent fixed the obvious TypeScript error. A founder records a clean screen share and, for about ten minutes, it feels like launch is done.
Then production adds the parts localhost never tested. The environment variable is missing. The checkout redirect works, but the webhook does not. A new account cannot see the thing the founder's seeded account can see. The database has no row for the paid user. The mobile nav hides the only upgrade path. The app is not fake. It is also not launched.
AI has made this failure more common because the demo appears faster. You can get from idea to clickable in an afternoon, which is useful. But speed compresses the difference between "there is a screen" and "a stranger can use this without you standing beside them." If you do not name the difference, you will accidentally sell the screen.
The fix is a proof ladder. Each rung answers a different question. Do not promote one rung into another.
The five receipts
A useful launch packet has five receipts:
- Local proof: the app runs in development and the intended flow works in your checkout.
- Hosted proof: the deployed URL serves the same flow with production environment variables.
- Account proof: a fresh account, a returning account, and a logged-out visitor each get the right state.
- Money proof: checkout, entitlement, cancellation, failed payment, and webhook state all line up.
- User proof: someone who is not you reaches the promised outcome and tells you where they got stuck.
Those receipts are not bureaucratic. They are different realities. Local proof tells you the code can work. Hosted proof tells you the deployed system can load. Account proof tells you identity boundaries work. Money proof tells you the business model has actually touched the product. User proof tells you the promise survived contact with a human who did not read your plan.
An AI agent can help gather every receipt. It should not be allowed to rename them.
Local proof: useful, but narrow
Local proof is still worth getting. It catches broken imports, dead routes, obvious state bugs, missing components, and a surprising amount of layout damage. A local run is where you want the cheap failures to happen.
But local proof has a small jurisdiction. It does not prove that the production URL has the right secrets. It does not prove that your auth callback is accepted by the provider. It does not prove that webhooks reach the deployed route. It does not prove a stranger can navigate the product from a cold start.
When an agent reports "fixed and verified," read the receipt. Did it run npm run build? Did it open the relevant route? Did it test a browser flow? Did it inspect the diff? Good. That is local proof.
Write it down as local proof.
Do not call it launched.
Hosted proof: the URL has to carry the claim
Hosted proof starts when the real URL works. Not a preview URL you will forget exists. Not a tunnel from your laptop. The actual domain or production deployment that a buyer will touch.
The minimum hosted receipt is simple:
- the page returns 200
- the critical route renders without a console crash
- the primary action completes
- the deployed environment matches the feature's needs
- the page still works on a phone-sized viewport
The trap is that a deployment receipt is not the same as a product receipt. A host can say "deployed successfully" while your product is unusable. It only means the platform accepted the build artifact. It does not know whether your onboarding is coherent, your database is connected, or your paywall is truthful.
For AI-built apps, I like a short hosted smoke script. It does not need to be fancy. It should open the homepage, the product page, the signup path, the main app route, and the money route. If a route is supposed to be gated, the test should prove the gate, not skip it because the route returns something.
This is where agent observability earns its keep. The receipt should include the command, the URL, the result, and the failure text if it failed. A vague "smoke passed" is weaker than three boring lines of output.
Account proof: fresh eyes, fresh state
The founder account is contaminated. It has old localStorage, old cookies, old database rows, old entitlements, and a memory of every path you took while building. It is the worst possible account to use as the only proof.
Account proof needs at least four views:
- logged out
- new account
- returning free account
- paid or entitled account
If the product has team roles, add owner, member, and outsider. If it stores private data, add "user A cannot see user B." If it has onboarding, test both completed and incomplete onboarding states.
This is not paranoia. AI-built apps often fail at state edges because agents optimize the happy path visible in the current session. They see your signed-in browser, your seeded data, and your Pro flag. Then they build a flow that assumes those facts are universal.
Make the agent say which identity it tested. "I checked /dashboard" is not enough. "Fresh account with no saved project saw the empty state and could create one" is a receipt.
Money proof: checkout is the start, not the end
Payment proof is where a lot of founder demos lie by accident.
Opening checkout is not payment proof. Returning from checkout is not payment proof. Seeing a "success" screen is not payment proof. The product is paid only when the payment provider, the webhook handler, the entitlement store, and the app UI agree about the user's state.
The proof set should include:
- checkout created for the right product and price
- successful payment changes the user's entitlement
- the paid user can access the paid surface
- the free user cannot access the paid surface
- failed payment does not grant access
- cancellation or expiration removes access at the right time
- webhook replay is idempotent
If that sounds tedious, good. Money is supposed to slow you down. This is one of the places where "move fast" can turn into support debt, refund debt, or a trust problem.
Keep a hard rule: any agent touching payment state must show the exact boundary it changed and the test that proves it. If the proof requires live keys, production data, or a real customer charge, the agent stops and asks. That is not lack of autonomy. That is basic blast-radius control.
The same security instinct applies here as in sandboxing untrusted agent code: the stronger the consequence, the stronger the gate.
User proof: the promise survived translation
The final rung is not a test suite. It is a person.
Give the product to someone who did not watch you build it. Do not narrate. Do not explain the interface. Give them one job: "Try to get this outcome." Then watch where the promise breaks.
The first user proof is rarely glamorous. The user misses the primary button. They do not understand a word you thought was obvious. They paste the wrong kind of input. They assume billing means one thing and you meant another. They ask whether the data is saved. They close the tab on the screen you thought was the value moment.
That is not failure. That is the product finally speaking outside your head.
Write the receipt as behavior, not opinion:
- user reached the intended outcome in 4 minutes
- user got stuck at account creation
- user thought "workspace" meant team account
- user expected export before share
- user asked whether the AI could see private files
Those lines are better than "feedback was positive." They turn into product work.
The launch packet
Put the receipts in one place. A launch packet can be a Markdown file, a saved board in Command Center, or a plain checklist in your repo. The format matters less than the separation.
Use headings like this:
## Local proof
- Command:
- Route:
- Result:
- Known gaps:
## Hosted proof
- URL:
- Routes checked:
- Console/network issues:
## Account proof
- Logged out:
- Fresh account:
- Returning free:
- Paid:
## Money proof
- Checkout:
- Webhook:
- Entitlement:
- Cancellation/failure:
## User proof
- Tester:
- Outcome attempted:
- Where they got stuck:
- Next change:
The value is not the template. The value is that it becomes difficult to say "launched" when only one section has evidence.
What to let the agent do
Agents are excellent launch assistants when the boundaries are clear. Give one the packet and ask it to fill the missing receipts. Ask it to run the build, inspect route behavior, create a smoke checklist, find untested identity states, and point at missing proof.
Do not ask it "is this ready?" without defining ready. It will answer from vibes, because you gave it a vibe-shaped question.
Ask:
Audit this launch packet. Identify which proof rungs are missing. Do not infer payment proof from checkout UI. Do not infer user proof from local testing. Return the weakest launch claim we can honestly make today.
That prompt does two things. It turns the agent into a critic instead of a hype machine, and it protects the language around the product. Sometimes the honest claim is "local demo works." Sometimes it is "production route is live, payment unverified." Sometimes it is "paid account verified, first-user onboarding still weak."
Those distinctions are the work.
The grounded take
AI lets you build the first version faster. It does not remove launch physics. Users still arrive logged out. Webhooks still fail. Production still differs from local. Money still has state. Trust still depends on what happened, not what the demo looked like.
So keep the ladder visible. Local proof is local. Hosted proof is hosted. Account proof is identity. Money proof is entitlement. User proof is a human reaching value.
When all five receipts are green, you can say launched without flinching. Before then, say the smaller true thing. Smaller true things compound. Big unproven claims turn into support tickets.