Files
triqura-ecd/docs/intent/bouwplan-cortex-v2.md
colinislit 6add89dc51 feat(cortex): Epic 5 - Integration & Polish complete (MVP DONE)
Epic 5 completes the Cortex V2 MVP with end-to-end integration:

E5.S1 - Feature Flag Guards
- ActionChainCard wrapped with CORTEX_MULTI_INTENT flag
- ClarificationCard wrapped with CORTEX_V2_ENABLED flag
- NudgeToast wrapped with CORTEX_NUDGE flag
- V1 UI remains functional when flags disabled

E5.S2 - Chain Execution Flow
- handleConfirmAction routes actions to artifacts via routeIntentToArtifact()
- Nudge evaluation triggered after successful action completion
- Sequential chain execution with auto-advance useEffect
- Chain auto-completes when all actions done

E5.S3 - Integration Tests (21 tests)
- Scenario 1: Simple input → Reflex handles (4 tests)
- Scenario 2: Multi-intent → Orchestrator handles (4 tests)
- Scenario 3: Context-dependent → Pronoun resolution (4 tests)
- Scenario 4: Wondzorg → Nudge suggestion (4 tests)
- Scenario 5: Graceful fallback (3 tests)
- Scenario 6: Chain building (2 tests)

E5.S4 - Demo Script
- 5-minute demo flow with exact phrases
- 5 scenes: Reflex speed, Multi-intent, Pronoun, Nudge, Clarification
- Backup scenarios documented
- Test phrases reference included

Files changed:
- components/cortex/chat/chat-panel.tsx (feature flags + execution)
- components/cortex/command-center/command-center.tsx (NudgeToast flag)
- lib/cortex/__tests__/cortex-v2.test.ts (NEW - 21 integration tests)
- docs/intent/demo-script-cortex-v2.md (NEW - demo documentation)
- docs/intent/bouwplan-cortex-v2.md (v1.5 - MVP complete)

MVP Status: 26/26 stories, 48/48 SP - 100% COMPLETE

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 13:16:20 +01:00

43 KiB

Bouwplan — Cortex Intent System V2

Projectnaam: Cortex V2 - Agentic Intent Architecture Versie: v1.5 Datum: 01-01-2026 Auteur: Colin Lit


1. Doel en context

Doel: Bouwen van een werkend MVP/prototype van het Cortex V2 Intent System dat de transformatie demonstreert van een reactief "spraakgestuurd toetsenbord" naar een AI Collega die context begrijpt, meerdere intenties verwerkt en proactief meedenkt.

Context: Het huidige Cortex systeem (V1) is reactief: gebruiker geeft commando → systeem voert uit. V2 introduceert een three-layer architectuur die intelligentie boven snelheid prioriteert.

Kernprincipe:

"We stoppen met optimaliseren voor milliseconden en starten met optimaliseren voor intelligentie."

Beoogd resultaat: Een demonstreerbaar prototype dat:

  • Multi-intents begrijpt ("Zeg Jan af en maak notitie")
  • Context-aware is (snapt wie "hij" is, wat "morgen" betekent)
  • Proactief suggesties geeft (na wondzorg → "Controle inplannen?")
  • Nooit "Ik snap het niet" zegt (altijd een poging tot begrip)

Referenties:

  • PRD: docs/intent/prd-cortex-v2.md
  • FO: docs/intent/fo-cortex-intent-system-v2.md
  • TO: docs/intent/to-cortex-v2.md
  • Architectuur: docs/intent/architecture-cortex-v2.md
  • MVP User Stories: docs/intent/mvp-userstories-intent-system.md

2. Dev Quick Start

Voor je begint

Lees eerst (5 min):

  • Dit bouwplan (je bent hier)
  • TO sectie 4.1 voor volledige type definities: docs/intent/to-cortex-v2.md

Codebase oriëntatie:

lib/cortex/                    # Cortex logic (V1 + V2)
├── types.ts                   # ✅ Bestaand - UITBREIDEN
├── intent-classifier.ts       # ✅ Bestaand V1 - NIET AANPASSEN
├── intent-classifier-ai.ts    # ✅ Bestaand V1 AI - referentie
├── entity-extractor.ts        # ✅ Bestaand - hergebruiken
├── reflex-classifier.ts       # 🆕 NIEUW in E1
├── orchestrator.ts            # 🆕 NIEUW in E2
├── nudge.ts                   # 🆕 NIEUW in E4
└── logger.ts                  # 🆕 NIEUW in E0

stores/
└── cortex-store.ts            # ✅ Bestaand - UITBREIDEN in E0.S4

components/cortex/
├── chat/
│   ├── action-chain-card.tsx  # 🆕 NIEUW in E3
│   └── clarification-card.tsx # 🆕 NIEUW in E3
└── command-center/
    └── nudge-toast.tsx        # 🆕 NIEUW in E4

app/api/cortex/
├── context/route.ts           # 🆕 NIEUW in E0.S2
└── classify/route.ts          # 🆕 NIEUW in E2.S5

lib/config/
└── feature-flags.ts           # 🆕 NIEUW in E0.S3

Werkwijze per story:

  1. Lees story + done criteria
  2. Check bestaande code (zie "Bestaande code" sectie per epic)
  3. Implementeer
  4. Run pnpm lint en pnpm build
  5. Test handmatig of met test command
  6. Commit met story ID: feat(cortex): E0.S1 - CortexContext types

Belangrijke conventies:

  • TypeScript strict mode
  • Nederlandse gebruikersteksten, Engelse code/comments
  • Zod voor runtime validatie waar nodig
  • Graceful degradation bij AI failures

3. Uitgangspunten

3.1 Technische Stack

Component Technologie Argumentatie
Frontend Next.js 15, React, TailwindCSS Bestaande stack, App Router
Backend Next.js API Routes Co-located met frontend
Database Supabase (PostgreSQL) Realtime, RLS, auth included
AI Model Claude 3.5 Haiku Snel (~400ms), goedkoop, excellent Nederlands
State Zustand Lightweight, devtools, persist
UI shadcn/ui Bestaande component library

