# Session Log — 03-02-2026

**Project:** Cortex Intake Blocks MVP
**Sessie:** Testing, Bugfixes & Integration
**Tijd:** Avond

---

## Samenvatting

Deze sessie richtte zich op het volledig werkend krijgen van de Intake Blocks MVP:
1. Testplan maken
2. Meerdere kritieke bugs oplossen
3. Intake intents integreren in de volledige flow

**Eindresultaat:** ✅ Alle 4 intake intents werken nu volledig

---

## Bugs Opgelost

### Bug 1: Chat API Validatiefout

**Symptoom:** `Chat API error: Error: Validatiefout`

**Oorzaak:** Twee issues in Zod schema:
1. `nudge` type ontbrak in `ChatMessageSchema.type` enum
2. `content: z.string().min(1)` blokkeerde lege streaming berichten

**Fix:** `app/api/cortex/chat/route.ts`
```typescript
// VOOR:
type: z.enum(['user', 'assistant', 'system', 'error']),
content: z.string().min(1),

// NA:
type: z.enum(['user', 'assistant', 'system', 'error', 'nudge']),
content: z.string(), // Allow empty
```

---

### Bug 2: AI Chat herkent intake intents niet

**Symptoom:** Chat AI vraagt "Wil je het dossier opzoeken?" ipv navigeren

**Oorzaak:** Intake intents (`intake_status`, `risico_query`, `diagnose_query`, `intake_navigeer`) ontbraken in de AI system prompt.

**Fix:** `app/api/cortex/chat/route.ts` - System prompt uitgebreid met:
- P3 Intents sectie met 4 intake intents
- Triggers en entities per intent
- 4 voorbeelden (voorbeeld 9-12) met correcte JSON format

---

### Bug 3: Intake blocks worden niet gerenderd

**Symptoom:** Console log toont "Opening artifact: intake_status" maar niets verschijnt

**Oorzaak:** `artifact-container.tsx` miste:
1. Imports voor intake block components
2. Switch cases in `renderArtifactBlock()`
3. Titles in `getArtifactTitle()`

**Fix:** `components/cortex/artifacts/artifact-container.tsx`
```typescript
// Imports toegevoegd:
import { IntakeStatusBlock } from '../blocks/intake-status-block';
import { RisicoBlock } from '../blocks/risico-block';
import { DiagnoseBlock } from '../blocks/diagnose-block';

// Switch cases toegevoegd:
case 'intake_status':
  return <IntakeStatusBlock key={artifact.id} prefill={artifact.prefill} />;
case 'risico_query':
  return <RisicoBlock key={artifact.id} prefill={artifact.prefill} />;
case 'diagnose_query':
  return <DiagnoseBlock key={artifact.id} prefill={artifact.prefill} />;
```

---

### Bug 4: API retourneert 400 Bad Request

**Symptoom:** `/api/cortex/intake/status?patientId=xxx` → 400 error

**Oorzaak:** `searchParams.get('intakeId')` retourneert `null`, maar Zod `.optional()` verwacht `undefined`.

**Fix:** Alle 3 intake API routes:
```typescript
// VOOR:
const intakeId = searchParams.get('intakeId');

// NA:
const intakeId = searchParams.get('intakeId') || undefined;
```

**Bestanden:**
- `app/api/cortex/intake/status/route.ts`
- `app/api/cortex/intake/risico/route.ts`
- `app/api/cortex/intake/diagnose/route.ts`

---

## Lessons Learned

### 1. Zod + URLSearchParams
`searchParams.get()` retourneert `null`, niet `undefined`. Gebruik altijd `|| undefined` voor optionele Zod parameters.

### 2. AI Chat System Prompt
Nieuwe intents moeten expliciet in de system prompt staan met:
- Intent naam
- Trigger voorbeelden
- Entities
- Voorbeeld JSON output

### 3. Artifact Rendering
Nieuwe blocks vereisen wijzigingen op 3 plekken in `artifact-container.tsx`:
1. Import statement
2. Switch case in `renderArtifactBlock()`
3. Title in `getArtifactTitle()`

### 4. Intent Flow
Een intent doorloopt meerdere lagen - elke laag moet de intent kennen:
1. Reflex classifier (patterns)
2. AI chat (system prompt)
3. Action parser (routing)
4. Artifact container (rendering)

---

## Checklist: Nieuwe Intent Toevoegen

### Stap 1: Types & Patterns

**`lib/cortex/types.ts`**
```typescript
// 1. Voeg toe aan CortexIntent type
type CortexIntent =
  | 'bestaande_intent'
  | 'nieuwe_intent'  // ← nieuw
  | 'unknown';

// 2. Voeg toe aan BLOCK_CONFIGS (als het een block is)
nieuwe_intent: {
  type: 'nieuwe_intent',
  title: 'Nieuwe Intent',
  size: 'md',
  icon: 'IconName',
},
```

**`lib/cortex/reflex-classifier.ts`**
```typescript
// Voeg patterns toe aan REFLEX_PATTERNS
nieuwe_intent: [
  { pattern: /^trigger woorden/i, weight: 1.0 },
  { pattern: /^alternatieve trigger/i, weight: 0.9 },
],
```

### Stap 2: AI Chat Integration

