WisyLink Blog

70% problemAI-generated codedemo to productionedge casesAI-assisted coding

The 70% Problem: Why Generated Software Needs a Human Last Mile

The 70% problem: AI gets software most of the way fast, then edge cases, integrations and hardening stall. Where the idea comes from and how to finish.

10 min read
The 70% Problem: Why Generated Software Needs a Human Last Mile

The 70% problem is Addy Osmani's name for a pattern in AI-assisted coding: tools get a project roughly 70% of the way surprisingly fast, then progress slows on the last 30%, which covers edge cases, integrations, security and production hardening. The number is an observation rather than a measurement, but the shape of the remaining work is consistent.

  • The "70%" comes from Addy Osmani's December 2024 essay and is a rule of thumb, not a statistic.
  • The remainder is different work: deciding behavior nobody specified, rather than typing more of the same code.
  • A demo proves one happy path; production meets every path at once.
  • Felt speed can mislead: in a 2025 METR trial, experienced developers believed AI made them faster while it made them slower.
  • Crossing the last mile is a checklist: seams, bad inputs, failure decisions and real load.
  • Hosted builders take infrastructure off your plate; judgment about edge cases stays yours.

Where does the 70% problem come from?

The phrase was popularized by engineer and author Addy Osmani in his December 2024 essay "The 70% problem: Hard truths about AI-assisted coding". Drawing on what he had seen across teams, he wrote that non-engineers using AI for coding hit a frustrating wall: they "can get 70% of the way there surprisingly quickly, but that final 30% becomes an exercise in diminishing returns." The final stretch, in his description, is the part that makes software production-ready, maintainable and robust, and it still requires real engineering knowledge.

Osmani presents this as an observation from working with teams, not as measured data, and it should be read that way. The 70/30 split is shorthand. On another project the split might be 50/50 or 90/10. What makes the idea useful is the description of what happens in the remainder: fixes that break other things (he calls it the "two steps back" pattern) and demos that fail when real users arrive.

The shape is much older than AI. Software teams have long quoted the ninety-ninety rule, attributed to Tom Cargill of Bell Labs and popularized by Jon Bentley's "Programming Pearls" column in 1985: the first 90 percent of the code takes the first 90 percent of the time, and the remaining 10 percent takes the other 90 percent. Generation compresses the first part dramatically. It doesn't change what the last part is made of.

Why is the last 30% different work?

The early part of a build is dense with patterns that have been written thousands of times: forms, lists, navigation, sign-up, a database table with predictable fields. Generation is strong here because the intent is clear and the patterns are common. Nobody argues about what a sortable table should do.

The remainder is where the description runs out and reality keeps going. What happens when two customers book the last slot at the same second? When the payment provider sends its confirmation twice? When someone pastes a phone number with spaces, or uploads a 40 MB photo, or presses back in the middle of checkout? These are not harder versions of the early questions. They are decisions about what the software should mean in situations the original request never mentioned.

There is also a reading cost. Generated code arrives fast and in volume, so the person who must make those decisions is looking at a structure they didn't write, with conventions they didn't choose. That comprehension cost lands exactly when the hard decisions start, the problem our essay on intent debt examines.

What does a demo hide that production reveals?

A demo is a controlled performance: one path, chosen inputs, a good connection and an audience that wants it to work. Production is the opposite. Every path runs at once, inputs are messy or hostile, services fail partially, and nobody is steering.

The demo-to-production gap
DimensionIn a demoIn production
Paths exercisedThe one being shownAll of them, including ones nobody designed
InputsClean and chosen in advanceEmpty, duplicated, too long, in the wrong format
UsersOne, acting in sequenceMany, acting at the same moment
Other servicesRespond instantly and correctlyTime out, retry, send duplicates
DataA few sample recordsReal volume, real history, real mistakes
When failure showsImmediately, on screenDays later, through a customer

The gap also has a social cost. A convincing demo tells everyone the work is nearly finished, so the remaining effort feels like a delay instead of what it is: a large share of the job. Stakeholders saw it work. Defending the time needed to make it dependable is hard when the missing parts are invisible to anyone who only watched the demo.

Why the hardest work hides in what nobody specified

The unspecified remainder is the behavior a system must have that no request, prompt or ticket ever described. It is the largest source of last-mile cost because a generator answers the question it was asked, and the hard part is the question nobody thought to ask.

Payments are the classic example. Nobody writes "if the card is charged but saving the order fails, do this", because nobody wants to think about it until it happens. The robust answer is to save the order first and treat it as paid only when the provider's verified confirmation arrives, never because the customer was redirected to a success page. That rule is easy to state once someone has noticed the gap. Noticing is the scarce skill.

Happy path
The single sequence of events a demo shows, in which every dependency behaves.
Unspecified remainder
Behavior the system needs that no request ever described.
Integration seam
The boundary between two systems, where each one's assumptions about the other go unstated.
Production hardening
The work of making generated structure survive inputs, failures and load it was never shown.

A practical way to surface the remainder is to walk through each step of the main flow and ask three questions: what if this happens twice, what if it never happens, and what if it happens out of order? For a booking app, "twice" is a double booking or a duplicate confirmation email, "never" is a customer who books and doesn't show up, and "out of order" is a cancellation that arrives after the reminder has already gone out. Each answer becomes a rule you can state, ask for and test.

Does AI actually speed up the last mile?

It is easy to assume that if AI made the first 70% fast, it must make everything fast. One of the few randomized trials on the question is a warning against trusting that feeling. In a randomized trial published by METR in July 2025, 16 experienced open-source developers worked on 246 real issues in large projects they knew well, with AI tools allowed on some issues and not on others. With AI allowed, they took 19% longer. They had expected a 24% speed-up, and afterwards still believed AI had made them about 20% faster.

