# Plan: Scenario Regression Depth + Housekeeping Stand: 2026-04-02 --- # Workstream E: Scenario Regression Depth ## Anforderungsanalyse Vier Szenario-Module haben **keine direkten Unit-Tests**: | Datei | Inhalt | Lücke | |-------|--------|-------| | `scenario-shared.ts` | Pure helpers: `roundToTenths`, `getScenarioAvailability`, `collectScenarioSkillSet`, `calculateScenarioEntryHours` | Keine Tests | | `scenario-baseline.ts` | `readProjectScenarioBaseline` — lädt Assignments/Demands, berechnet Kosten/Stunden | Keine Tests | | `scenario-apply.ts` | `applyProjectScenario` — CANCELLED/update/create Branches, appliedCount | Keine Tests | | `scenario-simulation.ts` | `simulateProjectScenario` — Baseline vs. Szenario-Delta, Warnungen, Skill-Coverage | Keine Tests | Bestehende Coverage: `scenario-router.test.ts` (Auth-Guards), `scenario-procedure-support.test.ts` (Delegation), `assistant-tools-scenarios.test.ts` (1 Integration-Test) — alles Delegation, keine Business-Logik. ## Betroffene Pakete & Dateien | Paket | Datei | Art | |-------|-------|-----| | `packages/api` | `src/__tests__/scenario-shared.test.ts` | create | | `packages/api` | `src/__tests__/scenario-apply.test.ts` | create | | `packages/api` | `src/__tests__/scenario-baseline.test.ts` | create | | `packages/api` | `src/__tests__/scenario-simulation.test.ts` | create | ## Task-Liste - [x] **E-1a:** `scenario-shared.test.ts` — Pure-Helper-Tests (keine Mocks außer resource-capacity) - `roundToTenths`: 0.15 → 0.2, 0.34 → 0.3, ganzer Integer bleibt - `getScenarioAvailability`: null → DEFAULT_AVAILABILITY; valides Objekt wird durchgereicht - `collectScenarioSkillSet`: null → leeres Set; leeres Array → leeres Set; doppelte Skills dedupliziert; lowercase-Normalisierung; leere Strings gefiltert; Mixed case dedupliziert - `calculateScenarioEntryHours`: ohne resourceId → delegiert an `calculateAllocation`; mit resourceId → delegiert an `calculateEffectiveBookedHours` - Mock: `@capakraken/engine/allocation` und `../lib/resource-capacity.js` - [x] **E-1b:** `scenario-apply.test.ts` — CRUD-Branch-Tests - NOT_FOUND wenn `project.findUnique` null zurückgibt - `remove: true` + `assignmentId` → `assignment.update` mit `status: "CANCELLED"`, appliedCount = 0 (cancel trifft `continue` vor `created.push`) - `assignmentId` ohne remove → `assignment.update` mit neuen Daten, appliedCount = 1 - kein `assignmentId`, kein `resourceId` → Zeile wird übersprungen, appliedCount = 0 - kein `assignmentId`, hat `resourceId` → `assignment.create` mit korrektem `dailyCostCents`, appliedCount = 1 - Mehrere Changes → korrekter appliedCount summiert - [x] **E-1c:** `scenario-baseline.test.ts` — Baseline-Lade-Tests - NOT_FOUND wenn Projekt nicht gefunden - Leeres Projekt (keine Assignments, keine Demands) → `totalCostCents: 0`, `totalHours: 0`, `assignments: []`, `demands: []` - Assignment mit bekanntem `lcrCents` und `hoursPerDay` → `costCents` korrekt berechnet - CANCELLED Assignments werden herausgefiltert (kommen nicht in `baselineAllocations`) - Demands werden korrekt gemappt (kein `costCents`, hat `headcount`, `roleName` aus roleEntity) - `totalCostCents` ist Summe aller Assignment-`costCents` - [x] **E-1d:** `scenario-simulation.test.ts` — Simulations-Logik-Tests - NOT_FOUND wenn Projekt nicht gefunden - remove-Change → Assignment fehlt im Scenario-headcount (`delta.headcount < 0`) - Neues Assignment hinzufügen → `delta.headcount > 0` - Budget-Warnung wenn `scenarioCostCents > budgetCents` → warnings enthält "exceeds budget" - Skill-Coverage: Szenario mit mehr Skills → `delta.skillCoveragePct > 100` - Szenario ohne Änderungen aber mit bestehenden Assignments → `delta.costCents = 0`, `delta.hours = 0` ## Abhängigkeiten - E-1a und E-1b können **parallel** geschrieben werden (separate Dateien) - E-1c und E-1d können **parallel** geschrieben werden - Keine Abhängigkeiten zwischen allen vier ## Akzeptanzkriterien - [x] `pnpm test:unit` läuft grün - [x] Alle 4 neuen Test-Dateien existieren mit ≥ 4 Tests jeweils (4 Dateien, 31 Tests, alle grün) --- # Workstream F: .env.example + Docs Housekeeping - [x] **F-1:** `.env.example` committen (commit 1ec56aa — erweitert auf ~85 Zeilen mit vollständiger Dokumentation) - [x] **F-2:** `plan.md` nach Abschluss mit erledigten Tasks aktualisieren