← Back to Blog
Building in Public

The Two Realities Problem: When Your Database is Sophisticated and Your Web Tier Has Zero Auth

christian crumlish•
A robot standing between two mismatched spaces, one secure and one completely exposed.
“Not sure about this security regime”

The Two Realities Problem: When Your Database is Sophisticated and Your Web Tier Has Zero Auth

October 31

Friday morning. The day after first alpha user onboarding. Thursday was the birthday breakthrough — three hours of reactive bug-chasing followed by systematic E2E testing first, leading to successful onboarding at 11:26 AM.

But success revealed a problem.

I can log in as alpha-one. The system works. Tests pass. I can use Piper Morgan. Everything functions. From inside the system, it looks complete.

Then I look at the code. Really look at it. Not from user perspective but from architecture perspective.

And I see something disturbing: We have two parallel realities.

Reality 1 — The Database/Service Layer:

  • Sophisticated multi-user support (85% complete)
  • JWT implementation designed (ADR-012: Protocol Ready JWT Authentication)
  • User sessions stored in database
  • Per-user API key storage working
  • alpha_users table separate from users table
  • Password hash fields exist
  • Session management infrastructure built

Reality 2 — The Web Layer:

  • Single-user assumption throughout
  • Zero authentication whatsoever
  • Any user can access any session
  • No session isolation
  • No JWT validation
  • No auth middleware
  • No login flow

The morning architecture review

I onboard a new Chief Architect (Opus 4.1). The previous chat ran successfully for six weeks (September 20 — October 31)! Completed the Great Refactor (GREAT sequence), Sprint A8, alpha onboarding breakthrough.

Strong track record. But new agent means fresh eyes.

First task: Think through multi-user architecture properly before coding.

The approach: Don’t start fixing bugs reactively. Understand the system holistically. What exists? What’s missing? Where are the gaps?

Discovery 1 — The PIPER.md Problem:

PIPER.md was originally designed as generic capabilities file. System capabilities, default personality traits, available integrations. Generic information any user would see.

But looking at actual PIPER.md content:

  • My Q4 goals (personal)
  • VA projects (work context)
  • DRAGONS team info (company-specific)
  • Personal preferences and context

Wait. This file is supposed to be generic but contains my personal data. And it’s in the repository. Shared across all users. Any alpha tester would see my Q4 goals. (Good thing it’s already Q1 now in the federal government!)

Security issue. Privacy issue. Architecture issue.

The file that should contain “here’s what Piper Morgan can do” instead contains “here’s Christian’s personal context.” Not by design. By accident. Because I was the only user and the distinction didn’t matter until it did.

Discovery 2 — The Authentication That Exists:

Reading through documentation and code:

  • ✅ User model exists
  • ✅ ADR-012 (Protocol Ready JWT Authentication) documented
  • ✅ alpha_users table with password_hash field
  • ✅ Per-user API keys stored
  • ✅ User sessions in database
  • ✅ Multi-user infrastructure at database layer

Infrastructure is 85% complete. Not abandoned work. Not poorly designed. But sophisticated, thoughtful, comprehensive infrastructure.

Discovery 3 — The Authentication That Doesn’t Exist:

Looking at web layer:

  • ❌ No password hashing service
  • ❌ No email system for account management
  • ❌ No login endpoints
  • ❌ No auth middleware
  • ❌ No JWT token generation
  • ❌ No JWT validation
  • ❌ No session management in web tier
  • ❌ No user context passed to services

Web tier assumes single user. Every request processes as if from same user. No authentication layer whatsoever.

The realization: We built an entire multi-user database architecture. Then built a single-user web interface on top of it. The foundation is solid. The house has no doors.

The two parallel realities

Friday’s architectural analysis names the pattern clearly: Two Parallel Realities.

It’s not that one layer is behind. It’s that the layers exist in different architectural universes.

Reality 1 thinks:

  • Multiple users exist
  • Each user has own data
  • Authentication required
  • Sessions are isolated
  • User context flows through system

Reality 2 thinks:

  • One user (me)
  • All data is mine
  • Authentication unnecessary
  • Sessions don’t matter
  • User context is implicit (it’s always me)

Both realities function internally. Database layer works beautifully for multi-user. Web layer works fine for single user.

But they can’t coexist. When second alpha user tries to onboard, which reality wins?

The dangerous part: Tests pass. System functions. First alpha user (me) had successful onboarding Thursday. From inside Reality 2, everything looks complete.

Only when you examine both realities do you see: We’re 85% complete and 0% secure simultaneously.

The PIPER.md architecture problem

