I was an AI skeptic, and my doubt was specific. Not whether a model could write code. Whether it could understand the complexity of a real system and make good decisions inside it.
Anyone who has built with Drupal for a while knows the answer to "can we do it in Drupal?" is probably "yes, but..." How much will it cost, who needs it, and where does it live? The same feature can be delivered a dozen ways. In the hands of an experienced developer you get one well-integrated piece. In other hands you get the same data updated in ten different places. A model trained on everything on the internet has seen both kinds. So could it choose the right one?
I only started using AI when I lost my job and needed to tailor applications faster than I could by hand. Then an emergency migration landed on me, and I had to decide whether to trust these tools with real work under a real deadline. What I found is close to the opposite of what I feared. AI did not make my engineering cheaper. It made my judgment worth more. Everything below is the evidence of that.
AI did not make my engineering cheaper. It made my judgment worth more.
What we inherited
The project was a three-month emergency migration for a large, long-established volunteer organization. Their Drupal site and Salesforce instance had grown together for more than a decade, through several data migrations, and the Salesforce side was being rebuilt with new objects and a more robust data structure. The Drupal side had to follow, and it had to keep volunteers signing up for programs the whole time.
Before I promised anyone a date, we measured the inherited system. Custom code forward, no core, no contrib, no extends. Nothing built by extending a core class, nothing reused. About 42,000 lines, not counting tests. The worst single file carried a Cyclomatic complexity of 38, where 10 is the accepted ceiling for a method and anything past 50 is considered un-testable. 6.6% of all lines were duplicated somewhere else, against an industry benchmark of under 3 percent. A type checker at its second-lowest strictness found 88 places where the code could fail at runtime. Priced by the SQALE method, the industry standard for turning code issues into remediation hours, the debt came to roughly 2,700 hours. AI made its first contribution. I could not have evaluated that in my first week without it.
However, the number that hurt day to day was not on that list. Most of the custom code did not use Drupal's standard data structures, so nothing sat where a Drupal developer expects to find it. Ten years of instinct about where to look were worth very little.
What the AI actually did
Three things, and I want to be exact about them, because the hype makes exactness hard.
It let me understand the system. Reading code that ignored the framework's conventions the old way would have taken weeks I did not have. With a model reading alongside me, I could follow how the old system actually behaved and connect that to what the new data structure needed. I still had to know which questions to ask and which answers to distrust, but the reading stopped being the bottleneck.
It wrote code with me. I say with me, not for me. We moved the custom code onto Drupal's own structures: profiles for volunteer roles, taxonomies for the things that are really lists, Webform for the forms, and custom entities through ECK, the Entity Construction Kit, where nothing standard fit. Webforms and the Salesforce contributed modules gave us control and visibility the old code never had. We could adjust the data easily and track it end to end. We wrote tests and documentation alongside the code, the part that usually gets dropped when the calendar is on fire. And yes, the model proposed things that violated Drupal patterns I knew. We argued, one change at a time, until the code was right.
It held the process. I worked with AIDA, a set of Claude Code skills Carlos built to keep our work honest. Every task went through research, architecture, implementation, and review, and a specification was written before any code. Tracking those specifications kept the MVP under control, so a workflow we had just fixed would not get quietly modified again. For the migration Drush commands we drew mermaid diagrams of every decision so the next iteration would not overwrite what we had already written. Under pressure that is exactly the discipline I would have skipped, and the tooling did not let me.
Here is what it did not do. It did not know the organization, which programs mattered most, or which volunteers would be hurt first if something broke. It did not know which code was following the business logic and which was leftover code nobody had removed, until we discussed it. It did not choose where to start or where to end, and it did not make the calls.
When the data pushed back
The launch held. Then the feedback tool on the site started filling up. Volunteers and Team Leaders can report issues from inside the system, and they did, in volume. For a couple of days the hard part was not fixing anything. It was reading the reports and working out which were one person's problem and which were the same problem wearing different names.
A pattern emerged. Accounts created in the last three years were fine. Accounts with a long history were not. We found duplicated accounts and records connected to the wrong one. The main cause was not in our code. It was a decade of partial data migrations, each one changing the data model while contacts from earlier eras were never brought fully in line. The older accounts followed whichever pattern was current when they were created, and our migration had trusted a consistency that did not exist.
This is the moment the post is really about, because what fixed it was not a fix.
The engineering answer was obvious and slow. Trace every inconsistency, write the cleanup, verify, repeat. Meanwhile long-time volunteers could not sign up and Team Leaders could not run their programs, and the programs are the whole point.
So we had to prioritize. We decided to get volunteers and Team Leaders working again first, and to fix the data and tighten the controls behind them. In two weeks most volunteers and Team Leaders could do their work. Tuning the tools and the data flowing between Drupal and Salesforce took months, and we are still working on it. But it happened in the background, where it belonged.
Something else came out of those weeks that was never in the plan. We closed gates. Roles and permissions now decide who can see what, far more strictly than before. Not because we distrust our volunteers, but because in an era where anyone can point a model at a data export, open access to information is a risk an organization cannot carry.
Those decisions came from reading the organization, not the code. No model proposed them.
The Playbook
What follows is the playbook, the five rules I took away from those months, written down so I do not have to learn them twice. Most of them are not about AI at all. I would hand these learnings to anyone about to build with AI under a deadline, inherited system or not.
Measure before you promise. Whatever you are starting from, put numbers on it first. Complexity, duplication, type errors, remediation hours, or whatever your field's equivalents are. The numbers will not tell you what to build, but they tell you how much you do not yet know, and that is the number a road map should rest on.
Write the specification before the code, and change one thing at a time. When AI makes code cheap, an unclear intent becomes cheap too, and you will produce a great deal of it. The specification is where the human decides what should exist, and tracking it is how you stop re-breaking what you just fixed.
Let the AI read so you can listen. The hours I did not spend tracing the old system were hours spent with the people who depended on it, connecting what it used to do to what it had to do next. That trade served the whole organization's purpose.
Assume the past will break your patterns, and design the recovery path before launch. Every long-lived system, and every long-lived organization, carries the fossils of earlier decisions. Decide in advance what happens when your new rules meet an old record, and who reads the feedback when it arrives in volume.
The AI proposes, the technical architect chooses. It will show you the well-integrated solution and the one that updates data in ten places, with equal confidence. Telling them apart is the job.
Still a skeptic
I still do not believe that AI writes software. Not in any sense that would let me stop paying attention. What I now believe is narrower and, for me, more uncomfortable. AI changes what a technical architect is worth. When the reading and the typing get cheap, the scarce skill is knowing the business well enough to decide what to build and what to protect, and keeping a human in the loop at every point where that decision is made.
One more thing about that inherited code. It looked like Drupal built alone. Patterns nobody in the community would recognize, solutions to problems the framework had already solved. I do not know how it came to be that way, and I am not here to judge whoever wrote it. But I know the cure, because it is the thing I value most about working with Drupal. The community. Learning alone is hard. Sitting in camp sessions and hearing the people who wrote the code explain why it works the way it does makes the whole framework legible in a way no solitary reading can. The AI can read the code with you. It cannot replace the room.