Initial project version
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

This commit is contained in:
2026-08-29 01:45:19 +02:00
commit ea2a2f2cbf
21 changed files with 2830 additions and 0 deletions
+193
View File
@@ -0,0 +1,193 @@
# 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