The authors are careful about scope: it is a snapshot of early-2025 tools in one setting, experienced developers in their own large codebases, and METR has since published newer data. The lesson that travels is narrower and more useful. Perceived speed and actual speed can point in opposite directions, so measure your own last mile instead of assuming it got shorter.

What clearly changes is where the hours go. Less time goes into first drafts and more into reading, verifying and deciding. The bottleneck moves from creating to confirming that the plausible thing is also the correct thing, which is why eval discipline for generated output matters as much for an app as for a model.

How to cross the last mile deliberately

Last-mile failures tend to arrive in a predictable order, so it pays to go looking for them in that order. Treat the generated app as a hypothesis and the remaining work as the attempt to break it:

  1. Map the seams. List every place the app touches something it doesn't control: payments, email, sign-in, uploads, other services.
  2. Collect the inputs the demo never used. Empty fields, duplicates, very long text, wrong formats, huge files, other languages.
  3. Decide each failure. For every seam and bad input, choose a response: retry, reject with a clear message, degrade gracefully or alert someone.
  4. Write the unspecified behavior down. Turn each decision into a sentence ("a slot can only be booked once") and ask for it explicitly.
  5. Test with real conditions. Two people booking at once, a real (small) payment, a real email to a real inbox, a phone on a slow connection.
  6. Check access and secrets. Confirm who can see which data, and that keys live in a secure settings area, never in page content or chat.
  7. Arrange to hear about failures. Make sure someone is notified when an order, booking or message fails after launch.

Order matters. Mapping the seams first prevents the common mistake of polishing the inside while the boundaries stay undefended. Our website launch checklist turns these steps into concrete pre-launch checks.

Who does the last mile if you don't code?

For a non-technical founder, the last mile looks different but doesn't disappear. Most of it is decision-making and testing, which needs care rather than programming. You know what a double booking costs your business, what your refund policy is and which emails customers must receive. Writing that down and testing it is the core of the job.

A useful habit is to write the rules as plain sentences before asking for them: "a customer can cancel up to 24 hours before the appointment", "the owner gets an email for every new booking", "a sold-out item can't be added to the cart". Sentences like these are easy to ask for in one message and easy to test afterwards, and they become the start of your test list.

The tool you choose decides how much else lands on you. Code-first AI editors hand you code that you then run, host, secure and keep up to date, a trade-off our comparison of vibe coding tools and AI app builders lays out. Hosted builders take infrastructure off the list and leave behavior and testing. And some projects (complex permissions, regulated data, heavy integrations) justify professional help; our guide to AI app builders vs hiring a developer helps you tell which kind you have.

WisyLink builds and hosts a complete web app from a chat, so a good part of the infrastructure last mile is handled by the platform. The judgment part stays with you, and it is worth being clear about the split:

Last-mile tasks on WisyLink
TaskHandled by WisyLinkStill yours
Hosting and HTTPSLive at its own address over HTTPS; certificates issued automaticallyKeeping the link live (free links last 30 days); connecting your own domain (any plan)
DeploysAll-or-nothing: a failed build never replaces the live versionDeciding when a change is ready to share
PaymentsOrders saved first and confirmed by a verified webhook, never by the redirectYour own Stripe or other provider account, with keys entered under Integrations
Search basicsServer-rendered pages, SEO tags, sitemap and robots.txtAccurate titles, descriptions and content
Edge-case behaviorBuilds the rules you describeDeciding the rules and testing them before launch

WisyLink's terms ask you to review and test what the AI generates, and the steps above are how to do it. Read how isolation and deploys work on the product page, then start free, describe your app, and spend your time on the part that needs you.

F.A.Q.

Frequently asked questions

Is the 70% problem real or just a saying?
It is a heuristic drawn from experience. No study has shown that projects stall at exactly 70%, and the point where progress slows varies with the project and the tool. What holds up is the shape: early, well-described work goes fast, and the remainder (unusual inputs, integrations, failure handling) takes disproportionate effort. Software teams were describing the same shape decades before AI coding tools existed.
Is AI-generated code ready for production?
Sometimes, but never by default. Generated code can be correct, yet it arrives without evidence that it handles bad inputs, concurrent users, failed payments or missing data. Treat it as a draft that has to pass the same checks as code a new hire wrote: tests of the failure paths, a review of anything touching money or personal data, and a check that every dependency it pulls in actually exists.
Why does fixing one bug with AI often break something else?
Addy Osmani calls this the two-steps-back pattern. The tool fixes the symptom you describe without a full picture of the system, so the change collides with behavior nobody mentioned. It helps to ask for small changes, describe the whole intended behavior rather than only the bug, keep a written list of rules the app must follow, and re-test earlier scenarios after every fix.
How long does the last 30% of a project take?
There is no trustworthy general figure, and estimates quoted online are rarely measured. The honest approach is to plan for it explicitly: once the main flow works, schedule separate time for testing failure paths, connecting real accounts such as payments and email, and fixing what testing finds. Track how long that phase takes on your first project and use it to plan the next one.
Can a non-developer finish an AI-built app without hiring anyone?
For many small business sites, booking pages, portals and internal tools, yes, especially on a platform that handles hosting, deploys and data storage. The work that remains is deciding behavior and testing it, which needs care rather than coding. Bring in a developer when the app needs complex permissions, regulated data, unusual integrations or performance at scale.
What should I test before launching an AI-built app?
Test every form, booking and payment twice: once on the normal path and once on a failure path such as a declined card or a full time slot. Try empty, duplicated and very long inputs, two people acting at the same moment, a phone screen, and every email the app should send. Confirm that integration keys are filled in, then repeat the core checks after each change.
Share