**`app/api/cortex/chat/route.ts`**
```typescript
// In buildSystemPrompt(), voeg toe aan intents lijst:
- **nieuwe_intent** — Beschrijving
  - Triggers: "woord1", "woord2", "woord3"
  - Entities: entity1 (type), entity2 (type)
  - Actie: Wat er gebeurt

// Voeg een voorbeeld toe:
### Voorbeeld N: Nieuwe Intent

**User:**
"trigger zin"

**AI Response:**
"Korte bevestiging.

\`\`\`json
{
  "type": "action",
  "intent": "nieuwe_intent",
  "entities": { ... },
  "confidence": 0.98,
  "artifact": {
    "type": "nieuwe_intent",
    "prefill": { ... }
  }
}
\`\`\`"
```

### Stap 3: Action Parser

**`lib/cortex/action-parser.ts`**
```typescript
// 1. Voeg toe aan VALID_INTENTS array
const VALID_INTENTS = [
  'bestaande_intent',
  'nieuwe_intent',  // ← nieuw
];

// 2. Voeg toe aan routeIntentToArtifact()
case 'nieuwe_intent':
  return {
    type: 'nieuwe_intent',
    prefill: { ...entities },
  };
```

### Stap 4: API Route (als data nodig is)

**`app/api/cortex/[domain]/route.ts`**
```typescript
// Query params validatie - let op null → undefined!
const optionalParam = searchParams.get('param') || undefined;

// Zod schema
const QuerySchema = z.object({
  requiredParam: z.string().uuid(),
  optionalParam: z.string().optional(), // NOT .nullable()!
});
```

### Stap 5: Block Component

**`components/cortex/blocks/nieuwe-intent-block.tsx`**
```typescript
export function NieuweIntentBlock({ prefill }: Props) {
  const { patientId, hasPatientContext } = useIntakeContext(prefill);

  const { data, isLoading, error } = useBlockData<ResponseType>({
    endpoint: '/api/cortex/...',
    params: { patientId },
    enabled: hasPatientContext,
  });

  if (!hasPatientContext) return <BlockEmpty ... />;
  if (isLoading) return <BlockLoading ... />;
  if (error) return <BlockError ... />;

  return <BlockContainer>...</BlockContainer>;
}
```

### Stap 6: Artifact Container

**`components/cortex/artifacts/artifact-container.tsx`**
```typescript
// 1. Import
import { NieuweIntentBlock } from '../blocks/nieuwe-intent-block';

// 2. renderArtifactBlock() switch case
case 'nieuwe_intent':
  return <NieuweIntentBlock key={artifact.id} prefill={artifact.prefill} />;

// 3. getArtifactTitle() switch case
case 'nieuwe_intent':
  return 'Nieuwe Intent Titel';
```

### Stap 7: Navigatie Intent (optioneel)

Als de intent navigeert ipv een block toont:

**`components/cortex/command-center/command-center.tsx`**
```typescript
// In useEffect voor pendingAction:
if (pendingAction.intent === 'nieuwe_navigeer') {
  // Extract target
  const target = pendingAction.entities.navigationTarget;

  // Navigate
  router.push(`/epd/path/${target}`);

  // Toast feedback
  toast({ title: 'Navigeren...', description: `Naar ${target}` });

  // Clear action
  setPendingAction(null);
  return;
}
```

---

## Checklist: Nieuwe UI Block

1. **Block component maken**
   - `components/cortex/blocks/xxx-block.tsx`
   - Gebruik shared components: `BlockContainer`, `BlockLoading`, `BlockError`, `BlockEmpty`
   - Gebruik hooks: `useBlockData`, `useIntakeContext`

2. **API route maken** (indien nodig)
   - `app/api/cortex/[domain]/route.ts`
   - Let op: `|| undefined` voor optionele params!

3. **Artifact container updaten**
   - Import toevoegen
   - Switch case toevoegen
   - Title toevoegen

4. **Types updaten**
   - `BLOCK_CONFIGS` in `types.ts`

---

## Gewijzigde Bestanden (Totaal)

| Bestand | Wijziging |
|---------|-----------|
| `app/api/cortex/chat/route.ts` | Zod fix + intake intents in prompt |
| `app/api/cortex/intake/status/route.ts` | null → undefined fix + logging |
| `app/api/cortex/intake/risico/route.ts` | null → undefined fix |
| `app/api/cortex/intake/diagnose/route.ts` | null → undefined fix |
| `lib/cortex/chat-api.ts` | Betere error logging |
| `lib/cortex/hooks/use-block-data.ts` | Error details logging |
| `components/cortex/artifacts/artifact-container.tsx` | Intake blocks import + render |
| `docs/.../testplan-intake-blocks-mvp.md` | Nieuw testplan |
| `docs/.../session-log-2026-02-03.md` | Deze log |

---

## Eindstatus

| Component | Status |
|-----------|--------|
| `intake_status` intent | ✅ Werkt |
| `risico_query` intent | ✅ Werkt |
| `diagnose_query` intent | ✅ Werkt |
| `intake_navigeer` intent | ✅ Werkt |
| IntakeStatusBlock | ✅ Toont data |
| RisicoBlock | ✅ Toont data |
| DiagnoseBlock | ✅ Toont data |
| Navigatie | ✅ Werkt met toast |

---

## Volgende Stappen

1. [ ] E2E tests uitvoeren volgens testplan
2. [ ] Performance monitoring (API response times)
3. [ ] Voice input testen
4. [ ] Fase 3b intents toevoegen (kindcheck, anamnese, behandeladvies)
