# 04 – Resultate & Report (Ausgabe-Dateien)

> Schema-Referenz für alle Artefakte der Test-Suite und Aufbau des generierten `report.html`.
> Diese Dateien werden **zur Laufzeit erzeugt** und **nicht versioniert** (→ `.gitignore`).

---

## 1. Übersicht der Artefakte

| Datei | Erzeugt von | Zweck |
|---|---|---|
| `audit-result.json` | `tests/audit.mjs` | Raw-Reports der 3 Audits + Assertions + Page-Errors + Summary |
| `selfplay-results.json` | `tests/selfplay.mjs` | Episoden-Log + Win-Rate + Aggregates |
| `perf-result.json` | `tests/perf-test.mjs` | FPS, Heap, Setup-Metadaten |
| `report.html` | `tests/report.mjs` | Zusammengefasster, menschlich lesbarer CI-Report |
| `audit-final.png` | `tests/audit.mjs` | Finaler Screenshot des Headless-Browsers |

> `report.mjs` liest die drei `*-result.json` und rendert daraus ein einzelnes `report.html`.
> Fehlt eine JSON-Datei, zeigt `report.html` für die entsprechende Sektion „no data".

---

## 2. `audit-result.json`

```json
{
  "timestamp": "2026-08-28T19:20:00.000Z",
  "self": {
    "connectivity": [
      { "level": 0, "name": "…", "reachable": true }
    ],
    "attacks": [
      { "id": "sniper", "projectiles": 12, "hits": 10 }
    ],
    "skills": [
      { "id": "…", "rank": 4 }
    ],
    "placement": { "wall": true, "path": true },
    "autoWave": true,
    "endlessTransition": true
  },
  "extension": {
    "mortarSplashTargets": 2,
    "teslaAoE": { "targets": 5, "frozen": true },
    "rewardDedup": true,
    "blockerAltPath": true,
    "blockerClosedPath": true
  },
  "redesign": {
    "sniperPriority": true,
    "quantumBeam": { "aligned": 3, "offLineUnharmed": true },
    "nanoSpawner": { "limit": true, "damage": true, "cleanup": true }
  },
  "pageErrors": [],
  "assertions": [
    { "name": "self.connectivity.allReachable", "pass": true },
    { "name": "self.attacks.noZeroProjectiles", "pass": true },
    { "name": "self.skills.allRank4", "pass": true }
  ],
  "summary": {
    "total": 12,
    "pass": 12,
    "fail": 0
  }
}
```

> **Exit-Code-Kopplung:** `audit.mjs` beendet sich mit `1`, sobald `summary.fail > 0`
> oder `pageErrors` nicht leer ist. Ein harter Crash im Browser führt zu `2`.

---

## 3. `selfplay-results.json`

```json
{
  "timestamp": "2026-08-28T19:30:00.000Z",
  "episodes": [
    {
      "placed": 40,
      "towerCount": 40,
      "maxKills": 120,
      "waveReached": 8,
      "totalUpgrades": 64,
      "finalState": "victory",
      "finalKills": 120,
      "finalLeaked": 0,
      "finalLives": 20
    }
  ],
  "summary": {
    "total": 10,
    "wins": 8,
    "losses": 2,
    "winRate": 80.0,
    "avgKills": 118,
    "avgWaves": 7.4
  }
}
```

**Felder:**

| Feld | Bedeutung |
|---|---|
| `placed` | Anzahl tatsächlich platzierter Türme in der Episode |
| `towerCount` | Endgültige Turm-Anzahl (inkl. Spawner) |
| `maxKills` | Höchststand an Kills während der Simulation |
| `waveReached` | Letzt erreichte Wave |
| `totalUpgrades` | Anzahl gekaufter Skill-Upgrades |
| `finalState` | `victory` \| `defeat` |
| `winRate` | `wins / total × 100` |

---

## 4. `perf-result.json`

```json
{
  "timestamp": "2026-08-28T19:45:00.000Z",
  "durationMs": 15000,
  "fps": 58,
  "targetFps": 55,
  "pass": true,
  "heap": { "usedMB": 48.3, "totalMB": 96.0 },
  "setup": {
    "levelIdx": 10,
    "levelName": "…",
    "placed": 50,
    "enemies": 40,
    "state": "playing"
  }
}
```

| Feld | Bedeutung |
|---|---|
| `fps` | Gemittelte Frames pro Sekunde während `durationMs` |
| `targetFps` | Zielwert (Default `55`) – `pass` = `fps >= targetFps` |
| `heap.usedMB` | `performance.memory.usedJSHeapSize` / 1048576 |
| `heap.totalMB` | `performance.memory.totalJSHeapSize` / 1048576 |

> Heap-Messung benötigt Chromium (`performance.memory`). In nicht-Chromium-Browsern ist
> `heap` ggf. `null` → `report.mjs` blendet dann die Heap-Spalte aus.

---

## 5. `report.html`

`report.mjs` rendert eine statische, single-file HTML-Seite:

```
┌──────────────────────────────────────────────────────────────────┐
│  Aegis Labyrinth – Test & Audit Report                            │
│  Timestamp: 2026-08-28 19:45                                     │
├──────────────────────────────────────────────────────────────────┤
│  ✔ AUDIT       pass 12/12   self ✔  extension ✔  redesign ✔       │
│  ✔ SELF-PLAY   winRate 80%  (8/10)  avgKills 118                  │
│  ✔ PERFORMANCE 58 fps (target 55)  heap 48.3 / 96.0 MB            │
├──────────────────────────────────────────────────────────────────┤
│  Assertion-Details (expandierbare Liste)                          │
│  Page-Errors (leer)                                               │
└──────────────────────────────────────────────────────────────────┘
```

**Verhalten:**

- Jede Sektion hat einen Ampel-Status: grün (pass) / gelb (teilweise) / rot (fail).
- Fehlende Quelldatei → Sektion wird als „no data" (grau) gerendert, statt zu crashen.
- Kein externes JS/CSS → `report.html` ist vollständig offline-viewbar.

---

## 6. .gitignore (Empfehlung)

```gitignore
# Test-Artefakte (werden zur Laufzeit erzeugt)
audit-result.json
selfplay-results.json
perf-result.json
report.html
audit-final.png

# Externe Game-Source (manuell in die Root legen)
Aegis-Labyrinth.html

# Node
node_modules/