I audited the same vibe coded app on iOS and Android. Here is what the AI did differently.
The setup
Homelab is a real app for monitoring home servers. It shipped to real users on both iOS and Android, built largely by AI agents. The repositories are public and archived, and they carry the receipts: a CLAUDE.md and a 118 line AGENTS.md with branch strategy and release instructions for the agents. Same product, same developer, same agents, same instructions.
That makes it a rare controlled experiment. If prompts and agents decided code quality, both codebases should have the same problems.
I audited both, the full 5 lens audit I sell, run exactly the same way on each. They scored 5.3 (iOS) and 5.9 (Android). The interesting part is not the half point. It is where the problems live.
What went wrong on iOS
The iOS app grew by duplication. When the agent needed a second dashboard, it copied the first one: two dashboards are 92 percent identical files. When it needed URL handling, it wrote it again: 28 separate copies of the same parsing rules, which had already drifted apart. Fixing a bug in one place means finding all the other places by hand.
The report's verdict: restructure, 6 to 8 engineer weeks. No rewrite needed.
What went wrong on Android
The Android app has the opposite shape. The layering is real. Not one of 138 screen files imports a repository class, dependency injection is used properly, and sibling services are only 22 percent similar where the iOS twins were 92.
The problems concentrated instead. One screen file holds nine dashboards in 4,216 lines. One repository grew to 3,059 lines and owns model types the screens import. And the shared code that exists was abandoned after day one: 15 URL normalizers drifted while a central one sat unused, and cancelled requests are silently swallowed in 33 of 39 view models.
The verdict: restructure, 4 to 6 weeks.
Why the difference
Not the prompts. The same instruction files drove both. The difference is the platform. Android's conventions, the standard project layout, dependency injection as the default, view models as the unit of work, gave the agents ready places to put things. SwiftUI gave them a blank page, and on a blank page the agents copied.
That matches something I now check for in every AI-built codebase: the agent output takes the shape of whatever structure already exists. Strong conventions produce structure. No conventions produce copies.
What failed identically
One thing was the same on both platforms, and it is the finding that matters most for anyone shipping AI-built software.
Both projects had a delivery pipeline that looked healthy and was not. The iOS app shipped 33 releases on a green checkmark that only proved the code compiled. The tests never ran. The Android repo has 37 real tests, and its CI never runs them either. The Android release build is not even reproducible: a file the build needs was never committed, so a clean checkout cannot produce the app that users run.
The agents built features. Nobody, human or agent, wired the safety net. That is invisible in a demo and expensive in production.
What this means if you built an app with AI
The app working is not the question. Both of these apps worked. The question is what happens on the first bad week: the first crash spike, the first OS update, the first developer who has to change code they did not write.
That is what an audit answers. Five lenses, every finding tied to a file and a number, a prioritized fix plan with effort estimates, and a clear verdict: harden, restructure, or rebuild. Both Homelab reports are public in exactly the format you would receive, at keystonesystems.eu/audit.
If you built something with AI and you want to know what is under it before your users find out, the audit is EUR 2,900 fixed, delivered in 7 to 10 working days.