Let’s look deeper at the configuration issue because it reveals how single-user assumptions corrupt architecture.

How it should work:

PIPER.md → Generic system capabilities
- Default personality traits
- Available integrations
- System-wide settings

config/users/{user_id}/
- preferences.yaml → User-specific preferences
- context.md → User's projects and context
- api_
keys.enc → Encrypted keys

How it actually works:

PIPER.md → Christian's personal everything
- System capabilities (correct)
- Christian's Q4 goals (wrong)
- Christian's VA projects (wrong)
- Christian's team context (wrong)
PIPER.user.md → Barely used overrides

The file meant for “everyone” contains “me.” Because when I was the only user, the distinction was meaningless. Generic capabilities and personal context merged because they both applied to the same person — me.

This is sloppy work but it’s also just the natural evolution when you’re building for yourself. Single-user development doesn’t force the separation between “system” and “user.” Everything is both.

Multi-user development forces the separation. But we built multi-user database layer while still developing in single-user web layer. The cognitive mismatch persisted.

The 75% pattern strikes again

Friday’s analysis reveals a pattern we keep encountering: The 75% Pattern.

Work that’s 75% complete. Not abandoned. Not poorly done. But incomplete. Wired up enough to function in development. Not finished enough for production.

The Todo System: Database exists. Repositories work. Services implemented. Tests written. But web routes missing. Chat handlers not wired. 75% complete.

The Learning System: Architecture exists. Logging infrastructure built. Pattern storage designed. But not recording new patterns. Using existing knowledge graph but not learning from conversations. 75% complete.

The CONVERSATION Handler: Works perfectly. Processes chat messages. Generates responses. But architecturally misplaced. Not in canonical handlers section where it belongs. 75% complete.

The Web Auth Layer: Designed (ADR-012). Database fields exist. Infrastructure ready. But implementation missing. 75% complete.

The pattern isn’t failure. It’s how development actually happens. You build infrastructure. You wire up enough to test it. You confirm it works. Then you move to next priority before completing vertical integration.

Later you return to finish. Except sometimes you don’t return. Or you forget what needs finishing. Or you think it’s more complete than it is.

75% looks very different from outside (incomplete) than from inside (works in my tests).

The systematic triage

Friday afternoon (3:07 PM): Chief Architect session shifts from analysis to action.

Context for new Chief Architect:

  • Previous architect ran 6 weeks successfully (Sept 20 — Oct 31)
  • Completed GREAT (Great Refactor), CRAFT (Craft Pride), Alpha Sprint A8
  • First alpha user successfully onboarded Thursday
  • Alpha testing revealed ~10 bugs needing systematic attention
  • Multiple issues discovered through actual usage

The process: Transform chaotic bug discovery into systematic sprint plan.

Not reactive fixing. But comprehensive triage. What’s blocking? What’s critical? What’s polish? What’s process improvement?

10 Issues Identified and Categorized:

P0 Blockers (Must fix before external alpha):

  1. CORE-ALPHA-DATA-LEAK — Remove personal data from PIPER.md (2–3 hours)
  2. CORE-ALPHA-WEB-AUTH — Implement authentication layer (8–12 hours)
  3. CORE-ALPHA-FILE-UPLOAD — Fix file upload functionality (2–4 hours)

P1 Critical (Core features broken):

4. CORE-ALPHA-ERROR-MESSAGES — Conversational error fallbacks (4 hours)

5. CORE-ALPHA-ACTION-MAPPING — Fix classifier/handler coordination (2 hours)

6. CORE-ALPHA-TODO-INCOMPLETE — Complete todo system (8–12 hours)

P2 Important (Significant UX impact):

7. CORE-ALPHA-CONVERSATION-PLACEMENT — Fix architectural placement (2 hours)

8. CORE-ALPHA-TEMPORAL-BUGS — Fix response rendering (2 hours)

P3 Investigation (Non-blocking):

9. CORE-ALPHA-LEARNING-INVESTIGATION — Document learning system behavior (3 hours)

Process Improvement:

10. CORE-ALPHA-MIGRATION-TESTING — Migration testing protocol (2 hours)

The phased implementation plan

The triage isn’t just listing issues. It’s creating execution strategy.

Phase 1 blocks external testing. Can’t invite alpha testers while data leak exists or web auth missing.

Phase 2 blocks core value delivery. Can’t claim “PM assistant works” when error messages break conversational experience or todos don’t function.

Phase 3 blocks quality perception. Can ship alpha with these issues. But perception suffers when temporal rendering is broken or architecture is inconsistent.