3.2 Projectkaders

Kader Waarde
Type release MVP / Public Prototype ("Build in Public")
Bouwtijd 11-15 werkdagen
Budget N.v.t. (prototype)
Team 1 developer + AI-assistentie
Data Mock-data, geen productie EPD-koppeling
Doel Demonstratie van "Agency" concept

3.3 Programmeer Uitgangspunten

Code Quality Principles:

  • DRY - Herbruikbare components en utility functions
  • KISS - Eenvoudige oplossingen, geen premature optimization
  • SOC - UI gescheiden van business logic, API calls in service layers
  • YAGNI - Alleen bouwen wat nu nodig is voor MVP

Development Practices:

  • TypeScript strict mode
  • Zod schemas voor runtime validatie
  • Error handling met user-friendly Nederlandse meldingen
  • Graceful degradation bij AI failures

4. Epics & Stories Overzicht

MVP Scope ( In Scope)

Epic ID Titel Doel Status Stories Story Points
E0 Foundation & Context Types, API, feature flags Done 5 8 SP
E1 Reflex Arc (Layer 1) Snelle lokale classificatie Done 4 6 SP
E2 Intent Orchestrator (Layer 2) AI-gedreven multi-intent Done 6 13 SP
E3 UI Components ActionChainCard, ClarificationCard Done 4 8 SP
E4 Nudge MVP (Layer 3) Proactieve suggesties Done 3 5 SP
E5 Integration & Polish End-to-end flow, testing Done 4 8 SP

Totaal MVP: 26 stories, 48 Story Points — MVP COMPLEET

Post-MVP Scope ( Niet in Scope)

Feature Reden Prioriteit
Complete medische protocollen Te complex voor prototype Post-MVP
Rollback/Undo Vereist transactie-systeem Post-MVP
Offline mode Prototype veronderstelt internet Low
Advanced error handling Retry-mechanismes, circuit breakers Post-MVP
Analytics & learning Telemetry opslag, model training Post-MVP
NEN7510 compliance Productie-beveiliging Post-MVP (kritiek)
Externe integraties Teams, ECD-koppelingen Post-MVP

Belangrijk: Voer niet in 1x het volledige plan uit. Bouw per epic en per story.


5. Epics & Stories (Uitwerking)

Epic 0 — Foundation & Context

Epic Doel: Werkende basis met types, context API en feature flags voor gecontroleerde rollout.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden SP
E0.S1 CortexContext types definiëren Types in lib/cortex/types.ts voor context, intents, chains 2
E0.S2 GET /api/cortex/context endpoint Retourneert actieve patiënt, agenda, recente acties E0.S1 2
E0.S3 Feature flags setup CORTEX_V2_ENABLED, CORTEX_MULTI_INTENT, CORTEX_NUDGE, CORTEX_LOGGING 1
E0.S4 CortexStore V2 extensions Zustand store met context, chains, suggestions state E0.S1 2
E0.S5 Classification logging utility Dev logging + production sanitization E0.S1 1

Deliverable: Context beschikbaar, types gedefinieerd, backward compatible


🔧 Dev Context & Instructies — Epic 0

Bestaande code (NIET VERVANGEN, wel uitbreiden):

lib/cortex/
├── types.ts              # Bestaande types: CortexIntent, ExtractedEntities, BlockType
├── intent-classifier.ts  # V1 classifier (niet aanpassen in E0)
├── entity-extractor.ts   # Entity extraction (hergebruiken)
└── index.ts              # Exports (uitbreiden)

stores/
└── cortex-store.ts       # Bestaande store met ChatMessage, Artifact, RecentAction

E0.S1 — CortexContext types

Bestand: lib/cortex/types.ts Actie: Voeg NIEUWE types toe NA bestaande types. Behoud alle bestaande exports.

Toe te voegen types:

  • CortexContext - Context voor AI classificatie
  • IntentChain - Multi-intent container
  • IntentAction - Enkele actie in een chain
  • NudgeSuggestion - Proactieve suggestie
  • LocalClassificationResult - Reflex output (uitbreiding van bestaande ClassificationResult)
  • EscalationReason - Waarom Reflex escaleert

Voorbeeld signature:

export interface CortexContext {
  activePatient: { id: string; name: string; } | null;
  currentView: 'dashboard' | 'patient-detail' | 'agenda' | 'reports' | 'chat';
  shift: ShiftType;  // Hergebruik bestaande type
  // ... zie TO sectie 4.1 voor volledige definitie
}

Done criteria:

  • pnpm lint slaagt
  • Bestaande imports (CortexIntent, ExtractedEntities) werken nog
  • Nieuwe types geëxporteerd via lib/cortex/index.ts

E0.S2 — Context API endpoint

Bestand: app/api/cortex/context/route.ts (NIEUW) Actie: Maak GET endpoint die context verzamelt uit store/database.

Endpoint gedrag:

  • Haal actieve patiënt uit request context of store
  • Haal agenda vandaag uit Supabase (mock data voor MVP)
  • Retourneer CortexContext object

Voorbeeld response:

{
  "context": {
    "activePatient": { "id": "123", "name": "Jan de Vries" },
    "currentView": "patient-detail",
    "shift": "ochtend",
    "currentTime": "2025-12-31T10:00:00Z",
    "agendaToday": [
      { "time": "14:00", "patientName": "Marie", "type": "intake" }
    ],
    "recentIntents": []
  }
}

Done criteria:

  • GET /api/cortex/context retourneert 200 met valid JSON
  • Response matcht CortexContext type

E0.S3 — Feature flags

Bestand: lib/config/feature-flags.ts (NIEUW) Actie: Maak feature flag utility met env var support.

Flags te implementeren:

