Files
Laby/docs/02_Audits.md
T
Lila-Kuh ea2a2f2cbf
Aegis CI / audit (push) Failing after 1m7s
Aegis CI / selfplay (push) Skipped
Aegis CI / perf (push) Failing after 3s
Aegis CI / report (push) Failing after 2s
Initial project version
2026-08-29 01:45:19 +02:00

193 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 02 Audits im Detail (self / extension / redesign)
> Was die drei eingebauten Audits konkret prüfen, welche **Assertions** `tests/audit.mjs` darauf aufsetzt und welche **Exit-Codes** daraus resultieren.
> API-Basis: [`01_Debug_API.md`](./01_Debug_API.md).
---
## 1. Übersicht
| Audit | API-Funktion | Fokus |
|---|---|---|
| **Self** | `runSelfAudit()` | Konnektivität (11 Levels), Attacks, Skills, Platzierung, AutoWave, Endless |
| **Extension** | `runExtensionAudit()` | Mortar-Splash, Tesla-Chain/Freeze, Reward-Dedup, Blocker-Logik |
| **Redesign** | `runRedesignAudit()` | Kryo, Sniper (Pierce), Mortar-FixImpact, Quantum-Beam, Nano-Spawner |
`audit.mjs` führt alle drei in einer Headless-Chromium-Session aus, sammelt `pageerror`-Events und bewertet die Rückgabe-Werte mit eigenen Assertion-Hilfsfunktionen.
---
## 2. `runSelfAudit()` Struktur & Assertions
### 2.1 Report-Struktur (Rückgabe der API)
```jsonc
{
"connectivity": [ { "level": 0, "starts": 2, "exit": true, "reachable": true }, ], // 11 Levels
"attacks": [ { "id": "sniper", "projectiles": 3, "holos": 0, "hurt": 2 }, ],
"skills": [ { "id": "sniper", "rank": 4 }, ],
"placement": { "wallAccepted": true, "pathAccepted": false, "count": 1 },
"autoWave": { "state": "playing", "active": true },
"endless": { "state": "endless", "endlessWave": 1 }
}
```
### 2.2 Assertions in `tests/audit.mjs` (`assertSelfAudit`)
| # | Assertion | Erwartung |
|---|---|---|
| S-conn | `L{n} has start` | `starts > 0` (pro Level) |
| S-conn | `L{n} has exit` | `exit === true` (pro Level) |
| S-conn | `L{n} reachable` | `reachable === true` (pro Level) |
| S-atk | `tower {id}: projectiles=… holos=… hurt=…` | **info** (Support-/Relay-Türme feuern absichtlich nicht → kein Hard-Fail) |
| S-sk | `skill {id} rank>=1` | `rank >= 1` (nach 4× `buySkill`) |
| S-plc | `placement: wallAccepted (tower on free cell)` | `wallAccepted === true` |
| S-plc | `placement: pathAccepted (tower on path rejected)` | `pathAccepted === false` |
| S-plc | `placement: tower count>=1` | `count >= 1` |
| S-aw | `autoWave: state` / `autoWave: active` | **info** (nur State prüfen) |
| S-ee | `endless: state` | **info** |
| S-ee | `endless: endlessWave>=0` | `endlessWave >= 0` |
> Hinweis: „Attacks“ und „AutoWave“ sind bewusst **Diagnose-/Info-Checks** die harten Pfade laufen über Konnektivität, Skills und Platzierung.
---
## 3. `runExtensionAudit()` Struktur & Assertions
### 3.1 Report-Struktur
```jsonc
{
"mortar": { "projectile": true, "hurt": true },
"tesla": { "damaged": 3, "frozen": 2 },
"reward": { "pointsAfterDuplicate": 1, "storedRank": 4, "rankAfterBuy": 4 },
"blockerAlternate":{ "placed": true, "finite": true, "soldPathRestored": true },
"blockerClosed": { "placed": true, "destroyed": true, "pathRestored": true }
}
```
### 3.2 Assertions (`assertExtensionAudit`)
| # | Assertion | Erwartung |
|---|---|---|
| E-mrt | `mortar: projectile spawned (may resolve instantly)` | **info** |
| E-mrt | `mortar: both targets hurt (splash)` | `hurt === true` |
| E-tes | `tesla: damaged enemies count` | `damaged > 1` |
| E-tes | `tesla: frozen count` | `frozen > 1` |
| E-rwd | `reward: pointsAfterDuplicate>=1` | `pointsAfterDuplicate >= 1` |
| E-rwd | `reward: storedRank matches rankAfterBuy` | `storedRank === rankAfterBuy` |
| E-blt | `blockerAlternate: placed` / `route still finite` / `path restored after sell` | `placed`, `finite`, `soldPathRestored` (falls Kandidat gefunden) |
| E-blc | `blockerClosed: placed` / `destroyed by enemy` / `path restored` | `placed`, `destroyed`, `pathRestored` (falls Kandidat gefunden) |
> Fehlt ein geeigneter Blocker-Kandidat, wird ein **info-Pass** („no candidate found (acceptable)") erzeugt kein Hard-Fail.
---
## 4. `runRedesignAudit()` Struktur & Assertions
### 4.1 Report-Struktur
```jsonc
{
"kryo": { "randomLastTarget": true, "visibleSlow": true },
"sniper": { "pierced": 3, "noDot": true, "highestAbsoluteHp": true },
"mortar": { "fixedImpact": true },
"quantum":{ "lineHits": 3, "offLineUntouched": true, "beam": true },
"nano": { "spawned": 5, "damaged": true, "cleaned": true }
}
```
### 4.2 Assertions (`assertRedesignAudit`)
| # | Assertion | Erwartung |
|---|---|---|
| R-kyo | `kryo: target hit` | `randomLastTarget || visibleSlow` |
| R-kyo | `kryo: slow applied` | `visibleSlow === true` |
| R-snp | `sniper: pierced count` | `pierced > 1` |
| R-snp | `sniper: no DoT (burn/poison)` | `noDot === true` |
| R-snp | `sniper: highest absolute HP targeting` | `highestAbsoluteHp === true` (falls vorhanden) |
| R-mrt | `mortar: fixed impact (witness hit, fleeer untouched)` | `fixedImpact === true` |
| R-qtm | `quantum: line hits` | `lineHits > 1` |
| R-qtm | `quantum: off-line untouched` | `offLineUntouched === true` |
| R-qtm | `quantum: beam created` | `beam === true` |
| R-nno | `nano: spawned count` | `spawned > 1` |
| R-nno | `nano: damaged target` | `damaged === true` |
| R-nno | `nano: cleaned up` | `cleaned === true` |
---
## 5. `audit-result.json` Schema (authoritative)
```jsonc
{
"timestamp": "2026-08-28T19:00:00.000Z",
"file": "…/Aegis-Labyrinth.html",
"fileHash": "a1b2c3d4e5f60718", // sha256, erste 16 Hex-Zeichen
"self": { /* Sektion 2.1 */ },
"extension": { /* Sektion 3.1 */ },
"redesign": { /* Sektion 4.1 */ },
"assertions": {
"self": [ { "name", "actual", "expected", "passed" } ],
"extension": [ ],
"redesign": [ ]
},
"pageErrors": [], // gemeldete JS-Fehler (pageerror-Events)
"summary": { "pass": 40, "fail": 0, "total": 42 } // total inkl. PageErrors
}
```
Das Gesamtverdict in `report.mjs` wird direkt aus `summary.fail === 0` **und** `pageErrors.length === 0` abgeleitet.
---
## 6. Exit-Code & Fail-Verhalten
```
exit 0 → summary.fail === 0 UND pageErrors leer
exit 1 → ≥ 1 Assertion failed ODER ≥ 1 PageError
exit 2 → harter Crash (Datei fehlt, Browser-Start, Timeout, …)
```
Zusätzlich werden immer `audit-result.json` **und** `audit-final.png` geschrieben (auch bei Fail), damit die Fehler in `report.html` nachvollziehbar bleiben.
---
## 7. Fehlerklassen, die die Audits typischerweise fangen
| Kategorie | Wo sichtbar | Häufige Ursache |
|---|---|---|
| Pfad unvollständig | `self.connectivity[n].reachable === false` | Flow-Field `rebuild()` nach `grid`-Change vergessen |
| Turm schießt nicht | `self.attacks[id].projectiles === 0` (info) | Cooldown nicht reset / Range zu klein |
| Skill nicht kaufbar | `self.skills[id].rank < 1` | `buySkill`-Cost > Credits / Skill-ID-Typo |
| Platzierung falsch | `self.placement.pathAccepted === true` | `placeTower` prüft `grid` nicht |
| Splash trifft nicht | `extension.mortar.hurt === false` | Splash-Radius / Ziel-Filter |
| Tesla ohne Effekt | `extension.tesla.frozen < 1` | Freeze-Status nicht gesetzt |
| Doppelte Rewards | `extension.reward.storedRank !== rankAfterBuy` | `triggerVictory` ohne Idempotenz |
| Pfad kaputt nach Blocker | `extension.blockerClosed.pathRestored === false` | `sellTower` ruft `Game.flow.rebuild()` nicht auf |
| Sniper kein Pierce | `redesign.sniper.pierced < 2` | Pierce-Logik fehlt |
| Quantum trifft Off-Line | `redesign.quantum.offLineUntouched === false` | Winkel-Test zu locker |
| Naniten lecken | `redesign.nano.cleaned === false` | Cleanup-Flag / `NANITE_LIMIT` |
---
## 8. Bug-Fix-Routine (empfohlen)
```
1. Replizieren
→ npm run audit
→ audit-result.json öffnen → failing Assertion identifizieren
→ Optional: In-Game-Debug-Console (Taste ` `) → `audit self` / `state`
2. Isolation
→ Spiel-State minimal halten:
Game.towers = [onlyTower]
Game.enemies = [onlyEnemy]
Game.projectiles = []
→ Einzelne Funktion aufrufen: towerFire(t, 1/60)
3. Fixen
→ Aegis-Labyrinth.html editieren
4. Verifizieren
→ npm run audit erneut → grün
→ npm run report → report.html prüfen