Your Codebase Doesn’t Have an AI Problem. It Has a Multiple-Personality Disorder.
How I designed an enforced engineering framework that turned a 4-week onboarding into a 1-week one and why I built it as a set of CI/CD gates, not a wiki page.
The plot twist nobody saw coming
Everyone predicted AI would make engineering teams faster. Fewer people predicted what it would make visible.
For years, every engineering team has quietly run on an open secret: there was never really one way anything got done. There were as many ways as there were engineers. One person’s “requirements doc” was another person’s Slack thread. One person’s “test coverage” was another person’s we’ll add tests later. Code review smoothed over the worst of it, slowly, informally, one grumpy comment at a time — and everyone learned to live with the rest.
Then AI-assisted development showed up, and that quiet compromise stopped being quiet.
When a person writes code by hand, their habits spread slowly. A messy pattern takes weeks to propagate because a human can only type so fast. But when that same person is directing an AI assistant to generate code, test cases, and even documentation, their personal style — good, bad, or idiosyncratic — gets stamped across the codebase at ten times the speed and with ten times the false confidence, because “the AI wrote it” feels more objective than it is.
AI didn’t create the inconsistency. It put a megaphone in front of it.
At the company, this stopped being an abstract concern the moment I started measuring what it was actually costing us — and it became the reason I designed the framework this post is about.
What the problem actually looks like on the ground
It almost never shows up as a single dramatic outage. It shows up as sand in every gear, everywhere, all at once. Here’s the full shape of it, stage by stage:
Requirements — captured in five different formats depending on who wrote them: a formal doc for one feature, three lines in a Jira ticket for another, a verbal hallway conversation for a third that never got written down at all. Nobody can point to a single source of truth, so nobody fully trusts any of them.
Design patterns — chosen ad hoc, module by module, sometimes file by file, based on whatever the author was most comfortable with that week. One service is repository pattern. The next is a thin wrapper straight to the ORM. A third invents its own half-pattern that exists nowhere else in the codebase.
Design templates — divergent UI structures that multiply the moment a product has more than a handful of screens, because nobody agreed on a canonical component shape before building started.
Task creation — some tasks scoped down to a single, clean, half-day unit of work; others left as a vague paragraph that could hide two weeks of surprises. The size and shape of a “task” depends entirely on who wrote it.
Code style — different naming conventions, different file structures, different opinions on what “clean” even means, all coexisting in the same repository like dialects of the same language that have drifted just far enough apart to cause misunderstandings.
Test cases — written thoroughly by some, written as an afterthought by others, and in some corners of the codebase, not written at all.
Security gates — not deliberately skipped, just never enforced. They existed as a checklist item in someone’s head, not as a gate the pipeline actually checked.
PR process — different sizes, different description quality, different expectations of what a reviewer should catch, so review quality becomes a function of who happens to be reviewing rather than what the process requires.
Individually, every one of these looks like a minor stylistic difference. Nobody would block a release over it. But stacked together across an entire SDLC, they compound into something much more expensive than the sum of their parts — and the compounding shows up in three very specific, very painful places.
1. Bug fixing turns into archaeology
The engineer who inherits the bug usually isn’t the engineer who wrote the code. Without a shared mental model to fall back on, they can’t infer intent from structure — they have to reconstruct intent from scratch, reading code that might follow none of the patterns they’re used to. What should be a two-hour fix becomes a two-day investigation.
2. Change requests become a tax on whoever didn’t write the original feature
Assign a change request to someone outside the original module, and the first day disappears into “wait, why is it built this way?” instead of actually making the change. The clock the business is watching starts before the engineer has even finished orienting themselves.
3. Knowledge transfer never actually transfers
New hires — and existing engineers rotating onto an unfamiliar module — get “KT” in name only. In practice it’s weeks of shadowing, tribal-knowledge Slack messages, and hoping the right senior engineer is available to answer the fourth “wait, why does this work this way?” question of the day. There’s no canonical answer to hand someone. There’s only whoever happens to remember.
Get i.vikash’s stories in your inbox
Join Medium for free to get updates from this writer.
None of this is anyone’s fault. It’s what naturally happens when a team scales without ever agreeing on a shared grammar — and it’s exactly the failure mode that AI-assisted development accelerates, because now inconsistency ships faster than teams can catch it.
The plot twist inside the plot twist: designers can ship code now too
There’s a second shift happening at the same time, and it doesn’t get nearly enough attention.
Designers used to hand off a Figma file and hope the implementation matched the intent closely enough. That handoff was always lossy — pixels don’t translate perfectly to code, and “close enough” was the best anyone could promise.
That’s no longer the ceiling. With AI-assisted tooling, a designer can now produce an actual working design template — real component code, not just a picture of one — that a developer can inherit directly, without the usual game of telephone. The design is the starting point for the implementation, not a reference for it.
That’s a genuinely exciting capability. It’s also a trap if you don’t have anywhere for it to land. Hand a perfectly-structured design template to a codebase with five different architectural patterns, and you haven’t closed the design-to-code gap — you’ve just created a sixth pattern. The capability only pays off if there’s one canonical structure for developers to inherit into — which is exactly what I had to define before this piece of the framework could work at all.
What I actually built
I didn’t bolt a new tool onto the existing workflow and hope discipline would follow. I designed a base framework with an explicit opinion at every stage of the SDLC — from the moment a requirement is written down, through implementation and review, all the way to how a release actually gets deployed — and then, deliberately, chose not to leave that opinion as documentation. I built it as custom CI/CD pipeline gates, so the standard is enforced mechanically at merge time, not requested politely in a review comment that someone can choose to ignore.
Here’s what that meant in practice, piece by piece.
A reusable architecture : not a reference architecture. Most teams have an architecture diagram somewhere in a wiki that everyone nods at and nobody actually builds against. Mine is different by design: it’s a literal scaffold that new work is built on top of, not a picture people are expected to remember and voluntarily follow. Consistency becomes the path of least resistance instead of an act of individual discipline.
Coding standards enforced by the pipeline, not by review etiquette. This is the piece I’m most specific about, because it’s the piece that actually changes behavior: formatting, structure, and pattern conventions are checked as part of the CI/CD pipeline itself. A PR that violates the standard fails the gate and doesn’t merge — full stop. Nobody has to be the reviewer who awkwardly flags it. The pipeline already did, before a human ever had to have that conversation.
One canonical path from requirement to production. Requirement capture, task creation, design template, implementation, test writing, PR structure, security review — every single stage has one defined way to do it, not five competing ones. Security review in particular moved from “a step someone is supposed to remember” to a gate the pipeline checks automatically before code can progress — closing exactly the kind of gap that used to get missed under deadline pressure.
Design-to-code inheritance, made literal. Because designers can now produce real templates, I defined exactly how developers inherit those templates — component structure, naming, styling conventions, all of it — so the pipeline validates the inherited template against the same standard it validates everything else against, instead of treating design-originated code as a special case.
Deployment and release, standardized too — not left as the wild west after merge. A merged PR isn’t the finish line the framework stops caring about. Deployment and release follow the same principle as everything upstream: one defined process — how a release is promoted, sequenced, and gated — instead of whichever approach the engineer on call that week happens to prefer. The same discipline that stops five architectural patterns from coexisting also stops five different release habits from coexisting.
Guardrails at every handoff point, not just at the end. The gates don’t wait until final code review to catch a problem. Every stage where work changes hands — requirement to task, task to code, code to test, code to PR, PR to release, release to production — has a defined, automated check attached to it, so problems get caught at the seam where they’re cheapest to fix, not three stages later where they’re expensive.
What actually changed
The clearest signal: onboarding time for a new engineer — or an existing engineer moving into an unfamiliar module — dropped from roughly weeks to about days.
That number is worth sitting with, because it’s really a proxy for something much bigger than “onboarding got faster.” A four-week onboarding means the codebase was only legible through osmosis — through enough hours spent absorbing conventions that were never written down anywhere except in the heads of the people who’d been there longest. A one-week onboarding means those conventions stopped being unwritten, because the CI/CD gates are the documentation — they’re the actual thing the code has to pass through, not a description of the code that goes stale the week after someone writes it.
The second signal, and the one I’d point to as proof this wasn’t just an onboarding trick: bug-fix and PR cycle time got noticeably faster. Once every module was built against the same architecture and passed through the same gates, an engineer fixing a bug in an unfamiliar part of the codebase no longer had to reverse-engineer a new set of conventions first — the conventions were already the ones they knew. Reviewers spent less time on style nitpicks the pipeline had already caught, and more time on the logic that actually mattered.
And the same underlying logic paid off in the two places that mattered most day to day, closing the exact loop the original problems opened:
- Change requests got faster, because the request now lands in a codebase that speaks one language, not five dialects that happen to share a repository — instead of losing the first day to “wait, why is this built this way?”
- KT stopped being a ritual and started being a reference. There’s a canonical structure to point new team members to, instead of a hope that the right senior engineer is in the room.
And one structural change worth calling out on its own: the bus factor went down. Because the architecture and standards were the same everywhere, no single person was the only one who understood a given module — vacations, attrition, and reassignments stopped being a risk to any one part of the system.
Why this matters more, not less, in the AI era
There’s a tempting but wrong intuition floating around right now: that AI tools make standardization less necessary, because the AI can just adapt to whatever style it sees.
In practice, it’s exactly backwards. AI tools are extraordinarily good at matching whatever pattern is already in front of them — that’s a feature, not a bug. But it means if your codebase has five competing patterns, an AI assistant will faithfully help you produce a sixth, seventh, and eighth variation, at a speed no human team could match on their own. Consistency was never something AI gives you for free. It’s still something someone has to deliberately design the scaffolding for — and in my experience, that scaffolding only holds if it’s enforced by the pipeline, not requested in a doc. What AI changes isn’t whether you need that scaffolding — it’s how expensive it gets the moment you don’t have it.
The teams that figure this out early aren’t the ones using AI the most. They’re the ones who built one shared, enforced grammar for their codebase before they let AI start writing in it at scale.
If your team is living through the same fragmentation different requirement formats, different design patterns, unclear KT, security gates that depend on memory. I’m happy to walk through what I built, the trade-offs I made along the way, and what I’d do differently starting today.









