15 Checks Non-Developers Should Keep in Mind Before Shipping AI-Written Code to Production Tadashi Shigeoka published a checklist on July 13, 2026, identifying 15 production-readiness checks that non-developers should apply before shipping AI-written code, citing common failures such as double charges, server outages, and audit log inaccuracies. The checklist includes specific review points like graceful degradation, idempotency, timeouts, and health checks, with examples from AI coding agents like Claude Code, Codex, and Cursor. 15 Checks Non-Developers Should Keep in Mind Before Shipping AI-Written Code to Production Tadashi Shigeoka /en/author/tadashi-shigeoka/ · Mon, July 13, 2026 With AI coding agents like Claude Code https://code.claude.com/docs/en/overview , Codex https://openai.com/codex/ , and Cursor https://cursor.com/ , a non-developer who can read code can stand up a working MVP or internal tool in a day. That part is well-known. The trouble arrives right after: “it seems to work, let’s ship it” is exactly where users get double-charged, servers fall over at 3 a.m., and audit logs start telling lies. This is not because the AI is being lazy. AI is good at writing code that meets the spec you stated. It is structurally weak at the parts of production operation you did not think to state. The good news is the parts it misses are almost always the same parts, so they can be turned into a checklist. This post is that checklist, condensed to fifteen items. What you will get from this article - A concrete picture of where AI-generated code tends to fail once it is under production load - Fifteen review points a non-developer can run without being a full-time engineer - For each point: a Bad code example that AI often produces, and the specific fix to look for - Incident scenarios in plain language double charges, blank screens, leaked PII rather than abstract “risks” - A ready-to-paste prompt that hands this checklist back to your AI so it can review its own diff 1. Does It Fail Without Whiting Out the Screen? — Graceful Degradation Graceful degradation keeping the system mostly usable when one part breaks is a baseline for production. AI is great at writing the happy path, and less great at putting a safety net under the exceptions. Here is the shape of the problem. The moment getUser returns null because the API is down, user.name throws, and the entire page renders as a blank white screen. From the user’s perspective, that is indistinguishable from “the service is dead.” - Check: does each page/route have a fallback UI for errors? React Error Boundary, Next.js error.tsx , and so on. 2. Is It Safe to Press the Same Button Twice? — Idempotency Idempotency the property that doing the same operation twice produces the same result as doing it once matters wherever “at most once” is required, such as charges, sign-ups, and notifications. On flaky networks, client libraries and SDKs that build in retry logic will resend automatically. If the server cannot say “I have seen this request before,” you get double sign-ups, double charges, and audit log entries written twice. The incident is easy to picture: a user does not see feedback, taps the button again, gets charged twice, and support hears about it the next morning. - Check: do your charge/create/notify POSTs deduplicate on an Idempotency-Key or equivalent request ID? 3. Do Your External Calls Know When to Give Up? — Timeout External APIs such as OpenAI https://openai.com/ , payment providers, and email services occasionally stop responding. AI-written code often forgets timeouts. If it says only fetch url , it is willing to wait forever. One hanging request is bad enough; if it takes down the entire server process, every other user on that instance is collateral damage. - Check: does every external call carry a timeout or? AbortSignal 4. Does Your Health Check Actually Check Health? — Health Check Load balancers and platforms like Kubernetes https://kubernetes.io/ poll a health endpoint and drop unhealthy instances. Asked to write one, AI usually delivers this: That only proves the Node.js process is alive. If the database is down, if Redis is down, this still returns 200, so the load balancer keeps sending real traffic to a broken box. That is the worst kind of failure: the outage is invisible from the outside. - Check: does /health ping the database and any critical dependency before returning ok? 5. Never Trust Input — Boundary Validation TypeScript types only exist at compile time. Values entering the running server may not match their declared types. There are five boundaries worth defending: HTTP request bodies, URL parameters, environment variables, values read from the database, and responses from external APIs. - Check: is runtime validation zod https://zod.dev/ , valibot https://valibot.dev/ , and so on applied at every boundary where data enters your system? 6. Do Your List APIs Have an Upper Bound? — Unbounded Query A “return all users” endpoint feels fine when there are ten users. In production with 100,000 users, it eats memory and takes the process with it. Typical incident: sales tries to export to a spreadsheet, hits your CSV export endpoint, and thirty seconds later the server dies from out-of-memory. - Check: does every list API clamp the result to a maximum say, 200 and offer pagination cursor or offset ? 7. Have You Considered Concurrent Edits? — Race Condition Two admins editing the same user at the same time is a scenario AI does not think about. It writes the naive “read, mutate, save” pattern. This also poisons your audit trail: an entry claiming “the user was viewer before this change” becomes false in hindsight. It stings most where the operation is one you may need to explain later, such as permission changes. - Check: do sensitive entities carry a version column or updated at , and do you enforce optimistic locking via If-Match or the equivalent? 8. Do Error Messages Leak Internals? — Information Disclosure Piping raw exceptions into the response ships stack traces, SQL, table names, internal paths, and library versions to the client, and thus to any attacker. - Check: does production return only generic messages “internal error” while the detail stays in server logs? 9. Are You Putting PII in the URL? — PII in URL A URL like GET / sits in email protected /cdn-cgi/l/email-protection &token=xxxx CDN https://developer.mozilla.org/en-US/docs/Glossary/CDN access logs, browser history, and the Referer https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Referer header attached to outgoing requests to third-party sites, all in plaintext, effectively forever. AI is happy to shove anything into a query string if that is what will make the code run. - Check: no email, phone number, token, or date of birth in URL query strings. Move them into the POST body or the Authorization header. 10. Do You Distinguish Retryable Errors from Fatal Ones? — Retry Semantics When an upstream API returns 429 Too Many Requests https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/429 , AI-written code often flattens it into something like: 400 means “the client sent something invalid, retrying will not help.” A 429 collapsed into a 400 turns “please slow down and try again” into “give up.” Every client’s retry policy stops working correctly. - Check: does your handler preserve the upstream status and the header when passing the error back? Retry-After 11. Do Logs Say Who and Which Request? — Structured Logging console.error "failed" is useless for tracking down a real incident. Among 100,000 requests, which user hit which endpoint, and when? - Check: do all logs include a request ID, user ID, and route name in a structured form typically JSON ? Are you using a structured logger like pino https://getpino.io/ or winston https://github.com/winstonjs/winston ? 12. Are You Leaving Auth Defaults Alone? — Auth Defaults The rule for security-adjacent code is: do not write it yourself. Even when AI generates the surrounding code, auth belongs to a proven library Auth.js https://authjs.dev/ , Clerk https://clerk.com/ , Better Auth https://www.better-auth.com/ . The classic slips to look for: - Cookies missing HttpOnly , Secure , or SameSite - Password reset and login endpoints without rate limiting - Access or session tokens stashed in localStorage , which means a single XSS https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/XSS exfiltrates every user’s session - Check: has the AI silently loosened any of the auth library’s default settings? 13. The Bare-Minimum Accessibility Bar — A11y Even for an internal tool, accessibility https://developer.mozilla.org/en-US/docs/Web/Accessibility the ability to use the app with a keyboard, a screen reader, and so on is a feature, not a nice touch. AI ships visually complete UI and tends to drop the invisible parts. - Does