← Back to Blog
Building in Public

7/12-7/13, 7/15 chat: From Broken Tests to Perfect Architecture: The Great Cleanup of July 14

christian crumlish•
A robot tidying a cluttered workspace, restoring order so a clean architecture can take shape.
“We’ll make it better than new”

From Broken Tests to Perfect Architecture: The Great Cleanup

July 14

What started as “let’s fix these 9 failing FileRepository tests” became “let’s eliminate three years–worth of accumulated technical debt and achieve 100% architectural pattern compliance.” Sometimes the best debugging sessions are the ones that refuse to stay in their lane.

(How we accumulated that much tech debt in less than three weeks is another testament to the power of AI.)

Eventually, we discovered that our test failures weren’t just broken tests — they were symptoms of fundamental architectural inconsistencies that had been lurking beneath a mostly-working system. By the end of a 14-hour session, we’d eliminated dual repository implementations, standardized on consistent patterns, and achieved something every architect dreams of: a codebase where everything follows the same rules.

The deceptively simple starting point

Fresh off PM-011’s completion and the test suite recovery to 87% pass rate, I thought July 14 would be a cleanup day. Just 27 remaining test failures across a few categories:

  • 9 FileRepository tests (connection pool vs session mismatch)
  • 3 API query tests (session management issues)
  • 14 assertion drift tests (float precision, logic updates)
  • 1 miscellaneous test (dataclass issue)

The FileRepository failures looked straightforward: tests were providing AsyncSession objects, but the repository expected connection pools with an .acquire() method. Classic interface mismatch. Should be a quick fix, right?

Famous last words.

The revealing architectural audit

Instead of band-aiding the FileRepository issue, I asked Claude Code to investigate our database patterns more systematically. What came back was a comprehensive architectural compliance audit that revealed uncomfortable truths about our codebase.

Repository Compliance: 71% (5/7 repositories)

The audit identified seven repositories across the system:

  • ✅ 5 repositories fully compliant with our documented Pattern #1
  • ❌ 1 repository using legacy raw SQL + connection pools
  • ⚠️ 1 repository in the wrong architectural layer

But the real shock was the footnote: “Dual WorkflowRepository implementation detected.”

We had two completely different WorkflowRepository classes in the codebase. Not variations on a theme — completely different implementations using different patterns, serving different parts of the system. (I was getting déjà vu again. Why did we keep “discovering” that we’d built parallel solutions in the past?)

The detective work begins

The FileRepository investigation led to a broader question: how much legacy code were we carrying from before we established architectural patterns?

Claude Code’s analysis revealed the scope:

Legacy Pattern (Raw SQL + Connection Pools):

class FileRepository:
def __init__(self, db_pool):
self.db_pool = db_pool
async def get_file_by_id(self, file_id: str):
async with self.db_pool.acquire() as conn:
row = await conn.fetchrow("SELECT * FROM uploaded_files WHERE id = $1", file_id)

Modern Pattern (SQLAlchemy + Sessions):

python

class FileRepository(BaseRepository):
def __init__(self, session: AsyncSession):
super().__init__(session, UploadedFileDB)
async def get_file_by_id(self, file_id: str) -> Optional[UploadedFile]:
result = await self.session.execute(
select(UploadedFileDB).where(UploadedFileDB.id == file_id)
)

The FileRepository was essentially prototype code that had never been migrated to our documented patterns. It worked, but it violated every architectural principle we’d established.

Suddenly, I was having nightmares again about the legacy spaghetti that powered AOL Instant Messenger in its final days.

The dual WorkflowRepository mystery

The WorkflowRepository situation was more complex. We had two implementations:

Legacy version (services/repositories/workflow_repository.py):

  • Raw SQL with connection pools
  • Used by API endpoints for read operations
  • Methods: find_by_id(), save()

Modern version (services/database/repositories.py):

  • Inherits from BaseRepository
  • Used by orchestration engine for write operations
  • Methods: create_from_domain(), update_status()

The interfaces didn’t even overlap! They were serving completely different use cases, with no obvious conflicts. This explained why the duplication had persisted — each implementation worked perfectly for its specific purpose.

But Claude Code’s investigation revealed the truth: “This is technical debt from an incomplete migration, not an architectural design choice.”

The evidence was clear:

  • The orchestration engine had been fully migrated to the RepositoryFactory pattern
  • API endpoints had never been migrated from direct imports
  • The two repositories existed because the migration was never completed

The systematic cleanup begins

Rather than patch around the inconsistencies, we decided to complete the architectural migration properly. The approach: Test-Driven Development for every change, ensuring we didn’t break anything that was working.

Phase 1: FileRepository migration

Claude Code created a comprehensive TDD test suite, then implemented the migration:

  • Migrated from raw SQL to SQLAlchemy ORM
  • Changed from connection pools to AsyncSession
  • Maintained the same public interface (returns domain models)
  • Followed Pattern #1 from our architecture documentation

The migration was clean. The repository now inherited from BaseRepository, used standard patterns, and integrated seamlessly with our test infrastructure.

