mjolnir-qa 0.4.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.de.md ADDED
@@ -0,0 +1,711 @@
1
+ <div align="center">
2
+
3
+ <img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
4
+
5
+ ### Deine Tests lügen. Wir beweisen es.
6
+
7
+ **Verification Trust Engine für QA.** Mjölnir prüft Testsuiten und
8
+ CI-Pipelines, meldet einen Würdigkeitswert und zeigt genau, wo Vertrauen
9
+ bricht.
10
+
11
+ [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=C9A227&labelColor=0B0F17)](https://www.npmjs.com/package/mjolnir-qa)
12
+ [![ci](https://img.shields.io/github/actions/workflow/status/Sergey-Bar/Mjolnir/ci.yml?branch=main&style=flat-square&label=ci&labelColor=0B0F17)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
13
+ [![license](https://img.shields.io/badge/license-MIT-C9A227.svg?style=flat-square&labelColor=0B0F17)](LICENSE)
14
+ [![node](https://img.shields.io/badge/node-%E2%89%A5%2022.18-2E8C7F.svg?style=flat-square&labelColor=0B0F17)](https://nodejs.org)
15
+
16
+ [English](README.md) | [简体中文](README.zh.md) | [繁體中文](README.zht.md) | [한국어](README.ko.md) | Deutsch | [Español](README.es.md) | [Français](README.fr.md) | [Italiano](README.it.md) | [Dansk](README.da.md) | [日本語](README.ja.md) | [Polski](README.pl.md) | [Русский](README.ru.md) | [Norsk](README.no.md) | [Português (Brasil)](README.br.md) | [ไทย](README.th.md) | [Türkçe](README.tr.md) | [Українська](README.uk.md) | [বাংলা](README.bn.md) | [Ελληνικά](README.gr.md) | [Tiếng Việt](README.vi.md) | [עברית](README.he.md) | [العربية](README.ar.md) | [Bosanski](README.bs.md)
17
+
18
+ > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-04.
19
+
20
+ ```bash
21
+ npx mjolnir-qa@latest
22
+ ```
23
+
24
+ **Sind deine Tests Vertrauen wert?**
25
+
26
+ [So funktioniert es](#-so-funktioniert-es) ·
27
+ [Schnellstart](#-schnellstart) ·
28
+ [Was es prüft](#-was-mjölnir-prüft) ·
29
+ [Scoring](#so-funktioniert-der-score) ·
30
+ [CI](#-ci-integration) · [Konfiguration](#konfiguration) ·
31
+ [Dokumentation](#-dokumentation)
32
+
33
+ </div>
34
+
35
+ ---
36
+
37
+ ## 🎬 So funktioniert es
38
+
39
+ <p align="center">
40
+ <img src="assets/readme/demo.svg" alt="Mjölnirs voller --verbose-Bericht über ein Demo-Repo: WORTHINESS 75/100 NEEDS WORK, eine Diagnose-Aufschlüsselung nach Kategorien, eine FIX-THIS-FIRST-Liste und jeder Befund mit Regel-ID und Zeilennummer über CI, Playwright, Test-Hygiene und Python-Regeln hinweg" width="900" />
41
+ </p>
42
+
43
+ <sub>Die komplette `npx mjolnir-qa ./examples/demo-repo --verbose`-Ausgabe,
44
+ gerendert vom echten Reporter — nichts gekürzt. Neu erzeugt per
45
+ `npm run docs:demo`;
46
+ [`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
47
+ lässt CI fehlschlagen, wenn es von dem abweicht, was das Tool ausgibt.</sub>
48
+
49
+ **Was da gerade passiert ist:**
50
+
51
+ 1. Mjölnir fand die Playwright-Specs, seine Konfiguration, den
52
+ CI-Workflow und eine Python-Testdatei — vier Sprachen/Formate, ein
53
+ Durchlauf.
54
+ 2. Es fand Belege, die das Vertrauen in die Suite schwächen — ein
55
+ `continue-on-error`, das einen Job maskiert, ein `|| true`, das einen
56
+ Exit-Code schluckt, harte Sleeps, einen spröden Selektor,
57
+ hartkodierte Staging-URLs, ein `networkidle`-Warten.
58
+ 3. Jeden davon machte es zu einem konkreten Befund mit Regel-ID, Ort
59
+ und Fix — und zu einem einzigen Score, an dem man einen PR gate-en
60
+ kann.
61
+
62
+ ### Ein Befund aus der Nähe
63
+
64
+ Führe `mjolnir explain QA-CI-001` für den ersten Befund oben aus, und du
65
+ erhältst:
66
+
67
+ ```text
68
+ ▚▞ QA-CI-001 — continue-on-error masks a failing verification gate
69
+
70
+ Severity: error
71
+ Confidence: high
72
+ Evidence: E2
73
+ Measured FP: not yet measured — this rule ships on assumption (see docs/FP-AUDIT.md)
74
+
75
+ WHAT WAS FOUND (real detector output, not a mockup)
76
+ Job `security-scan` runs a verification gate under `continue-on-error: true`.
77
+
78
+ WHY IT MATTERS
79
+ This job can fail every day and CI will still show green. The checkmark
80
+ on this workflow cannot be trusted.
81
+
82
+ HOW TO FIX
83
+ Remove continue-on-error, or scope it to individual non-blocking steps only.
84
+ ```
85
+
86
+ Das ist die Einheit des Werts: kein Stil-Nit, sondern eine Stelle, an
87
+ der dein CI etwas als bestanden ausweist, das nicht bestanden ist.
88
+
89
+ ---
90
+
91
+ ## ⚡ Schnellstart
92
+
93
+ Führe es gegen ein Repo aus — für einen vollen Bericht und einen
94
+ Würdigkeitswert:
95
+
96
+ ```bash
97
+ npx mjolnir-qa@latest
98
+ ```
99
+
100
+ **In CI ist das Produkt ein einziger Befehl.** Er scannt nur, was der
101
+ Branch berührt hat, und beendet sich mit einem Wert ungleich null bei
102
+ neuen Problemen:
103
+
104
+ ```bash
105
+ npx mjolnir-qa@latest --scope changed
106
+ ```
107
+
108
+ Wirf das in einen PR-Check — `mjolnir ci install` schreibt den Workflow —
109
+ und fertig. Alles andere ist optional.
110
+
111
+ | Befehl | Was er tut |
112
+ | ----------------------------------- | --------------------------------------------------------- |
113
+ | `mjolnir` | Repoweiter Scan + Würdigkeitswert |
114
+ | `mjolnir --scope changed` | Nur, was dein Branch eingeführt hat — die CI-Form |
115
+ | `mjolnir ci install` | Erzeugt den advisorischen PR-Workflow |
116
+ | `mjolnir explain QA-CI-001` | Was / warum / Fix + gemessene FP-Rate für eine Regel |
117
+ | `mjolnir rules --unmeasured` | Die Regeln, die auf Annahme statt Messung laufen |
118
+ | `mjolnir --json` / `--format sarif` | Maschinenlesbar / GitHub Code Scanning |
119
+ | `mjolnir --strict` | Auch Quarantine-Tier-Regeln ausführen (höheres FP-Risiko) |
120
+
121
+ <details>
122
+ <summary><strong>Wenn etwas flaky ist</strong></summary>
123
+
124
+ | Befehl | Was er tut |
125
+ | ----------------------------------- | -------------------------------------------------------------- |
126
+ | `mjolnir forensics ./test-results/` | Echte Laufdaten → `TRUE-FLAKE`-Urteile, `FLAKY.md` |
127
+ | `mjolnir triage ./test-results/` | Quarantine-Vorschlag aus der Ausführungshistorie |
128
+ | `mjolnir pw-report ./test-results/` | Playwright-Laufübersicht — Retries / Flakes / langsamste Tests |
129
+ | `mjolnir doctor:playwright` | Playwright-only Tiefenscan + Selector Health Score |
130
+
131
+ </details>
132
+
133
+ <details>
134
+ <summary><strong>Gelegentlich / Berichte</strong></summary>
135
+
136
+ | Befehl | Was er tut |
137
+ | ------------------------------- | ------------------------------------------------------ |
138
+ | `mjolnir fix --dry-run` / `fix` | Sichere Auto-Fixes mit Nachweis |
139
+ | `mjolnir baseline` / `diff` | Befunde speichern, dann nur neue/verschlimmerte melden |
140
+ | `mjolnir impact --since <ref>` | Was sich seit einem früheren Commit geändert hat |
141
+ | `mjolnir debt` | Test-Debt-Register mit Kostenmodell |
142
+ | `mjolnir handover` | Onboarding-Karte der Suite für neue QA-Leute |
143
+ | `mjolnir stats` | Lokale All-Time-Zähler der gesehenen Fixes |
144
+ | `mjolnir badge` | shields.io-Endpoint-JSON + Snippet |
145
+ | `mjolnir rules --md` | Voller Regelkatalog (JSON oder Markdown) |
146
+ | `mjolnir doctor` | Selbstaudit von Mjölnirs eigener Regelbasis |
147
+ | `mjolnir create-rule <ID>` | Neuen Regel-Scaffold + Fixtures anlegen |
148
+ | `mjolnir --format mermaid` | Test-Architekturdiagramm für einen PR-Kommentar |
149
+
150
+ </details>
151
+
152
+ Installiere es global statt per `npx`, wenn du lieber: `npm i -g
153
+ mjolnir-qa`. Erfordert Node.js ≥ 22.18. Läuft auf Windows, macOS und
154
+ Linux.
155
+
156
+ ---
157
+
158
+ ## 👥 Für wen ist das?
159
+
160
+ - **QA / SDET**, die eine e2e- oder Integration-Suite besitzen und
161
+ Belege brauchen, dass die Suite den grünen Haken wirklich verdient,
162
+ den sie produziert.
163
+ - **Plattform-/DevEx-Teams**, die für CI-Integrität und Release-Gates
164
+ verantwortlich sind — die Leute, denen ein `continue-on-error` nie
165
+ stillschweigend eine rote Pipeline grün färben darf.
166
+ - **OSS-Maintainer**, die ein günstiges, immer aktives
167
+ Verifikations-Gate wollen, das lokal und in CI ohne Netzwerkaufrufe
168
+ läuft.
169
+
170
+ ---
171
+
172
+ ## 🔨 Was Mjölnir prüft
173
+
174
+ | | |
175
+ | --- | ---------------------------------------------------------------------------------------------------------------------- |
176
+ | ⚖️ | **Würdigkeitswert** — eine Zahl, transparente Abzugstabelle, keine Blackbox |
177
+ | 🎭 | **Selector Health Score** — benotet deine Playwright-Locators, nicht nur deine Pass-Rate |
178
+ | 🔬 | **Runtime-Forensik** — liest echte Playwright/JUnit-Laufdaten und findet `TRUE-FLAKE`, nicht nur statische Vermutungen |
179
+ | 🚨 | **CI-Integritätsregeln** — findet `continue-on-error`, `\|\| true` und andere False-Green-Tricks |
180
+ | 🐍 | **Alle vier Playwright-Bindings** — TypeScript, Python, Java, C#/.NET — plus pytest, JUnit/TestNG und CI-Workflows |
181
+ | 🔒 | **Local-first** — null Netzwerkaufrufe beim Scannen, null Telemetrie, läuft in Sekunden |
182
+
183
+ ### Die Regeln
184
+
185
+ Jede Regel kommt mit Must-Fire- **und** Must-Not-Fire-Fixtures. Eine
186
+ Regel, die auf ihrem eigenen Negativ-Fixture auslöst, kann nicht
187
+ geshippt werden — das ist die False-Positive-Firewall.
188
+
189
+ <details>
190
+ <summary><strong>Test-Hygiene</strong></summary>
191
+
192
+ | ID | Regel | Severity |
193
+ | ----------- | ----------------------------------------------------- | -------- |
194
+ | QA-TEST-001 | Committeter Focused Test (`.only`, `fit`) | error |
195
+ | QA-TEST-002 | Übersprungener Test ohne Begründung | error |
196
+ | QA-TEST-002 | Übersprungener Test mit erfasster Begründung | warning |
197
+ | QA-TEST-003 | Test ohne Assertionen | error |
198
+ | QA-TEST-004 | Harter Sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning |
199
+ | QA-TEST-006 | Retry-Missbrauch, der Flakiness versteckt | warning |
200
+ | QA-TEST-010 | Leerer Testkörper | error |
201
+
202
+ </details>
203
+
204
+ <details>
205
+ <summary><strong>Test-Qualität</strong></summary>
206
+
207
+ | ID | Regel | Severity |
208
+ | ------------ | ----------------------------------- | -------- |
209
+ | QA-TQUAL-001 | Nur-Mock-Verifikation | info |
210
+ | QA-TQUAL-002 | Tautologische Assertion | error |
211
+ | QA-TQUAL-009 | Nicht abgewartete Promise-Assertion | error |
212
+ | QA-TQUAL-011 | Auskommentierte Tests | warning |
213
+
214
+ </details>
215
+
216
+ <details>
217
+ <summary><strong>Playwright 🎭</strong></summary>
218
+
219
+ | ID | Regel | Severity |
220
+ | --------- | ---------------------------------------- | -------- |
221
+ | QA-PW-002 | Nicht abgewartete Locator-Assertion | error |
222
+ | QA-PW-003 | `page.pause()` / `test.only()` committed | error |
223
+ | QA-PW-004 | Spröde CSS/XPath-Selektoren | warning |
224
+ | QA-PW-005 | Business-Logik in `page.evaluate()` | info |
225
+ | QA-PW-114 | Legacy Element Handles (`page.$`) | info |
226
+ | QA-PW-118 | `networkidle`-Warten (flaky by design) | info |
227
+ | QA-PW-123 | Hartkodierte Umgebungs-URLs | warning |
228
+
229
+ </details>
230
+
231
+ <details>
232
+ <summary><strong>CI-Integrität</strong></summary>
233
+
234
+ | ID | Regel | Severity |
235
+ | --------- | ------------------------------------------------------------------------- | -------- |
236
+ | QA-CI-001 | `continue-on-error` maskiert Fehler | error |
237
+ | QA-CI-002 | `\|\| true` schluckt Exit-Codes | error |
238
+ | QA-CI-005 | Report konsumiert, aber nie erzeugt | error |
239
+ | QA-CI-007 | Retry-Wrapper um Tests | warning |
240
+ | QA-CI-008 | Immer-erfolgreicher Step maskiert Fehler | error |
241
+ | QA-CI-009 | Test-Exit-Code wird nicht weitergereicht (`\|` ohne pipefail, `;`-Ketten) | error |
242
+ | QA-CI-010 | Tests übersprungen, wo sie blockieren müssen (skip-on-PR-Guards) | error |
243
+
244
+ </details>
245
+
246
+ <details>
247
+ <summary><strong>Python / pytest 🐍</strong></summary>
248
+
249
+ | ID | Regel | Severity |
250
+ | --------- | ---------------------------------------------------- | -------- |
251
+ | QA-PY-002 | Übersprungener Test (`skip`, nicht-strictes `xfail`) | warning |
252
+ | QA-PY-003 | Testfunktion ohne Assertionen | error |
253
+ | QA-PY-005 | `time.sleep()` in Tests | warning |
254
+ | QA-PY-006 | Leerer Testkörper (`pass`) | info |
255
+ | QA-PY-010 | Zufalls-/Zeitabhängigkeit ohne Freeze | info |
256
+ | QA-PY-012 | Tautologische Assertion | error |
257
+
258
+ 20 Python-Regeln insgesamt (QA-PY-001…012 pytest-Hygiene + QA-PY-101…108 Playwright-Python).
259
+
260
+ </details>
261
+
262
+ <details>
263
+ <summary><strong>Java / JUnit · TestNG ☕</strong></summary>
264
+
265
+ | ID | Regel | Severity |
266
+ | --------- | ------------------------------------------ | -------- |
267
+ | QA-JV-101 | Deaktivierter Test (`@Disabled`) | warning |
268
+ | QA-JV-102 | Harter Sleep (`Thread.sleep()`) | warning |
269
+ | QA-JV-103 | Testmethode ohne Assertionen | error |
270
+ | QA-JV-105 | Playwright `waitForTimeout()`-harter Sleep | warning |
271
+ | QA-JV-106 | Spröder Selektor statt Role-Locator | warning |
272
+ | QA-JV-108 | Hartkodierte Umgebungs-URL im Test | info |
273
+ | QA-JV-111 | Pauschales `page.route("**")`-Mock | info |
274
+
275
+ </details>
276
+
277
+ <details>
278
+ <summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
279
+
280
+ | ID | Regel | Severity |
281
+ | --------- | ------------------------------------------------- | -------- |
282
+ | QA-CS-101 | Übersprungener Test (`[Ignore]`, `[Fact(Skip=)]`) | warning |
283
+ | QA-CS-102 | Harter Sleep (`Thread.Sleep` / `Task.Delay`) | warning |
284
+ | QA-CS-103 | Testmethode ohne Assertionen | error |
285
+ | QA-CS-105 | `WaitForTimeoutAsync()`-harter Sleep | warning |
286
+ | QA-CS-106 | Spröder Selektor statt Role-Locator | warning |
287
+ | QA-CS-108 | Hartkodierte Umgebungs-URL im Test | info |
288
+ | QA-CS-111 | Pauschales `page.RouteAsync("**")`-Mock | info |
289
+
290
+ </details>
291
+
292
+ > Der volle Live-Katalog — jede Regel mit Tier, Confidence,
293
+ > False-Positive-Risiko und Autofix-Verfügbarkeit — wird aus der
294
+ > Registry erzeugt:
295
+ >
296
+ > ```bash
297
+ > mjolnir rules --md
298
+ > ```
299
+ >
300
+ > Pro-Regel-Seiten liegen unter [`docs/rules/`](docs/rules/).
301
+
302
+ ### Wie viel davon gemessen ist
303
+
304
+ **74 von 99 Regeln tragen eine False-Positive-Rate, gemessen an echtem
305
+ OSS-Code** (jeweils ≥ 10 handklassifizierte Befunde; siehe
306
+ [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Die anderen 19 gehen auf der
307
+ Schätzung des Autors. Jeder Scan-Footer sagt dir, wie viele der
308
+ _ausgelösten_ Regeln gemessen sind; `mjolnir rules --unmeasured` listet
309
+ die nicht gemessenen; die `mjolnir explain`-Seite jeder Regel nennt
310
+ ihren Status. Wir veröffentlichen die Rate, selbst wenn sie hässlich
311
+ ist — QA-CS-103 auditiert bei 95 % und ist deshalb quarantäniert. Diese
312
+ 78 zu vergrößern ist die fortlaufende Arbeit des Projekts.
313
+
314
+ ### Regel-Tiers und Sprachreife
315
+
316
+ Jede Regel ist `core`, `extended` oder `quarantine`, zugewiesen nach
317
+ ihrer **gemessenen** False-Positive-Rate:
318
+
319
+ | Tier | Bedeutung | Standard-Scan | `--strict` |
320
+ | ------------ | ------------------------------------------ | :-----------: | :--------: |
321
+ | `core` | ≤ 10 % gemessene FP | ✅ | ✅ |
322
+ | `extended` | ≤ 30 % gemessene FP | ✅ | ✅ |
323
+ | `quarantine` | darüber, oder noch nicht gemessen (n < 10) | ❌ | ✅ |
324
+
325
+ | Sprache | Adapter | Abdeckung heute |
326
+ | --------------- | ------------- | ------------------------------------------------------------ |
327
+ | TypeScript / JS | Compiler-AST | am breitesten, am meisten gemessen — meist `core`/`extended` |
328
+ | Python / pytest | Regex-Schicht | breit, corpus-auditiert — meist `core`/`extended` |
329
+ | Java | Regex-Schicht | neuer — meist `extended`/`quarantine` |
330
+ | C# / .NET | Regex-Schicht | neuer — meist `extended`/`quarantine` |
331
+
332
+ TypeScript und Python haben die breiteste gemessene Abdeckung. Java und
333
+ C# sind geshippt, dokumentiert und bleiben aus der Schlagzeilen-Zahl
334
+ heraus, bis eine echte Consumer-Suite (nicht die eigenen Tests einer
335
+ Binding-Library) auditiert wurde.
336
+
337
+ ---
338
+
339
+ ## So funktioniert der Score
340
+
341
+ <p align="center">
342
+ <img src="assets/readme/terminal-hero.svg" alt="Mjölnir-Terminalausgabe — WORTHINESS 75/100 NEEDS WORK, eine Diagnose-Aufschlüsselung nach Kategorien und eine FIX-THIS-FIRST-Liste" width="820" />
343
+ </p>
344
+
345
+ <sub>Neu erzeugt per `npm run docs:hero`;
346
+ [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
347
+ lässt CI fehlschlagen, wenn es von dem abweicht, was der Reporter
348
+ wirklich druckt.</sub>
349
+
350
+ Der Score ist transparent: **error −8, warning −3, info −1**, dann
351
+ normalisiert um die Suite-Exposition (Abzüge pro Testdeklaration).
352
+ Evidenzgewichtete Abzüge bedeuten: schwache Signale kosten weniger. Das
353
+ Terminal zeigt dieselben diskontierten Zahlen, die der Score verwendet —
354
+ keine Blackbox. Volle Methode: [docs/SCORING.md](docs/SCORING.md).
355
+
356
+ **Urteile**
357
+
358
+ | Score | Urteil |
359
+ | ------- | ---------------- |
360
+ | ≥ 80 | ✓ **WORTHY** |
361
+ | 50 – 79 | ⚠ **NEEDS WORK** |
362
+ | < 50 | ✖ **UNWORTHY** |
363
+
364
+ **Evidenzlevel** — jeder Befund trägt eines; es setzt das Gewicht des
365
+ Befunds im Score:
366
+
367
+ | Level | Bedeutung | Score-Auswirkung | Beispiel |
368
+ | ----- | ------------------------ | ---------------- | --------------------------------------------------------- |
369
+ | E2 | Deterministischer Defekt | Voller Abzug | `.only` committed — strukturell beweisbar |
370
+ | E1 | Heuristisches Muster | Halbierter Abzug | Regex-getroffenes `sleep()` — starkes Signal, kein Beweis |
371
+ | E0 | Beobachtung | Null (nur Info) | Gemeldet, gated aber nie CI und zieht nie ab |
372
+
373
+ Die meisten Regeln sind **E1**. Der Tagline „we prove it“ bezieht sich
374
+ auf dieses System: E2-Befunde sind struktureller Beweis; E1-Befunde
375
+ sind korrekt positionierte Warnungen, keine formalen Beweise.
376
+
377
+ Ein leeres Repo scored `null`, nie eine fake 100 — siehe
378
+ [Vertrauensmodell](#vertrauensmodell).
379
+
380
+ ---
381
+
382
+ ## 🎭 Selector Health Score
383
+
384
+ Die Headline-Metrik für Playwright-Suiten — wie belastbar deine
385
+ Locators sind:
386
+
387
+ ```text
388
+ ▚▞ SELECTOR HEALTH — e2e/checkout.spec.ts
389
+
390
+ [█████████████████░░░] 83 / 100
391
+ role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
392
+ ```
393
+
394
+ Rollenbasierte Locators bekommen die volle Punktzahl.
395
+ CSS-Klassenketten und XPath ruiniern den Score — sie brechen bei jedem
396
+ DOM-Refactor, ohne dir zu sagen, welches Verhalten regressiert ist.
397
+
398
+ ---
399
+
400
+ ## 🔬 Runtime-Evidenz
401
+
402
+ Statische Flakiness-Erkennung ist Raten. Mjölnir liest **echte
403
+ Ausführungsdaten** — Playwright-JSON-Reports und JUnit-XML von jedem
404
+ Runner:
405
+
406
+ ```bash
407
+ mjolnir forensics ./test-results/
408
+ ```
409
+
410
+ ```text
411
+ ▚▞ FLAKINESS LEADERBOARD
412
+
413
+ 3 tests · 1 failed · 1 flaky · 1 retried
414
+
415
+ TRUE-FLAKE completes checkout with saved card (e2e/checkout.spec.ts)
416
+ ████████████████████ 6.0s · 2 attempts
417
+ FAILING declines an expired card (e2e/checkout.spec.ts)
418
+ ████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
419
+ ```
420
+
421
+ Ein Test, der nur ab Versuch ≥ 2 besteht, ist kein bestandener Test —
422
+ es ist ein glücklicher Test. Er wird als `TRUE-FLAKE` markiert, egal
423
+ wie grün der finale Haken ist.
424
+
425
+ ---
426
+
427
+ ## ⚡ Mjölnir ist kein weiterer Linter
428
+
429
+ Linter sagen dir, ob Code Regeln folgt. Mjölnir sagt dir, ob deine
430
+ Verifikation vertraut werden kann.
431
+
432
+ | | ESLint / SonarQube | Coverage-Tools | Manueller Review | **Mjölnir** |
433
+ | ------------------------------------------------------------------- | :----------------: | :------------: | :--------------: | :---------: |
434
+ | CI-Workflow-Integrität (`continue-on-error`, `\|\| true`) | ❌ | ❌ | selten | ✅ |
435
+ | Cross-Sprache (TS, Python, Java, C#) aus einem Tool | ❌ | ❌ | ❌ | ✅ |
436
+ | Benotet die Belastbarkeit von Playwright-Locators (Selector Health) | ❌ | ❌ | selten | ✅ |
437
+ | Findet Tests ohne echte Assertionen | ✅ (Plugin)\* | ❌ | manchmal | ✅ |
438
+ | Findet harte Sleeps (`waitForTimeout`, `time.sleep`) | ✅ (Plugin)\* | ❌ | manchmal | ✅ |
439
+ | Läuft in Sekunden, null Netzwerkaufrufe beim Scannen | ✅ | ✅ | — | ✅ |
440
+
441
+ \*`eslint-plugin-jest` (`expect-expect`) und `eslint-plugin-playwright`
442
+ (`expect-expect`, `no-wait-for-timeout`) decken das für die jeweiligen
443
+ Frameworks ab.
444
+
445
+ **Runtime-Analyse** ist eine eigene Kategorie neben dem statischen
446
+ Linten:
447
+
448
+ | | Playwright Retry Reporter | Allure / ReportPortal | **Mjölnir Forensics** |
449
+ | ------------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
450
+ | Liest echte Laufdaten für `TRUE-FLAKE`-Urteile | teilweise\* | teilweise (Tag) | ✅ |
451
+ | Flaky-Triage-Bericht aus der Ausführungshistorie | ❌ | ✅ | ✅ |
452
+ | Integriert sich in den statischen Würdigkeitswert | ❌ | ❌ | ✅ |
453
+
454
+ \*Playwright trackt Retries intern, erzeugt aber keinen eigenständigen
455
+ Flakiness-Bericht mit Urteil-Labels.
456
+
457
+ ---
458
+
459
+ ## 🤖 Warum nicht einfach KI-Code-Review?
460
+
461
+ Anderes Problem, andere Schicht. KI-Review kann eine verdächtige
462
+ Teständerung in einem Diff erkennen; sie beweist nicht, dass das
463
+ Verifikationssystem als Ganzes vertrauenswürdig ist — und sie sieht nur
464
+ das Diff, das du ihr zeigst.
465
+
466
+ | | KI-Code-Review (Copilot & co.) | **Mjölnir** |
467
+ | -------------------------------------------------- | :--------------------------------: | :---------------------------: |
468
+ | Kosten pro Scan | Tokens (skaliert mit Diff-Größe) | **Null** (lokal, installiert) |
469
+ | Sieht die ganze Suite + alle CI-Konfigs | Nur das PR-Diff, das du zeigst | **Alles, jedes Mal** |
470
+ | Deterministisch (gleicher Input → gleicher Output) | ❌ (nicht-deterministisch) | **✅** |
471
+ | Findet monatelang schlafende Muster | Nur, wenn es im Kontext steht | **✅** (scannt alle Dateien) |
472
+ | Erinnert sich an Befunde zwischen Läufen | ❌ (kein Gedächtnis über Sessions) | **✅** (Baseline + Diff) |
473
+ | Läuft ohne menschlichen Auslöser | Braucht einen PR oder Prompt | **✅** (CI-Hook, 3 Sekunden) |
474
+
475
+ **Benutze beides.** KI findet Nuance, Intent und Designfehler, die
476
+ keine Regex findet. Mjölnir findet die strukturellen Muster, die KI
477
+ übersieht, weil sie „absichtlich“ aussehen — ein committetes `.only`,
478
+ ein geschluckter Exit-Code, ein `continue-on-error` auf einem
479
+ Test-Job. Das sind keine Bugs, die Denken brauchen; das sind Fakten,
480
+ die Scannen brauchen.
481
+
482
+ ---
483
+
484
+ ## 🤖 CI-Integration
485
+
486
+ Ein Befehl erzeugt einen PR-Workflow — standardmäßig advisory, nie
487
+ blockierend:
488
+
489
+ ```bash
490
+ mjolnir ci install
491
+ ```
492
+
493
+ Oder binde es nativ in GitHub Code Scanning über SARIF ein:
494
+
495
+ ```yaml
496
+ - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
497
+ - uses: github/codeql-action/upload-sarif@v3
498
+ with:
499
+ sarif_file: mjolnir.sarif
500
+ ```
501
+
502
+ Editor- und Pipeline-Setup für SARIF:
503
+ [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
504
+
505
+ ### Changed-Scope-Abdeckung
506
+
507
+ `--scope changed` attribuiert Befunde zu Zeilen, die dein Branch
508
+ gegenüber dem Merge-Base mit `main` hinzugefügt hat. Es deckt
509
+ Testdateien (`*.spec.*`, `*.test.*`) plus GitHub-Workflow-Dateien und
510
+ Playwright-Konfigurationen im Diff ab. Wenn sich das Merge-Base nicht
511
+ auflösen lässt — flacher Clone, detached HEAD, Nicht-git-Ziel,
512
+ abweichender Default-Branch — degradiert es ehrlich: Befunde fallen auf
513
+ Full-File-Attribution zurück, und der Bericht sagt es. Überschreibe die
514
+ Base-Ref mit `--base <ref>`.
515
+
516
+ ---
517
+
518
+ ## Konfiguration
519
+
520
+ Mjölnir ist Zero-Config. Eine optionale `mjolnir.config.json` (oder
521
+ `.mjolnir.json`) im Repo-Root stimmt Severity, Gating und Scope ab —
522
+ sie ändert nie die Erkennungssemantik.
523
+
524
+ | Key | Typ | Wirkung |
525
+ | ------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
526
+ | `exclude` | `string[]` | Zusätzliche Ignore-Globs (gitignore-Teilmenge), über den eingebauten Defaults |
527
+ | `gate` | `"advisory" \| "error" \| "warning"` | Welche Severities mit Wert ungleich null beenden (Default `error`; `advisory` blockiert nie) |
528
+ | `severityOverrides` | `{ "<RULE-ID>": severity }` | Rangiert die Befunde einer Regel für dein Repo um |
529
+ | `ignore` | `IgnoreEntry[]` | Unterdrückt Befunde — **`reason` ist Pflicht**; Einträge laufen nach 90 Tagen ab (ein explizites `expires`-Datum, oder die Last-Modified-Zeit der Config-Datei für Einträge ohne eines) |
530
+ | `plugins` | `string[]` | Drittanbieter-Regelpakete (siehe [Vertrauensmodell](#vertrauensmodell)) |
531
+
532
+ ```json
533
+ {
534
+ "gate": "error",
535
+ "exclude": ["legacy/**"],
536
+ "severityOverrides": { "QA-PW-118": "warning" },
537
+ "ignore": [
538
+ {
539
+ "ruleId": "QA-TEST-004",
540
+ "files": ["e2e/legacy-login.spec.ts"],
541
+ "reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
542
+ "expires": "2026-12-31"
543
+ }
544
+ ]
545
+ }
546
+ ```
547
+
548
+ - **`.mjolnirignore`** — eine schlichte gitignore-artige Datei für
549
+ Pfad-Ausschlüsse, gleicher Dialekt wie `exclude`. Nutze sie für
550
+ maschinenweites Rauschen; nutze `exclude`, wenn die Liste in die
551
+ Versionskontrolle gehört, neben dem Rest der Konfiguration.
552
+ - **CLI-Overrides** — `--strict` (Quarantine-Regeln einschließen),
553
+ `--width <cols>` und `--ascii` / `--no-ascii` (Terminal-Rendering),
554
+ `--tone blunt` (schärfere Meldungen), `--max-duration <sec>`
555
+ (begrenzter Teil-Scan).
556
+ - Regel-Unterdrückung und Deprecation-Lebenszyklus:
557
+ [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
558
+
559
+ `ignore`-Einträge speisen auch den eigenständigen Befehl
560
+ `mjolnir suppressions`, der auflistet, was aktuell unterdrückt ist und
561
+ wann jeder Eintrag abläuft.
562
+
563
+ ---
564
+
565
+ ## 📐 Exit-Codes & Verträge
566
+
567
+ Eingefroren — sicher, um CI-Logik darauf zu bauen:
568
+
569
+ | Exit-Code | Bedeutung |
570
+ | --------- | ------------------------------------------------------------------ |
571
+ | `0` | Sauber — keine Befunde auf oder über dem Gate |
572
+ | `1` | Befunde auf oder über dem Gate |
573
+ | `2` | Teil-Scan (Zeitbudget erreicht, unlesbare Dateien) — blockiert nie |
574
+ | `10` | Verwendungsfehler (bad flag, fehlendes Ziel) |
575
+ | `20` | Interner Fehler |
576
+
577
+ Der JSON/SARIF-Bericht ist `schemaVersion: 1`. Regel-IDs
578
+ (`QA-<FAMILY>-NNN`) sind nach dem Shipment unveränderlich und werden
579
+ nie wiederverwendet.
580
+
581
+ ---
582
+
583
+ ## Vertrauensmodell
584
+
585
+ - **Local-first** — null Netzwerkaufrufe während des Scannens. Nie.
586
+ Null Telemetrie.
587
+ - **Kein falscher Beweis** — wir sagen lieber „unbekannt“ als
588
+ „verifiziert“. Ein leeres Repo bekommt `score: null`, nie eine fake 100.
589
+ - **Partielle Ehrlichkeit** — wenn die Analyse vorzeitig abgebrochen
590
+ wurde, sagt die Ausgabe es. Nie „complete“, wenn es nicht stimmt.
591
+ - **FP-Firewall** — Erkennung läuft auf einer comment-/string-freien
592
+ Sicht des Codes (TypeScript-Regeln nutzen den Compiler-AST): ein
593
+ Muster in einem Prosa-Kommentar oder einem Doc-Beispiel-String ist
594
+ Dokumentation, kein Befund.
595
+ - **Gemessen, nicht behauptet** — nur Regeln mit einer
596
+ False-Positive-Rate aus echtem OSS-Code fahren in den
597
+ Headline-Tiers (siehe [Wie viel davon gemessen ist](#wie-viel-davon-gemessen-ist));
598
+ der Scan-Footer und `mjolnir rules --unmeasured` sagen dir, welche
599
+ welche sind.
600
+ - **Plugin-Vertrauen** — Plugins sind npm-Pakete, deklariert unter
601
+ `"plugins"`. Es gibt **keine Sandbox**: Plugin-Code läuft mit vollen
602
+ Node-Privilegien, dasselbe Vertrauensmodell wie ESLint- oder
603
+ Vitest-Plugins. Kern-Regel-ID-Präfixe sind reserviert und werden von
604
+ Plugins abgelehnt, um Spoofing zu verhindern.
605
+ - **Workspace-lokale externe Regeln** (ordnerbasiert, null Netzwerk) —
606
+ ein `mjolnir-rules/`-Verzeichnis neben dem Scan-Ziel lädt eigene
607
+ Regeln: JSON-Dateien deklarieren Regex-Muster (kein Code wird
608
+ ausgeführt), `.mjs`/`.js`-Module exportieren `rules` (Full-Node-Vertrauen,
609
+ wie Plugins). Externe Regeln tragen dieselben Trust-Metadaten wie
610
+ Core; sie können nie im Core-Tier fahren (Core verlangt eine
611
+ gemessene FP-Rate aus dem Corpus-Sidecar — ein deklariertes
612
+ `tier: "core"` wird auf `extended` geklemmt), gehorchen Tier-Caps und
613
+ sind drift-geprüft: `mjolnir rules --md --external` rendert den
614
+ Katalog aus den geladenen Dateien (Provenienz `external`), und der
615
+ Matrix-Generator akzeptiert `--external <root>`.
616
+
617
+ ---
618
+
619
+ ## 🏗️ Architektur
620
+
621
+ <details>
622
+ <summary>Baum ausklappen</summary>
623
+
624
+ ```
625
+ mjolnir/
626
+ ├── src/
627
+ │ ├── engine/ # LanguageAdapter interface + rule runner
628
+ │ ├── adapters/ # typescript · python · java · csharp · github-actions
629
+ │ ├── rules/ # rules across 8 families + the measured-FP table
630
+ │ ├── playwright/ # Selector Health Score engine
631
+ │ ├── discovery/ # workspace, frameworks, ignore resolution
632
+ │ ├── scope/ # git merge-base changed-scope engine
633
+ │ ├── scorer/ # transparent deduction table + prioritization
634
+ │ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
635
+ │ ├── forensics/ # run-data ingestion · flake verdicts · triage
636
+ │ ├── config/ # mjolnir.config.json + suppressions
637
+ │ ├── plugins/ # third-party rule loading (no sandbox)
638
+ │ └── commands/ # every subcommand
639
+ └── tests/
640
+ ├── fixtures/ # must-fire / must-not-fire per rule
641
+ └── golden/ # frozen score regression locks
642
+ ```
643
+
644
+ </details>
645
+
646
+ - **Regeln sind reine Funktionen** — `(SourceFileContext) → Finding[]`,
647
+ kein I/O, keine Globals. Ein neues Ökosystem = ein Adapter + seine
648
+ Regeln.
649
+ - **TypeScript/Playwright nutzt den Compiler-AST** (ts-morph). Python,
650
+ Java und C# laufen auf einer gemeinsamen comment-/string-maskierten
651
+ Regex-Schicht.
652
+ - Eine Tree-sitter-WASM-AST-Schicht für Java und C# existiert und ist
653
+ der nächste Präzisionsschritt — sie ist noch nicht in die synchrone
654
+ Scan-Pipeline verdrahtet.
655
+
656
+ ---
657
+
658
+ ## 📚 Dokumentation
659
+
660
+ | Dokument | Was drinsteht |
661
+ | ------------------------------------------------------ | ----------------------------------------- |
662
+ | [docs/SCORING.md](docs/SCORING.md) | Score-Normalisierung + Evidenzgewichtung |
663
+ | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Gemessene False-Positive-Raten + Methode |
664
+ | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Regelzustände, Unterdrückung, Deprecation |
665
+ | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | SARIF-Ausgabe + Editor/CI-Setup |
666
+ | [docs/rules/](docs/rules/) | Generierter Pro-Regel-Katalog |
667
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Dev-Setup + Beitrags-Workflow |
668
+ | [CHANGELOG.md](CHANGELOG.md) | Release-Historie |
669
+ | [SECURITY.md](SECURITY.md) | Schwachstellenmeldung |
670
+
671
+ ---
672
+
673
+ ## 📈 Status
674
+
675
+ **v0.5.x · offene Beta.** Das JSON-Schema und die Exit-Codes sind
676
+ eingefrorene Verträge. TypeScript und Python haben die breiteste
677
+ gemessene Abdeckung; Java und C# sind neuer — lies sie durch die
678
+ [Tiers-Tabelle](#regel-tiers-und-sprachreife).
679
+
680
+ ---
681
+
682
+ ## 🤝 Mitwirken
683
+
684
+ Neue Regeln sind der einfachste erste Beitrag — ein Befehl scaffolded
685
+ die Regel plus ihre Must-Fire- **und** Must-Not-Fire-Fixtures (die
686
+ generierte Regel schlägt absichtlich in ihren Fixtures fehl, bis du
687
+ echte Detektion implementierst — ein Stub kann nicht geshippt werden):
688
+
689
+ ```bash
690
+ mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
691
+ ```
692
+
693
+ Volles Dev-Setup, die Standing-Gate-Befehle und die
694
+ Anti-Creep-/Fixture-Firewall-Gesetze stehen in
695
+ [CONTRIBUTING.md](CONTRIBUTING.md).
696
+
697
+ ---
698
+
699
+ <div align="center">
700
+
701
+ **Ship keine Tests, denen du nicht vertraust.**
702
+
703
+ ```bash
704
+ npx mjolnir-qa@latest
705
+ ```
706
+
707
+ **Star ⭐ · Watch 👀 · Contribute 🤝**
708
+
709
+ Gebaut von [Sergey Bar](https://www.linkedin.com/in/sergeybar/)
710
+
711
+ </div>