export const FEATURE_FLAGS = {
  CORTEX_V2_ENABLED: process.env.NEXT_PUBLIC_CORTEX_V2 === 'true',
  CORTEX_MULTI_INTENT: process.env.NEXT_PUBLIC_CORTEX_MULTI_INTENT === 'true',
  CORTEX_NUDGE: process.env.NEXT_PUBLIC_CORTEX_NUDGE === 'true',
  CORTEX_LOGGING: process.env.NEXT_PUBLIC_CORTEX_LOGGING === 'true',
};

Done criteria:

  • Flags werken in dev (hardcoded true)
  • Flags leesbaar vanuit components

E0.S4 — CortexStore V2 extensions

Bestand: stores/cortex-store.ts Actie: UITBREIDEN met nieuwe state en actions. Behoud bestaande useCortexStore.

Toe te voegen state:

  • context: CortexContext - Huidige context
  • activeChain: IntentChain | null - Actieve multi-intent chain
  • chainHistory: IntentChain[] - Geschiedenis
  • suggestions: NudgeSuggestion[] - Pending nudges
  • pendingClarification - Clarification state

Toe te voegen actions:

  • setContext(), startChain(), updateActionStatus(), completeChain()
  • addSuggestion(), acceptSuggestion(), dismissSuggestion()

Done criteria:

  • Bestaande store werkt nog (backward compatible)
  • Nieuwe state observable in React DevTools
  • pnpm lint slaagt

E0.S5 — Classification logging

Bestand: lib/cortex/logger.ts (NIEUW) Actie: Logging utility met PII sanitization.

Functies:

  • logClassification(result) - Log naar console (dev) of API (prod)
  • sanitizeForLogging(input) - Verwijder namen, BSN, telefoonnummers

Voorbeeld:

// Input: "notitie Jan Jansen medicatie"
// Output: "notitie [NAAM] medicatie"

Done criteria:

  • Dev logs tonen classificatie resultaten
  • Namen worden gesanitized in productie mode

Epic 1 — Reflex Arc (Layer 1)

Epic Doel: Razendsnelle (<20ms) afhandeling van simpele, eenduidige commando's.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden SP
E1.S1 Pattern matching implementeren Regex patterns voor alle intent types met weights E0.S1 2
E1.S2 Escalatie triggers detectie Multi-intent signals, context signals, relative time E1.S1 2
E1.S3 Ambiguity detection Top-2 score delta < 0.1 → escaleer E1.S1 1
E1.S4 Unit tests Reflex classifier Test suite voor simpele en complexe inputs E1.S1-S3 1

Deliverable: Simpele commando's werken direct (<20ms)


🔧 Dev Context & Instructies — Epic 1

Bestaande code (ter referentie):

lib/cortex/
├── intent-classifier.ts  # V1 classifier - REFERENTIE, niet aanpassen
│                         # Bevat INTENT_PATTERNS die je kunt hergebruiken
└── types.ts              # ClassificationResult type bestaat al

Relatie V1 → V2: De bestaande intent-classifier.ts heeft al regex patterns en weights. De nieuwe reflex-classifier.ts bouwt hierop voort maar voegt toe:

  • Escalatie logica (wanneer naar AI sturen)
  • Ambiguity detection (top-2 vergelijking)
  • Multi-intent signal detectie

E1.S1 — Pattern matching

Bestand: lib/cortex/reflex-classifier.ts (NIEUW) Actie: Maak nieuwe classifier gebaseerd op V1 patterns, maar met escalatie-aware logic.

Kernfunctie:

export function classifyWithReflex(input: string): LocalClassificationResult {
  // 1. Check escalatie triggers EERST
  // 2. Pattern matching met weights
  // 3. Return result met shouldEscalateToAI flag
}

Hergebruik van V1:

  • Kopieer INTENT_PATTERNS uit intent-classifier.ts
  • Pas weights aan: alleen >= 0.7 is "high confidence"
  • Voeg secondBestIntent tracking toe

Constants:

export const CONFIDENCE_THRESHOLD = 0.7;
export const AMBIGUITY_THRESHOLD = 0.1;

Done criteria:

  • "agenda vandaag" → { intent: 'agenda_query', shouldEscalateToAI: false }
  • Processing time < 20ms
  • Bestaande V1 classifier blijft werken (backward compatible)

E1.S2 — Escalatie triggers

Bestand: lib/cortex/reflex-classifier.ts Actie: Voeg detectEscalationTriggers() functie toe.

Trigger patterns:

const MULTI_INTENT_SIGNALS = /\b(en|daarna|ook|eerst|dan|vervolgens)\b/i;
const CONTEXT_SIGNALS = /\b(hij|zij|hem|haar|zijn|die|deze|dat|dezelfde)\b/i;
const RELATIVE_TIME_SIGNALS = /\b(morgen|overmorgen|volgende week|over \d+ dagen?)\b/i;

Logic:

  • Als EEN trigger matcht → shouldEscalateToAI: true
  • Return escalationReason voor logging

Done criteria:

  • "Zeg Jan af en maak notitie" → escalates (multi_intent_detected)
  • "Maak notitie voor hem" → escalates (needs_context)
  • "Plan afspraak morgen" → escalates (relative_time)

E1.S3 — Ambiguity detection

Bestand: lib/cortex/reflex-classifier.ts Actie: Track top-2 matches en vergelijk scores.

Logic:

// Na pattern matching
const delta = bestMatch.confidence - secondBestMatch.confidence;
if (delta < AMBIGUITY_THRESHOLD) {
  return { ...result, shouldEscalateToAI: true, escalationReason: 'ambiguous' };
}

Voorbeeld:

  • "plan wondzorg" matcht zowel create_appointment (0.72) als dagnotitie (0.68)
  • Delta = 0.04 < 0.1 → escaleer naar AI

Done criteria:

  • Ambigue input triggert escalatie
  • secondBestIntent en secondBestConfidence in result

E1.S4 — Unit tests

Bestand: lib/cortex/__tests__/reflex-classifier.test.ts (NIEUW) Actie: Test suite met Vitest.

Test cases:

describe('Reflex Classifier', () => {
  describe('Simple intents - should NOT escalate', () => {
    test('"agenda vandaag"', ...);
    test('"zoek marie"', ...);
    test('"notitie jan medicatie"', ...);
  });
  
  describe('Complex intents - SHOULD escalate', () => {
    test('"zeg jan af en maak notitie"', ...);  // multi_intent
    test('"maak notitie voor hem"', ...);        // needs_context
    test('"plan afspraak morgen 14:00"', ...);   // relative_time
  });
  
  describe('Ambiguous intents - SHOULD escalate', () => {
    test('"plan wondzorg"', ...);  // ambiguous
  });
});

Done criteria:

  • pnpm tsx lib/cortex/__tests__/reflex-classifier.test.ts slaagt (25 tests)
  • Coverage voor alle escalatie scenarios

Epic 2 — Intent Orchestrator (Layer 2)

Epic Doel: AI-gedreven analyse voor complexe zinnen, multi-intents en context resolution.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden SP
E2.S1 System prompt voor Orchestrator Prompt met context, intent types, output format E0.S1 2
E2.S2 Context formatting voor AI formatContextForPrompt() functie E0.S2 1
E2.S3 AI classification endpoint classifyWithOrchestrator() met Claude 3.5 Haiku E2.S1, E2.S2 3
E2.S4 IntentChain parsing JSON response naar IntentChain met actions E2.S3 2
E2.S5 POST /api/cortex/classify Hybrid endpoint: Reflex → Orchestrator fallback E1.S1-S3, E2.S3-S4 3
E2.S6 Graceful fallback Bij AI failure → fallback naar Reflex-only E2.S5 2

Deliverable: "Zeg Jan af en maak notitie" wordt correct geparsed naar 2 acties


🔧 Dev Context & Instructies — Epic 2

Bestaande code (ter referentie):

lib/cortex/
├── intent-classifier-ai.ts  # V1 AI classifier - bevat Anthropic setup
├── chat-api.ts              # Bestaande chat API calls
└── entity-extractor.ts      # Entity extraction (hergebruiken)

app/api/cortex/             # Bestaande API routes (indien aanwezig)

Dependencies:

  • @anthropic-ai/sdk is al geïnstalleerd
  • ANTHROPIC_API_KEY in .env.local

E2.S1 — System prompt

Bestand: lib/cortex/orchestrator.ts (NIEUW) Actie: Definieer ORCHESTRATOR_SYSTEM_PROMPT constant.

Prompt structuur:

const ORCHESTRATOR_SYSTEM_PROMPT = `Je bent de Intent Orchestrator voor Cortex...

## Je Taak
Analyseer de gebruikersinput en extraheer ALLE intenties.

## Context die je krijgt
- Actieve patiënt, Agenda vandaag, Recente acties, Huidige weergave

## Intent Types
1. dagnotitie, 2. zoeken, 3. overdracht, 4. agenda_query, 
5. create_appointment, 6. cancel_appointment, 7. reschedule_appointment

## Multi-Intent Detectie
Let op: "en", "daarna", "ook", "eerst", "dan", "vervolgens"

## Pronoun Resolution
"hij/zij" → actieve patiënt

## Output Format
ALLEEN valid JSON (geen markdown):
{ "actions": [...], "reasoning": "...", "needsClarification": false }
`;

Zie TO sectie 8.3 voor volledige prompt.

Done criteria:

  • Prompt is duidelijk en in het Nederlands
  • JSON output format gedocumenteerd

E2.S2 — Context formatting

Bestand: lib/cortex/orchestrator.ts Actie: formatContextForPrompt(context: CortexContext): string

Output format:

🧑 Actieve patiënt: Jan de Vries (ID: 123)
📍 Huidige weergave: patient-detail
⏰ Tijd: 10:30 (ochtenddienst)
📅 Agenda vandaag:
   - 14:00: Marie (intake)
   - 15:30: Piet (follow-up)

Done criteria:

  • Context leesbaar voor AI
  • Graceful handling van null values

E2.S3 — AI classification

Bestand: lib/cortex/orchestrator.ts Actie: classifyWithOrchestrator() async functie.

Implementatie outline:

export async function classifyWithOrchestrator(
  input: string,
  context: CortexContext
): Promise<AIClassificationResult> {
  const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
  
  const response = await anthropic.messages.create({
    model: 'claude-3-5-haiku-20241022',
    max_tokens: 512,
    temperature: 0,  // Consistente output
    system: ORCHESTRATOR_SYSTEM_PROMPT,
    messages: [{ role: 'user', content: `## Context\n${formatContextForPrompt(context)}\n\n## Input\n"${input}"` }],
  });
  
  // Parse JSON response
  // Build IntentChain
  // Return result
}

Done criteria:

  • Multi-intent input → meerdere actions in response
  • Processing time ~400ms (acceptabel)
  • Tokens usage gelogd

E2.S4 — IntentChain parsing

Bestand: lib/cortex/orchestrator.ts Actie: parseAIResponse() functie met error handling.

Parsing logic:

function parseAIResponse(rawText: string): ParsedResponse {
  // 1. Strip markdown code blocks (```json ... ```)
  // 2. JSON.parse met try/catch
  // 3. Validate tegen schema
  // 4. Fallback naar { actions: [{ intent: 'unknown' }] } bij parse error
}

Edge cases:

  • AI retourneert markdown code fence → strip
  • Invalid JSON → fallback to unknown
  • Missing fields → defaults

Done criteria:

  • Valid JSON correct geparsed
  • Invalid JSON → graceful fallback
  • IntentChain correct opgebouwd

E2.S5 — Hybrid classify endpoint

Bestand: app/api/cortex/classify/route.ts (NIEUW) Actie: POST endpoint die Reflex → Orchestrator flow implementeert.

Flow:

export async function POST(request: NextRequest) {
  const { input, context } = await request.json();
  
  // Step 1: Try Reflex
  const reflexResult = classifyWithReflex(input);
  
  // Step 2: Escalate if needed
  if (reflexResult.shouldEscalateToAI) {
    const aiResult = await classifyWithOrchestrator(input, context);
    return NextResponse.json({ ...aiResult, handledBy: 'orchestrator' });
  }
  
  // Step 3: Return Reflex result
  return NextResponse.json({ chain: buildChainFromReflex(reflexResult), handledBy: 'reflex' });
}

Done criteria:

  • Simpele input → Reflex (geen AI call)
  • Complexe input → Orchestrator
  • Response bevat handledBy field

E2.S6 — Graceful fallback

Bestand: lib/cortex/orchestrator.ts Actie: try/catch rond AI call met fallback naar Reflex.

Fallback scenarios:

  • Anthropic API 503 → use Reflex result
  • Timeout (>5s) → use Reflex result
  • Parse error → use Reflex result met warning

Voorbeeld:

try {
  return await classifyWithOrchestrator(input, context);
} catch (error) {
  console.error('[Cortex] AI failed, fallback to Reflex:', error);
  return buildFallbackResult(classifyWithReflex(input));
}

Done criteria:

  • AI failure → geen crash
  • User ziet resultaat (mogelijk minder intelligent)
  • Error gelogd voor monitoring

Epic 3 — UI Components

Epic Doel: Visuele feedback voor multi-intent flows en clarification.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden SP
E3.S1 ActionChainCard component Stacked cards met sequence, status, confidence E0.S1 3
E3.S2 ActionItem sub-component Status icons, confirmation buttons, error states E3.S1 2
E3.S3 ClarificationCard component Vraag + keuze-knoppen bij ambigue input 2
E3.S4 Processing indicator Spinner/skeleton bij AI-acties 1

Deliverable: Multi-intent flows visueel weergegeven


🔧 Dev Context & Instructies — Epic 3

Bestaande code (ter referentie):

components/
├── cortex/
│   ├── chat/           # Bestaande chat components
│   ├── blocks/         # Artifact blocks (dagnotitie, agenda, etc.)
│   ├── command-center/ # Command center layout
│   └── artifacts/      # Artifact containers
└── ui/
    ├── button.tsx      # shadcn/ui button
    ├── card.tsx        # shadcn/ui card
    └── badge.tsx       # shadcn/ui badge

Styling conventies:

  • TailwindCSS utility classes
  • shadcn/ui component patterns
  • cn() utility voor conditional classes

E3.S1 — ActionChainCard component

Bestand: components/cortex/chat/action-chain-card.tsx (NIEUW) Actie: Container voor multi-intent flow weergave.

Props interface:

interface ActionChainCardProps {
  chain: IntentChain;
  onConfirm: (actionId: string) => void;
  onSkip: (actionId: string) => void;
  onRetry: (actionId: string) => void;
}

Structuur:

<div className="bg-white rounded-lg border">
  {/* Header: "2 acties gedetecteerd" */}
  {/* ActionItem per actie */}
  {/* Collapsible AI reasoning */}
</div>

Done criteria:

  • Toont alle acties in chain
  • Header toont aantal acties
  • AI reasoning collapsible (details/summary)

E3.S2 — ActionItem sub-component

Bestand: components/cortex/chat/action-chain-card.tsx (in zelfde file of apart) Actie: Enkele actie row met status en controls.

Status icons mapping:

const STATUS_ICONS = {
  pending: <div className="w-2 h-2 rounded-full bg-slate-300" />,
  confirming: <AlertCircle className="w-4 h-4 text-amber-500" />,
  executing: <Loader2 className="w-4 h-4 text-blue-500 animate-spin" />,
  success: <Check className="w-4 h-4 text-green-500" />,
  failed: <X className="w-4 h-4 text-red-500" />,
  skipped: <X className="w-4 h-4 text-slate-400" />,
};

Confidence badge kleuren:

confidence >= 0.9   "bg-green-100 text-green-700"
confidence >= 0.7   "bg-amber-100 text-amber-700"
confidence < 0.7    "bg-red-100 text-red-700"

Intent labels (Nederlands):

const INTENT_LABELS = {
  dagnotitie: 'Notitie',
  zoeken: 'Zoeken',
  cancel_appointment: 'Afspraak annuleren',
  // ...
};

Done criteria:

  • Status icon correct per status
  • Confidence badge met juiste kleur
  • Confirmation buttons bij confirming status
  • Retry button bij failed status

E3.S3 — ClarificationCard component

Bestand: components/cortex/chat/clarification-card.tsx (NIEUW) Actie: UI voor verduidelijkingsvragen.

Props interface:

interface ClarificationCardProps {
  question: string;           // "Bedoel je een notitie of afspraak?"
  options: string[];          // ["Notitie maken", "Afspraak inplannen"]
  onSelect: (option: string) => void;
}

Voorbeeld weergave:

┌─────────────────────────────────────────┐
│ 💡 Bedoel je een notitie of afspraak?   │
│                                         │
│ [Notitie maken]  [Afspraak inplannen]   │
└─────────────────────────────────────────┘

Done criteria:

  • Vraag duidelijk zichtbaar
  • Knoppen voor elke optie
  • Click triggert onSelect callback

E3.S4 — Processing indicator

Bestand: Integreer in components/cortex/chat/ of bestaande chat components Actie: Toon "denk" indicator wanneer AI werkt.

Wanneer tonen:

  • Na user input, tijdens classificatie
  • Alleen bij AI calls (niet bij Reflex)

Varianten:

// Optie 1: Simpele spinner met tekst
<div className="flex items-center gap-2 text-slate-500">
  <Loader2 className="w-4 h-4 animate-spin" />
  <span>Even nadenken...</span>
</div>

// Optie 2: Skeleton loader (chat message style)
<div className="animate-pulse bg-slate-100 rounded-lg h-20" />

Done criteria:

  • Indicator zichtbaar tijdens AI call
  • Verdwijnt zodra response binnen is
  • Geen "frozen" UI gevoel