Phase 2: WorkflowRepository consolidation

This was trickier because we needed to preserve functionality for both use cases:

Step 1: Add missing methods to the modern repository

python

async def find_by_id(self, workflow_id: str) -> Optional[Workflow]:
"""Add legacy method for API compatibility"""
db_workflow = await self.get_by_id(workflow_id)
return db_workflow.to_domain() if db_workflow else None

Step 2: Migrate API endpoints to use RepositoryFactory

# Before: Direct import and connection pool
from services.repositories.workflow_repository import WorkflowRepository
repo = WorkflowRepository(pool)

# After: Factory pattern with session management
repos = await RepositoryFactory.get_repositories()
db_workflow = await repos["workflows"].find_by_id(workflow_id)

Step 3: Remove the legacy implementation entirely

The migration was surgical. API functionality remained identical, but now everything used the same underlying patterns and session management.

The async session investigation

With the repository patterns unified, we still had those mysterious “operation in progress” errors in the FileRepository tests. This led to a deep investigation of async session management that revealed important patterns.

The error looked like a concurrency issue:

sqlalchemy.exc.InterfaceError: cannot perform operation: another operation is in progress

But systematic testing revealed the infrastructure was sound. We could run 20 sequential operations without issues. The problem was specific test anti-patterns that were reusing sessions inappropriately.

The solution was a session factory pattern for tests:

# Anti-pattern: Reusing session in loops
repo = FileRepository(db_session)
for item in items:
await repo.save_file_metadata(item) # Session reused!

# Better pattern: Fresh session per operation
async with await db_session_factory() as session:
repo
= FileRepository(session)
await repo.save_file_metadata(item)

This investigation taught us important principles about async database testing and session lifecycle management that will prevent similar issues in the future.

The moment of architectural victory

By evening, the audit results were transformed:

Repository Compliance: 100% (7/7 repositories)

  • ✅ All repositories inherit from BaseRepository
  • ✅ All repositories use AsyncSession pattern
  • ✅ All repositories follow documented patterns
  • ✅ No legacy implementations remaining
  • ✅ Consistent architectural layers

We’d achieved something rare in software development: complete pattern compliance across the entire system. Every repository now follows the same rules, uses the same base classes, and integrates with the same infrastructure.

The meta-lessons about technical debt

The July 14 cleanup taught us several important principles:

Legacy code compounds. What started as one non-compliant repository revealed systematic architectural inconsistencies. Technical debt doesn’t stay isolated — it spreads and creates maintenance burden across the system.

Good architecture makes debugging easier. Once we had consistent patterns, new issues became obvious. When everything follows the same rules, violations stand out immediately.

Test failures can be architectural feedback. The FileRepository test failures weren’t just broken tests — they were the system telling us about pattern violations we hadn’t noticed.

AI agents excel at systematic audits. Having Claude Code comprehensively audit all repository implementations revealed technical debt we might have missed for months. Different AI agents working in parallel (Cursor on session management, Claude Code on pattern compliance) accelerated the cleanup significantly.

The collaborative debugging pattern

The session demonstrated an effective pattern for complex architectural work:

Strategic AI (Opus) provides oversight and ensures architectural consistency

Investigative AI (Claude Code) conducts systematic audits and discovers technical debt

Implementation AI (Cursor) executes migrations with TDD discipline

Human (that’s me!) makes architectural decisions and coordinates the work

This multi-agent approach let us work on different aspects of the same problem simultaneously without conflicts. While Cursor was fixing async session patterns, Claude Code was migrating repository implementations. The parallel work streams accelerated progress significantly.

What this enables going forward

Achieving 100% pattern compliance isn’t just aesthetic satisfaction — it has practical benefits:

Onboarding new developers becomes easier when everything follows the same patterns. No need to learn multiple ways of doing database access.

Adding new repositories is straightforward — inherit from BaseRepository, follow the established pattern, integrate with RepositoryFactory.

Test infrastructure works consistently across all components. No special cases or interface mismatches.

Debugging database issues has clear troubleshooting patterns. When everything uses the same session management, problems are easier to isolate.

Architectural reviews can focus on new patterns rather than cleaning up old inconsistencies.

The honest assessment

Was the system perfect now? Not even close. We still had test assertion drift, float precision issues, and various edge cases to handle. But the foundational patterns were now solid and consistent.

Sometimes architectural work feels like “yak shaving” — endlessly preparing to do the real work. But July 14 proved that systematic cleanup creates compound benefits. Every repository that follows consistent patterns is one less maintenance burden. Every eliminated legacy implementation is cognitive overhead removed.

The unexpected satisfaction

There’s something deeply satisfying about achieving pattern compliance across a complex system. It’s the difference between a codebase that grew organically (with all the inconsistencies that implies) and one that follows coherent principles.

The FileRepository now looks like every other repository. The WorkflowRepository duplication is eliminated. The test infrastructure works consistently. When you open any database-related file, you know exactly what patterns to expect.

That consistency pays dividends every time you need to debug, extend, or modify the system.

← Back to BlogAlso available on Medium