I Have No Coding Skills. My Team Is 3 AI Models. Here’s the 100-Bug Audit That Saved My Second Startup.
Two weeks ago, I published the honest account of building ThumbRank with a team of three AI models and zero coding skills. The response was great — mainly because it wasn't a story about how AI writes perfect code. It was a story about how AI writes code that looks perfect until you try to charge m

Two weeks ago, I published the honest account of building ThumbRank with a team of three AI models and zero coding skills. The response was great — mainly because it wasn't a story about how AI writes perfect code. It was a story about how AI writes code that looks perfect until you try to charge money for it.
I didn't stop after ThumbRank. I pointed the same team at a much bigger problem: GrantPro AI.
It’s a funding intelligence platform. The core philosophy is simple: real numbers or guesses — there is no third option. Instead of asking an LLM to guess if you’ll win a grant, we ingest millions of public award records (USAspending, EU CORDIS, NIH, UKRI) and use deterministic code to calculate your real odds.
AI #1: Writes features (React, Supabase, Edge Functions).
AI #2: Handles design and infrastructure.
AI #3: Exists for one reason: to audit everything the first two ship.
Me: The founder, PM, and QA department of one.
Month 1 looked like progress. We had a data pipeline, a dashboard, and a Paddle checkout.
Then I pointed AI #3 at the codebase before letting anyone pay.
It came back with ~100 unique bugs and 56 code-quality issues. Some of them would have destroyed the product on day one. Here are the ones that almost killed us, and how we fixed them.
The Fix: We moved the idempotency check to the database level (Postgres unique index) instead of the application layer. If a webhook event arrives twice, or a mapping is wrong, the database throws an error and we log it.
sql CREATE UNIQUE INDEX uq_credit_transactions_kind_reference ON credit_transactions (kind, reference_id) WHERE reference_id IS NOT NULL;
The Fix: We deleted all client-side credit logic. Spending now happens exclusively via a Postgres SECURITY DEFINER RPC that checks the user's balance atomically on the server.
sql CREATE OR REPLACE FUNCTION public.spend_credit(p_kind text) RETURNS boolean LANGUAGE plpgsql SECURITY DEFINER AS $$ BEGIN UPDATE credits SET balance = balance - 1 WHERE user_id = auth.uid() AND kind = p_kind AND balance > 0; IF NOT FOUND THEN RETURN false; END IF; RETURN true; END; $$;
The Fix: We dropped the public read policies. If a table contains the "secret sauce" (historical awards, win probabilities), it is locked to service_role or authenticated users only.
The Fix: We added a CI gate that explicitly tests the exports of every Edge Function before deployment.
Why did the AI miss these? Here is the hard truth about coding with LLMs: The AI is incredible at writing isolated files. It is terrible at understanding cross-file intersections.
AI #1 wrote the React checkout. AI #2 wrote the Paddle webhook. Neither of them knew that they needed to agree on how a user_id is passed. The bug lived in the gap between them.
The Rule We Build By Now We didn't just fix the bugs. We changed the process.
The Invariants Doc: We wrote a document of cross-file rules. "Every paid checkout ends with credits on the right identity." "No public table is writable with the anon key." AI #1 reads this before coding. AI #3 reads this before auditing.
Regression-Testing the Auditor: We kept the old, buggy commit. Every time we update the auditor's prompt, we run it against the old code. If it doesn't find the 100 bugs again, the prompt got too soft, and we reject it.
What's Next? GrantPro AI is live. We are tracking real grants across the US, EU, UK, Canada, and Japan.
If you are building with AI, remember this: The code the AI writes is only half the product. The other half is the system you build to catch it.
You can run a free win-check on your next grant proposal here: grantproai.com/win-check