Epic 4 — Nudge MVP (Layer 3)

Epic Doel: Proactieve suggesties na succesvolle acties (proof of concept).

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden SP
E4.S1 Protocol rules definiëren Wondzorg-controle regel (hardcoded) E0.S1 1
E4.S2 evaluateNudge functie Check protocol rules na actie completion E4.S1 2
E4.S3 NudgeToast component Toast met countdown timer, accept/dismiss E0.S4 2

Demo Case:

Actie: Notitie "wond verzorgd" → Suggestie: "Wondcontrole inplannen over 3 dagen?"

Deliverable: Proactieve suggestie getoond na wondzorg notitie


🔧 Dev Context & Instructies — Epic 4

Concept uitleg: Nudge is een "post-action" systeem. Nadat een actie succesvol is uitgevoerd, checkt het systeem of er een protocol-regel matcht. Zo ja → toon suggestie.

Bestaande code:

  • Geen bestaande nudge code
  • stores/cortex-store.ts moet uitgebreid worden met suggestions state (E0.S4)

E4.S1 — Protocol rules

Bestand: lib/cortex/nudge.ts (NIEUW) Actie: Definieer ProtocolRule interface en hardcoded regels.

MVP regels (1-2 voor demo):

export const PROTOCOL_RULES: ProtocolRule[] = [
  {
    id: 'wondzorg-controle',
    name: 'Wondcontrole na verzorging',
    trigger: {
      intent: 'dagnotitie',
      conditions: [
        { field: 'content', operator: 'contains', value: 'wond' },
      ],
    },
    suggestion: {
      intent: 'create_appointment',
      message: 'Wondcontrole inplannen over 3 dagen?',
      prefillFrom: (source) => ({
        patientName: source.patientName,
        appointmentType: 'follow-up',
      }),
    },
    priority: 'medium',
    enabled: true,
  },
];

Condition operators:

  • equals - exact match
  • contains - substring (case insensitive)
  • matches - regex match
  • exists - field is not null/empty

Done criteria:

  • ProtocolRule type gedefinieerd
  • Minimaal 1 werkende regel (wondzorg)

E4.S2 — evaluateNudge functie

Bestand: lib/cortex/nudge.ts Actie: Check alle regels tegen een voltooide actie.

Functie signature:

export function evaluateNudge(completedAction: IntentAction): NudgeSuggestion[] {
  // 1. Filter enabled rules
  // 2. Check trigger.intent match
  // 3. Check all conditions
  // 4. Build suggestion if match
  // 5. Sort by priority (high first)
}

Condition checker:

function checkCondition(condition: ProtocolCondition, entities: ExtractedEntities): boolean {
  const value = entities[condition.field];
  switch (condition.operator) {
    case 'contains':
      return typeof value === 'string' && value.toLowerCase().includes(condition.value.toLowerCase());
    // ...
  }
}

Done criteria:

  • Notitie met "wond" → NudgeSuggestion returned
  • Notitie zonder "wond" → empty array
  • Suggesties gesorteerd op priority

E4.S3 — NudgeToast component

Bestand: components/cortex/command-center/nudge-toast.tsx (NIEUW) Actie: Toast UI met countdown en actions.

Props interface:

interface NudgeToastProps {
  suggestion: NudgeSuggestion;
  onAccept: (suggestionId: string) => void;
  onDismiss: (suggestionId: string) => void;
}

Features:

  • Progress bar countdown (5 minuten default)
  • Priority-based styling:
    • highborder-red-200 bg-red-50
    • mediumborder-amber-200 bg-amber-50
    • lowborder-blue-200 bg-blue-50
  • Accept/Dismiss buttons
  • Auto-dismiss na expiry

Countdown implementatie:

useEffect(() => {
  const interval = setInterval(() => {
    const remaining = expiresAt - Date.now();
    if (remaining <= 0) onDismiss(suggestion.id);
    setTimeLeft(remaining / total * 100);
  }, 1000);
  return () => clearInterval(interval);
}, []);

Done criteria:

  • Toast verschijnt na matching actie
  • Progress bar animeert
  • Accept triggert nieuwe actie
  • Dismiss verwijdert toast

Epic 5 — Integration & Polish

Epic Doel: End-to-end flow werkend, getest en demo-ready.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden SP
E5.S1 Feature flag guards V2 UI achter feature flags, V1 backward compatible E3, E4 3
E5.S2 Chain execution flow Route to artifacts, nudge trigger, sequential execution E5.S1 2
E5.S3 Integration tests 21 tests voor Cortex V2 scenarios E5.S1-S2 2
E5.S4 Demo scenario voorbereiden 5-min demo script met exacte zinnen E5.S3 1

Demo Flow (5 minuten):

  1. Simpel commando → Reflex (direct)
  2. Multi-intent commando → Orchestrator (ActionChainCard)
  3. Context-dependent → Pronoun resolution
  4. Wondzorg notitie → Nudge suggestie

Deliverable: Demo-ready prototype


🔧 Dev Context & Instructies — Epic 5

Bestaande code (aan te passen):

components/cortex/
├── command-center/
│   ├── command-center.tsx    # Hoofd container
│   ├── chat-panel.tsx        # Chat interface (indien aanwezig)
│   └── index.ts              # Exports
└── chat/
    └── chat-messages.tsx     # Message rendering

Feature flag check: Alle V2 features achter feature flags voor backward compatibility.


E5.S1 — CommandCenter V3 integratie

Bestanden:

  • components/cortex/command-center/command-center.tsx (AANPASSEN)
  • Eventueel chat panel component

Actie: Integreer nieuwe components in bestaande UI.

Integratie punten:

// In chat messages rendering
{result.chain.actions.length > 1 ? (
  <ActionChainCard 
    chain={result.chain} 
    onConfirm={handleConfirm}
    onSkip={handleSkip}
    onRetry={handleRetry}
  />
) : (
  // Bestaande single-action UI
)}

