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

7.9 KiB
Raw Blame History

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.


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)

{
  "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

{
  "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

{
  "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
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)

{
  "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