mjolnir-qa 0.4.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.pl.md ADDED
@@ -0,0 +1,699 @@
1
+ <div align="center">
2
+
3
+ <img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
4
+
5
+ ### Twoje testy kłamią. My to dowodzimy.
6
+
7
+ **Verification Trust Engine dla QA.** Mjölnir audytuje suite testowe i
8
+ pipeline'y CI, raportuje wskaźnik wiarygodności i pokazuje dokładnie,
9
+ gdzie zaufanie się łamie.
10
+
11
+ [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=C9A227&labelColor=0B0F17)](https://www.npmjs.com/package/mjolnir-qa)
12
+ [![ci](https://img.shields.io/github/actions/workflow/status/Sergey-Bar/Mjolnir/ci.yml?branch=main&style=flat-square&label=ci&labelColor=0B0F17)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
13
+ [![license](https://img.shields.io/badge/license-MIT-C9A227.svg?style=flat-square&labelColor=0B0F17)](LICENSE)
14
+ [![node](https://img.shields.io/badge/node-%E2%89%A5%2022.18-2E8C7F.svg?style=flat-square&labelColor=0B0F17)](https://nodejs.org)
15
+
16
+ [English](README.md) | [简体中文](README.zh.md) | [繁體中文](README.zht.md) | [한국어](README.ko.md) | [Deutsch](README.de.md) | [Español](README.es.md) | [Français](README.fr.md) | [Italiano](README.it.md) | [Dansk](README.da.md) | [日本語](README.ja.md) | Polski | [Русский](README.ru.md) | [Norsk](README.no.md) | [Português (Brasil)](README.br.md) | [ไทย](README.th.md) | [Türkçe](README.tr.md) | [Українська](README.uk.md) | [বাংলা](README.bn.md) | [Ελληνικά](README.gr.md) | [Tiếng Việt](README.vi.md) | [עברית](README.he.md) | [العربية](README.ar.md) | [Bosanski](README.bs.md)
17
+
18
+ > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-04.
19
+
20
+ ```bash
21
+ npx mjolnir-qa@latest
22
+ ```
23
+
24
+ **Czy twoje testy zasługują na zaufanie?**
25
+
26
+ [Zobacz w akcji](#-zobacz-w-akcji) ·
27
+ [Szybki start](#-szybki-start) ·
28
+ [Co sprawdza](#-co-sprawdza-mjölnir) ·
29
+ [Punktacja](#jak-działa-punktacja) ·
30
+ [CI](#-integracja-ci) · [Konfiguracja](#konfiguracja) ·
31
+ [Dokumentacja](#-dokumentacja)
32
+
33
+ </div>
34
+
35
+ ---
36
+
37
+ ## 🎬 Zobacz w akcji
38
+
39
+ <p align="center">
40
+ <img src="assets/readme/demo.svg" alt="Pełny raport --verbose Mjölnir na demo repo: WORTHINESS 75/100 NEEDS WORK, rozbicie diagnostyki wg kategorii, lista FIX THIS FIRST i każde znalezisko z ID reguły i numerem linii — CI, Playwright, higiena testów i reguły Pythona" width="900" />
41
+ </p>
42
+
43
+ <sub>Kompletny wynik `npx mjolnir-qa ./examples/demo-repo --verbose`,
44
+ wyrenderowany przez prawdziwy reporter — nic nie ucięto. Regenerowany
45
+ przez `npm run docs:demo`;
46
+ [`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
47
+ wywala CI, jeśli artefakt odjechał od tego, co wypisuje narzędzie.</sub>
48
+
49
+ **Co właśnie się stało:**
50
+
51
+ 1. Mjölnir znalazł specyfikacje Playwright, swoją konfigurację,
52
+ workflow CI i plik testowy Pythona — cztery języki/formaty, jeden
53
+ przebieg.
54
+ 2. Znalazł dowody osłabiające zaufanie do suity — `continue-on-error`
55
+ maskujący job, `|| true` połykający kod wyjścia, twarde sleepy,
56
+ kruchy selektor, zaszyte na sztywno URL-e stagingu, czekanie
57
+ `networkidle`.
58
+ 3. Każdy z nich zamienił w konkretne znalezisko z ID reguły, miejscem
59
+ i fixem — oraz w jedną punktację, na której można gate'ować PR.
60
+
61
+ ### Jedno znalezisko z bliska
62
+
63
+ Uruchom `mjolnir explain QA-CI-001` na pierwszym znalezisku powyżej, a
64
+ otrzymasz:
65
+
66
+ ```text
67
+ ▚▞ QA-CI-001 — continue-on-error masks a failing verification gate
68
+
69
+ Severity: error
70
+ Confidence: high
71
+ Evidence: E2
72
+ Measured FP: not yet measured — this rule ships on assumption (see docs/FP-AUDIT.md)
73
+
74
+ WHAT WAS FOUND (real detector output, not a mockup)
75
+ Job `security-scan` runs a verification gate under `continue-on-error: true`.
76
+
77
+ WHY IT MATTERS
78
+ This job can fail every day and CI will still show green. The checkmark
79
+ on this workflow cannot be trusted.
80
+
81
+ HOW TO FIX
82
+ Remove continue-on-error, or scope it to individual non-blocking steps only.
83
+ ```
84
+
85
+ To jest jednostka wartości: nie czepialstwo stylistyczne, lecz miejsce,
86
+ gdzie twój CI mówi ci, że coś przeszło, choć nie przeszło.
87
+
88
+ ---
89
+
90
+ ## ⚡ Szybki start
91
+
92
+ Uruchom na repozytorium — dostaniesz pełny raport i wskaźnik
93
+ wiarygodności:
94
+
95
+ ```bash
96
+ npx mjolnir-qa@latest
97
+ ```
98
+
99
+ **W CI produktem jest jedna komenda.** Skanuje tylko to, czego dotknął
100
+ branch, i kończy się kodem niezerowym przy nowych problemach:
101
+
102
+ ```bash
103
+ npx mjolnir-qa@latest --scope changed
104
+ ```
105
+
106
+ Wrzuć to jako check w PR — `mjolnir ci install` pisze workflow — i
107
+ gotowe. Wszystko inne jest opcjonalne.
108
+
109
+ | Komenda | Co robi |
110
+ | ----------------------------------- | -------------------------------------------------------- |
111
+ | `mjolnir` | Skan całego repo + wskaźnik wiarygodności |
112
+ | `mjolnir --scope changed` | Tylko to, co wprowadził twój branch — wariant CI |
113
+ | `mjolnir ci install` | Generuje doradczy workflow PR |
114
+ | `mjolnir explain QA-CI-001` | Co / dlaczego / fix + zmierzona stopa FP dla reguły |
115
+ | `mjolnir rules --unmeasured` | Reguły działające na założeniu, nie na pomiarze |
116
+ | `mjolnir --json` / `--format sarif` | Czytelne maszynowo / GitHub Code Scanning |
117
+ | `mjolnir --strict` | Uruchamia też reguły tieru quarantine (wyższe ryzyko FP) |
118
+
119
+ <details>
120
+ <summary><strong>Gdy coś jest flaky</strong></summary>
121
+
122
+ | Komenda | Co robi |
123
+ | ----------------------------------- | ----------------------------------------------------------------- |
124
+ | `mjolnir forensics ./test-results/` | Prawdziwe dane przebiegów → werdykty `TRUE-FLAKE`, `FLAKY.md` |
125
+ | `mjolnir triage ./test-results/` | Propozycja kwarantanny z historii wykonania |
126
+ | `mjolnir pw-report ./test-results/` | Podsumowanie przebiegu Playwright — retry / flaki / najwolniejsze |
127
+ | `mjolnir doctor:playwright` | Głęboki skan tylko Playwright + Selector Health Score |
128
+
129
+ </details>
130
+
131
+ <details>
132
+ <summary><strong>Okazjonalnie / raporty</strong></summary>
133
+
134
+ | Komenda | Co robi |
135
+ | ------------------------------- | --------------------------------------------------------- |
136
+ | `mjolnir fix --dry-run` / `fix` | Bezpieczne autofiksy z dowodem |
137
+ | `mjolnir baseline` / `diff` | Migawka znalezisk, potem raport tylko nowych/pogorszonych |
138
+ | `mjolnir impact --since <ref>` | Co się zmieniło od wcześniejszego commita |
139
+ | `mjolnir debt` | Rejestr długu testowego z modelem kosztów |
140
+ | `mjolnir handover` | Mapa onboardingu suity dla nowego QA |
141
+ | `mjolnir stats` | Lokalne liczniki wszystkich widzianych fixów |
142
+ | `mjolnir badge` | JSON endpointu shields.io + snippet |
143
+ | `mjolnir rules --md` | Pełny katalog reguł (JSON albo Markdown) |
144
+ | `mjolnir doctor` | Samoaudyt własnej bazy reguł Mjölnir |
145
+ | `mjolnir create-rule <ID>` | Szkielet nowej reguły + fixture |
146
+ | `mjolnir --format mermaid` | Diagram architektury testów do komentarza PR |
147
+
148
+ </details>
149
+
150
+ Zainstaluj globalnie zamiast `npx`, jeśli wolisz: `npm i -g mjolnir-qa`.
151
+ Wymaga Node.js ≥ 22.18. Działa na Windows, macOS i Linux.
152
+
153
+ ---
154
+
155
+ ## 👥 Dla kogo to jest?
156
+
157
+ - **QA / SDET** posiadający suitę e2e lub integracyjną, którzy
158
+ potrzebują dowodów, że suita naprawdę zasługuje na zielony check,
159
+ jaki wystawia.
160
+ - **Zespoły Platform / DevEx** odpowiedzialne za integralność CI i
161
+ release gate'y — ludzie, dla których `continue-on-error` nie może
162
+ nigdy po cichu przemalować czerwonego pipeline'u na zielono.
163
+ - **Maintainerzy OSS**, którzy chcą taniego, zawsze włączonego gate'a
164
+ weryfikacyjnego, działającego lokalnie i w CI bez wywołań sieciowych.
165
+
166
+ ---
167
+
168
+ ## 🔨 Co sprawdza Mjölnir
169
+
170
+ | | |
171
+ | --- | ------------------------------------------------------------------------------------------------------------------------------------- |
172
+ | ⚖️ | **Wskaźnik wiarygodności** — jedna liczba, przejrzysta tabela potrąceń, żadna czarna skrzynka |
173
+ | 🎭 | **Selector Health Score** — ocenia twoje lokatory Playwright, a nie tylko pass rate |
174
+ | 🔬 | **Kryminalistyka runtime** — czyta prawdziwe dane przebiegów Playwright/JUnit, by złapać `TRUE-FLAKE`, nie tylko statyczne zgadywanki |
175
+ | 🚨 | **Reguły integralności CI** — łapie `continue-on-error`, `\|\| true` i inne triki na fałszywą zieleń |
176
+ | 🐍 | **Wszystkie cztery bindingi Playwright** — TypeScript, Python, Java, C#/.NET — plus pytest, JUnit/TestNG i workflow CI |
177
+ | 🔒 | **Local-first** — zero wywołań sieciowych podczas skanu, zero telemetrii, działa w sekundy |
178
+
179
+ ### Reguły
180
+
181
+ Każda reguła jest dostarczana z fixture'ami must-fire **i**
182
+ must-not-fire. Reguła, która odpala na własnej negatywnej fixture,
183
+ nie może się wydać — to zapora na fałszywe pozytywy.
184
+
185
+ <details>
186
+ <summary><strong>Higiena testów</strong></summary>
187
+
188
+ | ID | Reguła | Severity |
189
+ | ----------- | ----------------------------------------------------- | -------- |
190
+ | QA-TEST-001 | Committowany test z fokusem (`.only`, `fit`) | error |
191
+ | QA-TEST-002 | Pominięty test bez uzasadnienia | error |
192
+ | QA-TEST-002 | Pominięty test z zarejestrowanym uzasadnieniem | warning |
193
+ | QA-TEST-003 | Test bez asercji | error |
194
+ | QA-TEST-004 | Twardy sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning |
195
+ | QA-TEST-006 | Nadużywanie retry, ukrywające flakiness | warning |
196
+ | QA-TEST-010 | Puste ciało testu | error |
197
+
198
+ </details>
199
+
200
+ <details>
201
+ <summary><strong>Jakość testów</strong></summary>
202
+
203
+ | ID | Reguła | Severity |
204
+ | ------------ | ----------------------------- | -------- |
205
+ | QA-TQUAL-001 | Weryfikacja wyłącznie mockami | info |
206
+ | QA-TQUAL-002 | Asercja tautologiczna | error |
207
+ | QA-TQUAL-009 | Asercja promise bez await | error |
208
+ | QA-TQUAL-011 | Zakomentowane testy | warning |
209
+
210
+ </details>
211
+
212
+ <details>
213
+ <summary><strong>Playwright 🎭</strong></summary>
214
+
215
+ | ID | Reguła | Severity |
216
+ | --------- | ------------------------------------------- | -------- |
217
+ | QA-PW-002 | Asercja lokatora bez await | error |
218
+ | QA-PW-003 | `page.pause()` / `test.only()` committowane | error |
219
+ | QA-PW-004 | Kruche selektory CSS/XPath | warning |
220
+ | QA-PW-005 | Logika biznesowa wewnątrz `page.evaluate()` | info |
221
+ | QA-PW-114 | Legacy element handles (`page.$`) | info |
222
+ | QA-PW-118 | Czekanie `networkidle` (flaky by design) | info |
223
+ | QA-PW-123 | Zaszyte na sztywno URL-e środowisk | warning |
224
+
225
+ </details>
226
+
227
+ <details>
228
+ <summary><strong>Integralność CI</strong></summary>
229
+
230
+ | ID | Reguła | Severity |
231
+ | --------- | ------------------------------------------------------------------ | -------- |
232
+ | QA-CI-001 | `continue-on-error` maskuje porażki | error |
233
+ | QA-CI-002 | `\|\| true` połyka kody wyjścia | error |
234
+ | QA-CI-005 | Raport konsumowany, ale nigdy nie generowany | error |
235
+ | QA-CI-007 | Wrapper'y retry wokół testów | warning |
236
+ | QA-CI-008 | Zawsze udany step maskuje porażki | error |
237
+ | QA-CI-009 | Kod wyjścia testu niepropagowany (`\|` bez pipefail, łańcuchy `;`) | error |
238
+ | QA-CI-010 | Testy pomijane tam, gdzie muszą blokować (strażniki skip-on-PR) | error |
239
+
240
+ </details>
241
+
242
+ <details>
243
+ <summary><strong>Python / pytest 🐍</strong></summary>
244
+
245
+ | ID | Reguła | Severity |
246
+ | --------- | ------------------------------------------ | -------- |
247
+ | QA-PY-002 | Pominięty test (`skip`, niestrykt `xfail`) | warning |
248
+ | QA-PY-003 | Funkcja testowa bez asercji | error |
249
+ | QA-PY-005 | `time.sleep()` w testach | warning |
250
+ | QA-PY-006 | Puste ciało testu (`pass`) | info |
251
+ | QA-PY-010 | Zależność od losowości/czasu bez freeze | info |
252
+ | QA-PY-012 | Asercja tautologiczna | error |
253
+
254
+ Łącznie 20 reguł Pythona (QA-PY-001…012 higiena pytest + QA-PY-101…108 Playwright-Python).
255
+
256
+ </details>
257
+
258
+ <details>
259
+ <summary><strong>Java / JUnit · TestNG ☕</strong></summary>
260
+
261
+ | ID | Reguła | Severity |
262
+ | --------- | ------------------------------------------ | -------- |
263
+ | QA-JV-101 | Wyłączony test (`@Disabled`) | warning |
264
+ | QA-JV-102 | Twardy sleep (`Thread.sleep()`) | warning |
265
+ | QA-JV-103 | Metoda testowa bez asercji | error |
266
+ | QA-JV-105 | Twardy sleep Playwright `waitForTimeout()` | warning |
267
+ | QA-JV-106 | Kruchy selektor zamiast role lokatora | warning |
268
+ | QA-JV-108 | Zaszyty na sztywno URL środowiska w teście | info |
269
+ | QA-JV-111 | Blanketowy mock `page.route("**")` | info |
270
+
271
+ </details>
272
+
273
+ <details>
274
+ <summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
275
+
276
+ | ID | Reguła | Severity |
277
+ | --------- | -------------------------------------------- | -------- |
278
+ | QA-CS-101 | Pominięty test (`[Ignore]`, `[Fact(Skip=)]`) | warning |
279
+ | QA-CS-102 | Twardy sleep (`Thread.Sleep` / `Task.Delay`) | warning |
280
+ | QA-CS-103 | Metoda testowa bez asercji | error |
281
+ | QA-CS-105 | Twardy sleep `WaitForTimeoutAsync()` | warning |
282
+ | QA-CS-106 | Kruchy selektor zamiast role lokatora | warning |
283
+ | QA-CS-108 | Zaszyty na sztywno URL środowiska w teście | info |
284
+ | QA-CS-111 | Blanketowy mock `page.RouteAsync("**")` | info |
285
+
286
+ </details>
287
+
288
+ > Pełny, żywy katalog — każda reguła z tierem, confidence, ryzykiem
289
+ > fałszywych pozytywów i dostępnością autofixa — jest generowany z
290
+ > rejestru:
291
+ >
292
+ > ```bash
293
+ > mjolnir rules --md
294
+ > ```
295
+ >
296
+ > Strony pojedynczych reguł mieszkają w [`docs/rules/`](docs/rules/).
297
+
298
+ ### Ile z tego jest zmierzone
299
+
300
+ **74 z 99 reguł niesie stopę fałszywych pozytywów zmierzoną na
301
+ prawdziwym kodzie OSS** (≥ 10 ręcznie zaklasyfikowanych znalezisk każda;
302
+ zob. [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Pozostałe 19 wychodzi na
303
+ oszacowaniu autora. Stopka każdego skanu mówi, ile z _odpalonych_
304
+ reguł jest zmierzonych; `mjolnir rules --unmeasured` wypisuje
305
+ niezmierzone; strona `mjolnir explain` każdej reguły deklaruje jej
306
+ status. Publikujemy stopę, nawet gdy jest brzydka — QA-CS-103 audytuje
307
+ się na 95 % i za to trafia do kwarantanny. Powiększanie tej 78-ki to
308
+ stale trwająca praca projektu.
309
+
310
+ ### Tiery reguł i dojrzałość językowa
311
+
312
+ Każda reguła to `core`, `extended` albo `quarantine`, przypisane z jej
313
+ **zmierzoną** stopą fałszywych pozytywów:
314
+
315
+ | Tier | Znaczenie | Skan domyślny | `--strict` |
316
+ | ------------ | ------------------------------------------------ | :-----------: | :--------: |
317
+ | `core` | ≤ 10 % zmierzonych FP | ✅ | ✅ |
318
+ | `extended` | ≤ 30 % zmierzonych FP | ✅ | ✅ |
319
+ | `quarantine` | powyżej 30 %, albo jeszcze niezmierzone (n < 10) | ❌ | ✅ |
320
+
321
+ | Język | Adapter | Pokrycie dziś |
322
+ | --------------- | --------------- | ------------------------------------------------------------ |
323
+ | TypeScript / JS | AST kompilatora | najszersze, najmocniej mierzone — głównie `core`/`extended` |
324
+ | Python / pytest | Warstwa regex | szerokie, audytowane na korpusie — głównie `core`/`extended` |
325
+ | Java | Warstwa regex | nowsze — głównie `extended`/`quarantine` |
326
+ | C# / .NET | Warstwa regex | nowsze — głównie `extended`/`quarantine` |
327
+
328
+ TypeScript i Python mają najszersze zmierzone pokrycie. Java i C#
329
+ się wydały, są udokumentowane i pozostają poza nagłówkową liczbą,
330
+ aż prawdziwa konsumująca suita (nie własne testy biblioteki bindingu)
331
+ zostanie audytowana.
332
+
333
+ ---
334
+
335
+ ## Jak działa punktacja
336
+
337
+ <p align="center">
338
+ <img src="assets/readme/terminal-hero.svg" alt="Wynik terminala Mjölnir — WORTHINESS 75/100 NEEDS WORK, rozbicie diagnostyki wg kategorii i lista FIX THIS FIRST" width="820" />
339
+ </p>
340
+
341
+ <sub>Regenerowany przez `npm run docs:hero`;
342
+ [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
343
+ wywala CI, jeśli artefakt odjechał od tego, co reporter naprawdę
344
+ wypisuje.</sub>
345
+
346
+ Punktacja jest przejrzysta: **error −8, warning −3, info −1**, potem
347
+ normalizacja o ekspozycję suity (potrącenia na deklarację testu).
348
+ Potrącenia ważone dowodami znaczą, że słabe sygnały kosztują mniej.
349
+ Terminal pokazuje te same zdyskontowane liczby, których używa
350
+ punktacja — żadnej czarnej skrzynki. Pełna metoda:
351
+ [docs/SCORING.md](docs/SCORING.md).
352
+
353
+ **Werdykty**
354
+
355
+ | Score | Werdykt |
356
+ | ------- | ---------------- |
357
+ | ≥ 80 | ✓ **WORTHY** |
358
+ | 50 – 79 | ⚠ **NEEDS WORK** |
359
+ | < 50 | ✖ **UNWORTHY** |
360
+
361
+ **Poziomy dowodów** — każde znalezisko niesie jeden; ustawia wagę
362
+ znaleziska w punktacji:
363
+
364
+ | Poziom | Znaczenie | Wpływ na punktację | Przykład |
365
+ | ------ | --------------------- | ------------------ | ------------------------------------------------------ |
366
+ | E2 | Deterministyczna wada | Pełne potrącenie | Committowany `.only` — dowodliwe strukturalnie |
367
+ | E1 | Heurystyczny wzorzec | Połowa potrącenia | Regex-owo trafiony `sleep()` — mocny sygnał, nie dowód |
368
+ | E0 | Obserwacja | Zero (tylko info) | Raportowane, ale nigdy nie gate'uje CI i nie potrąca |
369
+
370
+ Większość reguł to **E1**. Slogan „we prove it" odnosi się do tego
371
+ systemu: znaleziska E2 to dowód strukturalny; znaleziska E1 to
372
+ poprawnie pozycjonowane ostrzeżenia, nie formalne dowody.
373
+
374
+ Puste repo punktuje `null`, nigdy fałszywą setkę — zob.
375
+ [Model zaufania](#model-zaufania).
376
+
377
+ ---
378
+
379
+ ## 🎭 Selector Health Score
380
+
381
+ Flagowa metryka dla suite'ów Playwright — jak odporne są twoje
382
+ lokatory:
383
+
384
+ ```text
385
+ ▚▞ SELECTOR HEALTH — e2e/checkout.spec.ts
386
+
387
+ [█████████████████░░░] 83 / 100
388
+ role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
389
+ ```
390
+
391
+ Lokatory oparte na rolach dostają pełną punktację. Łańcuchy klas CSS i
392
+ XPath toną w punktacji — łamią się przy każdym refactorze DOM, nie
393
+ mówiąc, które zachowanie zregresowało.
394
+
395
+ ---
396
+
397
+ ## 🔬 Dowody z runtime
398
+
399
+ Statyczna detekcja flakiness to zgadywanie. Mjölnir czyta **prawdziwe
400
+ dane wykonania** — raporty JSON Playwright i XML JUnit z dowolnego
401
+ runnera:
402
+
403
+ ```bash
404
+ mjolnir forensics ./test-results/
405
+ ```
406
+
407
+ ```text
408
+ ▚▞ FLAKINESS LEADERBOARD
409
+
410
+ 3 tests · 1 failed · 1 flaky · 1 retried
411
+
412
+ TRUE-FLAKE completes checkout with saved card (e2e/checkout.spec.ts)
413
+ ████████████████████ 6.0s · 2 attempts
414
+ FAILING declines an expired card (e2e/checkout.spec.ts)
415
+ ████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
416
+ ```
417
+
418
+ Test, który przechodzi dopiero od próby ≥ 2, nie jest testem
419
+ przechodzącym — to szczęśliwy test. Zostaje oznaczony `TRUE-FLAKE`
420
+ niezależnie od finalnego zielonego checka.
421
+
422
+ ---
423
+
424
+ ## ⚡ Mjölnir nie jest kolejnym linterem
425
+
426
+ Lintery mówią ci, czy kod trzyma się reguł. Mjölnir mówi ci, czy twoja
427
+ weryfikacja da się uznać za wiarygodną.
428
+
429
+ | | ESLint / SonarQube | Narzędzia coverage | Ręczny review | **Mjölnir** |
430
+ | ----------------------------------------------------------- | :----------------: | :----------------: | :-----------: | :---------: |
431
+ | Integralność workflow CI (`continue-on-error`, `\|\| true`) | ❌ | ❌ | rzadko | ✅ |
432
+ | Cross-językowo (TS, Python, Java, C#) z jednego narzędzia | ❌ | ❌ | ❌ | ✅ |
433
+ | Ocenia odporność lokatorów Playwright (Selector Health) | ❌ | ❌ | rzadko | ✅ |
434
+ | Wyłapuje testy bez prawdziwych asercji | ✅ (plugin)\* | ❌ | czasem | ✅ |
435
+ | Łapie twarde sleepy (`waitForTimeout`, `time.sleep`) | ✅ (plugin)\* | ❌ | czasem | ✅ |
436
+ | Działa w sekundy, zero wywołań sieciowych podczas skanu | ✅ | ✅ | — | ✅ |
437
+
438
+ \*`eslint-plugin-jest` (`expect-expect`) i `eslint-plugin-playwright`
439
+ (`expect-expect`, `no-wait-for-timeout`) pokrywają to dla swoich
440
+ frameworków.
441
+
442
+ **Analiza runtime** to osobna kategoria obok statycznego lintowania:
443
+
444
+ | | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
445
+ | ---------------------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
446
+ | Czyta prawdziwe dane przebiegów dla werdyktów `TRUE-FLAKE` | częściowo\* | częściowo (tag) | ✅ |
447
+ | Raport triażu flakiness z historii wykonania | ❌ | ✅ | ✅ |
448
+ | Integruje się ze statycznym wskaźnikiem wiarygodności | ❌ | ❌ | ✅ |
449
+
450
+ \*Playwright śledzi retry wewnętrznie, ale nie produkuje samodzielnego
451
+ raportu flakiness z etykietami werdyktów.
452
+
453
+ ---
454
+
455
+ ## 🤖 Czemu nie użyć po prostu AI code review?
456
+
457
+ Inny problem, inna warstwa. AI review może dostrzec podejrzaną zmianę
458
+ testu w diffie; nie dowodzi, że system weryfikacji jako całość jest
459
+ godny zaufania — i widzi tylko diff, który mu pokażesz.
460
+
461
+ | | AI code review (Copilot i in.) | **Mjölnir** |
462
+ | ------------------------------------------------- | :-------------------------------: | :-------------------------------: |
463
+ | Koszt na skan | Tokeny (rośnie z rozmiarem diffа) | **Zero** (lokalny, zainstalowany) |
464
+ | Widzi całą suitę + wszystkie configi CI | Tylko diff PR, który mu pokażesz | **Wszystko, za każdym razem** |
465
+ | Deterministyczny (ten sam input → ten sam output) | ❌ (niedeterministyczny) | **✅** |
466
+ | Łapie wzorce śpiące miesiącami | Tylko jeśli jest w kontekście | **✅** (skanuje wszystkie pliki) |
467
+ | Pamięta znaleziska między przebiegami | ❌ (brak pamięci między sesjami) | **✅** (baseline + diff) |
468
+ | Działa bez ludzkiego wyzwalacza | Potrzebuje PR-a albo promptu | **✅** (hak CI, 3 sekundy) |
469
+
470
+ **Używaj obu.** AI łapie niuans, intencję i wady projektowe, których
471
+ żaden regex nie znajdzie. Mjölnir łapie strukturalne wzorce, które AI
472
+ pomija, bo wyglądają „intencjonalnie" — committowany `.only`,
473
+ połknięty kod wyjścia, `continue-on-error` na jobie testowym. To nie
474
+ są bugi wymagające rozumowania; to fakty wymagające skanowania.
475
+
476
+ ---
477
+
478
+ ## 🤖 Integracja CI
479
+
480
+ Jedna komenda generuje workflow PR — domyślnie doradczy, nigdy
481
+ blokujący:
482
+
483
+ ```bash
484
+ mjolnir ci install
485
+ ```
486
+
487
+ Albo podepnij go natywnie pod GitHub Code Scanning przez SARIF:
488
+
489
+ ```yaml
490
+ - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
491
+ - uses: github/codeql-action/upload-sarif@v3
492
+ with:
493
+ sarif_file: mjolnir.sarif
494
+ ```
495
+
496
+ Konfiguracja edytora i pipeline'u dla SARIF:
497
+ [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
498
+
499
+ ### Pokrycie changed-scope
500
+
501
+ `--scope changed` przypisuje znaleziska liniom dodanym w twoim branchu
502
+ względem merge-base z `main`. Pokrywa pliki testowe (`*.spec.*`,
503
+ `*.test.*`) plus pliki workflow GitHub i konfiguracje Playwright w
504
+ diffie. Gdy merge-base nie da się rozwiązać — shallow clone, detached
505
+ HEAD, cel spoza git, inny domyślny branch — degraduje się uczciwie:
506
+ znaleziska wracają do atrybucji na cały plik, a raport mówi o tym.
507
+ Nadpisz bazową ref przez `--base <ref>`.
508
+
509
+ ---
510
+
511
+ ## Konfiguracja
512
+
513
+ Mjölnir jest zero-config. Opcjonalny `mjolnir.config.json` (lub
514
+ `.mjolnir.json`) w korzeniu repo dostraja severity, gating i scope —
515
+ nigdy nie zmienia semantyki detekcji.
516
+
517
+ | Key | Typ | Działanie |
518
+ | ------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
519
+ | `exclude` | `string[]` | Dodatkowe globy ignorowania (podzbiór gitignore), na wierzchu wbudowanych domyślnych |
520
+ | `gate` | `"advisory" \| "error" \| "warning"` | Które severity kończą się kodem niezerowym (domyślnie `error`; `advisory` nigdy nie blokuje) |
521
+ | `severityOverrides` | `{ "<RULE-ID>": severity }` | Przerankowuje znaleziska reguły dla twojego repo |
522
+ | `ignore` | `IgnoreEntry[]` | Wycisza znaleziska — **`reason` jest wymagany**; wpisy wygasają po 90 dniach (jawna data `expires`, albo czas ostatniej modyfikacji pliku konfiga dla wpisów bez niej) |
523
+ | `plugins` | `string[]` | Zewnętrzne pakiety reguł (zob. [Model zaufania](#model-zaufania)) |
524
+
525
+ ```json
526
+ {
527
+ "gate": "error",
528
+ "exclude": ["legacy/**"],
529
+ "severityOverrides": { "QA-PW-118": "warning" },
530
+ "ignore": [
531
+ {
532
+ "ruleId": "QA-TEST-004",
533
+ "files": ["e2e/legacy-login.spec.ts"],
534
+ "reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
535
+ "expires": "2026-12-31"
536
+ }
537
+ ]
538
+ }
539
+ ```
540
+
541
+ - **`.mjolnirignore`** — prosty plik w stylu gitignore dla wykluczeń
542
+ ścieżek, ten sam dialekt co `exclude`. Użyj go na szum maszynowy; użyj
543
+ `exclude`, gdy lista należy do kontroli wersji, obok reszty configa.
544
+ - **Override'y CLI** — `--strict` (dołącz reguły kwarantanny),
545
+ `--width <cols>` i `--ascii` / `--no-ascii` (render terminala),
546
+ `--tone blunt` (ostrejsze komunikaty), `--max-duration <sec>`
547
+ (ograniczony skan częściowy).
548
+ - Wyciszanie reguł i cykl życia deprecacji:
549
+ [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
550
+
551
+ Wpisy `ignore` zasilają też samodzielną komendę `mjolnir suppressions`,
552
+ która wypisuje, co jest aktualnie wyciszone i kiedy wygasa każdy wpis.
553
+
554
+ ---
555
+
556
+ ## 📐 Kody wyjścia i kontrakty
557
+
558
+ Zamrożone — bezpieczna baza do budowania logiki CI:
559
+
560
+ | Kod wyjścia | Znaczenie |
561
+ | ----------- | ------------------------------------------------------------------------------- |
562
+ | `0` | Czysto — brak znalezisk na poziomie gate'a lub wyżej |
563
+ | `1` | Znaleziska na poziomie gate'a lub wyżej |
564
+ | `2` | Skan częściowy (wyczerpany budżet czasu, nieczytelne pliki) — nigdy nie blokuje |
565
+ | `10` | Błąd użycia (zły flag, brakujący cel) |
566
+ | `20` | Błąd wewnętrzny |
567
+
568
+ Raport JSON/SARIF to `schemaVersion: 1`. ID reguł (`QA-<FAMILY>-NNN`)
569
+ są niezmienne po wydaniu i nigdy nie są używane ponownie.
570
+
571
+ ---
572
+
573
+ ## Model zaufania
574
+
575
+ - **Local-first** — zero wywołań sieciowych podczas skanowania. Nigdy.
576
+ Zero telemetrii.
577
+ - **Żadnych fałszywych dowodów** — wolimy powiedzieć „nieznane" niż
578
+ „zweryfikowane". Puste repo dostaje `score: null`, nigdy fałszywej
579
+ setki.
580
+ - **Częściowa uczciwość** — jeśli analizę ucięto, wynik to mówi. Nigdy
581
+ „complete", gdy to nieprawda.
582
+ - **Zapora FP** — detekcja działa na widoku kodu wolnym od komentarzy i
583
+ stringów (reguły TypeScript używają AST kompilatora): wzorzec w
584
+ komentarzu prozatorskim czy doc- przykładzie-stringu to dokumentacja,
585
+ nie znalezisko.
586
+ - **Zmierzone, nie założone** — do tierów nagłówkowych trafiają tylko
587
+ reguły ze stopą fałszywych pozytywów z prawdziwego kodu OSS (zob.
588
+ [Ile z tego jest zmierzone](#ile-z-tego-jest-zmierzone)); stopka
589
+ skanu i `mjolnir rules --unmeasured` powiedzą ci, które które.
590
+ - **Zaufanie do pluginów** — pluginy to pakiety npm deklarowane pod
591
+ `"plugins"`. **Nie ma sandboxa**: kod pluginu działa z pełnymi
592
+ uprawnieniami Node, ten sam model zaufania co pluginy ESLint czy
593
+ Vitest. Prefiksy ID reguł core są zarezerwowane i odrzucane od
594
+ pluginów przeciw spoofingowi.
595
+ - **Zewnętrzne reguły lokalne wobec workspace'u** (folderowe, zero
596
+ sieci) — katalog `mjolnir-rules/` obok celu skanu ładuje własne
597
+ reguły: pliki JSON deklarują wzorce regex (żaden kod nie jest
598
+ wykonywany), moduły `.mjs`/`.js` eksportują `rules` (pełne zaufanie
599
+ Node, jak pluginy). Zewnętrzne reguły niosą te same metadane zaufania
600
+ co core; nie mogą nigdy wyjść w tierze core (core wymaga zmierzonej
601
+ stopy FP z sidecara korpusu — deklarowane `tier: "core"` jest
602
+ ściągane do `extended`), przestrzegają limitów tierów i są
603
+ sprawdzane na dryft: `mjolnir rules --md --external` renderuje
604
+ katalog z załadowanych plików (pochodzenie `external`), a generator
605
+ macierzy przyjmuje `--external <root>`.
606
+
607
+ ---
608
+
609
+ ## 🏗️ Architektura
610
+
611
+ <details>
612
+ <summary>Rozwiń drzewo</summary>
613
+
614
+ ```
615
+ mjolnir/
616
+ ├── src/
617
+ │ ├── engine/ # LanguageAdapter interface + rule runner
618
+ │ ├── adapters/ # typescript · python · java · csharp · github-actions
619
+ │ ├── rules/ # rules across 8 families + the measured-FP table
620
+ │ ├── playwright/ # Selector Health Score engine
621
+ │ ├── discovery/ # workspace, frameworks, ignore resolution
622
+ │ ├── scope/ # git merge-base changed-scope engine
623
+ │ ├── scorer/ # transparent deduction table + prioritization
624
+ │ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
625
+ │ ├── forensics/ # run-data ingestion · flake verdicts · triage
626
+ │ ├── config/ # mjolnir.config.json + suppressions
627
+ │ ├── plugins/ # third-party rule loading (no sandbox)
628
+ │ └── commands/ # every subcommand
629
+ └── tests/
630
+ ├── fixtures/ # must-fire / must-not-fire per rule
631
+ └── golden/ # frozen score regression locks
632
+ ```
633
+
634
+ </details>
635
+
636
+ - **Reguły to czyste funkcje** — `(SourceFileContext) → Finding[]`,
637
+ bez I/O, bez globali. Nowy ekosystem = jeden adapter + jego reguły.
638
+ - **TypeScript/Playwright używa AST kompilatora** (ts-morph). Python,
639
+ Java i C# działają na wspólnej warstwie regex z maskowaniem
640
+ komentarzy i stringów.
641
+ - Warstwa AST tree-sitter WASM dla Javy i C# istnieje i jest
642
+ następnym krokiem precyzji — nie jest jeszcze podpięta do
643
+ synchronicznego pipeline'u skanu.
644
+
645
+ ---
646
+
647
+ ## 📚 Dokumentacja
648
+
649
+ | Dokument | Co zawiera |
650
+ | ------------------------------------------------------ | ----------------------------------------------- |
651
+ | [docs/SCORING.md](docs/SCORING.md) | Normalizacja punktacji + ważenie dowodami |
652
+ | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Zmierzone stopy fałszywych pozytywów + metodyka |
653
+ | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Stany reguł, wyciszanie, deprecacja |
654
+ | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | Wyjście SARIF + konfiguracja edytora/CI |
655
+ | [docs/rules/](docs/rules/) | Generowany katalog per reguła |
656
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Setup dev + workflow kontrybucji |
657
+ | [CHANGELOG.md](CHANGELOG.md) | Historia wydań |
658
+ | [SECURITY.md](SECURITY.md) | Zgłaszanie podatności |
659
+
660
+ ---
661
+
662
+ ## 📈 Status
663
+
664
+ **v0.5.x · otwarta beta.** Schemat JSON i kody wyjścia to zamrożone
665
+ kontrakty. TypeScript i Python mają najszersze zmierzone pokrycie; Java
666
+ i C# są nowsze — czytaj o nich przez
667
+ [tabelę tierów](#tiery-reguł-i-dojrzałość-językowa).
668
+
669
+ ---
670
+
671
+ ## 🤝 Kontrybucja
672
+
673
+ Nowe reguły to najłatwiejszy pierwszy wkład — jedna komenda wystawia
674
+ szkielet reguły plus jej fixture must-fire **i** must-not-fire
675
+ (wygenerowana reguła celowo wypada na fixture'ach, dopóki nie
676
+ zaimplementujesz prawdziwej detekcji — stub nie może się wydać):
677
+
678
+ ```bash
679
+ mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
680
+ ```
681
+
682
+ Pełny setup dev, komendy stałego gate'a oraz prawa anti-creep /
683
+ zapory fixture'owej są w [CONTRIBUTING.md](CONTRIBUTING.md).
684
+
685
+ ---
686
+
687
+ <div align="center">
688
+
689
+ **Przestań wydawać testy, którym nie możesz ufać.**
690
+
691
+ ```bash
692
+ npx mjolnir-qa@latest
693
+ ```
694
+
695
+ **Star ⭐ · Watch 👀 · Contribute 🤝**
696
+
697
+ Zbudowane przez [Sergeya Bara](https://www.linkedin.com/in/sergeybar/)
698
+
699
+ </div>