The phases create natural checkpoints. Fix Phase 1 → Test → Evaluate → Proceed to Phase 2.

What Friday revealed about methodology

Friday wasn’t about fixing bugs. It was about understanding the system holistically before touching code.

The approach:

  1. Architectural analysis first (don’t just start fixing)
  2. Identify all issues systematically (don’t chase reactively)
  3. Categorize by impact (what blocks vs what polishes)
  4. Create phased execution plan (clear gates and sequencing)
  5. Estimate effort realistically (35–45 hours total)

Why this matters:

Thursday’s approach was reactive. Find bug → Fix bug → Find next bug → Fix that → Repeat. Works for small scope. But we found 10+ issues. Reactive chasing creates thrashing. Fix issue #3, break issue #7, fix #7, discover #11.

Friday’s approach was systematic. Understand all issues → Categorize impact → Sequence fixes → Execute phases → Test comprehensively.

The two parallel realities problem exemplifies why systematic analysis matters. You can’t fix “web auth missing” without understanding it exists within larger context of sophisticated database layer. You can’t fix data leak without understanding configuration architecture. You can’t prioritize issues without understanding dependencies.

Friday gave Saturday a gift: Clear problem definition. Comprehensive issue list. Execution roadmap. Effort estimates.

Saturday could execute efficiently because Friday analyzed thoroughly.

The “accidentally enterprise-ready” pattern

Friday’s analysis revealed something fascinating about the system’s evolution.

The database/service layer is 85% complete with multi-user infrastructure that was never explicitly intended for multi-user support initially.

We built:

  • User model (because we needed to track who’s using the system)
  • API keys per user (because different users need different API credentials)
  • Session storage (because we needed to maintain conversation context)
  • JWT architecture (because we knew auth would be needed eventually)

Each piece made sense individually for single-user development. But together they created enterprise-ready multi-user infrastructure.

Pattern name: “Accidentally Enterprise-Ready”

Infrastructure created for one purpose turns out suitable for another. Not by design. By accumulation of good individual decisions that happen to compose well.

This is different from the 75% pattern. The 75% pattern is intentional work left incomplete. “Accidentally enterprise-ready” is unintentional work that’s more complete than you realized.

The database layer wasn’t built for multi-user. It was built for single user with good practices (separation of concerns, proper data modeling, clean architecture). Those good practices happened to create multi-user foundation.

Then we needed multi-user for alpha testing. And discovered: The foundation exists. We just need to build the house.

What Friday means for Saturday

Friday ends not with code shipped but with understanding achieved.

10 issues documented. 3 phases planned. 35–45 hours estimated.

The path forward is clear. Not “reactively chase bugs until they’re gone.” But “systematically execute phases until criteria met.”

Phase 1 blocks external alpha. Must complete: Data leak + Web auth + File upload.

That becomes Saturday’s mission. Not “fix everything.” But “complete Phase 1.”

The gift Friday gives Saturday: Permission to focus. Don’t worry about todo system (Phase 2). Don’t worry about temporal rendering bugs (Phase 3). Don’t even worry about error messages (Phase 2).

Focus on three things: Data leak. Web auth. File upload.

Everything else can wait.

That focus enables Saturday’s achievement. New Lead Developer arrives. Looks at roadmap. Sees three P0 blockers. Deploys three agents in parallel. Fixes all three (plus bonus fourth issue) in 12.75 hours.

Friday’s systematic analysis enabled Saturday’s systematic execution.

The lesson of two realities

The two parallel realities problem teaches something important about system architecture: Layers can evolve independently in ways that create gaps.

Database layer advances (multi-user infrastructure). Web layer doesn’t advance at same rate (single-user assumption). Gap appears. Not because anyone made mistakes. Because different parts of system evolved at different paces for valid reasons.

You can’t see the gap from inside either reality. Database layer thinks “we’re ready for multi-user.” Web layer thinks “we work fine.” Only when you examine both simultaneously do you see: They’re incompatible.

This is why Friday’s architectural analysis matters. Not finding bugs. But understanding how the pieces relate. Where the gaps exist. What needs bridging.

Thursday proved the system works (first alpha user successful). Friday proved the system is incomplete (second alpha user would break). Both truths valid simultaneously.

The resolution isn’t choosing which reality is “correct.” It’s building the bridge between them. Web layer needs to catch up to database layer’s sophistication. Not rebuild database layer to match web layer’s simplicity.

That’s Saturday’s work. Build the 15% bridge between 85% complete database infrastructure and 0% complete web authentication.

Friday provided the map. Saturday built the bridge.

← Back to BlogAlso available on Medium