mjolnir-qa 1.0.9 → 2.0.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/CHANGELOG.md +204 -0
- package/README.ar.md +434 -478
- package/README.bn.md +434 -491
- package/README.br.md +434 -520
- package/README.bs.md +431 -500
- package/README.da.md +433 -509
- package/README.de.md +432 -522
- package/README.es.md +428 -517
- package/README.fr.md +426 -520
- package/README.gr.md +433 -517
- package/README.he.md +433 -475
- package/README.it.md +436 -525
- package/README.ja.md +436 -506
- package/README.ko.md +434 -494
- package/README.md +453 -438
- package/README.no.md +435 -509
- package/README.pl.md +433 -511
- package/README.ru.md +434 -515
- package/README.th.md +434 -484
- package/README.tr.md +427 -504
- package/README.uk.md +433 -505
- package/README.vi.md +436 -494
- package/README.zh.md +433 -462
- package/README.zht.md +433 -462
- package/dist/cli.d.mts +716 -110
- package/dist/cli.mjs +9815 -22027
- package/dist/mcp/stdio.mjs +2164 -886
- package/dist/rolldown-runtime-8H4AJuhK.mjs +14 -0
- package/dist/scan-pipeline-C0ka-RmX.mjs +2 -0
- package/dist/scan-pipeline-D3Yk2cef.mjs +15309 -0
- package/package.json +14 -8
package/README.de.md
CHANGED
|
@@ -1,403 +1,431 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="assets/readme/
|
|
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
|
-
|
|
5
|
+
<br />
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
12
|
-
[](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
|
|
13
|
-
[](LICENSE)
|
|
14
|
-
[](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
|
-
|
|
12
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
13
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
14
|
+
[](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
|
|
15
|
+
[](https://codecov.io/gh/Sergey-Bar/Mjolnir)
|
|
16
|
+
[](https://scorecard.dev/viewer/?uri=github.com/Sergey-Bar/Mjolnir)
|
|
17
|
+
[](LICENSE)
|
|
18
|
+
[](https://nodejs.org)
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
npx mjolnir-qa@latest
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
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
|
-
|
|
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 80/100 WORTHY, 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
|
-
|
|
92
|
+
<br />
|
|
38
93
|
|
|
39
94
|
<p align="center">
|
|
40
|
-
<
|
|
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>
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
87
|
-
|
|
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
|
-
|
|
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
|
-
|
|
94
|
-
|
|
160
|
+
<br />
|
|
161
|
+
|
|
162
|
+
## Schnellstart
|
|
95
163
|
|
|
96
164
|
```bash
|
|
97
165
|
npx mjolnir-qa@latest
|
|
98
166
|
```
|
|
99
167
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
|
|
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
|
|
127
|
-
| `mjolnir
|
|
128
|
-
| `mjolnir
|
|
129
|
-
| `mjolnir
|
|
130
|
-
|
|
131
|
-
|
|
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>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
| `mjolnir
|
|
141
|
-
| `mjolnir
|
|
142
|
-
| `mjolnir
|
|
143
|
-
| `mjolnir
|
|
144
|
-
| `mjolnir
|
|
145
|
-
| `mjolnir
|
|
146
|
-
| `mjolnir
|
|
147
|
-
| `mjolnir
|
|
148
|
-
| `mjolnir
|
|
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
|
-
|
|
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
|
-
##
|
|
230
|
+
## Was Mjölnir findet
|
|
173
231
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
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
|
|
208
|
-
| ------------ |
|
|
209
|
-
| QA-
|
|
210
|
-
| QA-
|
|
211
|
-
| QA-
|
|
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
|
-
|
|
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>
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
|
223
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
243
|
-
<summary><strong>Python / pytest 🐍</strong></summary>
|
|
303
|
+
### Selector Health Score
|
|
244
304
|
|
|
245
|
-
|
|
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
|
-
|
|
307
|
+
```text
|
|
308
|
+
▍ SELECTOR HEALTH
|
|
253
309
|
|
|
254
|
-
|
|
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
|
-
|
|
257
|
-
|
|
314
|
+
e2e/checkout.spec.ts
|
|
315
|
+
[██████████████████░░] 88 / 100
|
|
316
|
+
role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
|
|
317
|
+
```
|
|
258
318
|
|
|
259
|
-
|
|
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
|
-
|
|
321
|
+
<br />
|
|
268
322
|
|
|
269
|
-
|
|
270
|
-
<summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
|
|
323
|
+
## Der Worthiness-Score
|
|
271
324
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
|
|
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
|
-
**
|
|
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
|
-
|
|
343
|
+
<br />
|
|
304
344
|
|
|
305
|
-
|
|
306
|
-
ihrer **gemessenen** False-Positive-Rate:
|
|
345
|
+
## Das Evidenzmodell
|
|
307
346
|
|
|
308
|
-
|
|
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
|
-
|
|
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
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
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/
|
|
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
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
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
|
-
|
|
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
|
-
|
|
376
|
+
### Wie viel davon gemessen ist
|
|
346
377
|
|
|
347
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
367
|
-
|
|
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
|
-
|
|
395
|
+
Beförderung, Herabstufung und Reife pro Sprache: [Regel-Lebenszyklus](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle).
|
|
372
396
|
|
|
373
|
-
|
|
374
|
-
Locators sind:
|
|
397
|
+
### Warum das kein Linter ist
|
|
375
398
|
|
|
376
|
-
|
|
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
|
-
|
|
380
|
-
|
|
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
|
-
|
|
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
|
-
|
|
417
|
+
<br />
|
|
390
418
|
|
|
391
|
-
|
|
392
|
-
|
|
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
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
-
|
|
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
|
-
|
|
435
|
-
Linten:
|
|
476
|
+
### Zuordnung im Changed-Scope
|
|
436
477
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
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
|
-
|
|
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
|
-
|
|
486
|
+
<br />
|
|
449
487
|
|
|
450
|
-
|
|
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
|
-
|
|
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
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
|
|
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
|
-
|
|
476
|
-
blockierend:
|
|
504
|
+
Füge es einem Client hinzu, der eine eigene CLI mitbringt:
|
|
477
505
|
|
|
478
506
|
```bash
|
|
479
|
-
mjolnir
|
|
507
|
+
claude mcp add mjolnir -- npx -y mjolnir-qa@latest mcp
|
|
480
508
|
```
|
|
481
509
|
|
|
482
|
-
Oder
|
|
510
|
+
Oder jedem Client, der einen `mcpServers`-Block akzeptiert:
|
|
483
511
|
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
512
|
+
```json
|
|
513
|
+
{
|
|
514
|
+
"mcpServers": {
|
|
515
|
+
"mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@latest", "mcp"] }
|
|
516
|
+
}
|
|
517
|
+
}
|
|
489
518
|
```
|
|
490
519
|
|
|
491
|
-
|
|
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
|
-
|
|
522
|
+
<br />
|
|
495
523
|
|
|
496
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
619
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
563
|
+
<br />
|
|
656
564
|
|
|
657
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
589
|
+
### Mitwirken
|
|
680
590
|
|
|
681
|
-
Neue Regeln sind der einfachste erste Beitrag
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
616
|
+
<sub>Entwickelt von [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · MIT-lizenziert</sub>
|
|
707
617
|
|
|
708
618
|
</div>
|