Where Reality Meets the Road

In the previous Guide, I wrote that AI didn't create the architectural problem.

It exposed it.

This is where that idea met reality.

We had several products moving forward.

PageSnip had become a proving ground for a lot of ideas.

The ProHelp applications were taking shape.

We had core viewing and editing technologies underneath them.

Things worked.

The obvious thing to do was keep building.

Instead, we stopped.

Not because the core technology had failed.

Almost the opposite.

We stopped because some of it had worked well enough that we finally needed to treat it as what it had become.

Infrastructure.

We had already done the hard part

It would be easy to look at something like a Markdown editor and think the job is straightforward.

Put an editor on the screen.

Render the Markdown.

Add some buttons.

Done.

AI can certainly get you there quickly.

We've done enough AI-assisted development to know just how quickly.

But that wasn't what we had built.

We had spent an enormous amount of time selecting the underlying technologies, integrating them, refining them, and then living with the results in real applications.

We worked through the obvious cases.

Then the less obvious ones.

Then the cases you don't know exist until somebody does something you never expected.

Images.

Links.

Clipboard behavior.

Pasted content.

Preview behavior.

Formatting interactions.

Different kinds of source content.

The little inconsistencies that make a feature feel unfinished even when every individual part technically works.

Then came the regressions.

Fix something.

Discover that another path handles the same thing differently.

Fix that.

Make sure the first case still works.

Repeat.

Eventually the component stops being an experiment.

It becomes something you're willing to depend on.

That was the important distinction

The editing technology wasn't the problem.

The viewing technology wasn't the problem.

In fact, those were becoming some of the most mature parts of what we were building.

The problem was what happened around them.

We had multiple applications.

Each application had its own needs.

Each application was being developed with AI assistance.

And although we had established patterns and rules, the AI still had opportunities to build application-specific interpretations of those patterns.

The shared capability might be correct.

But one application would add a little behavior around it.

Another application would solve a similar problem differently.

Another worker would see the local code, decide the cleanest solution was to put something nearby, and create one more variation.

Nothing had to go dramatically wrong.

Drift doesn't require a disaster.

It just requires enough small reasonable decisions made independently.

We had made the guidelines better and better

We didn't ignore the problem.

We wrote instructions.

We documented patterns.

We created handoffs.

We identified which implementation was authoritative.

We told workers to examine the working version before making changes.

We became increasingly disciplined about how tasks moved from a project conductor to individual workers and back again.

All of that improved the results.

It still left one uncomfortable fact.

We were depending on AI to remember that several things which looked like separate implementation choices really weren't choices at all.

There was already a right answer.

The wrong question was "How do we make the AI copy this correctly?"

At some point, the answer became obvious.

Why were we asking the AI to copy it?

Suppose we had spent months building a Markdown editing capability that behaved the way we wanted.

Why should PageSnip have one interpretation of that capability and another application have another?

Why should we write an elaborate prompt explaining to one worker how another product implemented something correctly?

Why should we rely on a worker discovering the correct historical precedent?

Why should there be two implementations to compare in the first place?

We had already done the expensive part.

We had discovered what worked.

We were throwing some of that value away every time we asked AI to reproduce the lesson instead of using the result.

So we stopped

That was the uncomfortable decision.

There were plenty of things we could have continued building.

There always are.

PageSnip could move forward.

ProHelp could move forward.

There were features waiting.

There were bugs waiting.

There were visible things we could accomplish and point to at the end of the day.

Instead, we started working on the foundation.

The goal became much simpler to state:

If several products use the same capability, they should actually use the same capability.

Not copies.

Not compatible versions.

Not implementations that follow the same guidelines.

The same one.

That's a very different kind of consistency

If I tell two AI workers:

Build these two things so they behave exactly alike.

I have created a synchronization problem.

Maybe they will.

Maybe they'll be nearly identical.

Maybe one will contain a small improvement that the other never receives.

Maybe six months from now someone will fix a bug in one and not realize the other exists.

Maybe the next AI worker will inspect the wrong one and decide that it is authoritative.

Now compare that with:

Both products use this component.

There is nothing to synchronize.

That's the point.

This matters to the developer tools too

There was another advantage to making that transition.

Some of the core technologies we built for ourselves are also technologies we intend to put into the hands of Clarion developers.

That creates a standard I think is important.

I don't want the developer component to be something we built after the fact because we thought somebody might buy it.

I want it to be technology we trust enough to use ourselves.

