# 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
