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.gr.md ADDED
@@ -0,0 +1,705 @@
1
+ <div align="center">
2
+
3
+ <img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
4
+
5
+ ### Τα τεστ σου λένε ψέματα. Το αποδεικνύουμε.
6
+
7
+ **Verification Trust Engine για QA.** Το Mjölnir ελέγχει suites τεστ και
8
+ CI pipelines, αναφέρει δείκτη αξιοπιστίας και δείχνει ακριβώς πού
9
+ σπάει η εμπιστοσύνη.
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.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) | Ελληνικά | [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
+ **Είναι τα τεστ σου άξια εμπιστοσύνης;**
25
+
26
+ [Δες το σε δράση](#-δες-το-σε-δράση) ·
27
+ [Γρήγορη εκκίνηση](#-γρήγορη-εκκίνηση) ·
28
+ [Τι ελέγχει](#-τι-ελέγχει-το-mjölnir) ·
29
+ [Σκόρ](#πώς-λειτουργεί-το-σκόρ) ·
30
+ [CI](#-ενσωμάτωση-ci) · [Διαμόρφωση](#διαμόρφωση) ·
31
+ [Τεκμηρίωση](#-τεκμηρίωση)
32
+
33
+ </div>
34
+
35
+ ---
36
+
37
+ ## 🎬 Δες το σε δράση
38
+
39
+ <p align="center">
40
+ <img src="assets/readme/demo.svg" alt="Η πλήρης αναφορά --verbose του Mjölnir σε ένα demo repo: WORTHINESS 75/100 NEEDS WORK, ανάλυση διαγνώσεων ανά κατηγορία, λίστα FIX THIS FIRST και κάθε εύρημα με ID κανόνα και αριθμό γραμμής σε CI, Playwright, υγιεινή τεστ και κανόνες Python" width="900" />
41
+ </p>
42
+
43
+ <sub>Η πλήρης έξοδος του `npx mjolnir-qa ./examples/demo-repo --verbose`,
44
+ αποδομένη από τον πραγματικό reporter — τίποτα περικομμένο.
45
+ Αναδημιουργείται με `npm run docs:demo`;
46
+ [`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
47
+ ρίχνει το CI αν ο artifact αποκλίνει από ό,τι τυπώνει το εργαλείο.</sub>
48
+
49
+ **Τι μόλις συνέβη:**
50
+
51
+ 1. Το Mjölnir ανακάλυψε τα Playwright specs, τη διαμόρφωσή του, το CI
52
+ workflow και ένα αρχείο τεστ Python — τέσσερις γλώσσες/μορφές, ένα
53
+ πέρασμα.
54
+ 2. Βρήκε στοιχεία που εξασθενούν την εμπιστοσύνη στη σουίτα — ένα
55
+ `continue-on-error` που κρύβει job, ένα `|| true` που καταπίνει exit
56
+ code, σκληρά sleeps, εύθραυστο selector, σκληρά staging URL,
57
+ αναμονή `networkidle`.
58
+ 3. Μετέτρεψε το καθένα σε συγκεκριμένο εύρημα με ID κανόνα, τοποθεσία
59
+ και fix — και σε ένα σκόρ με το οποίο μπορείς να gated ένα PR.
60
+
61
+ ### Ένα εύρημα από κοντά
62
+
63
+ Τρέξε `mjolnir explain QA-CI-001` στο πρώτο εύρημα παραπάνω και θα
64
+ πάρεις:
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
+ Αυτή είναι η μονάδα αξίας: όχι νίττα στυλ, αλλά ένα σημείο όπου το CI
86
+ σου σου λέει ότι κάτι πέρασε ενώ δεν πέρασε.
87
+
88
+ ---
89
+
90
+ ## ⚡ Γρήγορη εκκίνηση
91
+
92
+ Τρέξ' το σε ένα repo για πλήρη αναφορά και δείκτη αξιοπιστίας:
93
+
94
+ ```bash
95
+ npx mjolnir-qa@latest
96
+ ```
97
+
98
+ **Στο CI το προϊόν είναι μία εντολή.** Σκανάρει μόνο ό,τι άγγιξε το
99
+ branch και βγαίνει μη μηδενικά σε νέα προβλήματα:
100
+
101
+ ```bash
102
+ npx mjolnir-qa@latest --scope changed
103
+ ```
104
+
105
+ Ρίξε αυτό σε ένα PR check — το `mjolnir ci install` γράφει το workflow —
106
+ και τελείωσες. Όλα τα άλλα είναι προαιρετικά.
107
+
108
+ | Εντολή | Τι κάνει |
109
+ | ----------------------------------- | ------------------------------------------------------------ |
110
+ | `mjolnir` | Πλήρες σκαν repo + δείκτης αξιοπιστίας |
111
+ | `mjolnir --scope changed` | Μόνο ό,τι引入ε το branch σου — η μορφή CI |
112
+ | `mjolnir ci install` | Δημιουργεί το συμβουλευτικό PR workflow |
113
+ | `mjolnir explain QA-CI-001` | Τι / γιατί / fix + μετρημένο ποσοστό FP για έναν κανόνα |
114
+ | `mjolnir rules --unmeasured` | Οι κανόνες που τρέχουν με υπόθεση, όχι με μέτρημα |
115
+ | `mjolnir --json` / `--format sarif` | Μηχανικά αναγνώσιμο / GitHub Code Scanning |
116
+ | `mjolnir --strict` | Εκτελεί και κανόνες tier quarantine (υψηλότερος κίνδυνος FP) |
117
+
118
+ <details>
119
+ <summary><strong>Όταν κάτι είναι flaky</strong></summary>
120
+
121
+ | Εντολή | Τι κάνει |
122
+ | ----------------------------------- | --------------------------------------------------------------- |
123
+ | `mjolnir forensics ./test-results/` | Πραγματικά δεδομένα runs → ετυμηγορίες `TRUE-FLAKE`, `FLAKY.md` |
124
+ | `mjolnir triage ./test-results/` | Πρόταση καραντίνας από ιστορικό εκτέλεσης |
125
+ | `mjolnir pw-report ./test-results/` | Σύνοψη run Playwright — retries / flakes / τα πιο αργά |
126
+ | `mjolnir doctor:playwright` | Βαθύ σκαν μόνο Playwright + Selector Health Score |
127
+
128
+ </details>
129
+
130
+ <details>
131
+ <summary><strong>Σπάνια / αναφορές</strong></summary>
132
+
133
+ | Εντολή | Τι κάνει |
134
+ | ------------------------------- | ------------------------------------------------------- |
135
+ | `mjolnir fix --dry-run` / `fix` | Ασφαλή αυτόματα fix με απόδειξη |
136
+ | `mjolnir baseline` / `diff` | Στιγμιότυπο ευρημάτων, μετά αναφορά μόνο νέων/χειρότερα |
137
+ | `mjolnir impact --since <ref>` | Τι άλλαξε από προηγούμενο commit |
138
+ | `mjolnir debt` | Μητρώο τεχνολογικού χρέους τεστ με μοντέλο κόστους |
139
+ | `mjolnir handover` | Χάρτης onboarding της σουίτας για νέο QA |
140
+ | `mjolnir stats` | Τοπικοί σωρευτικοί μετρητές όλων των fix που είδε |
141
+ | `mjolnir badge` | shields.io endpoint JSON + snippet |
142
+ | `mjolnir rules --md` | Πλήρης κατάλογος κανόνων (JSON ή Markdown) |
143
+ | `mjolnir doctor` | Αυτοέλεγχος της ίδιας της βάσης κανόνων του Mjölnir |
144
+ | `mjolnir create-rule <ID>` | Σκαφφάρει νέο κανόνα + fixtures |
145
+ | `mjolnir --format mermaid` | Διάγραμμα αρχιτεκτονικής τεστ για σχόλιο PR |
146
+
147
+ </details>
148
+
149
+ Εγκατάσταση globally αντί για `npx` αν προτιμάς: `npm i -g mjolnir-qa`.
150
+ Απαιτεί Node.js ≥ 22.18. Λειτουργεί σε Windows, macOS και Linux.
151
+
152
+ ---
153
+
154
+ ## 👥 Για ποιον είναι;
155
+
156
+ - **QA / SDET** που έχουν e2e ή integration σουίτα και χρειάζονται
157
+ αποδείξεις ότι η σουίτα αξίζει πραγματικά το πράσινο τσεκ που
158
+ παράγει.
159
+ - **Ομάδες Platform / DevEx** υπεύθυνες για ακεραιότητα CI και release
160
+ gates — οι άνθρωποι που νοιάζονται να μην μετατρέψει ποτέ ένα
161
+ `continue-on-error` βουβά κόκκινο pipeline σε πράσινο.
162
+ - **Maintainers OSS** που θέλουν φτηνή, πάντα ενεργή πύλη επαλήθευσης
163
+ που τρέχει τοπικά και σε CI χωρίς κλήσεις δικτύου.
164
+
165
+ ---
166
+
167
+ ## 🔨 Τι ελέγχει το Mjölnir
168
+
169
+ | | |
170
+ | --- | ------------------------------------------------------------------------------------------------------------------------------------ |
171
+ | ⚖️ | **Δείκτης αξιοπιστίας** — ένας αριθμός, διαφανής πίνακας αφαιρέσεων, καμία μαύρη κάψουλα |
172
+ | 🎭 | **Selector Health Score** — βαθμολογεί τα Playwright locators σου, όχι μόνο το pass rate |
173
+ | 🔬 | **Δικαστική ανάλυση runtime** — διαβάζει πραγματικά δεδομένα Playwright/JUnit για να πιάσει `TRUE-FLAKE`, όχι μόνο στατικές εικασίες |
174
+ | 🚨 | **Κανόνες ακεραιότητας CI** — πιάνει `continue-on-error`, `\|\| true` και άλλα κόλπα ψεύτικου πράσινου |
175
+ | 🐍 | **Και τα τέσσερα Playwright bindings** — TypeScript, Python, Java, C#/.NET — plus pytest, JUnit/TestNG και CI workflows |
176
+ | 🔒 | **Local-first** — μηδενικές κλήσεις δικτύου κατά το σκαν, μηδενική τηλεμετρία, τρέχει σε δευτερόλεπτα |
177
+
178
+ ### Οι κανόνες
179
+
180
+ Κάθε κανόνας έρχεται με fixtures must-fire **και** must-not-fire.
181
+ Κανόνας που ενεργοποιείται στη δική του αρνητική fixture δεν μπορεί να
182
+ να κυκλοφορήσει — αυτός είναι ο τείχος των false positives.
183
+
184
+ <details>
185
+ <summary><strong>Υγιεινή τεστ</strong></summary>
186
+
187
+ | ID | Κανόνας | Severity |
188
+ | ----------- | ----------------------------------------------------- | -------- |
189
+ | QA-TEST-001 | Commitμένος focused τεστ (`.only`, `fit`) | error |
190
+ | QA-TEST-002 | Παραλειμένο τεστ χωρίς δικαιολογία | error |
191
+ | QA-TEST-002 | Παραλειμένο τεστ με καταγεγραμμένη δικαιολογία | warning |
192
+ | QA-TEST-003 | Τεστ χωρίς assertions | error |
193
+ | QA-TEST-004 | Σκληρό sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning |
194
+ | QA-TEST-006 | Κατάχρηση retry που κρύβει flakiness | warning |
195
+ | QA-TEST-010 | Κενό σώμα τεστ | error |
196
+
197
+ </details>
198
+
199
+ <details>
200
+ <summary><strong>Ποιότητα τεστ</strong></summary>
201
+
202
+ | ID | Κανόνας | Severity |
203
+ | ------------ | ----------------------------- | -------- |
204
+ | QA-TQUAL-001 | Επαλήθευση μόνο με mocks | info |
205
+ | QA-TQUAL-002 | Ταυτολογική assertion | error |
206
+ | QA-TQUAL-009 | Assertion promise χωρίς await | error |
207
+ | QA-TQUAL-011 | Σχολιασμένα τεστ | warning |
208
+
209
+ </details>
210
+
211
+ <details>
212
+ <summary><strong>Playwright 🎭</strong></summary>
213
+
214
+ | ID | Κανόνας | Severity |
215
+ | --------- | ---------------------------------------------- | -------- |
216
+ | QA-PW-002 | Assertion locator χωρίς await | error |
217
+ | QA-PW-003 | `page.pause()` / `test.only()` στο commit | error |
218
+ | QA-PW-004 | Εύθραυστοι CSS/XPath selectors | warning |
219
+ | QA-PW-005 | Επιχειρησιακή λογική μέσα σε `page.evaluate()` | info |
220
+ | QA-PW-114 | Legacy element handles (`page.$`) | info |
221
+ | QA-PW-118 | Αναμονές `networkidle` (flaky by design) | info |
222
+ | QA-PW-123 | Σκληρά URL περιβάλλοντος | warning |
223
+
224
+ </details>
225
+
226
+ <details>
227
+ <summary><strong>Ακεραιότητα CI</strong></summary>
228
+
229
+ | ID | Κανόνας | Severity |
230
+ | --------- | --------------------------------------------------------------------- | -------- |
231
+ | QA-CI-001 | Το `continue-on-error` κρύβει αποτυχίες | error |
232
+ | QA-CI-002 | Το `\|\| true` καταπίνει exit codes | error |
233
+ | QA-CI-005 | Αναφορά καταναλώνεται αλλά ποτέ δεν παράγεται | error |
234
+ | QA-CI-007 | Περιτύλιξη retry γύρω από τεστ | warning |
235
+ | QA-CI-008 | Step πάντα επιτυχές κρύβει αποτυχίες | error |
236
+ | QA-CI-009 | Exit code του τεστ δεν προωθείται (`\|` χωρίς pipefail, αλυσίδες `;`) | error |
237
+ | QA-CI-010 | Τεστ παραλείπονται εκεί που πρέπει να μπλοκάρουν (skip-on-PR guards) | error |
238
+
239
+ </details>
240
+
241
+ <details>
242
+ <summary><strong>Python / pytest 🐍</strong></summary>
243
+
244
+ | ID | Κανόνας | Severity |
245
+ | --------- | --------------------------------------------- | -------- |
246
+ | QA-PY-002 | Παραλειμένο τεστ (`skip`, μη αυστηρό `xfail`) | warning |
247
+ | QA-PY-003 | Συνάρτηση τεστ χωρίς assertions | error |
248
+ | QA-PY-005 | `time.sleep()` σε τεστ | warning |
249
+ | QA-PY-006 | Κενό σώμα τεστ (`pass`) | info |
250
+ | QA-PY-010 | Εξάρτηση από τύχη/χρόνο χωρίς freeze | info |
251
+ | QA-PY-012 | Ταυτολογική assertion | error |
252
+
253
+ Συνολικά 20 κανόνες Python (QA-PY-001…012 υγιεινή pytest + QA-PY-101…108 Playwright-Python).
254
+
255
+ </details>
256
+
257
+ <details>
258
+ <summary><strong>Java / JUnit · TestNG ☕</strong></summary>
259
+
260
+ | ID | Κανόνας | Severity |
261
+ | --------- | ------------------------------------------ | -------- |
262
+ | QA-JV-101 | Απενεργοποιημένο τεστ (`@Disabled`) | warning |
263
+ | QA-JV-102 | Σκληρό sleep (`Thread.sleep()`) | warning |
264
+ | QA-JV-103 | Μέθοδος τεστ χωρίς assertions | error |
265
+ | QA-JV-105 | Σκληρό sleep Playwright `waitForTimeout()` | warning |
266
+ | QA-JV-106 | Εύθραυστος selector αντί για role locator | warning |
267
+ | QA-JV-108 | Σκληρό URL περιβάλλοντος στο τεστ | info |
268
+ | QA-JV-111 | Μαζικό mock `page.route("**")` | info |
269
+
270
+ </details>
271
+
272
+ <details>
273
+ <summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
274
+
275
+ | ID | Κανόνας | Severity |
276
+ | --------- | ---------------------------------------------- | -------- |
277
+ | QA-CS-101 | Παραλειμένο τεστ (`[Ignore]`, `[Fact(Skip=)]`) | warning |
278
+ | QA-CS-102 | Σκληρό sleep (`Thread.Sleep` / `Task.Delay`) | warning |
279
+ | QA-CS-103 | Μέθοδος τεστ χωρίς assertions | error |
280
+ | QA-CS-105 | Σκληρό sleep `WaitForTimeoutAsync()` | warning |
281
+ | QA-CS-106 | Εύθραυστος selector αντί για role locator | warning |
282
+ | QA-CS-108 | Σκληρό URL περιβάλλοντος στο τεστ | info |
283
+ | QA-CS-111 | Μαζικό mock `page.RouteAsync("**")` | info |
284
+
285
+ </details>
286
+
287
+ > Ο πλήρης ζωντανός κατάλογος — κάθε κανόνας με tier, confidence,
288
+ > κίνδυνο false positive και διαθεσιμότητα autofix — παράγεται από το
289
+ > μητρώο:
290
+ >
291
+ > ```bash
292
+ > mjolnir rules --md
293
+ > ```
294
+ >
295
+ > Οι σελίδες ανά κανόνα ζουν στο [`docs/rules/`](docs/rules/).
296
+
297
+ ### Πόσο από αυτό είναι μετρημένο
298
+
299
+ **74 από 99 κανόνες φέρουν ποσοστό false positive μετρημένο σε πραγματικό
300
+ κώδικα OSS** (≥ 10 χειροκίνητα ταξινομημένα ευρήματα ο καθένας· βλ.
301
+ [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Οι άλλοι 19 κυκλοφορούν πάνω στην
302
+ εκτίμηση του συγγραφέα. Το υποσέλιδο κάθε σκαν σου λέει πόσοι από τους
303
+ _ενεργούς_ κανόνες είναι μετρημένοι· `mjolnir rules --unmeasured`
304
+ παραθέτει τους άμετρητους· η σελίδα `mjolnir explain` κάθε κανόνα
305
+ δηλώνει την κατάστασή του. Δημοσιεύουμε το ποσοστό ακόμα κι όταν είναι
306
+ άσχημο — ο QA-CS-103 αυτοελέγχεται στο 95 % και είναι σε καραντίνα γι'
307
+ αυτό. Να μεγαλώσει αυτό το 78 είναι η συνεχιζόμενη δουλειά του έργου.
308
+
309
+ ### Tiers κανόνων και ωριμότητα γλωσσών
310
+
311
+ Κάθε κανόνας είναι `core`, `extended` ή `quarantine`, ανατεθειμένος από
312
+ το **μετρημένο** ποσοστό false positive του:
313
+
314
+ | Tier | Σημασία | Προεπιλεγμένο σκαν | `--strict` |
315
+ | ------------ | -------------------------------------- | :----------------: | :--------: |
316
+ | `core` | ≤ 10 % μετρημένο FP | ✅ | ✅ |
317
+ | `extended` | ≤ 30 % μετρημένο FP | ✅ | ✅ |
318
+ | `quarantine` | πάνω από 30 %, ή ακόμα άμετρο (n < 10) | ❌ | ✅ |
319
+
320
+ | Γλώσσα | Adapter | Κάλυψη σήμερα |
321
+ | --------------- | ----------------- | ------------------------------------------------------------------ |
322
+ | TypeScript / JS | AST μεταγλωττιστή | η ευρύτερη, η πιο μετρημένη — ως επί το πλείστον `core`/`extended` |
323
+ | Python / pytest | Στρώμα regex | ευρεία, ελεγμένη σε corpus — ως επί το πλείστον `core`/`extended` |
324
+ | Java | Στρώμα regex | νεότερη — ως επί το πλείστον `extended`/`quarantine` |
325
+ | C# / .NET | Στρώμα regex | νεότερη — ως επί το πλείστον `extended`/`quarantine` |
326
+
327
+ TypeScript και Python έχουν την ευρύτερη μετρημένη κάλυψη. Η Java και η
328
+ C# κυκλοφορούν, είναι τεκμηριωμένες και μένουν εκτός του headline αριθμού
329
+ μέχρι μια πραγματική σουίτα καταναλωτή (όχι τα ίδια τα τεστ μιας
330
+ βιβλιοθήκης binding) να ελεγχθεί.
331
+
332
+ ---
333
+
334
+ ## Πώς λειτουργεί το σκόρ
335
+
336
+ <p align="center">
337
+ <img src="assets/readme/terminal-hero.svg" alt="Έξοδος τερματικού Mjölnir — WORTHINESS 75/100 NEEDS WORK, ανάλυση διαγνώσεων ανά κατηγορία και λίστα FIX THIS FIRST" width="820" />
338
+ </p>
339
+
340
+ <sub>Αναδημιουργείται με `npm run docs:hero`;
341
+ [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
342
+ ρίχνει το CI αν ο artifact αποκλίνει από ό,τι τυπώνει ο reporter.</sub>
343
+
344
+ Το σκόρ είναι διαφανές: **error −8, warning −3, info −1**, μετά
345
+ κανονικοποίηση με την έκθεση της σουίτας (αφαιρέσεις ανά δήλωση τεστ).
346
+ Οι αφαίρεσεις σταθμισμένες με αποδείξεις σημαίνουν ότι τα αδύναμα σήματα
347
+ κοστίζουν λιγότερο. Το τερματικό δείχνει τους ίδιους εκπτώτους αριθμούς
348
+ που χρησιμοποιεί το σκόρ — καμία μαύρη κάψουλα. Πλήρης μέθοδος:
349
+ [docs/SCORING.md](docs/SCORING.md).
350
+
351
+ **Ετυμηγορίες**
352
+
353
+ | Score | Ετυμηγορία |
354
+ | ------- | ---------------- |
355
+ | ≥ 80 | ✓ **WORTHY** |
356
+ | 50 – 79 | ⚠ **NEEDS WORK** |
357
+ | < 50 | ✖ **UNWORTHY** |
358
+
359
+ **Επίπεδα αποδείξεων** — κάθε εύρημα φέρει ένα· ορίζει το βάρος του
360
+ ευρήματος στο σκόρ:
361
+
362
+ | Επίπεδο | Σημασία | Επίδραση στο σκόρ | Παράδειγμα |
363
+ | ------- | -------------------- | ----------------- | --------------------------------------------------- |
364
+ | E2 | Καθορισμένο ελάττωμα | Πλήρης αφαίρεση | Commitμένο `.only` — δομικά αποδείξιμο |
365
+ | E1 | Ευρετικό μοτίβο | Μισή αφαίρεση | Regex-βρεμένο `sleep()` — ισχυρό σήμα, όχι απόδειξη |
366
+ | E0 | Παρατήρηση | Μηδέν (μόνο info) | Αναφέρεται αλλά δεν gated ποτέ CI ούτε αφαιρεί |
367
+
368
+ Οι περισσότεροι κανόνες είναι **E1**. Το σύνθημα «we prove it»
369
+ αναφέρεται σε αυτό το σύστημα: τα ευρήματα E2 είναι δομική απόδειξη·
370
+ τα ευρήματα E1 είναι σωστά τοποθετημένες προειδοποιήσεις, όχι τυπικές
371
+ αποδείξεις.
372
+
373
+ Ένα άδειο repo σκοράρει `null`, ποτέ ψεύτικα 100 — δες
374
+ [Μοντέλο εμπιστοσύνης](#μοντέλο-εμπιστοσύνης).
375
+
376
+ ---
377
+
378
+ ## 🎭 Selector Health Score
379
+
380
+ Η headline μετρική για σουίτες Playwright — πόσο ανθεκτικοί είναι οι
381
+ locators σου:
382
+
383
+ ```text
384
+ ▚▞ SELECTOR HEALTH — e2e/checkout.spec.ts
385
+
386
+ [█████████████████░░░] 83 / 100
387
+ role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
388
+ ```
389
+
390
+ Locators με βάση τα roles παίρνουν πλήρες σκόρ. Οι αλυσίδες CSS class
391
+ και το XPath βυθίζουν το σκόρ — σπάνε σε κάθε refactor DOM χωρίς να σου
392
+ λένε ποια συμπεριφορά παλινδρόμησε.
393
+
394
+ ---
395
+
396
+ ## 🔬 Αποδείξεις runtime
397
+
398
+ Η στατική ανίχνευση flakiness είναι μαντεψιά. Το Mjölnir διαβάζει
399
+ **πραγματικά δεδομένα εκτέλεσης** — αναφορές JSON Playwright και XML
400
+ JUnit από οποιονδήποτε runner:
401
+
402
+ ```bash
403
+ mjolnir forensics ./test-results/
404
+ ```
405
+
406
+ ```text
407
+ ▚▞ FLAKINESS LEADERBOARD
408
+
409
+ 3 tests · 1 failed · 1 flaky · 1 retried
410
+
411
+ TRUE-FLAKE completes checkout with saved card (e2e/checkout.spec.ts)
412
+ ████████████████████ 6.0s · 2 attempts
413
+ FAILING declines an expired card (e2e/checkout.spec.ts)
414
+ ████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
415
+ ```
416
+
417
+ Τεστ που περνά μόνο από την προσπάθεια ≥ 2 δεν είναι τεστ που περνά —
418
+ είναι τυχερό τεστ. Χαρακτηρίζεται `TRUE-FLAKE` ανεξάρτητα από το τελικό
419
+ πράσινο τσεκ.
420
+
421
+ ---
422
+
423
+ ## ⚡ Το Mjölnir δεν είναι ακόμα ένα linter
424
+
425
+ Τα linters σου λένε αν ο κώδικας ακολουθεί κανόνες. Το Mjölnir σου λέει
426
+ αν η επαλήθευσή σου μπορεί να εμπιστευτεί.
427
+
428
+ | | ESLint / SonarQube | Εργαλεία coverage | Χειροκίνητο review | **Mjölnir** |
429
+ | -------------------------------------------------------------- | :----------------: | :---------------: | :----------------: | :---------: |
430
+ | Ακεραιότητα CI workflow (`continue-on-error`, `\|\| true`) | ❌ | ❌ | σπάνια | ✅ |
431
+ | Cross-γλώσσα (TS, Python, Java, C#) από ένα εργαλείο | ❌ | ❌ | ❌ | ✅ |
432
+ | Βαθμολογεί ανθεκτικότητα Playwright locators (Selector Health) | ❌ | ❌ | σπάνια | ✅ |
433
+ | Σημαίνει τεστ χωρίς πραγματικές assertions | ✅ (plugin)\* | ❌ | καμιά φορά | ✅ |
434
+ | Πιάνει σκληρά sleeps (`waitForTimeout`, `time.sleep`) | ✅ (plugin)\* | ❌ | καμιά φορά | ✅ |
435
+ | Τρέχει σε δευτερόλεπτα, μηδέν κλήσεις δικτύου κατά το σκαν | ✅ | ✅ | — | ✅ |
436
+
437
+ \*Το `eslint-plugin-jest` (`expect-expect`) και το
438
+ `eslint-plugin-playwright` (`expect-expect`, `no-wait-for-timeout`)
439
+ καλύπτουν αυτά για τα αντίστοιχα frameworks τους.
440
+
441
+ **Η ανάλυση runtime** είναι ξεχωριστή κατηγορία δίπλα στο στατικό
442
+ linting:
443
+
444
+ | | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
445
+ | -------------------------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
446
+ | Διαβάζει πραγματικά δεδομένα runs για ετυμηγορίες `TRUE-FLAKE` | μερικώς\* | μερικώς (tag) | ✅ |
447
+ | Αναφορά triage flakiness από ιστορικό εκτέλεσης | ❌ | ✅ | ✅ |
448
+ | Ενσωματώνεται με τον στατικό δείκτη αξιοπιστίας | ❌ | ❌ | ✅ |
449
+
450
+ \*Το Playwright παρακολουθεί εσωτερικά τα retries αλλά δεν παράγει
451
+ αυτόνομη αναφορά flakiness με ετικέτες ετυμηγοριών.
452
+
453
+ ---
454
+
455
+ ## 🤖 Γιατί όχι απλώς AI code review;
456
+
457
+ Διαφορετικό πρόβλημα, διαφορετικό στρώμα. Το AI review μπορεί να πιάσει
458
+ ύποπτη αλλαγή τεστ σε ένα diff· δεν αποδεικνύει ότι το σύστημα
459
+ επαλήθευσης συνολικά αξίζει εμπιστοσύνη — και βλέπει μόνο το diff που
460
+ του δείχνεις.
461
+
462
+ | | AI code review (Copilot κ.λπ.) | **Mjölnir** |
463
+ | -------------------------------------------- | :--------------------------------------: | :-------------------------------: |
464
+ | Κόστος ανά σκαν | Tokens (κλιμακώνεται με το μέγεθος diff) | **Μηδέν** (τοπικό, εγκατεστημένο) |
465
+ | Βλέπει όλη τη σουίτα + όλες τις ρυθμίσεις CI | Μόνο το PR diff που δείχνεις | **Όλα, κάθε φορά** |
466
+ | Καθοριστικό (ίδιο input → ίδιο output) | ❌ (μη καθοριστικό) | **✅** |
467
+ | Πιάνει μοτίβα που κοιμούνται μήνες | Μόνο αν είναι στο context | **✅** (σκανάρει όλα τα αρχεία) |
468
+ | Θυμάται ευρήματα μεταξύ runs | ❌ (καμία μνήμη μεταξύ συνεδριών) | **✅** (baseline + diff) |
469
+ | Τρέχει χωρίς ανθρώπινο έναυσμα | Χρειάζεται PR ή prompt | **✅** (CI hook, 3 δευτερόλεπτα) |
470
+
471
+ **Χρησιμοποίησέ τα και τα δύο.** Το AI πιάνει νύαντσε, πρόθεση και
472
+ σχεδιαστικά ελαττώματα που καμία regex δεν βρίσκει. Το Mjölnir πιάνει
473
+ τα δομικά μοτίβα που το AI παραβλέπει επειδή φαίνονται «εσκεμμένα» —
474
+ ένα commitμένο `.only`, ένα καταπιμένο exit code, ένα `continue-on-error`
475
+ σε τεστ job. Δεν είναι bugs που χρειάζονται συλλογισμό· είναι γεγονότα
476
+ που χρειάζονται σκαν.
477
+
478
+ ---
479
+
480
+ ## 🤖 Ενσωμάτωση CI
481
+
482
+ Μία εντολή παράγει PR workflow — συμβουλευτικό από προεπιλογή, ποτέ
483
+ μπλοκάρισμα:
484
+
485
+ ```bash
486
+ mjolnir ci install
487
+ ```
488
+
489
+ Ή σύνδεσέ το εγγενώς σε GitHub Code Scanning μέσω SARIF:
490
+
491
+ ```yaml
492
+ - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
493
+ - uses: github/codeql-action/upload-sarif@v3
494
+ with:
495
+ sarif_file: mjolnir.sarif
496
+ ```
497
+
498
+ Ρύθμιση editor και pipeline για SARIF:
499
+ [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
500
+
501
+ ### Κάλυψη changed-scope
502
+
503
+ Το `--scope changed` αποδίδει ευρήματα σε γραμμές που πρόσθεσε το branch
504
+ σου σε σχέση με το merge-base με το `main`. Καλύπτει αρχεία τεστ
505
+ (`*.spec.*`, `*.test.*`) συν αρχεία GitHub workflow και ρυθμίσεις
506
+ Playwright στο diff. Όταν το merge-base δεν λύνεται — shallow clone,
507
+ detached HEAD, μη-git στόχος, διαφορετικό default branch — υποβαθμίζει
508
+ ειλικρινά: τα ευρήματα επιστρέφουν σε απόδοση κατά σύνολο αρχείου και η
509
+ αναφορά το λέει. Υπενόμησε την base ref με `--base <ref>`.
510
+
511
+ ---
512
+
513
+ ## Διαμόρφωση
514
+
515
+ Το Mjölnir είναι zero-config. Ένα προαιρετικό `mjolnir.config.json` (ή
516
+ `.mjolnir.json`) στη ρίζα του repo ρυθμίζει severity, gating και scope —
517
+ δεν αλλάζει ποτέ τη σημασιολογία ανίχνευσης.
518
+
519
+ | Key | Τύπος | Επίδραση |
520
+ | ------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
521
+ | `exclude` | `string[]` | Επιπλέον ignore globs (υποσύνολο gitignore), πάνω από τα ενσωματωμένα defaults |
522
+ | `gate` | `"advisory" \| "error" \| "warning"` | Ποια severity βγαίνουν μη μηδενικά (default `error`; το `advisory` δεν μπλοκάρει ποτέ) |
523
+ | `severityOverrides` | `{ "<RULE-ID>": severity }` | Επανατάσσει τα ευρήματα ενός κανόνα για το repo σου |
524
+ | `ignore` | `IgnoreEntry[]` | Καταστέλλει ευρήματα — **το `reason` απαιτείται**· οι εγγραφές λήγουν μετά από 90 ημέρες (ρητό `expires` date, ή time last-modified του αρχείου ρυθμίσεων για εγγραφές χωρίς) |
525
+ | `plugins` | `string[]` | Πακέτα κανόνων τρίτων (δες [Μοντέλο εμπιστοσύνης](#μοντέλο-εμπιστοσύνης)) |
526
+
527
+ ```json
528
+ {
529
+ "gate": "error",
530
+ "exclude": ["legacy/**"],
531
+ "severityOverrides": { "QA-PW-118": "warning" },
532
+ "ignore": [
533
+ {
534
+ "ruleId": "QA-TEST-004",
535
+ "files": ["e2e/legacy-login.spec.ts"],
536
+ "reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
537
+ "expires": "2026-12-31"
538
+ }
539
+ ]
540
+ }
541
+ ```
542
+
543
+ - **`.mjolnirignore`** — απλό αρχείο τύπου gitignore για εξαιρέσεις
544
+ διαδρομών, ίδια διάλεκτος με το `exclude`. Χρησιμοποίησέ το για θόρυβο
545
+ ανά μηχανή· χρησιμοποίησε `exclude` όταν η λίστα ανήκει στον version
546
+ control, δίπλα στην υπόλοιπη ρύθμιση.
547
+ - **CLI overrides** — `--strict` (συμπερίληψη κανόνων καραντίνας),
548
+ `--width <cols>` και `--ascii` / `--no-ascii` (απόδοση τερματικού),
549
+ `--tone blunt` (πιο άκαμπτα μηνύματα), `--max-duration <sec>`
550
+ (περιορισμένη μερική σκαν).
551
+ - Καταστολή κανόνων και κύκλος ζωής deprecation:
552
+ [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
553
+
554
+ Οι εγγραφές `ignore` τροφοδοτούν και την αυτόνομη εντολή
555
+ `mjolnir suppressions`, που παραθέτει τι είναι κατασταλμένο τώρα και
556
+ πότε λήγει κάθε εγγραφή.
557
+
558
+ ---
559
+
560
+ ## 📐 Exit codes & συμβόλαια
561
+
562
+ Παγωμένα — ασφαλή για χτίσιμο CI λογικής:
563
+
564
+ | Exit code | Σημασία |
565
+ | --------- | ------------------------------------------------------------------------------------- |
566
+ | `0` | Καθαρό — κανένα εύρημα στο ή πάνω από το gate |
567
+ | `1` | Ευρήματα στο ή πάνω από το gate |
568
+ | `2` | Μερικό σκαν (τέλος χρονικού προϋπολογισμού, δυσανάγνωστα αρχεία) — δεν μπλοκάρει ποτέ |
569
+ | `10` | Λάθος χρήσης (bad flag, λείπει στόχος) |
570
+ | `20` | Εσωτερικό λάθος |
571
+
572
+ Η αναφορά JSON/SARIF είναι `schemaVersion: 1`. Τα IDs κανόνων
573
+ (`QA-<FAMILY>-NNN`) είναι αμετάβλητα μόλις κυκλοφορήσουν και δεν
574
+ επαναχρησιμοποιούνται ποτέ.
575
+
576
+ ---
577
+
578
+ ## Μοντέλο εμπιστοσύνης
579
+
580
+ - **Local-first** — μηδέν κλήσεις δικτύου κατά το σκαν. Ποτέ. Μηδενική
581
+ τηλεμετρία.
582
+ - **Καμία ψεύτικη απόδειξη** — προτιμούμε να πούμε «άγνωστο» παρά
583
+ «επαληθευμένο». Άδειο repo παίρνει `score: null`, ποτέ ψεύτικα 100.
584
+ - **Μερική ειλικρίνεια** — αν η ανάλυση κόπηκε, η έξοδος το λέει.
585
+ Ποτέ «complete» όταν δεν είναι.
586
+ - **FP τείχος** — η ανίχνευση τρέχει σε άποψη κώδικα χωρίς
587
+ σχόλια/strings (οι κανόνες TypeScript χρησιμοποιούν AST
588
+ μεταγλωττιστή): ένα μοτίβο μέσα σε σχόλιο πρόζας ή doc-παράδειγμα
589
+ string είναι τεκμηρίωση, όχι εύρημα.
590
+ - **Μετρημένο, όχι δηλωμένο** — μόνο κανόνες με ποσοστό false positive
591
+ από πραγματικό OSS κώδικα κυκλοφορούν στα headline tiers (δες
592
+ [Πόσο από αυτό είναι μετρημένο](#πόσο-από-αυτό-είναι-μετρημένο)); το
593
+ υποσέλιδο σκαν και το `mjolnir rules --unmeasured` σου λένε ποιος
594
+ ποιος.
595
+ - **Εμπιστοσύνη plugins** — τα plugins είναι πακέτα npm δηλωμένα κάτω
596
+ από `"plugins"`. **Δεν υπάρχει sandbox**: ο κώδικας plugin τρέχει με
597
+ πλήρη δικαιώματα Node, το ίδιο μοντέλο εμπιστοσύνης με plugins ESLint
598
+ ή Vitest. Core προθέματα rule-ID είναι δεσμευμένα και απορρίπτονται
599
+ από plugins κατά της πλαστοπροσωπίας.
600
+ - **Εξωτερικοί κανόνες τοπικοί στο workspace** (φάκελος, μηδέν δίκτυο) —
601
+ ένας φάκελος `mjolnir-rules/` δίπλα στον στόχο σκαν φορτώνει custom
602
+ κανόνες: JSON αρχεία δηλώνουν regex μοτίβα (κανένας κώδικας δεν
603
+ εκτελείται), `.mjs`/`.js` modules εξάγουν `rules` (πλήρης εμπιστοσύνη
604
+ Node, όπως plugins). Οι εξωτερικοί κανόνες φέρουν τα ίδια trust
605
+ metadata με το core· δεν μπορούν ποτέ να κυκλοφορήσουν στο core tier
606
+ (το core απαιτεί μετρημένο FP από το corpus sidecar — δηλωμένο
607
+ `tier: "core"` σφίγγεται σε `extended`), τηρούν tier πλαφόν και
608
+ ελέγχονται για drift: `mjolnir rules --md --external` απεικονίζει τον
609
+ κατάλογο από τα φορτωμένα αρχεία (provenance `external`), και ο
610
+ generator matrix δέχεται `--external <root>`.
611
+
612
+ ---
613
+
614
+ ## 🏗️ Αρχιτεκτονική
615
+
616
+ <details>
617
+ <summary>Ανάπτυξη δέντρου</summary>
618
+
619
+ ```
620
+ mjolnir/
621
+ ├── src/
622
+ │ ├── engine/ # LanguageAdapter interface + rule runner
623
+ │ ├── adapters/ # typescript · python · java · csharp · github-actions
624
+ │ ├── rules/ # rules across 8 families + the measured-FP table
625
+ │ ├── playwright/ # Selector Health Score engine
626
+ │ ├── discovery/ # workspace, frameworks, ignore resolution
627
+ │ ├── scope/ # git merge-base changed-scope engine
628
+ │ ├── scorer/ # transparent deduction table + prioritization
629
+ │ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
630
+ │ ├── forensics/ # run-data ingestion · flake verdicts · triage
631
+ │ ├── config/ # mjolnir.config.json + suppressions
632
+ │ ├── plugins/ # third-party rule loading (no sandbox)
633
+ │ └── commands/ # every subcommand
634
+ └── tests/
635
+ ├── fixtures/ # must-fire / must-not-fire per rule
636
+ └── golden/ # frozen score regression locks
637
+ ```
638
+
639
+ </details>
640
+
641
+ - **Οι κανόνες είναι καθαρές συναρτήσεις** —
642
+ `(SourceFileContext) → Finding[]`, χωρίς I/O, χωρίς globals. Νέο
643
+ οικοσύστημα = ένας adapter + οι κανόνες του.
644
+ - **TypeScript/Playwright χρησιμοποιεί AST μεταγλωττιστή** (ts-morph).
645
+ Python, Java και C# τρέχουν σε κοινό regex στρώμα με μεταμφιεσμένα
646
+ σχόλια/strings.
647
+ - Ένα στρώμα AST tree-sitter WASM για Java και C# υπάρχει και είναι το
648
+ επόμενο βήμα ακρίβειας — δεν είναι ακόμα συνδεμένο στον σύγχρονο
649
+ σκαν pipeline.
650
+
651
+ ---
652
+
653
+ ## 📚 Τεκμηρίωση
654
+
655
+ | Έγγραφο | Τι περιέχει |
656
+ | ------------------------------------------------------ | ------------------------------------------- |
657
+ | [docs/SCORING.md](docs/SCORING.md) | Κανονικοποίηση σκόρ + στάθμιση αποδείξεων |
658
+ | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Μετρημένα ποσοστά false positive + μέθοδος |
659
+ | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Καταστάσεις κανόνων, καταστολή, deprecation |
660
+ | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | Έξοδος SARIF + ρύθμιση editor/CI |
661
+ | [docs/rules/](docs/rules/) | Δημιουργημένος κατάλογος ανά κανόνα |
662
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Dev setup + workflow συμβολής |
663
+ | [CHANGELOG.md](CHANGELOG.md) | Ιστορικό εκδόσεων |
664
+ | [SECURITY.md](SECURITY.md) | Αναφορά ευπαθειών |
665
+
666
+ ---
667
+
668
+ ## 📈 Κατάσταση
669
+
670
+ **v0.5.x · ανοιχτή beta.** Το JSON schema και τα exit codes είναι
671
+ παγωμένα συμβόλαια. TypeScript και Python έχουν την ευρύτερη μετρημένη
672
+ κάλυψη· Java και C# είναι νεότερα — διαβάστε τα μέσω του
673
+ [πίνακα tiers](#tiers-κανόνων-και-ωριμότητα-γλωσσών).
674
+
675
+ ---
676
+
677
+ ## 🤝 Συνεισφορά
678
+
679
+ Νέοι κανόνες είναι ο ευκολότερος πρώτος συνεισφορά — μία εντολή
680
+ σκαφφάρει τον κανόνα συν τα fixtures must-fire **και** must-not-fire (ο
681
+ δημιουργημένος κανόνας αστοχεί σκόπιμα στα fixtures μέχρι να
682
+ υλοποιήσεις πραγματική ανίχνευση — stub δεν μπορεί να κυκλοφορήσει):
683
+
684
+ ```bash
685
+ mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
686
+ ```
687
+
688
+ Πλήρες dev setup, οι εντολές standing gate και οι νόμοι anti-creep /
689
+ τείχος fixtures είναι στο [CONTRIBUTING.md](CONTRIBUTING.md).
690
+
691
+ ---
692
+
693
+ <div align="center">
694
+
695
+ **Σταμάτα να στέλνεις τεστ που δεν εμπιστεύεσαι.**
696
+
697
+ ```bash
698
+ npx mjolnir-qa@latest
699
+ ```
700
+
701
+ **Star ⭐ · Watch 👀 · Contribute 🤝**
702
+
703
+ Κατασκευάστηκε από [Sergey Bar](https://www.linkedin.com/in/sergeybar/)
704
+
705
+ </div>