If you see one of our applications using our viewing technology, the corresponding core component isn't supposed to be a separate approximation of what we use internally.

If you see our Markdown editing capability in one of our products, the developer technology should come from that same foundation.

That gives us an enormous incentive to get the core right.

We live with it too.

"AI can build that" isn't the same question

This is where AI changes the economics but doesn't eliminate the value of mature components.

Could a Clarion developer ask AI to create a Markdown editor?

Absolutely.

Could the result be attractive?

Sure.

Could it even be useful?

Of course.

That isn't really the question.

The question is how much time you want to spend after the first demonstration works.

Because that's where we spent most of ours.

The first screen isn't where you discover the difficult cases.

You discover them after you use the thing.

After you integrate it.

After you put it in another application.

After somebody copies content you never tried.

After an image comes from an unexpected place.

After two features that each work independently collide.

After the bug you fixed last month returns through a different path.

Those lessons accumulate.

Eventually the component represents much more than the code currently sitting in the repository.

It represents everything you had to learn to get there.

That is what reuse should preserve

When people talk about code reuse, they often talk about saving typing.

That seems almost quaint now.

AI has made typing code incredibly cheap.

The more interesting thing to reuse is experience.

A mature shared component contains decisions.

It contains bug fixes.

It contains edge cases.

It contains interaction design.

It contains all of the things somebody discovered after the first version looked finished.

When another product consumes that component, it inherits those lessons automatically.

When AI creates another implementation, we have to hope it rediscovers them.

That is not a bet I want to make unnecessarily.

It also changes what "proven" means

I don't mean proven in the sense that software can never have another bug.

That's unrealistic.

I mean something much more practical.

We've used it.

We've found problems.

We've fixed them.

We've integrated it into real work.

We've discovered cases that weren't obvious when we started.

We've continued refining it instead of throwing it away and starting over every time a new product needed something similar.

That's the kind of technology I want underneath multiple products.

And it's the kind of technology I am comfortable making available to other developers.

The application drift was still real

None of this means the problems we found in PageSnip and the other applications were imaginary.

They weren't.

The application-level architecture had drifted.

AI had been allowed too much freedom to reproduce behavior around the core components.

Responsibilities weren't always as sharply divided as they should have been.

Sometimes a local implementation existed where a shared implementation should have owned the behavior.

Sometimes we were maintaining conceptual consistency through instructions rather than structural consistency through architecture.

That needed to be fixed.

But there is an important difference between saying:

Our underlying technology wasn't good enough.

and:

Our underlying technology had become good enough that the applications should stop recreating it.

The second one describes what happened much more accurately.

Stopping was faster than continuing

This is the part that can be hard to accept while you're in the middle of a product.

Stopping feels slow.

Refactoring feels slow.

Moving responsibility into a shared platform feels slow.

Writing guards feels slow.

Removing duplicate implementations feels slow.

Meanwhile, AI is sitting there perfectly capable of building the next feature.

It is tempting to keep going.

But every new feature built on top of the wrong boundary becomes one more thing you'll eventually have to move.

At some point, continuing is the slow choice.

We reached that point.

So we stopped building long enough to stop rebuilding.

Reality is a useful test

It's one thing to draw an architecture.

It's another to write a specification.

It's another to give an AI a carefully written set of instructions explaining how everything should work.

Then the applications grow.

Multiple workers touch them.

Months pass.

Bugs appear.

Fixes accumulate.

New products reuse old ideas.

That's where reality meets the road.

If the architecture survives that, good.

If it doesn't, you learn where the real boundaries need to be.

We learned that several of our core capabilities had already earned the right to become genuine shared infrastructure.

We also learned that asking AI to maintain several interpretations of those capabilities was unnecessary risk.

So the answer wasn't another paragraph in the worker instructions.

It was one implementation.

One authority.

And multiple products using it.

This is probably the biggest lesson of the whole series

First, we learned that important rules can't remain mostly guidelines.

Then we learned that AI's mistakes can expose weaknesses that were already present in the architecture.

Finally, we learned that once the correct solution exists, the strongest guard may be removing the alternative entirely.

Don't make every new AI worker understand months of history.

Don't make it rediscover every decision.

Don't make it reproduce a component you've already spent months refining.

Let the architecture carry that knowledge.

We had already built the technology.

The next step was making sure we only had to build it once.

Related guide

For the broader lesson about moving architectural knowledge out of AI instructions and into the structure of the software itself, read Don’t Make AI Remember What the Architecture Can Enforce.