← Back to Blog
Building in Public

The Real Bugs Live in the UI (A Testing Reality Check)

christian crumlish•
A robot swatting an oversized mosquito, representing bugs that lurk in the user interface.
“Yeeouch!”

The Real Bugs Live in the UI (A Testing Reality Check)

July 1

After weeks of building sophisticated architecture, implementing AI reasoning, and solving complex integration challenges, I sat down to run four simple UI tests.

How hard could that be?

Test 1: Can it say hello?

First challenge: The web UI wasn’t running.

Failed to fetch: Connection refused on port 8081

Oh. Right. The web server needs to be… started. Separately. Because it’s a separate FastAPI app that serves the frontend.

bash

cd web
uvicorn app:app --host 0.0.0.0 --port 8081

There we go. UI loads. But wait — where’s the logo? Just a 🤖 emoji staring back at me. Didn’t I just add that? Made a note to fix it later. First, the tests.

“How are you?” I typed.

The response was perfectly professional, task-oriented, and slightly cold. Exactly as designed. We built a PM assistant, not a friend. Working as intended.

Test 1: ✅

The CORS dance

Tried to continue testing but got hit with the classic “Failed to Fetch” error. Not connection refused this time — CORS.

I was accessing the UI via http://0.0.0.0:8081 but the API expected http://localhost:8081. Same machine, same port, different origin according to CORS.

Twenty minutes of my life I’ll never get back, debugging why identical addresses aren’t identical.

Solution: Use localhost. Always use localhost.

I swear, one month or so into this project, that I had by then spent more time chasing environment issues than writing fresh code or fixing actual bugs.

Test 2: The file upload saga

Time to test file uploads. This had four subcases:

  1. Basic upload
  2. Give context about a file
  3. Give instructions about a file
  4. Use file as reference for GitHub issue

Uploaded a file. Got back a UUID. Success!

Asked “What’s in the file I just uploaded?”

Error: 'Workflow' object has no attribute 'input_data'

Wait, what? This was working last week.

The bug hunt begins

Started digging. The intent was recognized correctly. The workflow was created. But when it tried to persist to the database… boom.

Domain model vs database model mismatch. Classic.

Dug deeper. Found another error:

QueryRouter missing conversation_query_service argument

The QueryRouter initialization was incomplete. Missing dependency injection. Another classic.

But the best was yet to come.

The asterisk incident

Deep in the orchestration engine, on line 483, Claude found this:

async def *analyze*file(self, workflow: Workflow, task: Task) -> TaskResult:

Those aren’t underscores. Those are asterisks. In a method name.

This turned out to be a red herring. At this point I was still pasting errors and terminal output into chat windows to get help, and unfortunately the markdown interpreter was reading _analyze_file as analyzefile (treating the underscores as italics, as markdown does) and then de-encoding the italics back to *analyze*file because * is another way of indicating italics in markdown.

There went another half hour of my life till I realized and explained it to Claude and we stopped hunting for nonexistent typos. Shades of the most expensive hyphen in history!

Fixed the logo, at least!

While taking a break between test 2.2 and 2.3, I decided to have Cursor just fix that missing logo, oh and make me a favicon at the same time. (I used to struggle with things like that!)

Found the static file configuration. Cursor added the logo path. Refreshed.

Piper Morgan’s dolphin logo smiled back at me from the UI. Sometimes the small victories matter most.

Testing just begun…

By end of day:

✅ Test 1: Greeting/chitchat — PASSED

⚠️ Test 2: File upload — PARTIAL

  • ✅ 2.1: Basic upload works
  • ❌ 2.2: Context fails (workflow persistence)
  • ❌ 2.3: Instructions fail (asterisk method name)
  • ⏳ 2.4: Not tested yet

⏳ Test 3: Error handling — NOT STARTED

⏳ Test 4: GitHub integration — NOT STARTED

Three major bugs found. Two architectural issues exposed. One logo fixed.

This is what testing really looks like.

Some lessons

  1. The UI is where reality lives — Your beautiful architecture meets actual users here
  2. Simple tests find real bugs — Forget edge cases; start with “does it turn on?”
  3. Environment issues waste more time than logic errors — CORS, ports, servers not running
  4. Typos can hide anywhere — Even in method names, somehow
  5. Small victories matter — Sometimes fixing a logo is the win you need

The beauty of systematic testing

The session log shows something important: methodical progress. Test 1, then 2.1, then 2.2. Each failure revealed something specific:

  • Workflow persistence wasn’t actually implemented (just mocked in unit tests)
  • Dependency injection was incomplete in query routing
  • Method names can somehow have asterisks

These aren’t sophisticated bugs. They’re the kind you only find by actually using the system.

Next session: more reality to come

Three more tests to go. Error handling and GitHub integration still await. Workflow persistence needs real implementation.

The architecture is sophisticated. The AI is intelligent. The orchestration is elegant.

But the real bugs? They live in the UI, wearing asterisks as disguises.

← Back to BlogAlso available on Medium