# UI Breakage Root Cause Analysis
**Date:** 2026-02-09  
**Issue:** Recurring UI breakage - Discovery page crashes

## Root Cause

**Location:** `/src/app/api/discovery/opportunities/route.ts` line 133-135

**Problem:** Unsafe `.toLowerCase()` calls on potentially undefined `name` fields from scan YAML files.

```typescript
// OLD CODE (UNSAFE):
const isDuplicate = allOpportunities.some(
  (existing) => 
    existing.name.toLowerCase() === opp.name.toLowerCase() ||
    (existing.name.toLowerCase().includes(opp.name.toLowerCase().substring(0, 20)))
);
```

**Why it happened:**
1. Scan YAML files have **inconsistent field names**:
   - Some use `title` (expected by code)
   - Some use `name`
   - Some use `id`
   - Some have no name field at all
2. Code assumed `scanOpp.title` always exists → `opp.name` became `undefined`
3. Duplicate check called `.toLowerCase()` on `undefined` → crash

**Error pattern:**
```
TypeError: Cannot read properties of undefined (reading 'toLowerCase')
at /api/discovery/opportunities/route.js:1:1832
```

## The Fix

Added defensive checks:

```typescript
// Skip entries without title
if (!scanOpp.title) {
  continue;
}

// Null-safe duplicate check
const isDuplicate = allOpportunities.some(
  (existing) => {
    if (!existing.name || !opp.name) return false;
    const existingLower = existing.name.toLowerCase();
    const oppLower = opp.name.toLowerCase();
    return existingLower === oppLower ||
           (oppLower.length >= 20 && existingLower.includes(oppLower.substring(0, 20)));
  }
);
```

## Why This Kept Happening

1. **No validation on scan file format** - scan scripts can write inconsistent YAML
2. **No build-time type safety** - TypeScript interfaces don't enforce runtime data
3. **No API error boundaries** - one bad scan file crashes the entire endpoint
4. **No monitoring/alerting** - breakages go unnoticed until user reports

## Prevention Measures Implemented

See `agency/docs/ui-breakage-prevention.md`
