tfolghosts11

Debug Ghosts, Part XI

May 04, 2026

The Mobile Page That Didn’t Need to Exist

It started, as these things often do, with a perfectly reasonable assumption.

Mobile editing was broken.

Not catastrophically broken. Not throwing errors. Just… unusable. The layout collapsed. The image upload worked inconsistently. And the content editor—powered by TinyMCE—felt like it had been designed for a different planet.

So I did what any rational developer would do.

I built a second path.

A mobile-only page. A simplified form. Hidden fields to satisfy validation. A special route:

 
/work/?mobile=1
 

No TinyMCE. No clutter. Just the essentials:

  • Image
  • Title
  • Summary
  • Menu
  • Public

It worked.

On desktop, in mobile emulation, everything behaved. Stories saved. Images uploaded. The flow was clean. It felt like progress.

But then the ghosts arrived.


The First Disturbance

The mobile page worked locally.

On staging, it didn’t.

Same code. Same URL. Different result.

The page loaded, but it wasn’t the mobile template. No yellow debug blocks. No hidden fields. Just the old desktop form staring back, as if nothing had changed.

I checked the route.

I checked the query string.

I checked the deployment.

Eventually, I realized the truth.

I hadn’t deployed the changes.

The ghost wasn’t in the code.

It was in my environment.


The Second Disturbance

Once deployed, the mobile page appeared.

But something else was wrong.

Fields that should have been set weren’t.

  • blog stubbornly remained 1
  • family_id disappeared entirely

Hidden inputs were added. Defaults were forced. Backend overrides were introduced.

Still, the data didn’t behave.

At this point, the system had grown more complex than the original problem.

Two templates.
Conditional routing.
Hidden fields compensating for missing ones.
Backend logic compensating for frontend assumptions.

The ghost was spreading.


The Accidental Clue

Then something unexpected happened.

While testing, the desktop form appeared again.

Not the mobile version.

The original work.html.

But this time, something was different.

The content field worked.

No TinyMCE toolbar.
No interference.
Just a plain textarea.

And it saved correctly.

On mobile.


The Realization

The problem was never the form.

It was never validation.
It was never routing.
It was never mobile support.

It was TinyMCE.

Once it wasn’t actively interfering, the original form worked everywhere.

The mobile page—the one built to solve the problem—was unnecessary.

The ghost wasn’t in the system.

It was in the assumption.


The Exorcism

No dramatic fix.

No rollback.

No rewrite.

Just a quiet change in perspective.

Keep one template.
Let TinyMCE load only when it behaves.
Let the textarea do its job everywhere else.

The second path disappeared.


Why This One Matters

This wasn’t a bug.

It was over-engineering in response to a misdiagnosed problem.

The instinct to isolate mobile was reasonable. The execution was careful. The result even worked.

But it wasn’t needed.

Every extra path adds weight:

  • More templates
  • More routing
  • More edge cases
  • More ghosts

Sometimes the fastest way forward is not building something new.

It’s removing the thing that’s in the way.


Ghost Survival Rule #11

Before building a second path, disable the thing haunting the first one.


A Calmer Ending Than It Began

In the end, nothing dramatic changed.

No new system.
No new architecture.

Just one form, doing what it was supposed to do all along.

And one fewer ghost in the codebase.


End of Part XI 👻

Posted in ghost-stories by TFOL BLOG

Comments