// Nudge toast (fixed position)
{suggestions.length > 0 && (
  <NudgeToast 
    suggestion={suggestions[0]}
    onAccept={handleAcceptSuggestion}
    onDismiss={handleDismissSuggestion}
  />
)}

Feature flag wrapper:

import { FEATURE_FLAGS } from '@/lib/config/feature-flags';

{FEATURE_FLAGS.CORTEX_MULTI_INTENT && chain.actions.length > 1 && (
  <ActionChainCard ... />
)}

Done criteria:

  • ActionChainCard toont bij multi-intent (wrapped met CORTEX_MULTI_INTENT)
  • NudgeToast verschijnt na matching actie (wrapped met CORTEX_NUDGE)
  • V1 UI werkt nog als flags uit staan

E5.S2 — Chain execution flow

Bestand: lib/cortex/chain-executor.ts (NIEUW) of in store actions Actie: Sequentiële uitvoering van acties in een chain.

Flow:

async function executeChain(chain: IntentChain): Promise<void> {
  for (const action of chain.actions) {
    // 1. Update status → 'confirming' (als requiresConfirmation)
    // 2. Wacht op user confirmation OF skip
    // 3. Update status → 'executing'
    // 4. Execute action
    // 5. Update status → 'success' of 'failed'
    // 6. Trigger Nudge evaluation
  }
}

Confirmation handling:

// Als action.requiresConfirmation === true
// Wacht tot user op "Bevestig" of "Overslaan" klikt
// Store: pendingConfirmation state

Done criteria:

  • Acties worden sequentieel uitgevoerd (useEffect auto-advance)
  • Confirmation dialog werkt (handleConfirmAction routes to artifact)
  • Failed action stopt niet hele chain
  • Nudge triggered na success (evaluateNudge + addSuggestion)

E5.S3 — Integration tests

Bestand: __tests__/integration/cortex-v2.test.ts (NIEUW) Actie: E2E tests voor complete flows.

Test scenarios:

describe('Cortex V2 Integration', () => {
  describe('Classification Flow', () => {
    test('simple input → Reflex handles', async () => {
      const response = await fetch('/api/cortex/classify', {
        method: 'POST',
        body: JSON.stringify({ input: 'agenda vandaag', context: mockContext }),
      });
      expect(response.handledBy).toBe('reflex');
    });
    
    test('multi-intent → Orchestrator handles', async () => {
      const response = await fetch('/api/cortex/classify', {
        method: 'POST',
        body: JSON.stringify({ input: 'zeg jan af en maak notitie', context: mockContext }),
      });
      expect(response.handledBy).toBe('orchestrator');
      expect(response.chain.actions).toHaveLength(2);
    });
  });
  
  describe('Nudge Flow', () => {
    test('wondzorg notitie → suggestion', ...);
  });
});

Done criteria:

  • pnpm tsx lib/cortex/__tests__/cortex-v2.test.ts slaagt (21 tests)
  • Coverage voor 6 scenarios (reflex, multi-intent, context, nudge, fallback, chain building)
  • AI responses gemockt via JSON strings voor deterministische tests

E5.S4 — Demo scenario

Bestand: docs/intent/demo-script-cortex-v2.md (NIEUW) Actie: Documenteer demo flow met exacte zinnen en verwachte resultaten.

Demo script (5 minuten):

## Demo: Cortex V2 - Van Reactief naar Proactief

### Setup
- Open EPD met patiënt "Jan de Vries"
- Shift: Ochtenddienst

### Scene 1: Snelheid (30 sec)
**Zeg:** "Agenda vandaag"
**Verwacht:** Direct resultaat (<20ms), geen spinner
**Highlight:** "Dit is Layer 1 - de Reflex Arc"

### Scene 2: Multi-Intent (1.5 min)
**Zeg:** "Zeg Jan af en maak notitie dat hij griep heeft"
**Verwacht:** ActionChainCard met 2 acties
**Highlight:** "Het systeem begrijpt dat dit twee dingen zijn"

### Scene 3: Context (1 min)
**Zeg:** "Maak notitie voor haar" (met Marie open)
**Verwacht:** Notitie voor Marie
**Highlight:** "Het snapt wie 'haar' is"

### Scene 4: Proactiviteit (1.5 min)
**Zeg:** "Notitie: wond verzorgd, ziet er goed uit"
**Verwacht:** NudgeToast - "Wondcontrole inplannen?"
**Highlight:** "Het denkt mee over vervolgacties"

### Backup
- Als AI down: toon Reflex-only (graceful degradation)
- Pre-seeded data beschikbaar

Done criteria:

  • Demo script geschreven (docs/intent/demo-script-cortex-v2.md)
  • 5 scenes met exacte zinnen en verwachte resultaten
  • Backup scenarios gedocumenteerd (AI timeout, no patient, feature flags)

6. Kwaliteit & Testplan

Test Types

Test Type Scope Tools Verantwoordelijke
Unit Tests Reflex classifier, entity extractor, nudge Vitest Developer
Integration Tests API endpoints, AI responses Vitest + MSW Developer
E2E Tests Complete flows Playwright Developer
Manual Tests Demo scenarios Checklist Developer

Test Coverage Targets

  • Unit tests: Reflex classifier, entity extractor
  • Integration tests: /api/cortex/classify, /api/cortex/context
  • E2E tests: Multi-intent flow, Nudge flow

Manual Test Checklist (MVP)

# Scenario Expected Result
1 "Agenda vandaag" Direct resultaat (<20ms), geen spinner
2 "Zoek Jan" Direct zoekresultaat
3 "Zeg Jan af en maak notitie: ziek" 2 acties in ActionChainCard
4 "Maak notitie voor hem" (met actieve patiënt) Patiëntnaam correct resolved
5 "Plan afspraak morgen 14:00" Datum correct berekend
6 "Notitie: wond verzorgd" NudgeToast verschijnt
7 Ambigue input ClarificationCard met opties
8 AI API down Graceful fallback naar Reflex

