mjolnir-qa 1.0.8 → 2.0.0

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 CHANGED
@@ -1,403 +1,431 @@
1
1
  <div align="center">
2
2
 
3
- <img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
3
+ <img src="assets/readme/hero.svg" alt="Mjölnir. Tests sagen dir, was bestanden hat. Mjölnir sagt dir, worauf du dich verlassen kannst." width="100%" />
4
4
 
5
- ### Deine Tests lügen. Wir beweisen es.
5
+ <br />
6
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.
7
+ Mjölnir findet Tests, die nicht fehlschlagen können, und Pipelines, die nie rot werden können,<br />
8
+ und bewertet dann, wie weit dem Ergebnis zu trauen ist – mit der Evidenz für jeden Punkt.
10
9
 
11
- [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=C19A34&labelColor=0A1119)](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=0A1119)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
13
- [![license](https://img.shields.io/badge/license-MIT-C19A34.svg?style=flat-square&labelColor=0A1119)](LICENSE)
14
- [![node](https://img.shields.io/badge/node-%E2%89%A5%2022.18-37ABBD.svg?style=flat-square&labelColor=0A1119)](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)
10
+ <br />
17
11
 
18
- > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-08.
12
+ [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=1F6F7C&labelColor=0A1119)](https://www.npmjs.com/package/mjolnir-qa)
13
+ [![downloads](https://img.shields.io/npm/dm/mjolnir-qa.svg?style=flat-square&color=1F6F7C&labelColor=0A1119)](https://www.npmjs.com/package/mjolnir-qa)
14
+ [![ci](https://img.shields.io/github/actions/workflow/status/Sergey-Bar/Mjolnir/ci.yml?branch=main&style=flat-square&label=ci&labelColor=0A1119)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
15
+ [![coverage](https://img.shields.io/codecov/c/github/Sergey-Bar/Mjolnir?style=flat-square&color=1F6F7C&labelColor=0A1119&label=coverage)](https://codecov.io/gh/Sergey-Bar/Mjolnir)
16
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/Sergey-Bar/Mjolnir/badge)](https://scorecard.dev/viewer/?uri=github.com/Sergey-Bar/Mjolnir)
17
+ [![license](https://img.shields.io/badge/license-MIT-1F6F7C.svg?style=flat-square&labelColor=0A1119)](LICENSE)
18
+ [![node](https://img.shields.io/badge/node-%E2%89%A5%2022.18-1F6F7C.svg?style=flat-square&labelColor=0A1119)](https://nodejs.org)
19
19
 
20
20
  ```bash
21
21
  npx mjolnir-qa@latest
22
22
  ```
23
23
 
24
- **Sind deine Tests Vertrauen wert?**
24
+ [So sieht es aus](#so-sieht-es-aus) · [Schnellstart](#schnellstart) · [Was es findet](#was-mjölnir-findet) · [Score](#der-worthiness-score) · [Evidenz](#das-evidenzmodell) · [Forensik](#laufzeit-forensik) · [CI](#ci-integrität) · [Agenten](#ki-agenten) · [Sicherheit](#vertrauen-und-sicherheit) · [Grenzen](#was-mjölnir-dir-nicht-sagen-kann) · [Doku](#dokumentation)
25
+
26
+ <details>
27
+ <summary>In einer anderen Sprache lesen – 22 Übersetzungen</summary>
28
+
29
+ [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)
30
+
31
+ > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-15.
32
+
33
+ <!-- Source hash: 3541b09e8d04 -->
25
34
 
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)
35
+ </details>
32
36
 
33
37
  </div>
34
38
 
35
- ---
39
+ <br />
40
+
41
+ ## Ein grüner Haken ist eine Behauptung, kein Beweis
42
+
43
+ Ein grüner Haken bedeutet, dass die Pipeline nicht fehlgeschlagen ist. Er bedeutet nicht, dass die Tests gelaufen sind oder dass sie hätten fehlschlagen können. Jeder dieser Fälle geht grün durch:
44
+
45
+ - ein committetes `.only`, das 3 statt 900 Tests ausgeführt hat
46
+ - `continue-on-error: true` auf dem Job, der eigentlich blockieren sollte
47
+ - `|| true` nach dem Testbefehl
48
+ - ein Test, der nichts prüft oder einen leeren Rumpf hat
49
+ - ein Retry-Wrapper, der einen echten Fehlschlag in einen Glückstreffer verwandelt
50
+ - ein Report, den der Workflow hochlädt, aber nie erzeugt hat
51
+ - ein hartes Sleep, das eine Race Condition zusammenhält
52
+
53
+ Keiner davon färbt die Pipeline rot, und jeder wirkt im Review beabsichtigt. Genau deshalb überleben sie. Hier liest Mjölnir einen echten Workflow:
54
+
55
+ <p align="center">
56
+ <img src="assets/readme/scan.svg" alt="Der CI-Workflow des Demo-Repositorys, Zeile für Zeile gelesen. Mjölnir markiert jeden Befund in der gemeldeten Zeile, mit seiner Regel, dem Problem, seinem Evidenzlevel und seiner gemessenen Falsch-Positiv-Rate." width="800" />
57
+ </p>
58
+
59
+ <sub>Jeder Befund, den der Demo-Scan für diesen Workflow gemeldet hat, in der gemeldeten Zeile. Erzeugt mit `npm run docs:readme-brand` aus [`demo-report.json`](assets/readme/demo-report.json) und in der CI gegen Abweichungen gesichert.</sub>
60
+
61
+ **Strenger Modus.** Die aggressivsten Erkennungen — `.only`, `continue-on-error`, leere Tests, Retry-Missbrauch — leben in der Quarantäne-Stufe. Sie laufen nur unter `--strict` und sind auf `info`-Schweregrad begrenzt: sie kennzeichnen, blocken aber nie. Der Standardscan (`npx mjolnir-qa@latest` ohne `--strict`) deckt nur Kern- und erweiterte Regeln ab. Fügen Sie `--strict` hinzu, wenn Sie auch die Beratungsebene wollen.
62
+
63
+ Mjölnir liest die Testsuite, die CI-Workflows und, falls vorhanden, den Report eines echten Laufs. Es führt deine Tests nicht aus, installiert keine Abhängigkeiten und führt den gescannten Code nicht aus. Und wenn es keine Evidenz hat, sagt es das, statt Zuversicht zu erfinden:
64
+
65
+ | Situation | Was Mjölnir meldet |
66
+ | ------------------------------------------------ | ---------------------------------------------------------------- |
67
+ | Keine Testdeklarationen gefunden | Score `null`, angezeigt als **UNKNOWN**. Nie eine erfundene 100. |
68
+ | Keine Baseline oder vergleichbare Revision | **UNKNOWN**, mit benanntem Grund. Nie eine angenommene 0. |
69
+ | Scan abgebrochen (Zeitbudget, unlesbare Dateien) | **PARTIAL**, Exit `2`. Nie als sauber dargestellt. |
70
+
71
+ <p align="center">
72
+ <img src="assets/readme/how-it-works.svg" alt="So funktioniert Mjölnir. Es liest die Testsuite und die CI-Pipeline statisch sowie den Report eines echten Laufs, wenn es einen gibt. Es gewichtet jeden Befund nach Evidenzlevel und Vertrauensstufe, wobei nur ein echter Lauf L3 bis L5 erreichen kann, und liefert Befunde, einen Worthiness-Score und ein CI-Gate mit eingefrorenen Exit-Codes. In der Agentenschleife schreibt die KI den Fix und Mjölnir scannt erneut, um ihn zu beweisen." width="880" />
73
+ </p>
74
+
75
+ <sub>Für diese Seite gestaltet und in 1:1 gezeigt. Erzeugt mit `npm run docs:readme-brand` und in der CI gegen Abweichungen gesichert; Score, Zahlen und Regel-ID stammen aus [`script.demo.json`](assets/video/script.demo.json), [`demo-report.json`](assets/readme/demo-report.json) und der Regel-Registry, nie von Hand getippt. Dasselbe Bild als Poster: [`architecture.svg`](assets/readme/architecture.svg).</sub>
76
+
77
+ <br />
78
+
79
+ ## So sieht es aus
80
+
81
+ Ein echter Scan von [`examples/demo-repo`](examples/demo-repo), einer kleinen Playwright-Suite mit CI-Workflow. Hier sind seine Punkte geblieben:
82
+
83
+ <p align="center">
84
+ <img src="assets/readme/terminal-hero.svg" alt="Mjölnirs Abzugsaufschlüsselung: WORTHINESS 75/100 NEEDS WORK, der Score nach Kategorie, die Abzugsbox nach Schweregrad und eine FIX THIS FIRST-Liste" width="520" />
85
+ </p>
86
+
87
+ <sub>Erzeugt mit `npm run docs:hero` aus einem echten Scan und in der CI gegen Abweichungen gesichert. Der vollständige `--verbose`-Report desselben Scans ist [`demo.svg`](assets/readme/demo.svg) (`npm run docs:demo`).</sub>
88
+
89
+ <details>
90
+ <summary><strong>Ansehen</strong> – ein Scan, der Fix, den er ausgibt, und der erneute Scan, der ihn beweist</summary>
36
91
 
37
- ## 🎬 So funktioniert es
92
+ <br />
38
93
 
39
94
  <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" />
95
+ <a href="assets/video/mjolnir-demo.mp4">
96
+ <img src="assets/video/mjolnir-demo-poster.png" alt="Ein Frame der Demo-Aufnahme: npx mjolnir-qa@latest scannt das Demo-Repository in einem Terminalfenster" width="900" />
97
+ </a>
41
98
  </p>
42
99
 
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.
100
+ <sub>Frame für Frame aus einem echten Scan gerendert mit `npm run docs:video`; nie per Bildschirmaufnahme. Wähle den Frame, um [`mjolnir-demo.mp4`](assets/video/mjolnir-demo.mp4) zu öffnen.</sub>
101
+
102
+ </details>
61
103
 
62
104
  ### Ein Befund aus der Nähe
63
105
 
64
- Führe `mjolnir explain QA-CI-001` für den ersten Befund oben aus, und du
65
- erhältst:
106
+ Jeder Befund beantwortet vier Fragen: wo er ist, wie sicher Mjölnir ist, wie oft die Regel falsch liegt und wie man ihn behebt.
107
+
108
+ <p align="center">
109
+ <img src="assets/readme/finding-anatomy.svg" alt="Der erste Befund des Demo-Scans, genau so, wie das Terminal ihn ausgibt, mit seinen vier markierten Teilen: wo, wie sicher, wie oft die Regel falsch liegt, und der Fix." width="100%" />
110
+ </p>
111
+
112
+ `mjolnir explain QA-CI-001` gibt die gesamte Vertrauensakte einer Regel aus, einschließlich ihrer gemessenen Falsch-Positiv-Rate und der Stufe, die ihr diese Rate eingebracht hat:
66
113
 
67
114
  ```text
68
- ▚ QA-CI-001 — continue-on-error masks a failing verification gate
115
+ ▍ QA-CI-001 — continue-on-error masks a failing verification gate
69
116
 
70
117
  Severity: error
71
118
  Confidence: high
119
+ Tier: quarantine
72
120
  Evidence: E2
73
- Measured FP: not yet measured — this rule ships on assumption (see docs/FP-AUDIT.md)
121
+ QA impact: False-green risk (FALSE-GREEN)
122
+ Measured FP: 11% (19 hand-classified corpus verdicts)
123
+ FP risk: low (author estimate)
124
+ Languages: yaml
125
+ Frameworks: github-actions, azure-pipelines
74
126
 
75
127
  WHAT WAS FOUND (real detector output, not a mockup)
76
128
  Job `security-scan` runs a verification gate under `continue-on-error: true`.
77
129
 
78
130
  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.
131
+ This job can fail every day and CI will still show green. The checkmark on
132
+ this workflow cannot be trusted.
81
133
 
82
134
  HOW TO FIX
83
135
  Remove continue-on-error, or scope it to individual non-blocking steps only.
84
- ```
85
136
 
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.
137
+ Example from this rule's own must-fire fixture: QA-CI-001/must-fire/masked.yml
138
+
139
+ WHAT WOULD CHANGE THE VERDICT
140
+ - a run report next to the scan target (mjolnir.report.json or test-results/)
141
+ corroborating this file lifts its findings to L3–L5
142
+ - a documented suppression (mjolnir.config.json) lowers the finding count
143
+ without claiming correctness
144
+ - quarantine findings run only under --strict and are advisory (E0) — they can
145
+ never gate CI
146
+
147
+ NEXT ACTION
148
+ Fix the first occurrence, then re-run: `mjolnir --scope changed`. Every
149
+ occurrence of this rule is listed in the scan output.
88
150
 
89
- ---
151
+ HOW TO VERIFY THE FIX
152
+ Re-run `mjolnir` on the changed file(s) — this finding should no longer
153
+ appear. `mjolnir --scope changed` scopes the check to just what you touched.
90
154
 
91
- ## ⚡ Schnellstart
155
+ Docs: mjolnir rules --md (full catalog, this rule included)
156
+ ```
157
+
158
+ Das ist die Werteinheit: eine Stelle, an der die CI ein Bestehen meldet, das sie nicht verdient hat.
92
159
 
93
- Führe es gegen ein Repo aus — für einen vollen Bericht und einen
94
- Würdigkeitswert:
160
+ <br />
161
+
162
+ ## Schnellstart
95
163
 
96
164
  ```bash
97
165
  npx mjolnir-qa@latest
98
166
  ```
99
167
 
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:
168
+ Es scannt das aktuelle Verzeichnis und gibt den Trust Report aus: was es gefunden hat, wie weit du dem trauen kannst, warum und was als Nächstes zu tun ist. Es endet mit `0`, wenn nichts auf oder über dem Gate gefunden wurde.
169
+
170
+ Scanne in der CI nur, was der Branch eingeführt hat, damit eine Legacy-Suite deinen ersten Pull Request nicht ertränkt:
103
171
 
104
172
  ```bash
105
173
  npx mjolnir-qa@latest --scope changed
106
174
  ```
107
175
 
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>
176
+ `mjolnir ci install` schreibt das als GitHub-Actions-Workflow, mit der [Action](https://github.com/Sergey-Bar/Mjolnir#readme), gepinnt auf das Major-Tag `v1` (oder schlichtes `npx` mit `--no-action`). Er bleibt beratend, bis du entscheidest, dass er blockieren soll.
123
177
 
124
178
  | Befehl | Was er tut |
125
179
  | ----------------------------------- | -------------------------------------------------------------- |
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>
180
+ | `mjolnir` | Trust Report: Urteil, Konfidenz, nächster Schritt |
181
+ | `mjolnir --scope changed` | Nur was dein Branch eingeführt hat (die CI-Form) |
182
+ | `mjolnir ci install` | Beratenden PR-Workflow erzeugen (Action-basiert) |
183
+ | `mjolnir explain QA-CI-001` | Was, warum und Fix, plus die gemessene FP-Rate |
184
+ | `mjolnir why src/a.spec.ts:42` | Warum genau diese Zeile markiert wurde. Blockiert nie. |
185
+ | `mjolnir forensics ./test-results/` | Laufzeit-Evidenz aus einem echten Lauf |
186
+ | `mjolnir trust-report` | Eigenständiges Trust-Artefakt (md + json) |
187
+ | `mjolnir handoff` | Behebungsplan für einen Coding-Agenten |
188
+ | `mjolnir --json` / `--format sarif` | Maschinenlesbare Ausgabe, GitHub Code Scanning |
189
+ | `mjolnir --format codequality` | GitLab-Code-Quality-Report (MR-Widget-Artefakt) |
190
+ | `mjolnir --strict` | Auch Regeln der Stufe quarantine ausführen (höheres FP-Risiko) |
132
191
 
133
192
  <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 |
193
+ <summary><strong>Alle weiteren Befehle</strong> – Flake-Triage, Reporting, Governance</summary>
194
+
195
+ <br />
196
+
197
+ | Befehl | Was er tut |
198
+ | ----------------------------------- | -------------------------------------------------------------------------------- |
199
+ | `mjolnir --classic` | Das Score-Banner aus der Zeit vor dem Trust Report |
200
+ | `mjolnir explain verdict` | Warum das Urteil des gespeicherten Scans so ist, wie es ist |
201
+ | `mjolnir triage ./test-results/` | Geführte Triage. Jede Zeile endet mit einem nächsten Schritt. |
202
+ | `mjolnir pw-report ./test-results/` | Playwright-Laufzusammenfassung: Retries, Flakes, langsamste Tests |
203
+ | `mjolnir doctor:playwright` | Tiefenscan nur für Playwright plus Selector Health Score |
204
+ | `mjolnir fix --dry-run` / `fix` | Sichere Auto-Fixes, jeder erneut gescannt, um zu beweisen, dass er gegriffen hat |
205
+ | `mjolnir baseline` / `diff` | Befunde als Snapshot sichern, dann nur neue oder schlimmere melden |
206
+ | `mjolnir impact --since <ref>` | Was ein Commit eingeführt und behoben hat |
207
+ | `mjolnir summary` | CI-Annotationen und eine Step-Zusammenfassung aus einem Report |
208
+ | `mjolnir pr-comment` | Ein auf den PR zugeschnittener Kommentar, als Markdown |
209
+ | `mjolnir debt` | Testschulden-Register mit Kostenmodell |
210
+ | `mjolnir handover` | Einarbeitungskarte der Suite für neue QA-Engineers |
211
+ | `mjolnir init` | Frameworks erkennen, Setup-Checkliste ausgeben |
212
+ | `mjolnir suppressions` | Unterdrückte Befunde auflisten, für die Governance |
213
+ | `mjolnir rules --unmeasured` | Die Regeln, die auf Annahme statt Messung laufen |
214
+ | `mjolnir rules --md` | Vollständiger Regelkatalog (JSON oder Markdown) |
215
+ | `mjolnir doctor` | Selbstaudit von Mjölnirs eigener Regelbasis |
216
+ | `mjolnir create-rule <ID>` | Gerüst für eine neue Regel und ihre Fixtures |
217
+ | `mjolnir stats` | Lokale Zähler aller jemals gesehenen Fixes |
218
+ | `mjolnir badge` | shields.io-Endpoint-JSON und Snippet |
219
+ | `mjolnir --cache` | Inkrementelle Re-Scans über einen lokalen Urteils-Cache |
220
+ | `mjolnir --format mermaid` | Testarchitektur-Diagramm für einen PR-Kommentar |
221
+
222
+ `mjolnir help <command>` gibt für jeden davon Verwendung, Beispiele und den nächsten Schritt aus.
149
223
 
150
224
  </details>
151
225
 
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.
226
+ Benötigt **Node.js ≥ 22.18** unter Windows, macOS oder Linux. Lieber global installieren? `npm i -g mjolnir-qa`. Die Untergrenze kommt von der Build-Toolchain (tsdown zielt darauf, und die Release-Pipeline macht Smoke-Tests dagegen); die Laufzeitabhängigkeiten brauchen nicht mehr.
169
227
 
170
- ---
228
+ <br />
171
229
 
172
- ## 🔨 Was Mjölnir prüft
230
+ ## Was Mjölnir findet
173
231
 
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>
232
+ <p align="center">
233
+ <img src="assets/readme/stack.svg" alt="Funktioniert mit deinem Stack: die Sprachen, Test-Frameworks und CI-Systeme, die seine Regeln abdecken, aus der Regel-Registry." width="100%" />
234
+ </p>
203
235
 
204
- <details>
205
- <summary><strong>Test-Qualität</strong></summary>
236
+ **79 Regeln** in vier Familien – Testhygiene, Testqualität, Playwright und CI-Integrität – für TypeScript und JavaScript, Python, Java, C# und GitHub-Actions-YAML. Sie decken Playwright in allen vier Bindings ab, dazu pytest, JUnit, TestNG, NUnit, xUnit, MSTest, Jest, Vitest und Mocha, mit Einstiegsabdeckung für Cypress und Selenium. Neun davon, um die Form zu zeigen:
206
237
 
207
- | ID | Regel | Severity |
208
- | ------------ | ----------------------------------- | -------- |
209
- | QA-TQUAL-002 | Tautologische Assertion | error |
210
- | QA-TQUAL-009 | Nicht abgewartete Promise-Assertion | error |
211
- | QA-TQUAL-011 | Auskommentierte Tests | warning |
238
+ | ID | Regel | Schweregrad | Stufe |
239
+ | ------------ | -------------------------------------------------------------------- | ----------- | ---------- |
240
+ | QA-CI-001 | `continue-on-error` maskiert ein fehlschlagendes Verifikations-Gate | error | quarantine |
241
+ | QA-CI-009 | Test-Exit-Code nicht weitergereicht (`\|` ohne pipefail, `;`-Ketten) | error | extended |
242
+ | QA-TEST-001 | Fokussierter Test committet (`.only`, `fit`) | error | quarantine |
243
+ | QA-TEST-003 | Test ohne Assertions | error | quarantine |
244
+ | QA-TQUAL-009 | Promise-Assertion ohne await | error | quarantine |
245
+ | QA-PW-002 | Locator-Assertion ohne await | error | core |
246
+ | QA-PW-004 | Fragile CSS/XPath-Selektoren | warning | quarantine |
247
+ | QA-PY-002 | Übersprungener Test (`skip`, nicht-striktes `xfail`) | warning | core |
248
+ | QA-CS-103 | Testmethode ohne Assertions | error | core |
212
249
 
213
- </details>
250
+ Der vollständige Katalog wird aus der Registry erzeugt, nie von Hand gepflegt: `mjolnir rules --md`, [`docs/rules/`](docs/rules/) oder der [What-it-checks-Leitfaden](https://sergey-bar.github.io/Mjolnir/guide/what-it-checks).
214
251
 
215
252
  <details>
216
- <summary><strong>Playwright 🎭</strong></summary>
217
-
218
- | ID | Regel | Severity |
219
- | --------- | ---------------------------------------- | -------- |
220
- | QA-PW-002 | Nicht abgewartete Locator-Assertion | error |
221
- | QA-PW-003 | `page.pause()` / `test.only()` committed | error |
222
- | QA-PW-004 | Spröde CSS/XPath-Selektoren | warning |
223
- | QA-PW-123 | Hartkodierte Umgebungs-URLs | warning |
253
+ <summary><strong>Jede in diesem README genannte Regel</strong>, in einer Tabelle</summary>
254
+
255
+ <br />
256
+
257
+ > `quarantine`-Regeln laufen nur unter `--strict` und blockieren nie (sie sind auf info begrenzt). Der gezeigte Schweregrad ist der vom Autor festgelegte.
258
+
259
+ | ID | Familie | Regel | Schweregrad | Stufe |
260
+ | ------------ | ---------- | -------------------------------------------------------------------- | ----------- | ---------- |
261
+ | QA-TEST-001 | Hygiene | Fokussierter Test committet (`.only`, `fit`) | error | quarantine |
262
+ | QA-TEST-002 | Hygiene | Übersprungener Test. Eskaliert ohne nachverfolgten Grund zu `error`. | warning | quarantine |
263
+ | QA-TEST-003 | Hygiene | Test ohne Assertions | error | quarantine |
264
+ | QA-TEST-004 | Hygiene | Hartes Sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning | extended |
265
+ | QA-TEST-006 | Hygiene | Retry-Missbrauch, der Flakiness verbirgt | warning | quarantine |
266
+ | QA-TEST-010 | Hygiene | Leerer Testrumpf | error | quarantine |
267
+ | QA-TQUAL-002 | Qualität | Tautologische Assertion | error | quarantine |
268
+ | QA-TQUAL-009 | Qualität | Promise-Assertion ohne await | error | quarantine |
269
+ | QA-TQUAL-011 | Qualität | Auskommentierte Tests | warning | extended |
270
+ | QA-PW-002 | Playwright | Locator-Assertion ohne await | error | core |
271
+ | QA-PW-003 | Playwright | `page.pause()` / `test.only()` committet | error | core |
272
+ | QA-PW-004 | Playwright | Fragile CSS/XPath-Selektoren | warning | quarantine |
273
+ | QA-PW-123 | Playwright | Fest codierte Umgebungs-URLs | warning | quarantine |
274
+ | QA-PW-140 | Playwright | Screenshot ohne `maxDiffPixelRatio` | warning | core |
275
+ | QA-CI-001 | CI | `continue-on-error` maskiert ein fehlschlagendes Gate | error | quarantine |
276
+ | QA-CI-002 | CI | `\|\| true` verschluckt Exit-Codes | error | extended |
277
+ | QA-CI-005 | CI | Report verwendet, aber nie erzeugt | error | quarantine |
278
+ | QA-CI-007 | CI | Retry-Wrapper um Tests | warning | extended |
279
+ | QA-CI-008 | CI | Immer erfolgreicher Step maskiert Fehlschläge | error | quarantine |
280
+ | QA-CI-009 | CI | Exit-Code nicht weitergereicht (`\|` ohne pipefail, `;`-Ketten) | error | extended |
281
+ | QA-CI-010 | CI | Tests übersprungen, wo sie blockieren müssen | error | quarantine |
282
+ | QA-PY-002 | Python | Übersprungener Test (`skip`, nicht-striktes `xfail`) | warning | core |
283
+ | QA-PY-003 | Python | Testfunktion ohne Assertions | error | quarantine |
284
+ | QA-PY-005 | Python | `time.sleep()` in Tests | warning | extended |
285
+ | QA-PY-012 | Python | Tautologische Assertion | error | quarantine |
286
+ | QA-JV-101 | Java | Deaktivierter Test (`@Disabled`) | warning | core |
287
+ | QA-JV-102 | Java | Hartes Sleep (`Thread.sleep()`) | warning | extended |
288
+ | QA-JV-103 | Java | Testmethode ohne Assertions | error | extended |
289
+ | QA-JV-105 | Java | Playwright-`waitForTimeout()` als hartes Sleep | warning | core |
290
+ | QA-JV-106 | Java | Fragiler Selektor statt Role-Locator | warning | quarantine |
291
+ | QA-CS-101 | C# | Übersprungener Test (`[Ignore]`, `[Fact(Skip=)]`) | warning | core |
292
+ | QA-CS-102 | C# | Hartes Sleep (`Thread.Sleep` / `Task.Delay`) | warning | core |
293
+ | QA-CS-103 | C# | Testmethode ohne Assertions | error | core |
294
+ | QA-CS-105 | C# | `WaitForTimeoutAsync()` als hartes Sleep | warning | extended |
295
+ | QA-CS-106 | C# | Fragiler Selektor statt Role-Locator | warning | quarantine |
296
+
297
+ Python bringt außerdem QA-PY-001…012 (pytest-Hygiene) und QA-PY-101…108 (Playwright für Python) mit. Cypress und Selenium haben Einstiegssets mit je drei Regeln.
224
298
 
225
299
  </details>
226
300
 
227
- <details>
228
- <summary><strong>CI-Integrität</strong></summary>
229
-
230
- | ID | Regel | Severity |
231
- | --------- | ------------------------------------------------------------------------- | -------- |
232
- | QA-CI-001 | `continue-on-error` maskiert Fehler | error |
233
- | QA-CI-002 | `\|\| true` schluckt Exit-Codes | error |
234
- | QA-CI-005 | Report konsumiert, aber nie erzeugt | error |
235
- | QA-CI-007 | Retry-Wrapper um Tests | warning |
236
- | QA-CI-008 | Immer-erfolgreicher Step maskiert Fehler | error |
237
- | QA-CI-009 | Test-Exit-Code wird nicht weitergereicht (`\|` ohne pipefail, `;`-Ketten) | error |
238
- | QA-CI-010 | Tests übersprungen, wo sie blockieren müssen (skip-on-PR-Guards) | error |
239
-
240
- </details>
301
+ Jede Regel wird mit einem Must-fire- **und** einem Must-not-fire-Fixture ausgeliefert, und eine Regel, die auf ihrem eigenen Negativ-Fixture anschlägt, kann nicht ausgeliefert werden. Das ist die Falsch-Positiv-Firewall; `mjolnir doctor` erzwingt sie in der eigenen CI dieses Repositorys.
241
302
 
242
- <details>
243
- <summary><strong>Python / pytest 🐍</strong></summary>
303
+ ### Selector Health Score
244
304
 
245
- | ID | Regel | Severity |
246
- | --------- | ---------------------------------------------------- | -------- |
247
- | QA-PY-002 | Übersprungener Test (`skip`, nicht-strictes `xfail`) | warning |
248
- | QA-PY-003 | Testfunktion ohne Assertionen | error |
249
- | QA-PY-005 | `time.sleep()` in Tests | warning |
250
- | QA-PY-012 | Tautologische Assertion | error |
305
+ `mjolnir doctor:playwright` bewertet jeden Locator danach, wie er ein Element findet: so wie ein Nutzer (Rolle, Label, Text), über einen expliziten Vertrag (`data-testid`) oder über einen strukturellen Zufall (CSS-Ketten, XPath). Jede Datei bekommt einen Score von 0 bis 100:
251
306
 
252
- 20 Python-Regeln insgesamt (QA-PY-001…012 pytest-Hygiene + QA-PY-101…108 Playwright-Python).
307
+ ```text
308
+ ▍ SELECTOR HEALTH
253
309
 
254
- </details>
310
+ e2e/login.spec.ts
311
+ [█████████████░░░░░░░] 65 / 100
312
+ role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
255
313
 
256
- <details>
257
- <summary><strong>Java / JUnit · TestNG ☕</strong></summary>
314
+ e2e/checkout.spec.ts
315
+ [█████████████████░░░] 86 / 100
316
+ role/text: 3 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
317
+ ```
258
318
 
259
- | ID | Regel | Severity |
260
- | --------- | ------------------------------------------ | -------- |
261
- | QA-JV-101 | Deaktivierter Test (`@Disabled`) | warning |
262
- | QA-JV-102 | Harter Sleep (`Thread.sleep()`) | warning |
263
- | QA-JV-103 | Testmethode ohne Assertionen | error |
264
- | QA-JV-105 | Playwright `waitForTimeout()`-harter Sleep | warning |
265
- | QA-JV-106 | Spröder Selektor statt Role-Locator | warning |
319
+ Das misst **Robustheit, nicht Korrektheit**. `.btn.btn-primary > div:nth-child(2)` besteht heute und besteht weiter, bis jemand das Markup anfasst. Ein niedriger Score behauptet nie, der Test sei kaputt, nur dass er von Markup abhängt, dessen Erhalt niemand versprochen hat.
266
320
 
267
- </details>
321
+ <br />
268
322
 
269
- <details>
270
- <summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
323
+ ## Der Worthiness-Score
271
324
 
272
- | ID | Regel | Severity |
273
- | --------- | ------------------------------------------------- | -------- |
274
- | QA-CS-101 | Übersprungener Test (`[Ignore]`, `[Fact(Skip=)]`) | warning |
275
- | QA-CS-102 | Harter Sleep (`Thread.Sleep` / `Task.Delay`) | warning |
276
- | QA-CS-103 | Testmethode ohne Assertionen | error |
277
- | QA-CS-105 | `WaitForTimeoutAsync()`-harter Sleep | warning |
278
- | QA-CS-106 | Spröder Selektor statt Role-Locator | warning |
325
+ <p align="center">
326
+ <img src="assets/readme/score-gauge.svg" alt="Die Worthiness-Skala von 0 bis 100, mit einer Markierung, die jeden Score durchläuft: UNWORTHY unter 50, NEEDS WORK von 50 bis 79, WORTHY von 80 bis 99, FORGED bei 100" width="720" />
327
+ </p>
279
328
 
280
- </details>
329
+ <sub>Jeder Score von 0 bis 100, platziert vom echten `deriveScoreState`. Erzeugt mit `npm run docs:gauge` und in der CI gegen Abweichungen gesichert.</sub>
281
330
 
282
- > Der volle Live-Katalog — jede Regel mit Tier, Confidence,
283
- > False-Positive-Risiko und Autofix-Verfügbarkeit — wird aus der
284
- > Registry erzeugt:
285
- >
286
- > ```bash
287
- > mjolnir rules --md
288
- > ```
289
- >
290
- > Pro-Regel-Seiten liegen unter [`docs/rules/`](docs/rules/).
331
+ | Score | Urteil |
332
+ | --------- | --------------------------------------------- |
333
+ | `0 – 49` | **UNWORTHY** |
334
+ | `50 – 79` | **NEEDS WORK** |
335
+ | `80 – 99` | **WORTHY** |
336
+ | `100` | **FORGED** |
337
+ | `null` | **UNKNOWN**: keine Testdeklarationen gefunden |
291
338
 
292
- ### Wie viel davon gemessen ist
339
+ **Wie er berechnet wird.** Der Schweregrad legt einen Grundabzug fest (`error −8`, `warning −3`, `info −1`), und das Evidenzlevel rabattiert ihn: E2 zählt voll, E1 halb (abgerundet), E0 gar nicht. Die Summe wird nach der Exposition der Suite normalisiert, also Abzüge pro Testdeklaration statt pro Datei. Das Terminal gibt dieselben rabattierten Zahlen aus, die der Score verwendet hat; es gibt kein verstecktes zweites Modell. Details: [docs/SCORING.md](docs/SCORING.md) und der [Scoring-Leitfaden](https://sergey-bar.github.io/Mjolnir/guide/scoring).
293
340
 
294
- **78 von 99 Regeln tragen eine False-Positive-Rate, gemessen an echtem
295
- OSS-Code** (jeweils ≥ 10 handklassifizierte Befunde; siehe
296
- [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Die anderen 21 gehen auf der
297
- Schätzung des Autors. Jeder Scan-Footer sagt dir, wie viele der
298
- _ausgelösten_ Regeln gemessen sind; `mjolnir rules --unmeasured` listet
299
- die nicht gemessenen; die `mjolnir explain`-Seite jeder Regel nennt
300
- ihren Status. Wir veröffentlichen die Rate, selbst wenn sie hässlich
301
- Zahl zu vergrößern ist die fortlaufende Arbeit des Projekts.
341
+ **Was 100 nicht bedeutet.** Es bedeutet nicht, dass die Software korrekt, die Suite ausreichend oder das Produkt fehlerfrei ist. Es bedeutet genau eines: **keine der von Mjölnir ausgewerteten Regeln hat unter diesem Scan und diesem Evidenzmodell einen Abzug erzeugt.**
302
342
 
303
- ### Regel-Tiers und Sprachreife
343
+ <br />
304
344
 
305
- Jede Regel ist `core`, `extended` oder `quarantine`, zugewiesen nach
306
- ihrer **gemessenen** False-Positive-Rate:
345
+ ## Das Evidenzmodell
307
346
 
308
- | Tier | Bedeutung | Standard-Scan | `--strict` |
309
- | ------------ | ------------------------------------------ | :-----------: | :--------: |
310
- | `core` | ≤ 10 % gemessene FP | ✅ | ✅ |
311
- | `extended` | ≤ 30 % gemessene FP | ✅ | ✅ |
312
- | `quarantine` | darüber, oder noch nicht gemessen (n < 10) | ❌ | ✅ |
347
+ Jeder Befund trägt zwei Labels: wie sicher Mjölnir ist und wie weit der Befund geprüft wurde. Das ist der Unterschied zwischen einem Tool, das Muster meldet, und einem Tool, an dem du ein Release festmachen kannst.
313
348
 
314
- | Sprache | Adapter | Abdeckung heute |
315
- | --------------- | ------------- | ------------------------------------------------------------ |
316
- | TypeScript / JS | Compiler-AST | am breitesten, am meisten gemessen — meist `core`/`extended` |
317
- | Python / pytest | Regex-Schicht | breit, corpus-auditiert — meist `core`/`extended` |
318
- | Java | Regex-Schicht | neuer — meist `extended`/`quarantine` |
319
- | C# / .NET | Regex-Schicht | neuer — meist `extended`/`quarantine` |
349
+ **Wie sicher – das Evidenzlevel.**
320
350
 
321
- TypeScript und Python haben die breiteste gemessene Abdeckung. Java und
322
- C# sind geshippt, dokumentiert und bleiben aus der Schlagzeilen-Zahl
323
- heraus, bis eine echte Consumer-Suite (nicht die eigenen Tests einer
324
- Binding-Library) auditiert wurde.
351
+ | Level | Name | Bedeutet | Abzug |
352
+ | ------ | ------------------------ | --------------------------------------------------------------- | ----- |
353
+ | **E2** | Deterministischer Beweis | Der Defekt steckt im Code, so wie er geschrieben ist | Voll |
354
+ | **E1** | Musterevidenz | Ein Muster, das eng mit dem Defekt verbunden ist, hat gegriffen | Halb |
355
+ | **E0** | Beobachtung | Gut zu wissen. Keine Behauptung, dass etwas falsch ist. | Null |
325
356
 
326
- ---
357
+ Konfidenz in einer Erkennung ist nicht die Stärke des Beweises. Eine Regel kann sicher sein, gefunden zu haben, wonach sie gesucht hat, und trotzdem auf eine Heuristik blicken. E1-Befunde sind dazu da, gelesen und beurteilt zu werden, nie blind angewendet, und diese Grenze ist auf dem Befund vermerkt – im Terminal, im JSON und in der Agenten-Übergabe.
327
358
 
328
- ## So funktioniert der Score
359
+ **Wie weit geprüft – die Vertrauensstufe.** Die meisten Befunde entstehen durch das Lesen deines Codes. Gib Mjölnir den Report eines echten Testlaufs, und es kann bestätigen, dass der Code tatsächlich gelaufen ist.
329
360
 
330
361
  <p align="center">
331
- <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" />
362
+ <img src="assets/readme/trust-ladder.svg" alt="Die Vertrauensleiter von L0 bis L5. L0 bis L2 entstehen durch das Lesen des Codes; L3 bis L5 brauchen einen echten Laufreport, markiert durch eine Lücke in der Leiter." width="100%" />
332
363
  </p>
333
364
 
334
- <sub>Neu erzeugt per `npm run docs:hero`;
335
- [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
336
- lässt CI fehlschlagen, wenn es von dem abweicht, was der Reporter
337
- wirklich druckt.</sub>
365
+ | Level | In einfachen Worten | Was es braucht |
366
+ | ------ | -------------------------- | ----------------------------------------------------------------- |
367
+ | **L0** | Notiert | Den Code lesen |
368
+ | **L1** | Sieht nach dem Problem aus | Den Code lesen: ein Muster hat gegriffen |
369
+ | **L2** | Im Code bewiesen | Den Code lesen: der Defekt ist strukturell |
370
+ | **L3** | Die Datei lief | Ein Laufreport zeigt, dass die Datei des Befunds ausgeführt wurde |
371
+ | **L4** | Der Test lief | Ein Laufreport zeigt, dass der Test des Befunds ausgeführt wurde |
372
+ | **L5** | Der Lauf stimmt zu | Das Ergebnis des Laufs selbst bestätigt die Defektklasse |
338
373
 
339
- Der Score ist transparent: **error −8, warning −3, info −1**, dann
340
- normalisiert um die Suite-Exposition (Abzüge pro Testdeklaration).
341
- Evidenzgewichtete Abzüge bedeuten: schwache Signale kosten weniger. Das
342
- Terminal zeigt dieselben diskontierten Zahlen, die der Score verwendet —
343
- keine Blackbox. Volle Methode: [docs/SCORING.md](docs/SCORING.md).
374
+ Ein statischer Scan endet bei L2. Nur ein echter Laufreport (Playwright JSON, Jest oder Vitest JSON, JUnit XML) kann einen Befund auf L3 oder höher heben, sodass ein Befund, der nie beim Laufen gesehen wurde, das auch nie behaupten kann. Definitionen: [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md).
344
375
 
345
- **Urteile**
376
+ ### Wie viel davon gemessen ist
346
377
 
347
- | Score | Urteil |
348
- | ------- | ---------------- |
349
- | ≥ 80 | ✓ **WORTHY** |
350
- | 50 – 79 | ⚠ **NEEDS WORK** |
351
- | < 50 | ✖ **UNWORTHY** |
378
+ **74 von 79 Regeln haben eine gegen echten OSS-Code gemessene Falsch-Positiv-Rate** (mindestens 10 von Hand klassifizierte Befunde je Regel; siehe [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Die übrigen 5 laufen auf der Schätzung des Autors und sagen das Regel für Regel in `mjolnir explain`. `mjolnir rules --unmeasured` listet sie auf, und jede Scan-Fußzeile meldet, wie viele der tatsächlich _ausgelösten_ Regeln gemessen sind.
352
379
 
353
- **Evidenzlevel** — jeder Befund trägt eines; es setzt das Gewicht des
354
- Befunds im Score:
380
+ Raten bleiben öffentlich, auch wenn sie schlecht sind. QA-TEST-001 (ein committetes `.only`) schneidet auf echten Repositorys schlecht ab und sitzt deshalb in quarantine. Die aktuelle Zahl für jede Regel, QA-PW-141 eingeschlossen, steht im Audit.
355
381
 
356
- | Level | Bedeutung | Score-Auswirkung | Beispiel |
357
- | ----- | ------------------------ | ---------------- | --------------------------------------------------------- |
358
- | E2 | Deterministischer Defekt | Voller Abzug | `.only` committed — strukturell beweisbar |
359
- | E1 | Heuristisches Muster | Halbierter Abzug | Regex-getroffenes `sleep()` — starkes Signal, kein Beweis |
360
- | E0 | Beobachtung | Null (nur Info) | Gemeldet, gated aber nie CI und zieht nie ab |
382
+ ### Vertrauensstufen
361
383
 
362
- Die meisten Regeln sind **E1**. Der Tagline „we prove it“ bezieht sich
363
- auf dieses System: E2-Befunde sind struktureller Beweis; E1-Befunde
364
- sind korrekt positionierte Warnungen, keine formalen Beweise.
384
+ Die Stufen folgen der gemessenen Falsch-Positiv-Rate, nicht einer Meinung:
365
385
 
366
- Ein leeres Repo scored `null`, nie eine fake 100 — siehe
367
- [Vertrauensmodell](#vertrauensmodell).
386
+ | Stufe | Gemessene FP | Verhalten |
387
+ | -------------- | ------------------------------ | ------------------------------------------------ |
388
+ | **core** | ≤ 10% | Standardreport, blockiert |
389
+ | **extended** | ≤ 30% | Standardreport, geringere Konfidenz |
390
+ | **quarantine** | > 30% oder explizit deklariert | Nur `--strict`, auf info begrenzt, blockiert nie |
391
+ | _ungemessen_ | n < 10 | Kann erst nach Messung zu core befördert werden |
368
392
 
369
- ---
393
+ FP-Bänder können nur herabstufen — sie befördern eine Regel nie aus `quarantine` heraus, wenn sie dort explizit deklariert wurde. Eine explizit unter Quarantäne gestellte Regel bleibt in quarantine, unabhängig von ihrer gemessenen FP-Rate.
370
394
 
371
- ## 🎭 Selector Health Score
395
+ Beförderung, Herabstufung und Reife pro Sprache: [Regel-Lebenszyklus](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle).
372
396
 
373
- Die Headline-Metrik für Playwright-Suiten — wie belastbar deine
374
- Locators sind:
397
+ ### Warum das kein Linter ist
375
398
 
376
- ```text
377
- ▚ SELECTOR HEALTH — e2e/checkout.spec.ts
399
+ Linter sagen dir, ob Code Regeln befolgt. Mjölnir sagt dir, ob deiner Verifikation zu trauen ist.
378
400
 
379
- [█████████████████░░░] 83 / 100
380
- role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
381
- ```
401
+ | | Linter (ESLint, SonarQube) | Coverage-Tools | KI-Code-Review | **Mjölnir** |
402
+ | ----------------------------------------------------------------- | :------------------------: | :------------: | :------------: | :--------------: |
403
+ | Bewertet das **Verifikationssystem**, nicht den Produktcode | Nein | Nein | Nein | Ja |
404
+ | Integrität von CI-Workflows (`continue-on-error`, `\|\| true`) | Nein | Nein | nur den Diff | Ja |
405
+ | Bewertet die Robustheit von Playwright-Locators (Selector Health) | Nein | Nein | Nein | Ja |
406
+ | Liest echte Laufdaten für `TRUE-FLAKE`-Urteile | Nein | Nein | Nein | Ja |
407
+ | Veröffentlicht eine gemessene Falsch-Positiv-Rate pro Regel | Nein | Nein | Nein | Ja |
408
+ | Markiert Tests ohne Assertions | Ja\* | Nein | manchmal | Ja |
409
+ | Findet harte Sleeps (`waitForTimeout`, `time.sleep`) | Ja\* | Nein | manchmal | Ja |
410
+ | Deterministisch (gleiche Eingabe, gleiche Ausgabe) | Ja | Ja | Nein | Ja |
411
+ | Kosten pro Scan | kostenlos | kostenlos | Tokens | **null** (lokal) |
382
412
 
383
- Rollenbasierte Locators bekommen die volle Punktzahl.
384
- CSS-Klassenketten und XPath ruiniern den Score — sie brechen bei jedem
385
- DOM-Refactor, ohne dir zu sagen, welches Verhalten regressiert ist.
413
+ <sub>\*Abgedeckt durch `eslint-plugin-jest` und `eslint-plugin-playwright` (`expect-expect`, `no-wait-for-timeout`) sowie durch SonarQubes eigene Assertion-Regeln. Die Spalten beschreiben das Standardverhalten bei der Verifikation von Testsuiten; Plugins, bezahlte Stufen und eigene Regeln ändern manche Antworten. Das ist eine Positionierungsübersicht, kein Benchmark.</sub>
386
414
 
387
- ---
415
+ Nutze auch KI-Review. Es erkennt Nuancen, Absicht und Designfehler, die kein Muster findet. Mjölnir findet, was KI-Review übersieht, weil es beabsichtigt aussieht: ein committetes `.only`, ein verschluckter Exit-Code, ein `continue-on-error` auf einem Test-Job. Dafür braucht es Scannen, nicht Schlussfolgern.
388
416
 
389
- ## 🔬 Runtime-Evidenz
417
+ <br />
390
418
 
391
- Statische Flakiness-Erkennung ist Raten. Mjölnir liest **echte
392
- Ausführungsdaten** — Playwright-JSON-Reports und JUnit-XML von jedem
393
- Runner:
419
+ ## Laufzeit-Forensik
420
+
421
+ Statische Analyse argumentiert über Code, der nie gelaufen ist. Die Forensik liest, was tatsächlich passiert ist: Playwright JSON, Jest JSON, Vitest JSON und JUnit XML von jedem Runner.
394
422
 
395
423
  ```bash
396
424
  mjolnir forensics ./test-results/
397
425
  ```
398
426
 
399
427
  ```text
400
- ▚ FLAKINESS LEADERBOARD
428
+ ▍ FLAKINESS LEADERBOARD
401
429
 
402
430
  3 tests · 1 failed · 1 flaky · 1 retried
403
431
 
@@ -407,302 +435,184 @@ FAILING declines an expired card (e2e/checkout.spec.ts)
407
435
  ████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
408
436
  ```
409
437
 
410
- Ein Test, der nur ab Versuch ≥ 2 besteht, ist kein bestandener Test —
411
- es ist ein glücklicher Test. Er wird als `TRUE-FLAKE` markiert, egal
412
- wie grün der finale Haken ist.
438
+ `TRUE-FLAKE` bedeutet nicht, dass der Test wiederholt wurde. Es bedeutet, dass der Test **mindestens einen Versuch nicht bestanden und dann grün geendet hat**: ein Glückstreffer, markiert unabhängig davon, was der letzte Haken sagt. `mjolnir triage` macht aus diesem Verlauf einen Quarantäne-Vorschlag, und `mjolnir pw-report` fasst einen Lauf zusammen. Dieselben Laufreports sind es, die Befunde auf die Vertrauensstufen L3 und höher heben.
439
+
440
+ <br />
441
+
442
+ ## CI-Integrität
443
+
444
+ Ein Test kann bestehen, während die Pipeline um ihn herum nicht fehlschlagen kann. Mjölnir liest auch die Workflows: `continue-on-error`, `|| true`, Exit-Codes, die nie weitergereicht werden, immer erfolgreiche Steps, Reports, die verwendet, aber nie erzeugt werden, und Gates, die bei genau den Events übersprungen werden, die blockieren sollten. Jeder Befund nennt Job, Step und Zeile und trägt sein eigenes Evidenzlevel.
445
+
446
+ Erzeuge den PR-Workflow, standardmäßig beratend:
447
+
448
+ ```bash
449
+ mjolnir ci install
450
+ ```
451
+
452
+ Oder füge die Marketplace-Action zu einem bestehenden Workflow hinzu:
413
453
 
414
- ---
454
+ ```yaml
455
+ - uses: Sergey-Bar/Mjolnir@v1
456
+ with:
457
+ scope: changed
458
+ fail-on: error
459
+ ```
415
460
 
416
- ## ⚡ Mjölnir ist kein weiterer Linter
461
+ Pinne `@v1`, um der Major-Linie zu folgen, oder ein exaktes Tag (`@v0.5.32`) für ein reproduzierbares Gate. [docs/DISTRIBUTION-KIT.md](docs/DISTRIBUTION-KIT.md) behandelt den Marketplace, Smithery und die MCP-Registries.
417
462
 
418
- Linter sagen dir, ob Code Regeln folgt. Mjölnir sagt dir, ob deine
419
- Verifikation vertraut werden kann.
463
+ Um Befunde in GitHub Code Scanning zu bringen, lade SARIF hoch (erfordert `security-events: write` auf Workflow- oder Job-Ebene):
420
464
 
421
- | | ESLint / SonarQube | Coverage-Tools | Manueller Review | **Mjölnir** |
422
- | ------------------------------------------------------------------- | :----------------: | :------------: | :--------------: | :---------: |
423
- | CI-Workflow-Integrität (`continue-on-error`, `\|\| true`) | ❌ | ❌ | selten | ✅ |
424
- | Cross-Sprache (TS, Python, Java, C#) aus einem Tool | ❌ | ❌ | ❌ | ✅ |
425
- | Benotet die Belastbarkeit von Playwright-Locators (Selector Health) | ❌ | ❌ | selten | ✅ |
426
- | Findet Tests ohne echte Assertionen | ✅ (Plugin)\* | ❌ | manchmal | ✅ |
427
- | Findet harte Sleeps (`waitForTimeout`, `time.sleep`) | ✅ (Plugin)\* | ❌ | manchmal | ✅ |
428
- | Läuft in Sekunden, null Netzwerkaufrufe beim Scannen | ✅ | ✅ | — | ✅ |
465
+ ```yaml
466
+ - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
467
+ continue-on-error: true
468
+ - uses: github/codeql-action/upload-sarif@v3
469
+ if: ${{ !cancelled() }}
470
+ with:
471
+ sarif_file: mjolnir.sarif
472
+ ```
429
473
 
430
- \*`eslint-plugin-jest` (`expect-expect`) und `eslint-plugin-playwright`
431
- (`expect-expect`, `no-wait-for-timeout`) decken das für die jeweiligen
432
- Frameworks ab.
474
+ Auf GitLab schreibt `--format codequality` den Code-Quality-Report, den das MR-Widget und die Diff-Annotationen lesen ([docs/GITLAB-CI.md](docs/GITLAB-CI.md)). Editor- und Pipeline-Einrichtung: [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
433
475
 
434
- **Runtime-Analyse** ist eine eigene Kategorie neben dem statischen
435
- Linten:
476
+ ### Zuordnung im Changed-Scope
436
477
 
437
- | | Playwright Retry Reporter | Allure / ReportPortal | **Mjölnir Forensics** |
438
- | ------------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
439
- | Liest echte Laufdaten für `TRUE-FLAKE`-Urteile | teilweise\* | teilweise (Tag) | ✅ |
440
- | Flaky-Triage-Bericht aus der Ausführungshistorie | ❌ | ✅ | ✅ |
441
- | Integriert sich in den statischen Würdigkeitswert | ❌ | ❌ | ✅ |
478
+ ```bash
479
+ npx mjolnir-qa@latest --scope changed
480
+ ```
442
481
 
443
- \*Playwright trackt Retries intern, erzeugt aber keinen eigenständigen
444
- Flakiness-Bericht mit Urteil-Labels.
482
+ Befunde werden den Zeilen zugeordnet, die dein Branch hinzugefügt hat, gemessen gegen die **merge-base**. Der Scope ist dieselbe Dateimenge, die ein vollständiger Scan findet (TS/JS-Specs und Adapter-Konfigurationen, `test_*.py`, `*Test.java`, `*Tests.cs`, `.github/workflows/*.yml`), plus nicht committete und nicht verfolgte Änderungen, sodass es schon vor dem Commit funktioniert. Die Basis wird aufgelöst als `main → master → origin/main → origin/master → origin/HEAD`; überschreibe sie mit `--base <ref>`.
445
483
 
446
- ---
484
+ Wenn die merge-base nicht aufgelöst werden kann (ein Shallow Clone, ein Detached HEAD, ein Ziel außerhalb von git), fallen die Befunde auf eine Zuordnung zur ganzen Datei zurück, **und der Report sagt das.** Ein stiller Fallback wäre genau die Art von Defekt, die dieses Tool finden soll.
447
485
 
448
- ## 🤖 Warum nicht einfach KI-Code-Review?
486
+ <br />
449
487
 
450
- Anderes Problem, andere Schicht. KI-Review kann eine verdächtige
451
- Teständerung in einem Diff erkennen; sie beweist nicht, dass das
452
- Verifikationssystem als Ganzes vertrauenswürdig ist — und sie sieht nur
453
- das Diff, das du ihr zeigst.
488
+ ## KI-Agenten
454
489
 
455
- | | KI-Code-Review (Copilot & co.) | **Mjölnir** |
456
- | -------------------------------------------------- | :--------------------------------: | :---------------------------------: |
457
- | Kosten pro Scan | Tokens (skaliert mit Diff-Größe) | **Null** (lokal, installiert) |
458
- | Sieht die ganze Suite + alle CI-Konfigs | Nur das PR-Diff, das du zeigst | **Alles, jedes Mal** |
459
- | Deterministisch (gleicher Input → gleicher Output) | ❌ (nicht-deterministisch) | **✅** |
460
- | Findet monatelang schlafende Muster | Nur, wenn es im Kontext steht | **✅** (scannt alle Dateien) |
461
- | Erinnert sich an Befunde zwischen Läufen | ❌ (kein Gedächtnis über Sessions) | **✅** (Baseline + Diff) |
462
- | Läuft ohne menschlichen Auslöser | Braucht einen PR oder Prompt | **✅** (CI-Hook, läuft in Sekunden) |
490
+ Befunde sind nur etwas wert, wenn etwas auf sie reagiert.
463
491
 
464
- **Benutze beides.** KI findet Nuance, Intent und Designfehler, die
465
- keine Regex findet. Mjölnir findet die strukturellen Muster, die KI
466
- übersieht, weil sie „absichtlich“ aussehen — ein committetes `.only`,
467
- ein geschluckter Exit-Code, ein `continue-on-error` auf einem
468
- Test-Job. Das sind keine Bugs, die Denken brauchen; das sind Fakten,
469
- die Scannen brauchen.
492
+ ```text
493
+ SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
494
+ ```
470
495
 
471
- ---
496
+ **Die KI schreibt den Fix. Mjölnir verifiziert ihn.** Der Beweis kommt vom erneuten Scan, nie vom Erfolgsbericht des Agenten selbst.
472
497
 
473
- ## 🤖 CI-Integration
498
+ | Befehl | Was der Agent bekommt |
499
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
500
+ | `mjolnir mcp` | Ein [MCP](https://modelcontextprotocol.io)-Server über stdio. `scan`, `explain` und `diff` werden zu aufrufbaren Tools. |
501
+ | `mjolnir handoff` | Ein gespeicherter `--json`-Report wird zu einem deterministischen Markdown-Plan: was erkannt wurde, die Evidenzgrenze pro Befund, was sich **nicht** ändern darf, wie zu verifizieren ist. |
502
+ | `mjolnir install` | Schreibt in die Agenten-Oberflächen, die dein Repo bereits hat (`.claude/`, `.cursor/`, `.kilo/`, `AGENTS.md`), damit der Agent erneut scannt, bevor er behauptet, fertig zu sein. |
474
503
 
475
- Ein Befehl erzeugt einen PR-Workflow — standardmäßig advisory, nie
476
- blockierend:
504
+ Füge es einem Client hinzu, der eine eigene CLI mitbringt:
477
505
 
478
506
  ```bash
479
- mjolnir ci install
507
+ claude mcp add mjolnir -- npx -y mjolnir-qa@latest mcp
480
508
  ```
481
509
 
482
- Oder binde es nativ in GitHub Code Scanning über SARIF ein:
510
+ Oder jedem Client, der einen `mcpServers`-Block akzeptiert:
483
511
 
484
- ```yaml
485
- - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
486
- - uses: github/codeql-action/upload-sarif@v3
487
- with:
488
- sarif_file: mjolnir.sarif
512
+ ```json
513
+ {
514
+ "mcpServers": {
515
+ "mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@latest", "mcp"] }
516
+ }
517
+ }
489
518
  ```
490
519
 
491
- Editor- und Pipeline-Setup für SARIF:
492
- [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
520
+ **Die Leitplanke zählt mehr als die Bequemlichkeit.** Jeder Befund in einer Übergabe trägt seine Grenze. **E2** sagt _deterministisch: Stelle prüfen und den Fix anwenden_. **E1** sagt _BESTÄTIGUNG ERFORDERLICH: die Beobachtung allein beweist den Defekt nicht_. Ein Agent, der E1 blind behebt, eine Regel unterdrückt oder eine Regel ändert, um den Score zu heben, tut genau das, was dieses Tool finden soll – deshalb sagt die Übergabe das im Prompt, direkt neben dem Befund.
493
521
 
494
- ### Changed-Scope-Abdeckung
522
+ <br />
495
523
 
496
- `--scope changed` attribuiert Befunde zu Zeilen, die dein Branch
497
- gegenüber dem Merge-Base mit `main` hinzugefügt hat. Es deckt
498
- Testdateien (`*.spec.*`, `*.test.*`) plus GitHub-Workflow-Dateien und
499
- Playwright-Konfigurationen im Diff ab. Wenn sich das Merge-Base nicht
500
- auflösen lässt — flacher Clone, detached HEAD, Nicht-git-Ziel,
501
- abweichender Default-Branch — degradiert es ehrlich: Befunde fallen auf
502
- Full-File-Attribution zurück, und der Bericht sagt es. Überschreibe die
503
- Base-Ref mit `--base <ref>`.
524
+ ## Vertrauen und Sicherheit
504
525
 
505
- ---
526
+ **Local-first, null Telemetrie.** Keine netzwerkfähige API (`fetch`, `http`, `https`, `net`, `dns`, `dgram`, WebSocket) existiert irgendwo in `src/`, und [`privacy-network-isolation.spec.ts`](tests/contract/privacy-network-isolation.spec.ts) lässt den Build fehlschlagen, sobald eine auftaucht. Es verbietet auch `eval` und `new Function`. Das Scannen nicht vertrauenswürdigen Codes führt ihn nie aus: Die statische Analyse liest Quelltext, und die Forensik parst Reportdateien, die bereits auf der Platte liegen.
506
527
 
507
- ## Konfiguration
528
+ Zwei Einschränkungen: `npx` selbst lädt das Paket herunter, bevor irgendetwas läuft, und die Garantie gilt für `src/`, nicht für Plugins von Drittanbietern.
508
529
 
509
- Mjölnir ist Zero-Config. Eine optionale `mjolnir.config.json` (oder
510
- `.mjolnir.json`) im Repo-Root stimmt Severity, Gating und Scope ab —
511
- sie ändert nie die Erkennungssemantik.
530
+ **Plugins laufen nicht in einer Sandbox.** JS-Plugins (`mjolnir-rules/*.mjs` oder unter `"plugins"` gelistete npm-Pakete) laufen mit vollen Node-Rechten, dasselbe Vertrauensmodell wie bei ESLint- oder Vitest-Plugins. Sie zu laden ist ein Opt-in **pro Scan**: Ohne `--enable-plugins` (oder `MJOLNIR_ENABLE_PLUGINS=1`) werden ihre Quellen nie geladen, und ein Hinweis auf stderr listet auf, was übersprungen wurde. JSON-Regelmanifeste führen keinen Code aus, und die Präfixe der Core-Regel-IDs sind reserviert, damit sich kein Plugin als eine davon ausgeben kann. Melde Schwachstellen über [SECURITY.md](SECURITY.md).
512
531
 
513
- | Key | Typ | Wirkung |
514
- | ------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
515
- | `exclude` | `string[]` | Zusätzliche Ignore-Globs (gitignore-Teilmenge), über den eingebauten Defaults |
516
- | `gate` | `"advisory" \| "error" \| "warning"` | Welche Severities mit Wert ungleich null beenden (Default `error`; `advisory` blockiert nie) |
517
- | `severityOverrides` | `{ "<RULE-ID>": severity }` | Rangiert die Befunde einer Regel für dein Repo um |
518
- | `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) |
519
- | `plugins` | `string[]` | Drittanbieter-Regelpakete (siehe [Vertrauensmodell](#vertrauensmodell)) |
532
+ **Es läuft auf sich selbst.** Eine Verification Trust Engine hat keine Glaubwürdigkeit, wenn sie nicht selbst verifizierbar ist. Jeder CI-Lauf scannt dieses Repository mit dem Build, den derselbe Lauf erzeugt hat. Das Gate schlägt bei jedem Befund mit Schweregrad error fehl, und ebenso bei einem **partiellen** Scan oder einer **abgestürzten Regel**, denn ein abgeschnittener Selbstscan, der nichts meldet, ist genau das falsche Grün, das dieses Projekt finden soll. `mjolnir doctor` prüft die Regelbasis im selben Lauf erneut (Fixture-Firewall, Ehrlichkeit der Stufen, die Obergrenze für core), und eine INCONCLUSIVE-Prüfung schlägt genauso fehl wie eine fehlgeschlagene. Beide Reports werden als Build-Artefakte hochgeladen.
520
533
 
521
- ```json
522
- {
523
- "gate": "error",
524
- "exclude": ["legacy/**"],
525
- "severityOverrides": { "QA-PW-141": "warning" },
526
- "ignore": [
527
- {
528
- "ruleId": "QA-TEST-004",
529
- "files": ["e2e/legacy-login.spec.ts"],
530
- "reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
531
- "expires": "2026-12-31"
532
- }
533
- ]
534
- }
535
- ```
534
+ ### Exit-Codes und der Maschinenvertrag
536
535
 
537
- - **`.mjolnirignore`** — eine schlichte gitignore-artige Datei für
538
- Pfad-Ausschlüsse, gleicher Dialekt wie `exclude`. Nutze sie für
539
- maschinenweites Rauschen; nutze `exclude`, wenn die Liste in die
540
- Versionskontrolle gehört, neben dem Rest der Konfiguration.
541
- - **CLI-Overrides** — `--strict` (Quarantine-Regeln einschließen),
542
- `--width <cols>` und `--ascii` / `--no-ascii` (Terminal-Rendering),
543
- `--tone blunt` (schärfere Meldungen), `--max-duration <sec>`
544
- (begrenzter Teil-Scan).
545
- - Regel-Unterdrückung und Deprecation-Lebenszyklus:
546
- [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
547
-
548
- `ignore`-Einträge speisen auch den eigenständigen Befehl
549
- `mjolnir suppressions`, der auflistet, was aktuell unterdrückt ist und
550
- wann jeder Eintrag abläuft.
551
-
552
- ---
553
-
554
- ## 📐 Exit-Codes & Verträge
555
-
556
- Eingefroren — sicher, um CI-Logik darauf zu bauen:
557
-
558
- | Exit-Code | Bedeutung |
559
- | --------- | ------------------------------------------------------------------ |
560
- | `0` | Sauber — keine Befunde auf oder über dem Gate |
561
- | `1` | Befunde auf oder über dem Gate |
562
- | `2` | Teil-Scan (Zeitbudget erreicht, unlesbare Dateien) — blockiert nie |
563
- | `10` | Verwendungsfehler (bad flag, fehlendes Ziel) |
564
- | `20` | Interner Fehler |
565
-
566
- Der JSON/SARIF-Bericht ist `schemaVersion: 1`. Regel-IDs
567
- (`QA-<FAMILY>-NNN`) sind nach dem Shipment unveränderlich und werden
568
- nie wiederverwendet.
569
-
570
- ---
571
-
572
- ## Vertrauensmodell
573
-
574
- - **Local-first** — null Netzwerkaufrufe während des Scannens. Nie.
575
- Null Telemetrie.
576
- - **Kein falscher Beweis** — wir sagen lieber „unbekannt“ als
577
- „verifiziert“. Ein leeres Repo bekommt `score: null`, nie eine fake 100.
578
- - **Partielle Ehrlichkeit** — wenn die Analyse vorzeitig abgebrochen
579
- wurde, sagt die Ausgabe es. Nie „complete“, wenn es nicht stimmt.
580
- - **FP-Firewall** — Erkennung läuft auf einer comment-/string-freien
581
- Sicht des Codes (TypeScript-Regeln nutzen den Compiler-AST): ein
582
- Muster in einem Prosa-Kommentar oder einem Doc-Beispiel-String ist
583
- Dokumentation, kein Befund.
584
- - **Gemessen, nicht behauptet** — nur Regeln mit einer
585
- False-Positive-Rate aus echtem OSS-Code fahren in den
586
- Headline-Tiers (siehe [Wie viel davon gemessen ist](#wie-viel-davon-gemessen-ist));
587
- der Scan-Footer und `mjolnir rules --unmeasured` sagen dir, welche
588
- welche sind.
589
- - **Plugin-Vertrauen & Ausführungs-Gate** — Plugins sind npm-Pakete,
590
- deklariert unter `"plugins"`; JS-Module liegen in `mjolnir-rules/*.mjs`.
591
- Es gibt **keine Sandbox**: Plugin-Code läuft mit vollen
592
- Node-Privilegien, dasselbe Vertrauensmodell wie ESLint- oder
593
- Vitest-Plugins. Deshalb ist Code-Ausführung **bei jedem Scan
594
- Opt-in**: Übergib `--enable-plugins` (oder setze
595
- `MJOLNIR_ENABLE_PLUGINS=1`), sonst werden die Quellen NICHT geladen —
596
- ein deutlicher stderr-Hinweis listet genau, was übersprungen wurde.
597
- Das Scannen nicht vertrauenswürdigen Codes führt ihn nie aus.
598
- JSON-Regel-Manifeste (`mjolnir-rules/*.json`) sind davon unberührt:
599
- sie deklarieren Regex-Muster und führen per Design keinen Code aus.
600
- Kern-Regel-ID-Präfixe sind reserviert und werden von Plugins und
601
- externen Regeln abgelehnt, um Spoofing zu verhindern.
602
- - **Workspace-lokale externe Regeln** (ordnerbasiert, null Netzwerk) —
603
- ein `mjolnir-rules/`-Verzeichnis neben dem Scan-Ziel lädt eigene
604
- Regeln: JSON-Dateien deklarieren Regex-Muster (kein Code wird
605
- ausgeführt), `.mjs`/`.js`-Module exportieren `rules` (Full-Node-Vertrauen,
606
- wie Plugins). Externe Regeln tragen dieselben Trust-Metadaten wie
607
- Core; sie können nie im Core-Tier fahren (Core verlangt eine
608
- gemessene FP-Rate aus dem Corpus-Sidecar — ein deklariertes
609
- `tier: "core"` wird auf `extended` geklemmt), gehorchen Tier-Caps und
610
- sind drift-geprüft: `mjolnir rules --md --external` rendert den
611
- Katalog aus den geladenen Dateien (Provenienz `external`), und der
612
- Matrix-Generator akzeptiert `--external <root>`.
613
-
614
- ---
615
-
616
- ## 🏗️ Architektur
536
+ Eingefroren, damit du CI-Logik darauf bauen kannst:
617
537
 
618
- <details>
619
- <summary>Baum ausklappen</summary>
538
+ | Exit-Code | Bedeutung |
539
+ | --------- | ------------------------------------------------------------------------ |
540
+ | `0` | Sauber: keine Befunde auf oder über dem Gate |
541
+ | `1` | Befunde auf oder über dem Gate |
542
+ | `2` | Partieller Scan (Zeitbudget erreicht, unlesbare Dateien). Blockiert nie. |
543
+ | `10` | Bedienfehler (falsches Flag, fehlendes Ziel) |
544
+ | `20` | Interner Fehler |
620
545
 
621
- ```
622
- mjolnir/
623
- ├── src/
624
- │ ├── engine/ # LanguageAdapter interface + rule runner
625
- │ ├── adapters/ # typescript · python · java · csharp · github-actions
626
- │ ├── rules/ # rules across 8 families + the measured-FP table
627
- │ ├── playwright/ # Selector Health Score engine
628
- │ ├── discovery/ # workspace, frameworks, ignore resolution
629
- │ ├── scope/ # git merge-base changed-scope engine
630
- │ ├── scorer/ # transparent deduction table + prioritization
631
- │ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
632
- │ ├── forensics/ # run-data ingestion · flake verdicts · triage
633
- │ ├── config/ # mjolnir.config.json + suppressions
634
- │ ├── plugins/ # third-party rule loading (no sandbox)
635
- │ └── commands/ # every subcommand
636
- └── tests/
637
- ├── fixtures/ # must-fire / must-not-fire per rule
638
- └── golden/ # frozen score regression locks
639
- ```
546
+ `2` ist bewusst von `0` verschieden: Ein Scan, der nicht fertig wurde, hat nicht nichts gefunden. Er ist nur mit dem Suchen nicht fertig geworden.
640
547
 
641
- </details>
548
+ Alles, was eine Maschine konsumiert (MCP-Tool-Ergebnisse, `--json`, SARIF 2.1), stammt aus einem kanonischen Ergebnis unter einem versionierten, **nur additiv erweiterten** Schema (`schemaVersion: 1`, `contractVersion: 1`), sodass kein Konsument Bedeutung aus gerendertem Text rekonstruieren muss. Siehe [den Maschinenvertrag](docs/machine-contract.md). Regel-IDs (`QA-<FAMILY>-NNN`) sind nach der Auslieferung unveränderlich und werden nie wiederverwendet.
549
+
550
+ <br />
642
551
 
643
- - **Regeln sind reine Funktionen** — `(SourceFileContext) → Finding[]`,
644
- kein I/O, keine Globals. Ein neues Ökosystem = ein Adapter + seine
645
- Regeln.
646
- - **TypeScript/Playwright nutzt den Compiler-AST** (ts-morph). Python,
647
- Java und C# laufen auf einer gemeinsamen comment-/string-maskierten
648
- Regex-Schicht.
649
- - Eine Tree-sitter-WASM-AST-Schicht für Java und C# existiert und ist
650
- der nächste Präzisionsschritt — sie ist noch nicht in die synchrone
651
- Scan-Pipeline verdrahtet.
552
+ ## Was Mjölnir dir nicht sagen kann
652
553
 
653
- ---
554
+ - **Es führt deine Tests nicht aus.** Ein sauberer Scan ist keine bestandene Suite.
555
+ - **Es kann dir nicht sagen, dass eine Assertion _falsch_ ist.** `expect(total).toBe(41)` sieht gesund aus. Mjölnir findet Tests, die _nicht fehlschlagen können_, und Pipelines, die _nicht rot werden können_, keine Tests, die das Falsche prüfen.
556
+ - **Es beweist keine fachliche Korrektheit.** Nichts hier sagt, dass dein Produkt tut, was die Anforderung verlangt hat.
557
+ - **Eine 100 ist kein Beweis für eine gute Suite.** Ob deine Suite dein echtes Risiko abdeckt, ist eine andere Frage, und dieses Tool beantwortet sie nicht.
558
+ - **5 von 79 Regeln laufen auf einer Schätzung**, nicht auf einer gemessenen Rate. Jede davon sagt das auf ihrem eigenen Befund.
559
+ - **E1 ist nicht E2.** Heuristische Befunde sind es wert, gelesen zu werden, nicht, blind angewendet zu werden.
560
+ - **Ein leeres Repo bekommt `null`, nie 100.**
561
+ - **Eine Datei namens `*.spec.ts` ohne Testdeklarationen zählt nicht als Abdeckung.** Ein Repo, dessen einzige Spec-Dateien Imports oder Typen enthalten (null `it`/`test`-Aufrufe), bekommt `null`, nicht 100.
654
562
 
655
- ## 📚 Dokumentation
563
+ <br />
656
564
 
657
- | Dokument | Was drinsteht |
658
- | ------------------------------------------------------ | ----------------------------------------- |
659
- | [docs/SCORING.md](docs/SCORING.md) | Score-Normalisierung + Evidenzgewichtung |
660
- | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Gemessene False-Positive-Raten + Methode |
661
- | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Regelzustände, Unterdrückung, Deprecation |
662
- | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | SARIF-Ausgabe + Editor/CI-Setup |
663
- | [docs/rules/](docs/rules/) | Generierter Pro-Regel-Katalog |
664
- | [CONTRIBUTING.md](CONTRIBUTING.md) | Dev-Setup + Beitrags-Workflow |
665
- | [CHANGELOG.md](CHANGELOG.md) | Release-Historie |
666
- | [SECURITY.md](SECURITY.md) | Schwachstellenmeldung |
565
+ ## Dokumentation
667
566
 
668
- ---
567
+ Die vollständige Doku-Website findest du unter <https://sergey-bar.github.io/Mjolnir/>.
669
568
 
670
- ## 📈 Status
569
+ | Dokument | Was drinsteht |
570
+ | ------------------------------------------------------ | ------------------------------------------------------------------ |
571
+ | [docs/SCORING.md](docs/SCORING.md) | Score-Normalisierung und Evidenzgewichtung |
572
+ | [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md) | Kanonisches Vokabular: ein Wort pro Begriff |
573
+ | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Gemessene Falsch-Positiv-Raten und die Methode |
574
+ | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Regelzustände, Stufen, Unterdrückung, Abkündigung |
575
+ | [docs/VERSIONING.md](docs/VERSIONING.md) | Semver-Richtlinie, eingefrorene Schnittstellen, Abkündigungszyklus |
576
+ | [docs/machine-contract.md](docs/machine-contract.md) | Das kanonische maschinenlesbare Ergebnis |
577
+ | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | SARIF-Ausgabe und Editor- oder CI-Einrichtung |
578
+ | [docs/GITLAB-CI.md](docs/GITLAB-CI.md) | GitLab: Code-Quality-Report, MR-Rezept, Gate |
579
+ | [docs/rules/](docs/rules/) | Generierter Katalog pro Regel |
580
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Entwicklungsumgebung und Beitrags-Workflow |
581
+ | [SUPPORT.md](SUPPORT.md) | Wo man fragt, meldet und Hilfe bekommt |
582
+ | [SECURITY.md](SECURITY.md) | Melden von Schwachstellen |
583
+ | [CHANGELOG.md](CHANGELOG.md) | Versionshistorie |
671
584
 
672
- **v0.5.x · offene Beta.** Das JSON-Schema und die Exit-Codes sind
673
- eingefrorene Verträge. TypeScript und Python haben die breiteste
674
- gemessene Abdeckung; Java und C# sind neuer — lies sie durch die
675
- [Tiers-Tabelle](#regel-tiers-und-sprachreife).
585
+ ### Status
676
586
 
677
- ---
587
+ **Version 1.** Das JSON-Schema und die Exit-Codes sind eingefrorene Verträge. TypeScript und Python haben die breiteste gemessene Abdeckung. Java und C# sind neuer; lies sie durch die [Reifetabelle](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle). Was als Nächstes kommt, ohne erfundene Termine: [die öffentliche Roadmap](https://sergey-bar.github.io/Mjolnir/reference/roadmap).
678
588
 
679
- ## 🤝 Mitwirken
589
+ ### Mitwirken
680
590
 
681
- Neue Regeln sind der einfachste erste Beitrag — ein Befehl scaffolded
682
- die Regel plus ihre Must-Fire- **und** Must-Not-Fire-Fixtures (die
683
- generierte Regel schlägt absichtlich in ihren Fixtures fehl, bis du
684
- echte Detektion implementierst — ein Stub kann nicht geshippt werden):
591
+ Neue Regeln sind der einfachste erste Beitrag. Ein Befehl erzeugt das Gerüst der Regel mit ihren Must-fire- **und** Must-not-fire-Fixtures. Die erzeugte Regel besteht ihre eigenen Fixtures absichtlich nicht, bis echte Erkennung geschrieben ist, denn ein ausgelieferter Stub ist eine Regel, die niemand gemessen hat:
685
592
 
686
593
  ```bash
687
594
  mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
688
595
  ```
689
596
 
690
- Volles Dev-Setup, die Standing-Gate-Befehle und die
691
- Anti-Creep-/Fixture-Firewall-Gesetze stehen in
692
- [CONTRIBUTING.md](CONTRIBUTING.md).
597
+ Die Entwicklungsumgebung, die Befehle der ständigen Gates sowie die Anti-Creep- und Fixture-Firewall-Gesetze stehen in [CONTRIBUTING.md](CONTRIBUTING.md).
693
598
 
694
- ---
599
+ <br />
695
600
 
696
601
  <div align="center">
697
602
 
698
- **Ship keine Tests, denen du nicht vertraust.**
603
+ <img src="assets/readme/closing.svg" alt="Lass es auf dein Repo los." width="100%" />
699
604
 
700
605
  ```bash
701
606
  npx mjolnir-qa@latest
702
607
  ```
703
608
 
704
- **Star ⭐ · Watch 👀 · Contribute 🤝**
609
+ [Zum Leitfaden](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [Doku-Website](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)
610
+
611
+ <br />
612
+
613
+ Frag nicht, ob die Tests bestanden haben.<br />
614
+ Frag, ob die Evidenz beweist, dass sie Vertrauen verdienen.
705
615
 
706
- Gebaut von [Sergey Bar](https://www.linkedin.com/in/sergeybar/)
616
+ <sub>Entwickelt von [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · MIT-lizenziert</sub>
707
617
 
708
618
  </div>