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.uk.md
CHANGED
|
@@ -1,394 +1,431 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="assets/readme/
|
|
3
|
+
<img src="assets/readme/hero.svg" alt="Mjölnir. Тести кажуть, що пройшло. Mjölnir каже, чому можна довіряти." width="100%" />
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<br />
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
довіра.
|
|
7
|
+
Mjölnir знаходить тести, які не можуть впасти, і пайплайни, які не можуть почервоніти,<br />
|
|
8
|
+
а потім оцінює, наскільки можна довіряти результату, з доказом для кожного пункту.
|
|
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](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.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
|
+
[Подивитися в роботі](#подивитися-в-роботі) · [Швидкий старт](#швидкий-старт) · [Що знаходить](#що-знаходить-mjölnir) · [Оцінка](#оцінка-надійності) · [Докази](#модель-доказів) · [Аналіз прогонів](#аналіз-прогонів-тестів) · [CI](#цілісність-ci) · [Агенти](#ші-агенти) · [Безпека](#довіра-і-безпека) · [Обмеження](#чого-mjölnir-сказати-не-може) · [Документація](#документація)
|
|
25
|
+
|
|
26
|
+
<details>
|
|
27
|
+
<summary>Читати іншою мовою — 22 переклади</summary>
|
|
28
|
+
|
|
29
|
+
[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.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
|
-
[Швидкий старт](#-швидкий-старт) ·
|
|
28
|
-
[Що він перевіряє](#-що-перевіряє-mjölnir) ·
|
|
29
|
-
[Скоринг](#як-працює-скор) ·
|
|
30
|
-
[CI](#-інтеграція-ci) · [Конфігурація](#конфігурація) ·
|
|
31
|
-
[Документація](#-документація)
|
|
35
|
+
</details>
|
|
32
36
|
|
|
33
37
|
</div>
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
<br />
|
|
40
|
+
|
|
41
|
+
## Зелена галочка — це заява, а не доказ
|
|
42
|
+
|
|
43
|
+
Зелена галочка означає, що пайплайн не впав. Вона не означає, що тести запускалися або що вони могли впасти. Кожен із цих випадків проходить зеленим:
|
|
44
|
+
|
|
45
|
+
- закомічений `.only`, через який запустилося 3 тести замість 900
|
|
46
|
+
- `continue-on-error: true` на джобі, яка мала блокувати
|
|
47
|
+
- `|| true` після команди запуску тестів
|
|
48
|
+
- тест, який нічого не перевіряє або має порожнє тіло
|
|
49
|
+
- обгортка з повторами, яка перетворює справжній провал на випадковий успіх
|
|
50
|
+
- звіт, який workflow завантажує, але ніколи не створював
|
|
51
|
+
- жорсткий sleep, на якому тримається стан гонитви
|
|
52
|
+
|
|
53
|
+
Жоден із них не робить пайплайн червоним, і кожен на рев'ю виглядає навмисним. Саме тому вони виживають. Ось як Mjölnir читає реальний приклад:
|
|
54
|
+
|
|
55
|
+
<p align="center">
|
|
56
|
+
<img src="assets/readme/scan.svg" alt="CI-workflow демонстраційного репозиторію, прочитаний рядок за рядком. Mjölnir позначає кожну знахідку на вказаному рядку: правило, що не так, рівень доказовості та виміряну частку хибних спрацювань." width="800" />
|
|
57
|
+
</p>
|
|
58
|
+
|
|
59
|
+
<sub>Кожна знахідка, яку демонстраційне сканування видало для цього workflow, на вказаному рядку. Згенеровано командою `npm run docs:readme-brand` з [`demo-report.json`](assets/readme/demo-report.json) і захищено від розбіжностей у CI.</sub>
|
|
60
|
+
|
|
61
|
+
**Суворий режим.** Найагресивніші детекції — `.only`, `continue-on-error`, порожні тести, зловживання повторами — живуть у карантинному ярусі. Вони запускаються лише з `--strict` і обмежені серйозністю `info`: позначають, але ніколи не блокують. Сканування за замовчуванням (`npx mjolnir-qa@latest` без `--strict`) покриває лише основні та розширені правила. Додайте `--strict`, коли хочете і консультаційний шар.
|
|
62
|
+
|
|
63
|
+
Mjölnir читає набір тестів, CI-workflow і, якщо він є, звіт реального прогону. Він не запускає ваші тести, не встановлює залежності й не виконує код, який сканує. А коли доказів немає, він так і каже, замість того щоб вигадувати впевненість:
|
|
64
|
+
|
|
65
|
+
| Ситуація | Що повідомляє Mjölnir |
|
|
66
|
+
| ----------------------------------------------------- | --------------------------------------------------------------------- |
|
|
67
|
+
| Оголошень тестів не знайдено | Оцінка `null`, відображається як **UNKNOWN**. Ніколи не вигадані 100. |
|
|
68
|
+
| Немає базової лінії або порівнянної ревізії | **UNKNOWN**, із зазначеною причиною. Ніколи не припущений 0. |
|
|
69
|
+
| Сканування перервано (ліміт часу, нечитабельні файли) | **PARTIAL**, код виходу `2`. Ніколи не видається за чистий результат. |
|
|
70
|
+
|
|
71
|
+
<p align="center">
|
|
72
|
+
<img src="assets/readme/how-it-works.svg" alt="Як працює Mjölnir. Він статично читає набір тестів і CI-пайплайн, а також звіт реального прогону, якщо він є. Кожну знахідку він зважує за рівнем доказовості та рівнем довіри, причому лише реальний прогін може досягти L3–L5, і видає знахідки, оцінку надійності та CI-гейт із замороженими кодами виходу. У циклі агента ШІ пише виправлення, а Mjölnir сканує повторно, щоб його довести." width="880" />
|
|
73
|
+
</p>
|
|
74
|
+
|
|
75
|
+
<sub>Створено для цієї сторінки й показано в масштабі 1:1. Згенеровано командою `npm run docs:readme-brand` і захищено від розбіжностей у CI; оцінка, лічильники та ID правила беруться з [`script.demo.json`](assets/video/script.demo.json), [`demo-report.json`](assets/readme/demo-report.json) і реєстру правил, ніколи не вводяться вручну. Те саме зображення у вигляді постера: [`architecture.svg`](assets/readme/architecture.svg).</sub>
|
|
76
|
+
|
|
77
|
+
<br />
|
|
78
|
+
|
|
79
|
+
## Подивитися в роботі
|
|
36
80
|
|
|
37
|
-
|
|
81
|
+
Реальне сканування [`examples/demo-repo`](examples/demo-repo), невеликого набору тестів Playwright із CI-workflow. Ось куди пішли його бали:
|
|
38
82
|
|
|
39
83
|
<p align="center">
|
|
40
|
-
<img src="assets/readme/
|
|
84
|
+
<img src="assets/readme/terminal-hero.svg" alt="Розбивка вирахувань Mjölnir: WORTHINESS 80/100 WORTHY, оцінка за категоріями, блок вирахувань за серйозністю та список FIX THIS FIRST" width="520" />
|
|
41
85
|
</p>
|
|
42
86
|
|
|
43
|
-
<sub
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
87
|
+
<sub>Згенеровано командою `npm run docs:hero` з реального сканування і захищено від розбіжностей у CI. Повний звіт `--verbose` того самого сканування — [`demo.svg`](assets/readme/demo.svg) (`npm run docs:demo`).</sub>
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary><strong>Дивитися</strong> — сканування, виправлення, яке воно виводить, і повторне сканування, яке його доводить</summary>
|
|
91
|
+
|
|
92
|
+
<br />
|
|
93
|
+
|
|
94
|
+
<p align="center">
|
|
95
|
+
<a href="assets/video/mjolnir-demo.mp4">
|
|
96
|
+
<img src="assets/video/mjolnir-demo-poster.png" alt="Кадр демонстраційного запису: npx mjolnir-qa@latest сканує демонстраційний репозиторій у вікні термінала" width="900" />
|
|
97
|
+
</a>
|
|
98
|
+
</p>
|
|
48
99
|
|
|
49
|
-
|
|
100
|
+
<sub>Відрендерено кадр за кадром з реального сканування командою `npm run docs:video`; ніколи не записувалося з екрана. Виберіть кадр, щоб відкрити [`mjolnir-demo.mp4`](assets/video/mjolnir-demo.mp4).</sub>
|
|
50
101
|
|
|
51
|
-
|
|
52
|
-
Python-тестовий файл — чотири мови/формати за один прохід.
|
|
53
|
-
2. Він знайшов докази, що послаблюють довіру до сьюта —
|
|
54
|
-
`continue-on-error`, що маскує job, `|| true`, що ковтає exit-код,
|
|
55
|
-
жорсткі sleep'и, крихкий селектор, захардкоджені staging-URL,
|
|
56
|
-
очікування `networkidle`.
|
|
57
|
-
3. Кожну він перетворив на конкретну знахідку з ID правила, місцем і
|
|
58
|
-
фіксом — і в єдиний скор, за яким можна гейтити PR.
|
|
102
|
+
</details>
|
|
59
103
|
|
|
60
104
|
### Одна знахідка зблизька
|
|
61
105
|
|
|
62
|
-
|
|
63
|
-
|
|
106
|
+
Кожна знахідка відповідає на чотири запитання: де вона, наскільки Mjölnir упевнений, як часто правило помиляється і як це виправити.
|
|
107
|
+
|
|
108
|
+
<p align="center">
|
|
109
|
+
<img src="assets/readme/finding-anatomy.svg" alt="Перша знахідка демонстраційного сканування, саме так, як її виводить термінал, із позначеними чотирма частинами: де, наскільки впевнено, як часто правило помиляється, і виправлення." width="100%" />
|
|
110
|
+
</p>
|
|
111
|
+
|
|
112
|
+
`mjolnir explain QA-CI-001` виводить повне досьє довіри правила, зокрема виміряну частку хибних спрацювань і рівень, який ця частка йому забезпечила:
|
|
64
113
|
|
|
65
114
|
```text
|
|
66
|
-
|
|
115
|
+
▍ QA-CI-001 — continue-on-error masks a failing verification gate
|
|
67
116
|
|
|
68
117
|
Severity: error
|
|
69
118
|
Confidence: high
|
|
119
|
+
Tier: quarantine
|
|
70
120
|
Evidence: E2
|
|
71
|
-
|
|
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
|
|
72
126
|
|
|
73
127
|
WHAT WAS FOUND (real detector output, not a mockup)
|
|
74
128
|
Job `security-scan` runs a verification gate under `continue-on-error: true`.
|
|
75
129
|
|
|
76
130
|
WHY IT MATTERS
|
|
77
|
-
This job can fail every day and CI will still show green. The checkmark
|
|
78
|
-
|
|
131
|
+
This job can fail every day and CI will still show green. The checkmark on
|
|
132
|
+
this workflow cannot be trusted.
|
|
79
133
|
|
|
80
134
|
HOW TO FIX
|
|
81
135
|
Remove continue-on-error, or scope it to individual non-blocking steps only.
|
|
82
|
-
```
|
|
83
136
|
|
|
84
|
-
|
|
85
|
-
щось пройшло, хоча воно не пройшло.
|
|
137
|
+
Example from this rule's own must-fire fixture: QA-CI-001/must-fire/masked.yml
|
|
86
138
|
|
|
87
|
-
|
|
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
|
|
88
146
|
|
|
89
|
-
|
|
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.
|
|
90
150
|
|
|
91
|
-
|
|
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.
|
|
92
154
|
|
|
93
|
-
|
|
94
|
-
npx mjolnir-qa@latest
|
|
155
|
+
Docs: mjolnir rules --md (full catalog, this rule included)
|
|
95
156
|
```
|
|
96
157
|
|
|
97
|
-
|
|
98
|
-
|
|
158
|
+
Ось одиниця цінності: одне місце, де CI повідомляє про успіх, якого не заслужив.
|
|
159
|
+
|
|
160
|
+
<br />
|
|
161
|
+
|
|
162
|
+
## Швидкий старт
|
|
99
163
|
|
|
100
164
|
```bash
|
|
101
|
-
npx mjolnir-qa@latest
|
|
165
|
+
npx mjolnir-qa@latest
|
|
102
166
|
```
|
|
103
167
|
|
|
104
|
-
|
|
105
|
-
Все інше опціональне.
|
|
168
|
+
Він сканує поточний каталог і виводить Trust Report: що знайдено, наскільки цьому можна довіряти, чому і що робити далі. Він завершується з кодом `0`, якщо на рівні гейта або вище нічого не знайдено.
|
|
106
169
|
|
|
107
|
-
|
|
108
|
-
| ----------------------------------- | --------------------------------------------------------- |
|
|
109
|
-
| `mjolnir` | Скан усього репо + показник гідності |
|
|
110
|
-
| `mjolnir --scope changed` | Лише те, що принесла ваша гілка — CI-режим |
|
|
111
|
-
| `mjolnir ci install` | Генерує рекомендаційний PR-workflow |
|
|
112
|
-
| `mjolnir explain QA-CI-001` | Що / чому / фікс + виміряний FP-рейт для правила |
|
|
113
|
-
| `mjolnir rules --unmeasured` | Правила, що працюють за припущенням, а не за вимірюванням |
|
|
114
|
-
| `mjolnir --json` / `--format sarif` | Машинночитабельно / GitHub Code Scanning |
|
|
115
|
-
| `mjolnir --strict` | Також правила tier-у quarantine (вищий ризик FP) |
|
|
116
|
-
|
|
117
|
-
<details>
|
|
118
|
-
<summary><strong>Коли щось флає</strong></summary>
|
|
170
|
+
У CI скануйте лише те, що внесла гілка, щоб успадкований набір тестів не втопив ваш перший pull request:
|
|
119
171
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
| `mjolnir triage ./test-results/` | Пропозиція карантину з історії виконання |
|
|
124
|
-
| `mjolnir pw-report ./test-results/` | Зведення прогону Playwright — ретраї / флейки / найповільніші |
|
|
125
|
-
| `mjolnir doctor:playwright` | Глибокий скан лише Playwright + Selector Health Score |
|
|
172
|
+
```bash
|
|
173
|
+
npx mjolnir-qa@latest --scope changed
|
|
174
|
+
```
|
|
126
175
|
|
|
127
|
-
|
|
176
|
+
`mjolnir ci install` записує це як workflow GitHub Actions з [action](https://github.com/Sergey-Bar/Mjolnir#readme), закріпленим на мажорному тезі `v1` (або просто `npx` з `--no-action`). Він залишається рекомендаційним, доки ви не вирішите, що він має блокувати.
|
|
177
|
+
|
|
178
|
+
| Команда | Що робить |
|
|
179
|
+
| ----------------------------------- | ---------------------------------------------------------- |
|
|
180
|
+
| `mjolnir` | Trust Report: вердикт, упевненість, наступна дія |
|
|
181
|
+
| `mjolnir --scope changed` | Лише те, що внесла ваша гілка (варіант для CI) |
|
|
182
|
+
| `mjolnir ci install` | Створює рекомендаційний workflow для PR (на основі action) |
|
|
183
|
+
| `mjolnir explain QA-CI-001` | Що, чому і як виправити, плюс виміряна частка FP |
|
|
184
|
+
| `mjolnir why src/a.spec.ts:42` | Чому позначено саме цей рядок. Ніколи не блокує. |
|
|
185
|
+
| `mjolnir forensics ./test-results/` | Докази з реального прогону |
|
|
186
|
+
| `mjolnir trust-report` | Самодостатній Trust Artifact (md + json) |
|
|
187
|
+
| `mjolnir handoff` | План виправлень для агента-програміста |
|
|
188
|
+
| `mjolnir --json` / `--format sarif` | Машинозчитуваний вивід, GitHub Code Scanning |
|
|
189
|
+
| `mjolnir --format codequality` | Звіт GitLab Code Quality (артефакт віджета MR) |
|
|
190
|
+
| `mjolnir --strict` | Також запускає правила рівня quarantine (вищий ризик FP) |
|
|
128
191
|
|
|
129
192
|
<details>
|
|
130
|
-
<summary><strong
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
| `mjolnir
|
|
137
|
-
| `mjolnir
|
|
138
|
-
| `mjolnir
|
|
139
|
-
| `mjolnir
|
|
140
|
-
| `mjolnir
|
|
141
|
-
| `mjolnir
|
|
142
|
-
| `mjolnir
|
|
143
|
-
| `mjolnir
|
|
144
|
-
| `mjolnir
|
|
193
|
+
<summary><strong>Усі інші команди</strong> — розбір нестабільних тестів, звіти, контроль</summary>
|
|
194
|
+
|
|
195
|
+
<br />
|
|
196
|
+
|
|
197
|
+
| Команда | Що робить |
|
|
198
|
+
| ----------------------------------- | ------------------------------------------------------------------------------- |
|
|
199
|
+
| `mjolnir --classic` | Банер оцінки з часів до Trust Report |
|
|
200
|
+
| `mjolnir explain verdict` | Чому вердикт збереженого сканування саме такий |
|
|
201
|
+
| `mjolnir triage ./test-results/` | Покроковий розбір. Кожен рядок завершується наступною дією. |
|
|
202
|
+
| `mjolnir pw-report ./test-results/` | Зведення прогону Playwright: повтори, нестабільні тести, найповільніші |
|
|
203
|
+
| `mjolnir doctor:playwright` | Глибоке сканування лише для Playwright плюс Selector Health Score |
|
|
204
|
+
| `mjolnir fix --dry-run` / `fix` | Безпечні автовиправлення, кожне пересканується, щоб довести, що воно спрацювало |
|
|
205
|
+
| `mjolnir baseline` / `diff` | Знімок знахідок, потім звіт лише про нові або погіршені |
|
|
206
|
+
| `mjolnir impact --since <ref>` | Що вніс і що виправив коміт |
|
|
207
|
+
| `mjolnir summary` | Анотації CI і зведення кроку на основі звіту |
|
|
208
|
+
| `mjolnir pr-comment` | Коментар до PR у межах змін, у форматі Markdown |
|
|
209
|
+
| `mjolnir debt` | Реєстр тестового боргу з моделлю витрат |
|
|
210
|
+
| `mjolnir handover` | Карта набору тестів для нового QA-інженера |
|
|
211
|
+
| `mjolnir init` | Визначає фреймворки, виводить чекліст налаштування |
|
|
212
|
+
| `mjolnir suppressions` | Список придушених знахідок для контролю |
|
|
213
|
+
| `mjolnir rules --unmeasured` | Правила, що працюють на припущенні, а не на вимірюванні |
|
|
214
|
+
| `mjolnir rules --md` | Повний каталог правил (JSON або Markdown) |
|
|
215
|
+
| `mjolnir doctor` | Самоаудит власної бази правил Mjölnir |
|
|
216
|
+
| `mjolnir create-rule <ID>` | Створює заготовку нового правила та його фікстур |
|
|
217
|
+
| `mjolnir stats` | Локальні лічильники всіх помічених виправлень |
|
|
218
|
+
| `mjolnir badge` | JSON для ендпоінта shields.io і фрагмент коду |
|
|
219
|
+
| `mjolnir --cache` | Інкрементальні пересканування через локальний кеш вердиктів |
|
|
220
|
+
| `mjolnir --format mermaid` | Діаграма архітектури тестів для коментаря до PR |
|
|
221
|
+
|
|
222
|
+
`mjolnir help <command>` виводить використання, приклади та наступний крок для будь-якої з них.
|
|
145
223
|
|
|
146
224
|
</details>
|
|
147
225
|
|
|
148
|
-
|
|
149
|
-
`npm i -g mjolnir-qa`. Потребує Node.js ≥ 22.18. Працює на Windows,
|
|
150
|
-
macOS і Linux.
|
|
151
|
-
|
|
152
|
-
---
|
|
153
|
-
|
|
154
|
-
## 👥 Для кого це?
|
|
155
|
-
|
|
156
|
-
- **QA / SDET**, які володіють e2e- чи інтеграційним с'ютом і яким
|
|
157
|
-
потрібні докази, що с'ют справді заслуговує зелену галочку, яку він
|
|
158
|
-
видає.
|
|
159
|
-
- **Платформові / DevEx-команди**, відповідальні за цілісність CI та
|
|
160
|
-
release-gates — ті, для кого `continue-on-error` ніколи не повинен
|
|
161
|
-
мовчки перефарбовувати червоний пайплайн у зелений.
|
|
162
|
-
- **OSS-мейнтейнери**, яким потрібен дешевий, завжди увімкнений
|
|
163
|
-
верифікаційний гейт, що працює локально й у CI без мережевих
|
|
164
|
-
викликів.
|
|
165
|
-
|
|
166
|
-
---
|
|
226
|
+
Потрібен **Node.js ≥ 22.18** на Windows, macOS або Linux. Віддаєте перевагу глобальному встановленню? `npm i -g mjolnir-qa`. Мінімальна версія визначається інструментами збирання (tsdown орієнтований на неї, а пайплайн релізів проганяє на ній smoke-тести); залежностям часу виконання більшого не потрібно.
|
|
167
227
|
|
|
168
|
-
|
|
228
|
+
<br />
|
|
169
229
|
|
|
170
|
-
|
|
171
|
-
| --- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
172
|
-
| ⚖️ | **Показник гідності** — одне число, прозора таблиця відрахувань, жодного чорного ящика |
|
|
173
|
-
| 🎭 | **Selector Health Score** — оцінює ваші Playwright-локатори, а не лише pass-rate |
|
|
174
|
-
| 🔬 | **Runtime-криміналістика** — читає реальні дані прогонів Playwright/JUnit і ловить `TRUE-FLAKE`, а не лише статичні здогадки |
|
|
175
|
-
| 🚨 | **Правила цілісності CI** — ловить `continue-on-error`, `\|\| true` та інші трюки з хибним зеленим |
|
|
176
|
-
| 🐍 | **Усі чотири Playwright-бінінги** — TypeScript, Python, Java, C#/.NET — плюс pytest, JUnit/TestNG і CI-workflows |
|
|
177
|
-
| 🔒 | **Local-first** — нуль мережевих викликів під час сканування, нуль телеметрії, робота за секунди |
|
|
230
|
+
## Що знаходить Mjölnir
|
|
178
231
|
|
|
179
|
-
|
|
232
|
+
<p align="center">
|
|
233
|
+
<img src="assets/readme/stack.svg" alt="Працює з вашим стеком: мови, тестові фреймворки та CI-системи, які покривають його правила, за даними реєстру правил." width="100%" />
|
|
234
|
+
</p>
|
|
180
235
|
|
|
181
|
-
|
|
182
|
-
Правило, що спрацьовує на власній негативній фікстурі, не може вийти —
|
|
183
|
-
це фаєрвол хибних спрацювань.
|
|
236
|
+
**79 правил** у чотирьох родинах — гігієна тестів, якість тестів, Playwright і цілісність CI — для TypeScript і JavaScript, Python, Java, C# та YAML GitHub Actions. Вони охоплюють Playwright у всіх чотирьох прив'язках, а також pytest, JUnit, TestNG, NUnit, xUnit, MSTest, Jest, Vitest і Mocha, з початковим покриттям Cypress і Selenium. Дев'ять із них, щоб показати загальний вигляд:
|
|
184
237
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
|
189
|
-
|
|
|
190
|
-
| QA-TEST-
|
|
191
|
-
| QA-
|
|
192
|
-
| QA-
|
|
193
|
-
| QA-
|
|
194
|
-
| QA-
|
|
195
|
-
| QA-
|
|
196
|
-
| QA-TEST-010 | Порожнє тіло тесту | error |
|
|
238
|
+
| ID | Правило | Серйозність | Рівень |
|
|
239
|
+
| ------------ | ----------------------------------------------------------------------- | ----------- | ---------- |
|
|
240
|
+
| QA-CI-001 | `continue-on-error` маскує гейт перевірки, що падає | error | quarantine |
|
|
241
|
+
| QA-CI-009 | Код виходу тестів не передається далі (`\|` без pipefail, ланцюжки `;`) | error | extended |
|
|
242
|
+
| QA-TEST-001 | Закомічено сфокусований тест (`.only`, `fit`) | error | quarantine |
|
|
243
|
+
| QA-TEST-003 | Тест без тверджень | error | quarantine |
|
|
244
|
+
| QA-TQUAL-009 | Твердження на promise без await | error | quarantine |
|
|
245
|
+
| QA-PW-002 | Твердження на локаторі без await | error | core |
|
|
246
|
+
| QA-PW-004 | Крихкі селектори CSS/XPath | warning | quarantine |
|
|
247
|
+
| QA-PY-002 | Пропущений тест (`skip`, нестрогий `xfail`) | warning | core |
|
|
248
|
+
| QA-CS-103 | Тестовий метод без тверджень | error | core |
|
|
197
249
|
|
|
198
|
-
|
|
250
|
+
Повний каталог генерується з реєстру й ніколи не ведеться вручну: `mjolnir rules --md`, [`docs/rules/`](docs/rules/) або [посібник про те, що він перевіряє](https://sergey-bar.github.io/Mjolnir/guide/what-it-checks).
|
|
199
251
|
|
|
200
252
|
<details>
|
|
201
|
-
<summary><strong
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
|
253
|
+
<summary><strong>Усі правила, згадані в цьому README</strong>, в одній таблиці</summary>
|
|
254
|
+
|
|
255
|
+
<br />
|
|
256
|
+
|
|
257
|
+
> Правила `quarantine` запускаються лише з `--strict` і ніколи не блокують (їхній рівень обмежено info). Показано серйозність, задану автором.
|
|
258
|
+
|
|
259
|
+
| ID | Родина | Правило | Серйозність | Рівень |
|
|
260
|
+
| ------------ | ---------- | ------------------------------------------------------------------- | ----------- | ---------- |
|
|
261
|
+
| QA-TEST-001 | Гігієна | Закомічено сфокусований тест (`.only`, `fit`) | error | quarantine |
|
|
262
|
+
| QA-TEST-002 | Гігієна | Пропущений тест. Без відстежуваної причини підвищується до `error`. | warning | quarantine |
|
|
263
|
+
| QA-TEST-003 | Гігієна | Тест без тверджень | error | quarantine |
|
|
264
|
+
| QA-TEST-004 | Гігієна | Жорсткий sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning | extended |
|
|
265
|
+
| QA-TEST-006 | Гігієна | Зловживання повторами, що приховує нестабільність | warning | quarantine |
|
|
266
|
+
| QA-TEST-010 | Гігієна | Порожнє тіло тесту | error | quarantine |
|
|
267
|
+
| QA-TQUAL-002 | Якість | Тавтологічне твердження | error | quarantine |
|
|
268
|
+
| QA-TQUAL-009 | Якість | Твердження на promise без await | error | quarantine |
|
|
269
|
+
| QA-TQUAL-011 | Якість | Закоментовані тести | warning | extended |
|
|
270
|
+
| QA-PW-002 | Playwright | Твердження на локаторі без await | error | core |
|
|
271
|
+
| QA-PW-003 | Playwright | Закомічено `page.pause()` / `test.only()` | error | core |
|
|
272
|
+
| QA-PW-004 | Playwright | Крихкі селектори CSS/XPath | warning | quarantine |
|
|
273
|
+
| QA-PW-123 | Playwright | Жорстко задані URL оточень | warning | quarantine |
|
|
274
|
+
| QA-PW-140 | Playwright | Скриншот без `maxDiffPixelRatio` | warning | core |
|
|
275
|
+
| QA-CI-001 | CI | `continue-on-error` маскує гейт, що падає | error | quarantine |
|
|
276
|
+
| QA-CI-002 | CI | `\|\| true` ковтає коди виходу | error | extended |
|
|
277
|
+
| QA-CI-005 | CI | Звіт використовується, але ніколи не створюється | error | quarantine |
|
|
278
|
+
| QA-CI-007 | CI | Обгортки з повторами навколо тестів | warning | extended |
|
|
279
|
+
| QA-CI-008 | CI | Завжди успішний крок маскує падіння | error | quarantine |
|
|
280
|
+
| QA-CI-009 | CI | Код виходу не передається далі (`\|` без pipefail, ланцюжки `;`) | error | extended |
|
|
281
|
+
| QA-CI-010 | CI | Тести пропускаються там, де мають блокувати | error | quarantine |
|
|
282
|
+
| QA-PY-002 | Python | Пропущений тест (`skip`, нестрогий `xfail`) | warning | core |
|
|
283
|
+
| QA-PY-003 | Python | Тестова функція без тверджень | error | quarantine |
|
|
284
|
+
| QA-PY-005 | Python | `time.sleep()` у тестах | warning | extended |
|
|
285
|
+
| QA-PY-012 | Python | Тавтологічне твердження | error | quarantine |
|
|
286
|
+
| QA-JV-101 | Java | Вимкнений тест (`@Disabled`) | warning | core |
|
|
287
|
+
| QA-JV-102 | Java | Жорсткий sleep (`Thread.sleep()`) | warning | extended |
|
|
288
|
+
| QA-JV-103 | Java | Тестовий метод без тверджень | error | extended |
|
|
289
|
+
| QA-JV-105 | Java | Жорсткий sleep через `waitForTimeout()` у Playwright | warning | core |
|
|
290
|
+
| QA-JV-106 | Java | Крихкий селектор замість локатора за роллю | warning | quarantine |
|
|
291
|
+
| QA-CS-101 | C# | Пропущений тест (`[Ignore]`, `[Fact(Skip=)]`) | warning | core |
|
|
292
|
+
| QA-CS-102 | C# | Жорсткий sleep (`Thread.Sleep` / `Task.Delay`) | warning | core |
|
|
293
|
+
| QA-CS-103 | C# | Тестовий метод без тверджень | error | core |
|
|
294
|
+
| QA-CS-105 | C# | Жорсткий sleep через `WaitForTimeoutAsync()` | warning | extended |
|
|
295
|
+
| QA-CS-106 | C# | Крихкий селектор замість локатора за роллю | warning | quarantine |
|
|
296
|
+
|
|
297
|
+
Для Python також є QA-PY-001…012 (гігієна pytest) і QA-PY-101…108 (Playwright для Python). Cypress і Selenium мають стартові набори по три правила.
|
|
208
298
|
|
|
209
299
|
</details>
|
|
210
300
|
|
|
211
|
-
|
|
212
|
-
<summary><strong>Playwright 🎭</strong></summary>
|
|
301
|
+
Кожне правило постачається з фікстурою must-fire **і** фікстурою must-not-fire, а правило, що спрацьовує на власній негативній фікстурі, не може бути випущене. Це захист від хибних спрацювань; `mjolnir doctor` забезпечує його у власному CI цього репозиторію.
|
|
213
302
|
|
|
214
|
-
|
|
215
|
-
| --------- | --------------------------------------- | -------- |
|
|
216
|
-
| QA-PW-002 | Ассерт локатора без await | error |
|
|
217
|
-
| QA-PW-003 | `page.pause()` / `test.only()` у коміті | error |
|
|
218
|
-
| QA-PW-004 | Крихкі CSS/XPath-селектори | warning |
|
|
219
|
-
| QA-PW-123 | Захардкоджені URL середовищ | warning |
|
|
303
|
+
### Selector Health Score
|
|
220
304
|
|
|
221
|
-
|
|
305
|
+
`mjolnir doctor:playwright` оцінює кожен локатор за тим, як він знаходить елемент: так, як це зробив би користувач (роль, мітка, текст), через явний контракт (`data-testid`) або через структурну випадковість (ланцюжки CSS, XPath). Кожен файл отримує оцінку від 0 до 100:
|
|
222
306
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
| ID | Правило | Severity |
|
|
227
|
-
| --------- | ---------------------------------------------------------------- | -------- |
|
|
228
|
-
| QA-CI-001 | `continue-on-error` маскує падіння | error |
|
|
229
|
-
| QA-CI-002 | `\|\| true` ковтає exit-коди | error |
|
|
230
|
-
| QA-CI-005 | Звіт споживається, але ніколи не генерується | error |
|
|
231
|
-
| QA-CI-007 | Retry-обгортки навколо тестів | warning |
|
|
232
|
-
| QA-CI-008 | Завжди успішний крок маскує падіння | error |
|
|
233
|
-
| QA-CI-009 | Exit-код тесту не прокидається (`\|` без pipefail, ланцюжки `;`) | error |
|
|
234
|
-
| QA-CI-010 | Тести пропускаються там, де мають блокувати (skip-on-PR-гарди) | error |
|
|
235
|
-
|
|
236
|
-
</details>
|
|
237
|
-
|
|
238
|
-
<details>
|
|
239
|
-
<summary><strong>Python / pytest 🐍</strong></summary>
|
|
240
|
-
|
|
241
|
-
| ID | Правило | Severity |
|
|
242
|
-
| --------- | ------------------------------------------- | -------- |
|
|
243
|
-
| QA-PY-002 | Пропущений тест (`skip`, нестрогий `xfail`) | warning |
|
|
244
|
-
| QA-PY-003 | Тестова функція без ассертів | error |
|
|
245
|
-
| QA-PY-005 | `time.sleep()` у тестах | warning |
|
|
246
|
-
| QA-PY-012 | Тавтологічний ассерт | error |
|
|
247
|
-
|
|
248
|
-
Усього 20 Python-правил (QA-PY-001…012 гігієна pytest + QA-PY-101…108 Playwright-Python).
|
|
307
|
+
```text
|
|
308
|
+
▍ SELECTOR HEALTH
|
|
249
309
|
|
|
250
|
-
|
|
310
|
+
e2e/login.spec.ts
|
|
311
|
+
[█████████████░░░░░░░] 65 / 100
|
|
312
|
+
role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
|
|
251
313
|
|
|
252
|
-
|
|
253
|
-
|
|
314
|
+
e2e/checkout.spec.ts
|
|
315
|
+
[██████████████████░░] 88 / 100
|
|
316
|
+
role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
|
|
317
|
+
```
|
|
254
318
|
|
|
255
|
-
|
|
256
|
-
| --------- | -------------------------------------------- | -------- |
|
|
257
|
-
| QA-JV-101 | Вимкнений тест (`@Disabled`) | warning |
|
|
258
|
-
| QA-JV-102 | Жорсткий sleep (`Thread.sleep()`) | warning |
|
|
259
|
-
| QA-JV-103 | Тестовий метод без ассертів | error |
|
|
260
|
-
| QA-JV-105 | Жорсткий sleep Playwright `waitForTimeout()` | warning |
|
|
261
|
-
| QA-JV-106 | Крихкий селектор замість role-локатора | warning |
|
|
319
|
+
Це вимірює **стійкість, а не коректність**. `.btn.btn-primary > div:nth-child(2)` проходить сьогодні й проходитиме, доки хтось не торкнеться розмітки. Низька оцінка ніколи не стверджує, що тест зламаний, — лише що він залежить від розмітки, яку ніхто не обіцяв зберігати.
|
|
262
320
|
|
|
263
|
-
|
|
321
|
+
<br />
|
|
264
322
|
|
|
265
|
-
|
|
266
|
-
<summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
|
|
323
|
+
## Оцінка надійності
|
|
267
324
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
| QA-CS-102 | Жорсткий sleep (`Thread.Sleep` / `Task.Delay`) | warning |
|
|
272
|
-
| QA-CS-103 | Тестовий метод без ассертів | error |
|
|
273
|
-
| QA-CS-105 | Жорсткий sleep `WaitForTimeoutAsync()` | warning |
|
|
274
|
-
| QA-CS-106 | Крихкий селектор замість role-локатора | warning |
|
|
325
|
+
<p align="center">
|
|
326
|
+
<img src="assets/readme/score-gauge.svg" alt="Шкала надійності від 0 до 100 з маркером, що проходить по кожній оцінці: UNWORTHY нижче 50, NEEDS WORK від 50 до 79, WORTHY від 80 до 99, FORGED при 100" width="720" />
|
|
327
|
+
</p>
|
|
275
328
|
|
|
276
|
-
|
|
329
|
+
<sub>Кожна оцінка від 0 до 100, розміщена справжнім `deriveScoreState`. Згенеровано командою `npm run docs:gauge` і захищено від розбіжностей у CI.</sub>
|
|
277
330
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
> Сторінки за правилами лежать у [`docs/rules/`](docs/rules/).
|
|
331
|
+
| Оцінка | Вердикт |
|
|
332
|
+
| --------- | ----------------------------------------- |
|
|
333
|
+
| `0 – 49` | **UNWORTHY** |
|
|
334
|
+
| `50 – 79` | **NEEDS WORK** |
|
|
335
|
+
| `80 – 99` | **WORTHY** |
|
|
336
|
+
| `100` | **FORGED** |
|
|
337
|
+
| `null` | **UNKNOWN**: оголошень тестів не знайдено |
|
|
286
338
|
|
|
287
|
-
|
|
339
|
+
**Як вона обчислюється.** Серйозність задає базове вирахування (`error −8`, `warning −3`, `info −1`), а рівень доказовості його зменшує: E2 враховується повністю, E1 наполовину (з округленням униз), E0 не враховується. Сума нормується за охопленням набору, тобто вирахування на одне оголошення тесту, а не на файл. Термінал виводить ті самі зменшені числа, які використала оцінка; прихованої другої моделі немає. Подробиці: [docs/SCORING.md](docs/SCORING.md) і [посібник з оцінки](https://sergey-bar.github.io/Mjolnir/guide/scoring).
|
|
288
340
|
|
|
289
|
-
|
|
290
|
-
OSS-коді** (по ≥ 10 вручну класифікованих знахідок на правило; див.
|
|
291
|
-
[docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Інші 21 виходять на оцінці
|
|
292
|
-
автора. Футер кожного скана каже, скільки із _спрацьованих_ правил
|
|
293
|
-
виміряно; `mjolnir rules --unmeasured` перелічує невиміряні; сторінка
|
|
294
|
-
`mjolnir explain` кожного правила вказує її статус. Ми публікуємо
|
|
295
|
-
це відправлено в карантин. Збільшувати це число — постійна робота проєкту.
|
|
341
|
+
**Чого не означає 100.** Це не означає, що програма коректна, набір тестів достатній або продукт вільний від дефектів. Це означає лише одне: **жодне з правил, перевірених Mjölnir, не дало вирахування в цьому скануванні та за цієї моделі доказів.**
|
|
296
342
|
|
|
297
|
-
|
|
343
|
+
<br />
|
|
298
344
|
|
|
299
|
-
|
|
300
|
-
**виміряною** частотою хибних спрацювань:
|
|
345
|
+
## Модель доказів
|
|
301
346
|
|
|
302
|
-
|
|
303
|
-
| ------------ | -------------------------------------- | :-------------------: | :--------: |
|
|
304
|
-
| `core` | ≤ 10 % виміряних FP | ✅ | ✅ |
|
|
305
|
-
| `extended` | ≤ 30 % виміряних FP | ✅ | ✅ |
|
|
306
|
-
| `quarantine` | понад 30 % або ще не виміряно (n < 10) | ❌ | ✅ |
|
|
347
|
+
Кожна знахідка має дві мітки: наскільки впевнений Mjölnir і наскільки далеко знахідку перевірено. У цьому різниця між інструментом, що повідомляє про шаблони, та інструментом, від якого можна ставити в залежність реліз.
|
|
307
348
|
|
|
308
|
-
|
|
309
|
-
| --------------- | --------------- | ----------------------------------------------------------- |
|
|
310
|
-
| TypeScript / JS | AST компілятора | найширший, найбільш виміряний — переважно `core`/`extended` |
|
|
311
|
-
| Python / pytest | Regex-шар | широкий, перевірений корпусом — переважно `core`/`extended` |
|
|
312
|
-
| Java | Regex-шар | новіший — переважно `extended`/`quarantine` |
|
|
313
|
-
| C# / .NET | Regex-шар | новіший — переважно `extended`/`quarantine` |
|
|
349
|
+
**Наскільки впевнено — рівень доказовості.**
|
|
314
350
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
351
|
+
| Рівень | Назва | Значення | Вирахування |
|
|
352
|
+
| ------ | -------------------- | -------------------------------------------------------- | ----------- |
|
|
353
|
+
| **E2** | Детермінований доказ | Дефект присутній у коді в тому вигляді, як він написаний | Повне |
|
|
354
|
+
| **E1** | Доказ за шаблоном | Збігся шаблон, тісно пов'язаний із дефектом | Половина |
|
|
355
|
+
| **E0** | Спостереження | Варто знати. Не твердження, що щось не так. | Нуль |
|
|
318
356
|
|
|
319
|
-
|
|
357
|
+
Упевненість у виявленні — це не сила доказу. Правило може бути впевнене, що знайшло те, що шукало, і все одно дивитися на евристику. Знахідки E1 призначені для того, щоб їх читали й оцінювали, а не застосовували наосліп, і ця межа позначена на знахідці в терміналі, у JSON і в передачі агенту.
|
|
320
358
|
|
|
321
|
-
|
|
359
|
+
**Наскільки далеко перевірено — рівень довіри.** Більшість знахідок отримано читанням вашого коду. Дайте Mjölnir звіт реального прогону тестів, і він зможе підтвердити, що код справді виконувався.
|
|
322
360
|
|
|
323
361
|
<p align="center">
|
|
324
|
-
<img src="assets/readme/
|
|
362
|
+
<img src="assets/readme/trust-ladder.svg" alt="Драбина довіри від L0 до L5. L0–L2 отримуються читанням коду; для L3–L5 потрібен звіт реального прогону, що позначено розривом у драбині." width="100%" />
|
|
325
363
|
</p>
|
|
326
364
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
365
|
+
| Рівень | Простими словами | Що для цього потрібно |
|
|
366
|
+
| ------ | ------------------ | -------------------------------------------------- |
|
|
367
|
+
| **L0** | Помічено | Читання коду |
|
|
368
|
+
| **L1** | Схоже на проблему | Читання коду: збігся шаблон |
|
|
369
|
+
| **L2** | Доведено в коді | Читання коду: дефект структурний |
|
|
370
|
+
| **L3** | Файл виконувався | Звіт прогону показує, що файл знахідки виконувався |
|
|
371
|
+
| **L4** | Тест виконувався | Звіт прогону показує, що тест знахідки виконувався |
|
|
372
|
+
| **L5** | Прогін підтверджує | Власний результат прогону підтверджує клас дефекту |
|
|
330
373
|
|
|
331
|
-
|
|
332
|
-
експозицію с'юта (відрахування на оголошення тесту). Відрахування,
|
|
333
|
-
зважені за доказами, означають, що слабкі сигнали коштують дешевше.
|
|
334
|
-
Термінал показує ті самі зі скидкою числа, що використовує скор —
|
|
335
|
-
жодного чорного ящика. Повна методика: [docs/SCORING.md](docs/SCORING.md).
|
|
374
|
+
Статичне сканування зупиняється на L2. Лише звіт реального прогону (Playwright JSON, Jest або Vitest JSON, JUnit XML) може підняти знахідку до L3 і вище, тож знахідка, яку жодного разу не бачили в роботі, ніколи не може стверджувати протилежне. Визначення: [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md).
|
|
336
375
|
|
|
337
|
-
|
|
376
|
+
### Скільки з цього виміряно
|
|
338
377
|
|
|
339
|
-
|
|
340
|
-
| ------- | ---------------- |
|
|
341
|
-
| ≥ 80 | ✓ **WORTHY** |
|
|
342
|
-
| 50 – 79 | ⚠ **NEEDS WORK** |
|
|
343
|
-
| < 50 | ✖ **UNWORTHY** |
|
|
378
|
+
**У 74 з 79 правил частку хибних спрацювань виміряно на реальному OSS-коді** (щонайменше 10 вручну класифікованих знахідок на кожне; див. [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Решта 5 спираються на оцінку автора й прямо про це кажуть, правило за правилом, у `mjolnir explain`. `mjolnir rules --unmeasured` перелічує їх, а підвал кожного сканування повідомляє, скільки з правил, які справді _спрацювали_, виміряно.
|
|
344
379
|
|
|
345
|
-
|
|
346
|
-
скорі:
|
|
380
|
+
Показники залишаються публічними, навіть коли вони погані. QA-TEST-001 (закомічений `.only`) погано проходить аудит на реальних репозиторіях і тому перебуває в quarantine. Актуальне значення для кожного правила, зокрема QA-PW-141, є в аудиті.
|
|
347
381
|
|
|
348
|
-
|
|
349
|
-
| ------ | --------------------- | ---------------------- | ------------------------------------------------------- |
|
|
350
|
-
| E2 | Детермінований дефект | Повне відрахування | `.only` у коміті — структурно доказово |
|
|
351
|
-
| E1 | Евристичний патерн | Половинне відрахування | Знайдений regex'ом `sleep()` — сильний сигнал, не доказ |
|
|
352
|
-
| E0 | Спостереження | Нуль (тільки info) | Репортиться, але ніколи не гейтить CI і не віднімає |
|
|
382
|
+
### Рівні довіри правил
|
|
353
383
|
|
|
354
|
-
|
|
355
|
-
системи: знахідки E2 — структурне доказ; знахідки E1 — коректно
|
|
356
|
-
позиційовані попередження, не формальні докази.
|
|
384
|
+
Рівні визначаються виміряною часткою хибних спрацювань, а не думкою:
|
|
357
385
|
|
|
358
|
-
|
|
359
|
-
|
|
386
|
+
| Рівень | Виміряна FP | Поведінка |
|
|
387
|
+
| -------------- | ------------------------ | ------------------------------------------------------- |
|
|
388
|
+
| **core** | ≤ 10% | Звіт за замовчуванням, блокує |
|
|
389
|
+
| **extended** | ≤ 30% | Звіт за замовчуванням, знижена впевненість |
|
|
390
|
+
| **quarantine** | > 30% або явно оголошене | Лише `--strict`, обмежено рівнем info, ніколи не блокує |
|
|
391
|
+
| _не виміряно_ | n < 10 | Не може бути підвищене до core, доки не виміряне |
|
|
360
392
|
|
|
361
|
-
|
|
393
|
+
Смуги FP можуть лише понизити рівень — вони ніколи не підвищують правило з `quarantine`, якщо воно було туди явно оголошене. Явно поміщене в карантин правило залишається в quarantine незалежно від виміряного рівня FP.
|
|
362
394
|
|
|
363
|
-
|
|
395
|
+
Підвищення, пониження і зрілість за мовами: [життєвий цикл правил](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle).
|
|
364
396
|
|
|
365
|
-
|
|
397
|
+
### Чому це не лінтер
|
|
366
398
|
|
|
367
|
-
|
|
368
|
-
▚ SELECTOR HEALTH — e2e/checkout.spec.ts
|
|
399
|
+
Лінтери кажуть, чи дотримується код правил. Mjölnir каже, чи можна довіряти вашій перевірці.
|
|
369
400
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
401
|
+
| | Лінтери (ESLint, SonarQube) | Інструменти покриття | Код-рев'ю зі ШІ | **Mjölnir** |
|
|
402
|
+
| -------------------------------------------------------------- | :-------------------------: | :------------------: | :-------------: | :-----------------: |
|
|
403
|
+
| Оцінює **систему перевірки**, а не код продукту | Ні | Ні | Ні | Так |
|
|
404
|
+
| Цілісність CI-workflow (`continue-on-error`, `\|\| true`) | Ні | Ні | лише diff | Так |
|
|
405
|
+
| Оцінює стійкість локаторів Playwright (Selector Health) | Ні | Ні | Ні | Так |
|
|
406
|
+
| Читає реальні дані прогонів для вердиктів `TRUE-FLAKE` | Ні | Ні | Ні | Так |
|
|
407
|
+
| Публікує виміряну частку хибних спрацювань для кожного правила | Ні | Ні | Ні | Так |
|
|
408
|
+
| Позначає тести без тверджень | Так\* | Ні | іноді | Так |
|
|
409
|
+
| Знаходить жорсткі sleep (`waitForTimeout`, `time.sleep`) | Так\* | Ні | іноді | Так |
|
|
410
|
+
| Детермінованість (однаковий вхід — однаковий вихід) | Так | Так | Ні | Так |
|
|
411
|
+
| Вартість сканування | безкоштовно | безкоштовно | токени | **нуль** (локально) |
|
|
412
|
+
|
|
413
|
+
<sub>\*Покривається `eslint-plugin-jest` і `eslint-plugin-playwright` (`expect-expect`, `no-wait-for-timeout`), а також власними правилами SonarQube для тверджень. Стовпці описують поведінку за замовчуванням під час перевірки наборів тестів; плагіни, платні тарифи й власні правила змінюють деякі відповіді. Це зведення позиціонування, а не бенчмарк.</sub>
|
|
373
414
|
|
|
374
|
-
|
|
375
|
-
XPath топлять скор — вони ламаються на будь-якому DOM-рефакторі, не
|
|
376
|
-
повідомляючи, яку поведінку регресовано.
|
|
415
|
+
Використовуйте й рев'ю зі ШІ. Воно вловлює нюанси, наміри та помилки проєктування, яких не знайде жоден шаблон. Mjölnir знаходить те, що рев'ю зі ШІ пропускає, бо це виглядає навмисним: закомічений `.only`, проковтнутий код виходу, `continue-on-error` на тестовій джобі. Тут потрібне сканування, а не міркування.
|
|
377
416
|
|
|
378
|
-
|
|
417
|
+
<br />
|
|
379
418
|
|
|
380
|
-
##
|
|
419
|
+
## Аналіз прогонів тестів
|
|
381
420
|
|
|
382
|
-
|
|
383
|
-
виконання** — JSON-звіти Playwright та XML JUnit від будь-якого
|
|
384
|
-
раннера:
|
|
421
|
+
Статичний аналіз міркує про код, який ніколи не виконувався. Аналіз прогонів читає те, що сталося насправді: Playwright JSON, Jest JSON, Vitest JSON і JUnit XML від будь-якого ранера.
|
|
385
422
|
|
|
386
423
|
```bash
|
|
387
424
|
mjolnir forensics ./test-results/
|
|
388
425
|
```
|
|
389
426
|
|
|
390
427
|
```text
|
|
391
|
-
|
|
428
|
+
▍ FLAKINESS LEADERBOARD
|
|
392
429
|
|
|
393
430
|
3 tests · 1 failed · 1 flaky · 1 retried
|
|
394
431
|
|
|
@@ -398,293 +435,184 @@ FAILING declines an expired card (e2e/checkout.spec.ts)
|
|
|
398
435
|
████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
|
|
399
436
|
```
|
|
400
437
|
|
|
401
|
-
|
|
402
|
-
тест. Він позначається `TRUE-FLAKE` незалежно від фінальної зеленої
|
|
403
|
-
галочки.
|
|
438
|
+
`TRUE-FLAKE` не означає, що тест перезапускався. Це означає, що тест **провалив щонайменше одну спробу, а потім завершився зеленим**: випадковий успіх, позначений незалежно від того, що показує підсумкова галочка. `mjolnir triage` перетворює цю історію на пропозицію карантину, а `mjolnir pw-report` підсумовує прогін. Саме ці звіти прогонів піднімають знахідки до рівнів довіри L3 і вище.
|
|
404
439
|
|
|
405
|
-
|
|
440
|
+
<br />
|
|
406
441
|
|
|
407
|
-
##
|
|
442
|
+
## Цілісність CI
|
|
408
443
|
|
|
409
|
-
|
|
410
|
-
довіряти вашій верифікації.
|
|
444
|
+
Тест може проходити, поки навколишній пайплайн не здатен упасти. Mjölnir читає і workflow: `continue-on-error`, `|| true`, коди виходу, які ніколи не передаються далі, завжди успішні кроки, звіти, які використовуються, але ніколи не створюються, і гейти, що пропускаються саме в тих подіях, які мають блокувати. Кожна знахідка називає джобу, крок і рядок і має власний рівень доказовості.
|
|
411
445
|
|
|
412
|
-
|
|
413
|
-
| --------------------------------------------------------- | :----------------: | :------------------: | :---------: | :---------: |
|
|
414
|
-
| Цілісність CI-workflow (`continue-on-error`, `\|\| true`) | ❌ | ❌ | рідко | ✅ |
|
|
415
|
-
| Крос-мова (TS, Python, Java, C#) з одного інструменту | ❌ | ❌ | ❌ | ✅ |
|
|
416
|
-
| Оцінює стійкість Playwright-локаторів (Selector Health) | ❌ | ❌ | рідко | ✅ |
|
|
417
|
-
| Позначає тести без справжніх ассертів | ✅ (плагін)\* | ❌ | іноді | ✅ |
|
|
418
|
-
| Ловить жорсткі sleep'и (`waitForTimeout`, `time.sleep`) | ✅ (плагін)\* | ❌ | іноді | ✅ |
|
|
419
|
-
| Працює за секунди, нуль мережевих викликів під час скана | ✅ | ✅ | — | ✅ |
|
|
446
|
+
Створіть workflow для PR, за замовчуванням рекомендаційний:
|
|
420
447
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
448
|
+
```bash
|
|
449
|
+
mjolnir ci install
|
|
450
|
+
```
|
|
424
451
|
|
|
425
|
-
|
|
452
|
+
Або додайте action із Marketplace до вже наявного workflow:
|
|
426
453
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
454
|
+
```yaml
|
|
455
|
+
- uses: Sergey-Bar/Mjolnir@v1
|
|
456
|
+
with:
|
|
457
|
+
scope: changed
|
|
458
|
+
fail-on: error
|
|
459
|
+
```
|
|
432
460
|
|
|
433
|
-
|
|
434
|
-
звіту про флейкість з вердиктними мітками.
|
|
461
|
+
Закріпіть `@v1`, щоб слідувати мажорній лінії, або точний тег (`@v0.5.32`) для відтворюваного гейта. [docs/DISTRIBUTION-KIT.md](docs/DISTRIBUTION-KIT.md) описує Marketplace, Smithery та реєстри MCP.
|
|
435
462
|
|
|
436
|
-
|
|
463
|
+
Щоб надіслати знахідки в GitHub Code Scanning, завантажте SARIF (потрібен `security-events: write` на рівні workflow або job):
|
|
437
464
|
|
|
438
|
-
|
|
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
|
+
```
|
|
439
473
|
|
|
440
|
-
|
|
441
|
-
в дифі; воно не доводить, що система верифікації в цілому заслуговує
|
|
442
|
-
довіри — і бачить лише показаний йому диф.
|
|
474
|
+
У GitLab `--format codequality` записує звіт Code Quality, який читають віджет MR і анотації diff ([docs/GITLAB-CI.md](docs/GITLAB-CI.md)). Налаштування редактора й пайплайна: [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
|
|
443
475
|
|
|
444
|
-
|
|
445
|
-
| ------------------------------------------------- | :------------------------------: | :-------------------------------------: |
|
|
446
|
-
| Ціна за скан | Токени (ростуть з розміром дифа) | **Нуль** (локально, встановлений) |
|
|
447
|
-
| Бачить увесь с'ют + усі CI-конфіги | Лише PR-диф, показаний йому | **Все, щоразу** |
|
|
448
|
-
| Детермінований (той самий вхід → той самий вихід) | ❌ (недетермінований) | **✅** |
|
|
449
|
-
| Ловить патерни, що дрімають місяцями | Лише якщо в контексті | **✅** (сканує всі файли) |
|
|
450
|
-
| Пам'ятає знахідки між запусками | ❌ (немає пам'яті між сесіями) | **✅** (baseline + diff) |
|
|
451
|
-
| Запускається без людини | Потрібен PR чи промпт | **✅** (CI-хук, виконується за секунди) |
|
|
476
|
+
### Прив'язка до змін гілки
|
|
452
477
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
проковтнутий exit-код, `continue-on-error` на тестовому job. Це не
|
|
457
|
-
баги, що потребують міркувань; це факти, що потребують сканування.
|
|
478
|
+
```bash
|
|
479
|
+
npx mjolnir-qa@latest --scope changed
|
|
480
|
+
```
|
|
458
481
|
|
|
459
|
-
|
|
482
|
+
Знахідки прив'язуються до рядків, доданих вашою гілкою, відносно **merge-base**. Область — той самий набір файлів, що знаходить повне сканування (специфікації TS/JS і конфігурації адаптерів, `test_*.py`, `*Test.java`, `*Tests.cs`, `.github/workflows/*.yml`), плюс незакомічені й невідстежувані зміни, тож це працює ще до коміту. Базу визначають у порядку `main → master → origin/main → origin/master → origin/HEAD`; її можна перевизначити через `--base <ref>`.
|
|
460
483
|
|
|
461
|
-
|
|
484
|
+
Якщо merge-base визначити не вдається (неглибокий клон, від'єднаний HEAD, ціль поза git), знахідки відкочуються до прив'язки до всього файлу, **і звіт про це повідомляє.** Тихий відкат був би саме тим дефектом, заради пошуку якого існує цей інструмент.
|
|
462
485
|
|
|
463
|
-
|
|
464
|
-
ніколи блокувальний:
|
|
486
|
+
<br />
|
|
465
487
|
|
|
466
|
-
|
|
467
|
-
mjolnir ci install
|
|
468
|
-
```
|
|
488
|
+
## ШІ-агенти
|
|
469
489
|
|
|
470
|
-
|
|
490
|
+
Знахідки чогось варті, лише якщо на них хтось реагує.
|
|
471
491
|
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
- uses: github/codeql-action/upload-sarif@v3
|
|
475
|
-
with:
|
|
476
|
-
sarif_file: mjolnir.sarif
|
|
492
|
+
```text
|
|
493
|
+
SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
|
|
477
494
|
```
|
|
478
495
|
|
|
479
|
-
|
|
480
|
-
[docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
|
|
496
|
+
**ШІ пише виправлення. Mjölnir його перевіряє.** Доказ дає повторне сканування, а не власний звіт агента про успіх.
|
|
481
497
|
|
|
482
|
-
|
|
498
|
+
| Команда | Що отримує агент |
|
|
499
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
500
|
+
| `mjolnir mcp` | Сервер [MCP](https://modelcontextprotocol.io) через stdio. `scan`, `explain` і `diff` стають інструментами, які можна викликати. |
|
|
501
|
+
| `mjolnir handoff` | Збережений звіт `--json` перетворюється на детермінований план у Markdown: що виявлено, межа доказовості для кожної знахідки, що **не** має змінюватися і як це перевірити. |
|
|
502
|
+
| `mjolnir install` | Записує в місця для агентів, які вже є у вашому репозиторії (`.claude/`, `.cursor/`, `.kilo/`, `AGENTS.md`), щоб агент пересканував код, перш ніж заявити, що закінчив. |
|
|
483
503
|
|
|
484
|
-
|
|
485
|
-
відносно merge-base з `main`. Він покриває тестові файли
|
|
486
|
-
(`*.spec.*`, `*.test.*`), плюс workflow-файли GitHub і конфігурації
|
|
487
|
-
Playwright у дифі. Коли merge-base не розв'язується — shallow clone,
|
|
488
|
-
detached HEAD, не-git-ціль, інша дефолтна гілка — він чесно деградує:
|
|
489
|
-
знахідки повертаються до атрибуції на весь файл, і звіт про це каже.
|
|
490
|
-
Перевизначте базову ref через `--base <ref>`.
|
|
504
|
+
Додайте його до клієнта, який має власний CLI:
|
|
491
505
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
Mjölnir — zero-config. Опціональний `mjolnir.config.json` (або
|
|
497
|
-
`.mjolnir.json`) у корені репо підлаштовує severity, гейтинг і scope —
|
|
498
|
-
він ніколи не змінює семантику детекції.
|
|
506
|
+
```bash
|
|
507
|
+
claude mcp add mjolnir -- npx -y mjolnir-qa@latest mcp
|
|
508
|
+
```
|
|
499
509
|
|
|
500
|
-
|
|
501
|
-
| ------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
502
|
-
| `exclude` | `string[]` | Додаткові ignore-глоби (підмножина gitignore), поверх вбудованих дефолтів |
|
|
503
|
-
| `gate` | `"advisory" \| "error" \| "warning"` | Які severity завершують процес ненульовим кодом (за замовчуванням `error`; `advisory` ніколи не блокує) |
|
|
504
|
-
| `severityOverrides` | `{ "<RULE-ID>": severity }` | Переранговує знахідки правила для вашого репо |
|
|
505
|
-
| `ignore` | `IgnoreEntry[]` | Пригнічує знахідки — **`reason` обов'язковий**; записи спливають через 90 днів (явна дата `expires`, або час останньої зміни файлу конфіга для записів без неї) |
|
|
506
|
-
| `plugins` | `string[]` | Сторонні пакети правил (див. [Модель довіри](#модель-довіри)) |
|
|
510
|
+
Або до будь-якого клієнта, що приймає блок `mcpServers`:
|
|
507
511
|
|
|
508
512
|
```json
|
|
509
513
|
{
|
|
510
|
-
"
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
"ignore": [
|
|
514
|
-
{
|
|
515
|
-
"ruleId": "QA-TEST-004",
|
|
516
|
-
"files": ["e2e/legacy-login.spec.ts"],
|
|
517
|
-
"reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
|
|
518
|
-
"expires": "2026-12-31"
|
|
519
|
-
}
|
|
520
|
-
]
|
|
514
|
+
"mcpServers": {
|
|
515
|
+
"mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@latest", "mcp"] }
|
|
516
|
+
}
|
|
521
517
|
}
|
|
522
518
|
```
|
|
523
519
|
|
|
524
|
-
|
|
525
|
-
шляхів, той самий діалект, що `exclude`. Використовуйте його для
|
|
526
|
-
машинного шуму; використовуйте `exclude`, коли список має жити у
|
|
527
|
-
версійному контролі разом з іншою конфігурацією.
|
|
528
|
-
- **CLI-перевизначення** — `--strict` (увімкнути правила карантину),
|
|
529
|
-
`--width <cols>` і `--ascii` / `--no-ascii` (термінальний рендер),
|
|
530
|
-
`--tone blunt` (різкіші повідомлення), `--max-duration <sec>`
|
|
531
|
-
(обмежений частковий скан).
|
|
532
|
-
- Пригнічення правил і життєвий цикл депрекації:
|
|
533
|
-
[docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
|
|
534
|
-
|
|
535
|
-
Записи `ignore` також живлять окрему команду `mjolnir suppressions`,
|
|
536
|
-
яка перелічує поточні пригнічення та час спливання кожного запису.
|
|
537
|
-
|
|
538
|
-
---
|
|
539
|
-
|
|
540
|
-
## 📐 Коди виходу та контракти
|
|
541
|
-
|
|
542
|
-
Заморожені — безпечно будувати на них CI-логіку:
|
|
543
|
-
|
|
544
|
-
| Код виходу | Значення |
|
|
545
|
-
| ---------- | ----------------------------------------------------------------------------- |
|
|
546
|
-
| `0` | Чисто — немає знахідок на рівні гейта або вище |
|
|
547
|
-
| `1` | Знахідки на рівні гейта або вище |
|
|
548
|
-
| `2` | Частковий скан (вичерпано бюджет часу, нечитабельні файли) — ніколи не блокує |
|
|
549
|
-
| `10` | Помилка використання (поганий прапор, відсутня ціль) |
|
|
550
|
-
| `20` | Внутрішня помилка |
|
|
551
|
-
|
|
552
|
-
JSON/SARIF-звіт — `schemaVersion: 1`. ID правил (`QA-<FAMILY>-NNN`)
|
|
553
|
-
незмінні після виходу і ніколи не використовуються повторно.
|
|
554
|
-
|
|
555
|
-
---
|
|
556
|
-
|
|
557
|
-
## Модель довіри
|
|
558
|
-
|
|
559
|
-
- **Local-first** — нуль мережевих викликів під час сканування. Ніколи.
|
|
560
|
-
Нуль телеметрії.
|
|
561
|
-
- **Жодних хибних доказів** — ми радше скажемо «невідомо», ніж
|
|
562
|
-
«перевірено». Порожнє репо отримує `score: null`, ніколи фейкову
|
|
563
|
-
сотню.
|
|
564
|
-
- **Часткова чесність** — якщо аналіз обірвано, вивід про це каже.
|
|
565
|
-
Ніколи «complete», коли це не так.
|
|
566
|
-
- **FP-фаєрвол** — детекція працює на очищеному від коментарів і рядків
|
|
567
|
-
поданні коду (правила TypeScript використовують AST компілятора):
|
|
568
|
-
патерн усередині прозаїчного коментаря чи док-прикладу-рядка — це
|
|
569
|
-
документація, а не знахідка.
|
|
570
|
-
- **Виміряно, а не заявлено** — у головні тіри виходять лише правила з
|
|
571
|
-
частотою хибних спрацювань з реального OSS-коду (див.
|
|
572
|
-
[Скільки з цього виміряно](#скільки-з-цього-виміряно)); футер скана і
|
|
573
|
-
`mjolnir rules --unmeasured` скажуть, які які.
|
|
574
|
-
- **Довіра до плагінів і ворота виконання** — плагіни — це npm-пакети,
|
|
575
|
-
оголошені у
|
|
576
|
-
`"plugins"`; JS-модулі живуть у `mjolnir-rules/*.mjs`.
|
|
577
|
-
**Пісочниці немає**: код плагіна працює з повними
|
|
578
|
-
привілеями Node, та сама модель довіри, що в плагінів ESLint чи
|
|
579
|
-
Vitest. Саме тому виконання коду — **opt-in при кожному скані**:
|
|
580
|
-
передайте `--enable-plugins` (або задайте `MJOLNIR_ENABLE_PLUGINS=1`),
|
|
581
|
-
інакше джерела НЕ завантажуються — гучне повідомлення у stderr точно
|
|
582
|
-
перелічує пропущене. Сканування недовіреного коду ніколи його не
|
|
583
|
-
виконує. JSON-маніфести правил (`mjolnir-rules/*.json`) не зачеплені:
|
|
584
|
-
вони декларують regex-патерни й за конструкцією не виконують код.
|
|
585
|
-
Префікси ID основних правил зарезервовані й відкидаються від
|
|
586
|
-
плагінів і зовнішніх правил проти підміни.
|
|
587
|
-
- **Workspace-локальні зовнішні правила** (фолдерні, нуль мережі) —
|
|
588
|
-
каталог `mjolnir-rules/` поруч із ціллю скана завантажує власні
|
|
589
|
-
правила: JSON-файли декларують regex-патерни (код не виконується),
|
|
590
|
-
модулі `.mjs`/`.js` експортують `rules` (повна довіра Node, як у
|
|
591
|
-
плагінів). Зовнішні правила несуть ті самі trust-метадані, що й
|
|
592
|
-
core; вони ніколи не можуть вийти в core-тирі (core вимагає
|
|
593
|
-
виміряної FP-частоти з corpus-сайдкара — заявлений `tier: "core"`
|
|
594
|
-
затискається до `extended`), дотримуються тирових лімітів і
|
|
595
|
-
перевіряються на дрейф: `mjolnir rules --md --external` рендерить
|
|
596
|
-
каталог із завантажених файлів (походження `external`), а генератор
|
|
597
|
-
матриці приймає `--external <root>`.
|
|
598
|
-
|
|
599
|
-
---
|
|
600
|
-
|
|
601
|
-
## 🏗️ Архітектура
|
|
520
|
+
**Обмежувач важливіший за зручність.** Кожна знахідка в передачі має свою межу. **E2** каже _детерміновано: перевірте місце і застосуйте виправлення_. **E1** каже _ПОТРІБНЕ ПІДТВЕРДЖЕННЯ: саме спостереження не доводить дефект_. Агент, який наосліп виправляє E1, придушує правило або редагує правило, щоб підняти оцінку, робить саме те, заради пошуку чого існує цей інструмент, тому передача каже про це прямо в промпті, поруч зі знахідкою.
|
|
602
521
|
|
|
603
|
-
<
|
|
604
|
-
<summary>Розгорнути дерево</summary>
|
|
522
|
+
<br />
|
|
605
523
|
|
|
606
|
-
|
|
607
|
-
mjolnir/
|
|
608
|
-
├── src/
|
|
609
|
-
│ ├── engine/ # LanguageAdapter interface + rule runner
|
|
610
|
-
│ ├── adapters/ # typescript · python · java · csharp · github-actions
|
|
611
|
-
│ ├── rules/ # rules across 8 families + the measured-FP table
|
|
612
|
-
│ ├── playwright/ # Selector Health Score engine
|
|
613
|
-
│ ├── discovery/ # workspace, frameworks, ignore resolution
|
|
614
|
-
│ ├── scope/ # git merge-base changed-scope engine
|
|
615
|
-
│ ├── scorer/ # transparent deduction table + prioritization
|
|
616
|
-
│ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
|
|
617
|
-
│ ├── forensics/ # run-data ingestion · flake verdicts · triage
|
|
618
|
-
│ ├── config/ # mjolnir.config.json + suppressions
|
|
619
|
-
│ ├── plugins/ # third-party rule loading (no sandbox)
|
|
620
|
-
│ └── commands/ # every subcommand
|
|
621
|
-
└── tests/
|
|
622
|
-
├── fixtures/ # must-fire / must-not-fire per rule
|
|
623
|
-
└── golden/ # frozen score regression locks
|
|
624
|
-
```
|
|
524
|
+
## Довіра і безпека
|
|
625
525
|
|
|
626
|
-
|
|
526
|
+
**Локально, без телеметрії.** Ніде в `src/` немає жодного API з мережевими можливостями (`fetch`, `http`, `https`, `net`, `dns`, `dgram`, WebSocket), а [`privacy-network-isolation.spec.ts`](tests/contract/privacy-network-isolation.spec.ts) провалює збірку, якщо такий з'явиться. Він також забороняє `eval` і `new Function`. Сканування недовіреного коду ніколи його не виконує: статичний аналіз читає вихідний текст, а аналіз прогонів розбирає файли звітів, які вже є на диску.
|
|
527
|
+
|
|
528
|
+
Два застереження: сам `npx` завантажує пакет до того, як щось запуститься, а гарантія поширюється на `src/`, але не на сторонні плагіни.
|
|
529
|
+
|
|
530
|
+
**Плагіни не ізольовані в пісочниці.** JS-плагіни (`mjolnir-rules/*.mjs` або npm-пакети, перелічені в `"plugins"`) працюють із повними привілеями Node — та сама модель довіри, що й у плагінів ESLint чи Vitest. Їх завантаження вмикається явно **для кожного сканування**: без `--enable-plugins` (або `MJOLNIR_ENABLE_PLUGINS=1`) їхні вихідні файли ніколи не завантажуються, а повідомлення в stderr перелічує пропущене. JSON-маніфести правил не виконують код, а префікси ID core-правил зарезервовані, щоб плагін не міг видати себе за одне з них. Повідомляйте про вразливості через [SECURITY.md](SECURITY.md).
|
|
531
|
+
|
|
532
|
+
**Він перевіряє сам себе.** Рушій довіри до перевірок нічого не вартий, якщо його самого не можна перевірити. Кожен прогін CI сканує цей репозиторій збіркою, створеною тим самим прогоном. Гейт падає за будь-якої знахідки рівня error, а також за **часткового** сканування чи **правила, що впало**, бо обрізане самосканування, яке ні про що не повідомляє, — це і є хибний зелений, заради пошуку якого існує цей проєкт. `mjolnir doctor` у тому самому прогоні заново перевіряє базу правил (захист фікстур, чесність рівнів, ліміт рівня core), а перевірка з результатом INCONCLUSIVE падає так само, як провалена. Обидва звіти завантажуються як артефакти збірки.
|
|
533
|
+
|
|
534
|
+
### Коди виходу та машинний контракт
|
|
627
535
|
|
|
628
|
-
|
|
629
|
-
I/O, без глобалів. Новий екосистем = один адаптер + його правила.
|
|
630
|
-
- **TypeScript/Playwright використовує AST компілятора** (ts-morph).
|
|
631
|
-
Python, Java і C# працюють на спільному regex-шарі з маскуванням
|
|
632
|
-
коментарів і рядків.
|
|
633
|
-
- Шар tree-sitter WASM AST для Java і C# існує і є наступним кроком
|
|
634
|
-
точності — він ще не підключений до синхронного скан-пайплайну.
|
|
536
|
+
Заморожені, щоб на них можна було будувати логіку CI:
|
|
635
537
|
|
|
636
|
-
|
|
538
|
+
| Код виходу | Значення |
|
|
539
|
+
| ---------- | --------------------------------------------------------------------------------- |
|
|
540
|
+
| `0` | Чисто: немає знахідок на рівні гейта або вище |
|
|
541
|
+
| `1` | Є знахідки на рівні гейта або вище |
|
|
542
|
+
| `2` | Часткове сканування (вичерпано ліміт часу, нечитабельні файли). Ніколи не блокує. |
|
|
543
|
+
| `10` | Помилка використання (неправильний прапорець, немає цілі) |
|
|
544
|
+
| `20` | Внутрішня помилка |
|
|
637
545
|
|
|
638
|
-
|
|
546
|
+
`2` навмисно відрізняється від `0`: сканування, яке не завершилося, не «нічого не знайшло». Воно просто не закінчило шукати.
|
|
639
547
|
|
|
640
|
-
|
|
641
|
-
| ------------------------------------------------------ | --------------------------------------------- |
|
|
642
|
-
| [docs/SCORING.md](docs/SCORING.md) | Нормування скора + зважування за доказами |
|
|
643
|
-
| [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Виміряні частоти хибних спрацювань + методика |
|
|
644
|
-
| [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Стани правил, пригнічення, депрекація |
|
|
645
|
-
| [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | SARIF-вивід + налаштування редактора/CI |
|
|
646
|
-
| [docs/rules/](docs/rules/) | Згенерований каталог за правилами |
|
|
647
|
-
| [CONTRIBUTING.md](CONTRIBUTING.md) | Dev-сетап + процес контрибуції |
|
|
648
|
-
| [CHANGELOG.md](CHANGELOG.md) | Історія релізів |
|
|
649
|
-
| [SECURITY.md](SECURITY.md) | Повідомлення про вразливості |
|
|
548
|
+
Усе, що споживає машина (результати інструментів MCP, `--json`, SARIF 2.1), береться з одного канонічного результату за версіонованою схемою, **що розширюється лише додаванням** (`schemaVersion: 1`, `contractVersion: 1`), тож жодному споживачеві не треба відновлювати зміст із відрендереного тексту. Див. [машинний контракт](docs/machine-contract.md). ID правил (`QA-<FAMILY>-NNN`) незмінні після випуску й ніколи не використовуються повторно.
|
|
650
549
|
|
|
651
|
-
|
|
550
|
+
<br />
|
|
652
551
|
|
|
653
|
-
##
|
|
552
|
+
## Чого Mjölnir сказати не може
|
|
654
553
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
554
|
+
- **Він не запускає ваші тести.** Чисте сканування — це не набір тестів, що проходить.
|
|
555
|
+
- **Він не може сказати, що твердження _хибне_.** `expect(total).toBe(41)` виглядає здоровим. Mjölnir знаходить тести, які _не можуть упасти_, і пайплайни, які _не можуть почервоніти_, а не тести, що перевіряють не те.
|
|
556
|
+
- **Він не доводить бізнес-коректність.** Ніщо тут не каже, що ваш продукт робить те, чого вимагала вимога.
|
|
557
|
+
- **100 — не доказ хорошого набору тестів.** Чи покриває ваш набір реальні ризики — окреме питання, і цей інструмент на нього не відповідає.
|
|
558
|
+
- **5 з 79 правил спираються на оцінку**, а не на виміряну частку. Кожне з них каже про це у своїй знахідці.
|
|
559
|
+
- **E1 — це не E2.** Евристичні знахідки варто читати, але не варто застосовувати наосліп.
|
|
560
|
+
- **Порожній репозиторій отримує `null`, ніколи не 100.**
|
|
561
|
+
- **Файл з ім'ям `*.spec.ts` без оголошень тестів не вважається покриттям.** Репозиторій, де єдині spec-файли містять імпорти або типи (нуль викликів `it`/`test`), отримує `null`, а не 100.
|
|
659
562
|
|
|
660
|
-
|
|
563
|
+
<br />
|
|
661
564
|
|
|
662
|
-
##
|
|
565
|
+
## Документація
|
|
663
566
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
567
|
+
Повний сайт документації розміщено за адресою <https://sergey-bar.github.io/Mjolnir/>.
|
|
568
|
+
|
|
569
|
+
| Документ | Що всередині |
|
|
570
|
+
| ------------------------------------------------------ | --------------------------------------------------------------- |
|
|
571
|
+
| [docs/SCORING.md](docs/SCORING.md) | Нормування оцінки та зважування доказів |
|
|
572
|
+
| [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md) | Канонічний словник: одне слово на поняття |
|
|
573
|
+
| [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Виміряні частки хибних спрацювань і методика |
|
|
574
|
+
| [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Стани правил, рівні, придушення, виведення з ужитку |
|
|
575
|
+
| [docs/VERSIONING.md](docs/VERSIONING.md) | Політика semver, заморожені інтерфейси, цикл виведення з ужитку |
|
|
576
|
+
| [docs/machine-contract.md](docs/machine-contract.md) | Канонічний машинозчитуваний результат |
|
|
577
|
+
| [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | Вивід SARIF і налаштування редактора або CI |
|
|
578
|
+
| [docs/GITLAB-CI.md](docs/GITLAB-CI.md) | GitLab: звіт Code Quality, рецепт для MR, гейт |
|
|
579
|
+
| [docs/rules/](docs/rules/) | Згенерований каталог за правилами |
|
|
580
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Середовище розробки та процес внесення змін |
|
|
581
|
+
| [SUPPORT.md](SUPPORT.md) | Де запитати, повідомити про проблему й отримати допомогу |
|
|
582
|
+
| [SECURITY.md](SECURITY.md) | Повідомлення про вразливості |
|
|
583
|
+
| [CHANGELOG.md](CHANGELOG.md) | Історія релізів |
|
|
584
|
+
|
|
585
|
+
### Статус
|
|
586
|
+
|
|
587
|
+
**Версія 1.** JSON-схема та коди виходу — заморожені контракти. TypeScript і Python мають найширше виміряне покриття. Java і C# новіші; оцінюйте їх за [таблицею зрілості](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle). Що буде далі, без вигаданих дат: [публічна дорожня карта](https://sergey-bar.github.io/Mjolnir/reference/roadmap).
|
|
588
|
+
|
|
589
|
+
### Участь у розробці
|
|
590
|
+
|
|
591
|
+
Нові правила — найпростіший перший внесок. Одна команда створює заготовку правила з фікстурами must-fire **і** must-not-fire. Згенероване правило навмисно провалює власні фікстури, доки не написано справжнє виявлення, бо випущена заглушка — це правило, яке ніхто не вимірював:
|
|
668
592
|
|
|
669
593
|
```bash
|
|
670
594
|
mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
|
|
671
595
|
```
|
|
672
596
|
|
|
673
|
-
|
|
674
|
-
фікстурного фаєрвола — у [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
597
|
+
Середовище розробки, команди постійних гейтів, а також закони anti-creep і захисту фікстур описано в [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
675
598
|
|
|
676
|
-
|
|
599
|
+
<br />
|
|
677
600
|
|
|
678
601
|
<div align="center">
|
|
679
602
|
|
|
680
|
-
|
|
603
|
+
<img src="assets/readme/closing.svg" alt="Запустіть його на своєму репозиторії." width="100%" />
|
|
681
604
|
|
|
682
605
|
```bash
|
|
683
606
|
npx mjolnir-qa@latest
|
|
684
607
|
```
|
|
685
608
|
|
|
686
|
-
|
|
609
|
+
[Читати посібник](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [Сайт документації](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)
|
|
610
|
+
|
|
611
|
+
<br />
|
|
612
|
+
|
|
613
|
+
Не питайте, чи пройшли тести.<br />
|
|
614
|
+
Запитайте, чи доводять докази, що вони заслуговують на довіру.
|
|
687
615
|
|
|
688
|
-
|
|
616
|
+
<sub>Створив [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · Ліцензія MIT</sub>
|
|
689
617
|
|
|
690
618
|
</div>
|