Test Zinnen Dataset

{
  "single_intent": [
    { "input": "notitie jan medicatie", "expected": ["dagnotitie"] },
    { "input": "zoek marie", "expected": ["zoeken"] },
    { "input": "agenda vandaag", "expected": ["agenda_query"] }
  ],
  "multi_intent": [
    {
      "input": "Zeg Jan af en maak notitie dat hij griep heeft",
      "expected": ["cancel_appointment", "dagnotitie"]
    }
  ],
  "context_dependent": [
    {
      "input": "Maak notitie voor hem",
      "context": { "activePatient": { "name": "Piet" } },
      "expected": ["dagnotitie"],
      "entities": [{ "patientResolution": "pronoun" }]
    }
  ]
}

7. Demo & Presentatieplan

Demo Scenario

Duur: 5 minuten Doelgroep: Developers, stakeholders, social media (Build in Public) Locatie: Localhost of Vercel preview

Demo Flow

Stap Actie Doel Tijd
1 "Agenda vandaag" Toon Reflex snelheid 30s
2 "Zeg Jan af en maak notitie: hij heeft griep" Toon Multi-intent + ActionChainCard 1.5m
3 "Maak notitie voor haar" (met Marie open) Toon Pronoun resolution 1m
4 "Plan afspraak morgen 14:00" Toon Relatieve tijd 30s
5 "Wond verzorgd, ziet er goed uit" Toon Nudge suggestie 1.5m

Backup Plan

  • Lokale versie bij internet issues
  • Pre-seeded data als AI API niet reageert
  • Screenshots als complete fallback

8. Risico's & Mitigatie

Risico Kans Impact Mitigatie Owner
AI output inconsistent Middel Hoog Temperature=0, strikte JSON schema, fallback to unknown Dev
Multi-intent parsing faalt Laag Hoog Uitgebreide test dataset, fallback naar single intent Dev
Anthropic API down Laag Middel Graceful degradation naar Reflex-only Dev
Scope creep Hoog Middel Strikte MVP scope, 6 user stories max PM
Privacy breach (logs) Laag Hoog Input sanitization, geen PII in production logs Dev
False positive Nudge Middel Laag Specifieke regex met word boundaries Dev
Performance degradatie Laag Middel Caching, monitoring, threshold tuning Dev

9. MVP User Stories Mapping

De MVP User Stories uit mvp-userstories-intent-system.md zijn als volgt verdeeld:

Thema 1: De Slimme Assistent (Core Intelligence)

User Story Epic Stories
US-MVP-01: Twee acties in één zin E2 E2.S1-S5
US-MVP-02: Verwijzen naar "deze patiënt" of "hij" E2 E2.S2-S4
US-MVP-03: Impliciete tijd ("morgen") E1, E2 E1.S2, E2.S2

Thema 2: Hybride Snelheid (Architecture)

User Story Epic Stories
US-MVP-04: Simpele commando's direct (<20ms) E1 E1.S1-S4
US-MVP-05: Zien dat systeem nadenkt E3 E3.S4

Thema 3: De Partner (Proactivity)

User Story Epic Stories
US-MVP-06: Proactieve suggestie (wondzorg) E4 E4.S1-S3

10. Succescriteria

Functionele Criteria

Criterium Target Meetmethode
Multi-intent herkenning "X en Y" zinnen correct gesplitst Test dataset
Pronoun resolution "hij/zij" correct resolved Test met actieve patiënt
Reflex hit rate >70% lokaal afgehandeld Logging metrics
AI latency p95 <800ms Performance monitoring
Nudge trigger Wondzorg → suggestie getoond Manual test

UX Criteria

Criterium Target
Geen "Ik begrijp het niet" Altijd poging tot begrip of clarification
Processing feedback Spinner bij AI-acties
Demo duur Volledige flow in ≤5 minuten

Technische Criteria

Criterium Target
Reflex latency <20ms
AI fallback werkt Bij Anthropic 503 → graceful degradation
Geen PII in logs Input gesanitized

11. Referenties

Mission Control Documents

Document Locatie
PRD docs/intent/prd-cortex-v2.md
FO docs/intent/fo-cortex-intent-system-v2.md
TO docs/intent/to-cortex-v2.md
Architectuur docs/intent/architecture-cortex-v2.md
MVP User Stories docs/intent/mvp-userstories-intent-system.md
Haalbaarheidsanalyse docs/intent/haalbaarheidsanalyse-cortex-v2.md

Tech Documentatie


12. Glossary

Term Betekenis
Cortex Het intent classificatie systeem (voorheen "Swift")
Reflex Arc Layer 1 - snelle lokale pattern matching (<20ms)
Orchestrator Layer 2 - AI-gedreven classificatie (~400ms)
Nudge Layer 3 - proactieve suggesties na acties
IntentChain Lijst van intents uit één gebruikersinput
Entity Geëxtraheerde data (patiëntnaam, datum, etc.)
Artifact UI component voor een specifieke taak
Escalatie Doorsturen van Reflex naar Orchestrator

Versiehistorie

Versie Datum Auteur Wijziging
v1.0 30-12-2025 Colin Lit Initiële versie op basis van PRD, FO, TO, Architecture docs
v1.1 31-12-2025 Colin Lit Dev-instructies per epic toegevoegd, file mappings, done criteria
v1.2 01-01-2026 Colin Lit Epic 2 (Intent Orchestrator) compleet - alle 6 stories afgerond
v1.3 01-01-2026 Colin Lit Epic 3 (UI Components) compleet - ActionChainCard, ActionItem, ClarificationCard, ProcessingIndicator
v1.4 01-01-2026 Colin Lit Epic 4 (Nudge MVP) compleet - ProtocolRules, evaluateNudge, NudgeToast, DagnotatieBlock integratie
v1.5 01-01-2026 Colin Lit MVP COMPLEET - Epic 5 (Integration & Polish) afgerond: feature flags, chain execution, 21 integration tests, demo script