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.br.md
CHANGED
|
@@ -1,401 +1,431 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="assets/readme/
|
|
3
|
+
<img src="assets/readme/hero.svg" alt="Mjölnir. Os testes dizem o que passou. O Mjölnir diz em que você pode confiar." width="100%" />
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<br />
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
e
|
|
9
|
-
exatamente onde a confiança se quebra.
|
|
7
|
+
O Mjölnir encontra testes que não podem falhar e pipelines que não podem ficar vermelhos,<br />
|
|
8
|
+
e depois pontua até onde o resultado merece confiança, com a evidência de cada ponto.
|
|
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.th.md) | [Türkçe](README.tr.md) | [Українська](README.uk.md) | [বাংলা](README.bn.md) | [Ελληνικά](README.gr.md) | [Tiếng Việt](README.vi.md) | [עברית](README.he.md) | [العربية](README.ar.md) | [Bosanski](README.bs.md)
|
|
10
|
+
<br />
|
|
17
11
|
|
|
18
|
-
|
|
12
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
13
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
14
|
+
[](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
|
|
15
|
+
[](https://codecov.io/gh/Sergey-Bar/Mjolnir)
|
|
16
|
+
[](https://scorecard.dev/viewer/?uri=github.com/Sergey-Bar/Mjolnir)
|
|
17
|
+
[](LICENSE)
|
|
18
|
+
[](https://nodejs.org)
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
npx mjolnir-qa@latest
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
[Veja funcionando](#veja-funcionando) · [Início rápido](#início-rápido) · [O que encontra](#o-que-o-mjölnir-encontra) · [Pontuação](#a-pontuação-de-confiabilidade) · [Evidência](#o-modelo-de-evidência) · [Forense](#forense-de-execução) · [CI](#integridade-de-ci) · [Agentes](#agentes-de-ia) · [Segurança](#confiança-e-segurança) · [Limites](#o-que-o-mjölnir-não-pode-dizer) · [Docs](#documentação)
|
|
25
|
+
|
|
26
|
+
<details>
|
|
27
|
+
<summary>Leia em outro idioma — 22 traduções</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.th.md) | [Türkçe](README.tr.md) | [Українська](README.uk.md) | [বাংলা](README.bn.md) | [Ελληνικά](README.gr.md) | [Tiếng Việt](README.vi.md) | [עברית](README.he.md) | [العربية](README.ar.md) | [Bosanski](README.bs.md)
|
|
30
|
+
|
|
31
|
+
> 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-15.
|
|
32
|
+
|
|
33
|
+
<!-- Source hash: 3541b09e8d04 -->
|
|
25
34
|
|
|
26
|
-
|
|
27
|
-
[Início rápido](#-início-rápido) ·
|
|
28
|
-
[O que ele verifica](#-o-que-o-mjölnir-verifica) ·
|
|
29
|
-
[Pontuação](#como-a-pontuação-funciona) ·
|
|
30
|
-
[CI](#-integração-ci) · [Configuração](#configuração) ·
|
|
31
|
-
[Documentação](#-documentação)
|
|
35
|
+
</details>
|
|
32
36
|
|
|
33
37
|
</div>
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
<br />
|
|
40
|
+
|
|
41
|
+
## Um check verde é uma afirmação, não uma prova
|
|
42
|
+
|
|
43
|
+
Um check verde significa que o pipeline não falhou. Não significa que os testes rodaram, nem que poderiam ter falhado. Todos estes casos passam verdes:
|
|
44
|
+
|
|
45
|
+
- um `.only` commitado que rodou 3 testes em vez de 900
|
|
46
|
+
- `continue-on-error: true` no job que deveria bloquear
|
|
47
|
+
- `|| true` depois do comando de testes
|
|
48
|
+
- um teste que não verifica nada, ou que tem o corpo vazio
|
|
49
|
+
- um wrapper de retry que transforma uma falha real em uma aprovação por sorte
|
|
50
|
+
- um relatório que o workflow envia, mas que nunca foi gerado
|
|
51
|
+
- um sleep fixo segurando uma condição de corrida
|
|
52
|
+
|
|
53
|
+
Nenhum deles deixa o pipeline vermelho, e todos parecem intencionais na revisão. É por isso que sobrevivem. Aqui está o Mjölnir lendo um caso real:
|
|
54
|
+
|
|
55
|
+
<p align="center">
|
|
56
|
+
<img src="assets/readme/scan.svg" alt="O workflow de CI do repositório de demonstração, lido linha por linha. O Mjölnir aponta cada achado na linha reportada, com sua regra, o que está errado, seu nível de evidência e sua taxa de falsos positivos medida." width="800" />
|
|
57
|
+
</p>
|
|
58
|
+
|
|
59
|
+
<sub>Cada achado que o scan de demonstração reportou para este workflow, na linha reportada. Gerado por `npm run docs:readme-brand` a partir de [`demo-report.json`](assets/readme/demo-report.json) e travado contra desvios na CI.</sub>
|
|
60
|
+
|
|
61
|
+
**Modo estrito.** As detecções mais agressivas — `.only`, `continue-on-error`, testes vazios, abuso de retry — ficam na quarentena. Só rodam com `--strict` e são limitadas a severidade `info`: elas sinalizam, nunca bloqueiam. O scan padrão (`npx mjolnir-qa@latest` sem `--strict`) cobre apenas regras core e extended. Adicione `--strict` quando quiser a camada de consultoria também.
|
|
62
|
+
|
|
63
|
+
O Mjölnir lê a suíte, os workflows de CI e, se você tiver, o relatório de uma execução real. Ele não roda seus testes, não instala suas dependências e não executa o código que analisa. E quando não tem evidência, ele diz isso em vez de inventar confiança:
|
|
64
|
+
|
|
65
|
+
| Situação | O que o Mjölnir reporta |
|
|
66
|
+
| ---------------------------------------------------------- | ------------------------------------------------------------------- |
|
|
67
|
+
| Nenhuma declaração de teste encontrada | Pontuação `null`, exibida como **UNKNOWN**. Nunca um 100 inventado. |
|
|
68
|
+
| Nenhuma baseline ou revisão comparável | **UNKNOWN**, com o motivo informado. Nunca um 0 presumido. |
|
|
69
|
+
| Scan interrompido (orçamento de tempo, arquivos ilegíveis) | **PARTIAL**, saída `2`. Nunca apresentado como limpo. |
|
|
70
|
+
|
|
71
|
+
<p align="center">
|
|
72
|
+
<img src="assets/readme/how-it-works.svg" alt="Como o Mjölnir funciona. Ele lê a suíte de testes e o pipeline de CI de forma estática, e o relatório de uma execução real quando existe um. Ele pondera cada achado pelo nível de evidência e pelo nível de confiança, em que só uma execução real alcança L3 a L5, e produz achados, uma pontuação de confiabilidade e um gate de CI com códigos de saída congelados. No ciclo do agente, a IA escreve a correção e o Mjölnir refaz o scan para prová-la." width="880" />
|
|
73
|
+
</p>
|
|
74
|
+
|
|
75
|
+
<sub>Composto para esta página e exibido em 1:1. Gerado por `npm run docs:readme-brand` e travado contra desvios na CI; a pontuação, as contagens e o ID da regra vêm de [`script.demo.json`](assets/video/script.demo.json), [`demo-report.json`](assets/readme/demo-report.json) e do registro de regras, nunca digitados à mão. A mesma imagem como pôster: [`architecture.svg`](assets/readme/architecture.svg).</sub>
|
|
76
|
+
|
|
77
|
+
<br />
|
|
78
|
+
|
|
79
|
+
## Veja funcionando
|
|
80
|
+
|
|
81
|
+
Um scan real de [`examples/demo-repo`](examples/demo-repo), uma pequena suíte Playwright com um workflow de CI. Foi para cá que os pontos dela foram:
|
|
82
|
+
|
|
83
|
+
<p align="center">
|
|
84
|
+
<img src="assets/readme/terminal-hero.svg" alt="O detalhamento das deduções do Mjölnir: WORTHINESS 80/100 WORTHY, a pontuação por categoria, o quadro de deduções por severidade e uma lista FIX THIS FIRST" width="520" />
|
|
85
|
+
</p>
|
|
86
|
+
|
|
87
|
+
<sub>Gerado por `npm run docs:hero` a partir de um scan real e travado contra desvios na CI. O relatório `--verbose` completo do mesmo scan é [`demo.svg`](assets/readme/demo.svg) (`npm run docs:demo`).</sub>
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary><strong>Assista</strong> — um scan, a correção que ele imprime e o novo scan que a prova</summary>
|
|
36
91
|
|
|
37
|
-
|
|
92
|
+
<br />
|
|
38
93
|
|
|
39
94
|
<p align="center">
|
|
40
|
-
<
|
|
95
|
+
<a href="assets/video/mjolnir-demo.mp4">
|
|
96
|
+
<img src="assets/video/mjolnir-demo-poster.png" alt="Um quadro da gravação de demonstração: npx mjolnir-qa@latest analisando o repositório de demonstração em uma janela de terminal" width="900" />
|
|
97
|
+
</a>
|
|
41
98
|
</p>
|
|
42
99
|
|
|
43
|
-
<sub>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
[`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
|
|
47
|
-
faz a CI falhar se ela divergir do que a ferramenta imprime.</sub>
|
|
100
|
+
<sub>Renderizado quadro a quadro a partir de um scan real por `npm run docs:video`; nunca gravado da tela. Selecione o quadro para abrir [`mjolnir-demo.mp4`](assets/video/mjolnir-demo.mp4).</sub>
|
|
101
|
+
|
|
102
|
+
</details>
|
|
48
103
|
|
|
49
|
-
|
|
104
|
+
### Um achado, de perto
|
|
50
105
|
|
|
51
|
-
|
|
52
|
-
workflow de CI e um arquivo de teste Python — quatro
|
|
53
|
-
linguagens/formatos, uma única passada.
|
|
54
|
-
2. Ele encontrou evidências que enfraquecem a confiança na suíte — um
|
|
55
|
-
`continue-on-error` mascarando um job, um `|| true` engolindo um
|
|
56
|
-
código de saída, sleeps fixos, um seletor frágil, URLs de staging
|
|
57
|
-
fixas no código, uma espera `networkidle`.
|
|
58
|
-
3. Ele transformou cada uma em um finding concreto com ID de regra,
|
|
59
|
-
localização e correção — e uma única pontuação sobre a qual você
|
|
60
|
-
pode fazer o gate de uma PR.
|
|
106
|
+
Todo achado responde a quatro perguntas: onde está, quão seguro o Mjölnir está, com que frequência a regra erra e como corrigir.
|
|
61
107
|
|
|
62
|
-
|
|
108
|
+
<p align="center">
|
|
109
|
+
<img src="assets/readme/finding-anatomy.svg" alt="O primeiro achado do scan de demonstração, exatamente como o terminal o imprime, com suas quatro partes destacadas: onde, quão seguro, com que frequência a regra erra, e a correção." width="100%" />
|
|
110
|
+
</p>
|
|
63
111
|
|
|
64
|
-
|
|
65
|
-
recebe:
|
|
112
|
+
`mjolnir explain QA-CI-001` imprime o histórico de confiança completo de uma regra, incluindo sua taxa de falsos positivos medida e o nível que essa taxa lhe rendeu:
|
|
66
113
|
|
|
67
114
|
```text
|
|
68
|
-
|
|
115
|
+
▍ QA-CI-001 — continue-on-error masks a failing verification gate
|
|
69
116
|
|
|
70
117
|
Severity: error
|
|
71
118
|
Confidence: high
|
|
119
|
+
Tier: quarantine
|
|
72
120
|
Evidence: E2
|
|
73
|
-
|
|
121
|
+
QA impact: False-green risk (FALSE-GREEN)
|
|
122
|
+
Measured FP: 11% (19 hand-classified corpus verdicts)
|
|
123
|
+
FP risk: low (author estimate)
|
|
124
|
+
Languages: yaml
|
|
125
|
+
Frameworks: github-actions, azure-pipelines
|
|
74
126
|
|
|
75
127
|
WHAT WAS FOUND (real detector output, not a mockup)
|
|
76
128
|
Job `security-scan` runs a verification gate under `continue-on-error: true`.
|
|
77
129
|
|
|
78
130
|
WHY IT MATTERS
|
|
79
|
-
This job can fail every day and CI will still show green. The checkmark
|
|
80
|
-
|
|
131
|
+
This job can fail every day and CI will still show green. The checkmark on
|
|
132
|
+
this workflow cannot be trusted.
|
|
81
133
|
|
|
82
134
|
HOW TO FIX
|
|
83
135
|
Remove continue-on-error, or scope it to individual non-blocking steps only.
|
|
84
|
-
```
|
|
85
136
|
|
|
86
|
-
|
|
87
|
-
o seu CI diz que algo passou quando não passou.
|
|
137
|
+
Example from this rule's own must-fire fixture: QA-CI-001/must-fire/masked.yml
|
|
88
138
|
|
|
89
|
-
|
|
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
|
|
90
146
|
|
|
91
|
-
|
|
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.
|
|
92
150
|
|
|
93
|
-
|
|
94
|
-
|
|
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.
|
|
95
154
|
|
|
96
|
-
|
|
97
|
-
npx mjolnir-qa@latest
|
|
155
|
+
Docs: mjolnir rules --md (full catalog, this rule included)
|
|
98
156
|
```
|
|
99
157
|
|
|
100
|
-
|
|
101
|
-
|
|
158
|
+
Essa é a unidade de valor: um lugar onde a CI reporta uma aprovação que não mereceu.
|
|
159
|
+
|
|
160
|
+
<br />
|
|
161
|
+
|
|
162
|
+
## Início rápido
|
|
102
163
|
|
|
103
164
|
```bash
|
|
104
|
-
npx mjolnir-qa@latest
|
|
165
|
+
npx mjolnir-qa@latest
|
|
105
166
|
```
|
|
106
167
|
|
|
107
|
-
|
|
108
|
-
workflow — e pronto. Todo o resto é opcional.
|
|
168
|
+
Ele analisa o diretório atual e imprime o Trust Report: o que encontrou, até onde você pode confiar, por quê e o que fazer em seguida. Sai com `0` quando nada foi encontrado no nível do gate ou acima.
|
|
109
169
|
|
|
110
|
-
|
|
111
|
-
| ----------------------------------- | ------------------------------------------------------------ |
|
|
112
|
-
| `mjolnir` | Escaneio completo do repo + pontuação de merecimento |
|
|
113
|
-
| `mjolnir --scope changed` | Apenas o que a sua branch introduziu — a forma de CI |
|
|
114
|
-
| `mjolnir ci install` | Gera o workflow de PR consultivo |
|
|
115
|
-
| `mjolnir explain QA-CI-001` | O quê / por quê / correção + taxa de FP medida de uma regra |
|
|
116
|
-
| `mjolnir rules --unmeasured` | As regras rodando por suposição, não por medição |
|
|
117
|
-
| `mjolnir --json` / `--format sarif` | Legível por máquina / GitHub Code Scanning |
|
|
118
|
-
| `mjolnir --strict` | Também executa regras do tier quarentena (maior risco de FP) |
|
|
119
|
-
|
|
120
|
-
<details>
|
|
121
|
-
<summary><strong>Quando algo está instável</strong></summary>
|
|
170
|
+
Na CI, analise só o que a branch introduziu, para que uma suíte legada não afogue seu primeiro pull request:
|
|
122
171
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
| `mjolnir triage ./test-results/` | Proposta de quarentena a partir do histórico de execução |
|
|
127
|
-
| `mjolnir pw-report ./test-results/` | Resumo de execução do Playwright — retries / flakes / mais lentos |
|
|
128
|
-
| `mjolnir doctor:playwright` | Escaneio profundo só do Playwright + Selector Health Score |
|
|
172
|
+
```bash
|
|
173
|
+
npx mjolnir-qa@latest --scope changed
|
|
174
|
+
```
|
|
129
175
|
|
|
130
|
-
|
|
176
|
+
`mjolnir ci install` grava isso como um workflow do GitHub Actions, usando a [action](https://github.com/Sergey-Bar/Mjolnir#readme) fixada na tag principal `v1` (ou `npx` puro com `--no-action`). Ele continua consultivo até você decidir que deve bloquear.
|
|
177
|
+
|
|
178
|
+
| Comando | O que faz |
|
|
179
|
+
| ----------------------------------- | ------------------------------------------------------------- |
|
|
180
|
+
| `mjolnir` | Trust Report: veredito, confiança, próxima ação |
|
|
181
|
+
| `mjolnir --scope changed` | Só o que sua branch introduziu (a forma para CI) |
|
|
182
|
+
| `mjolnir ci install` | Gera o workflow consultivo de PR (baseado na action) |
|
|
183
|
+
| `mjolnir explain QA-CI-001` | O quê, por quê e correção, mais a taxa de FP medida |
|
|
184
|
+
| `mjolnir why src/a.spec.ts:42` | Por que exatamente esta linha foi apontada. Nunca bloqueia. |
|
|
185
|
+
| `mjolnir forensics ./test-results/` | Evidência de runtime de uma execução real |
|
|
186
|
+
| `mjolnir trust-report` | Trust Artifact autocontido (md + json) |
|
|
187
|
+
| `mjolnir handoff` | Plano de correção para um agente de código |
|
|
188
|
+
| `mjolnir --json` / `--format sarif` | Saída legível por máquina, GitHub Code Scanning |
|
|
189
|
+
| `mjolnir --format codequality` | Relatório do GitLab Code Quality (artefato do widget de MR) |
|
|
190
|
+
| `mjolnir --strict` | Também roda as regras do nível quarantine (maior risco de FP) |
|
|
131
191
|
|
|
132
192
|
<details>
|
|
133
|
-
<summary><strong>
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
|
138
|
-
|
|
|
139
|
-
| `mjolnir
|
|
140
|
-
| `mjolnir
|
|
141
|
-
| `mjolnir
|
|
142
|
-
| `mjolnir
|
|
143
|
-
| `mjolnir
|
|
144
|
-
| `mjolnir
|
|
145
|
-
| `mjolnir
|
|
146
|
-
| `mjolnir
|
|
147
|
-
| `mjolnir
|
|
193
|
+
<summary><strong>Todos os outros comandos</strong> — triagem de testes instáveis, relatórios, governança</summary>
|
|
194
|
+
|
|
195
|
+
<br />
|
|
196
|
+
|
|
197
|
+
| Comando | O que faz |
|
|
198
|
+
| ----------------------------------- | ----------------------------------------------------------------------------- |
|
|
199
|
+
| `mjolnir --classic` | O banner de pontuação anterior ao Trust Report |
|
|
200
|
+
| `mjolnir explain verdict` | Por que o veredito do scan salvo é o que é |
|
|
201
|
+
| `mjolnir triage ./test-results/` | Triagem guiada. Cada linha termina em uma próxima ação. |
|
|
202
|
+
| `mjolnir pw-report ./test-results/` | Resumo da execução do Playwright: retries, instáveis, os mais lentos |
|
|
203
|
+
| `mjolnir doctor:playwright` | Scan profundo só de Playwright mais Selector Health Score |
|
|
204
|
+
| `mjolnir fix --dry-run` / `fix` | Correções automáticas seguras, cada uma reanalisada para provar que funcionou |
|
|
205
|
+
| `mjolnir baseline` / `diff` | Registra os achados e depois reporta só os novos ou piores |
|
|
206
|
+
| `mjolnir impact --since <ref>` | O que um commit introduziu e resolveu |
|
|
207
|
+
| `mjolnir summary` | Anotações de CI e um resumo do step a partir de um relatório |
|
|
208
|
+
| `mjolnir pr-comment` | Um comentário de PR com escopo, em Markdown |
|
|
209
|
+
| `mjolnir debt` | Registro de dívida de testes com um modelo de custo |
|
|
210
|
+
| `mjolnir handover` | Mapa de integração da suíte para um novo engenheiro de QA |
|
|
211
|
+
| `mjolnir init` | Detecta frameworks e imprime um checklist de configuração |
|
|
212
|
+
| `mjolnir suppressions` | Lista os achados suprimidos, para governança |
|
|
213
|
+
| `mjolnir rules --unmeasured` | As regras que rodam por suposição, não por medição |
|
|
214
|
+
| `mjolnir rules --md` | Catálogo completo de regras (JSON ou Markdown) |
|
|
215
|
+
| `mjolnir doctor` | Autoauditoria da base de regras do próprio Mjölnir |
|
|
216
|
+
| `mjolnir create-rule <ID>` | Cria o esqueleto de uma nova regra e suas fixtures |
|
|
217
|
+
| `mjolnir stats` | Contadores locais de todas as correções já vistas |
|
|
218
|
+
| `mjolnir badge` | JSON de endpoint do shields.io e snippet |
|
|
219
|
+
| `mjolnir --cache` | Novos scans incrementais via um cache local de vereditos |
|
|
220
|
+
| `mjolnir --format mermaid` | Diagrama da arquitetura de testes para um comentário de PR |
|
|
221
|
+
|
|
222
|
+
`mjolnir help <command>` imprime uso, exemplos e o próximo passo de qualquer um deles.
|
|
148
223
|
|
|
149
224
|
</details>
|
|
150
225
|
|
|
151
|
-
|
|
152
|
-
`npm i -g mjolnir-qa`. Requer Node.js ≥ 22.18. Funciona no Windows,
|
|
153
|
-
macOS e Linux.
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## 👥 Para quem é isto?
|
|
158
|
-
|
|
159
|
-
- **QA / SDET** donos de uma suíte e2e ou de integração que precisam de
|
|
160
|
-
evidências de que a suíte realmente merece o visto verde que produz.
|
|
161
|
-
- **Equipes de Plataforma / DevEx** responsáveis pela integridade de CI
|
|
162
|
-
e pelos release gates — as pessoas que se importam que um
|
|
163
|
-
`continue-on-error` nunca torne uma pipeline vermelha verde em
|
|
164
|
-
silêncio.
|
|
165
|
-
- **Mantenedores de OSS** que querem um gate de verificação barato,
|
|
166
|
-
sempre ativo, que roda localmente e na CI sem chamadas de rede.
|
|
167
|
-
|
|
168
|
-
---
|
|
226
|
+
Requer **Node.js ≥ 22.18** no Windows, macOS ou Linux. Prefere uma instalação global? `npm i -g mjolnir-qa`. O mínimo vem da cadeia de build (o tsdown mira nele e o pipeline de release faz smoke tests contra ele); as dependências de runtime não precisam de mais que isso.
|
|
169
227
|
|
|
170
|
-
|
|
228
|
+
<br />
|
|
171
229
|
|
|
172
|
-
|
|
173
|
-
| --- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
174
|
-
| ⚖️ | **Pontuação de merecimento** — um número, tabela de deduções transparente, sem caixa-preta |
|
|
175
|
-
| 🎭 | **Selector Health Score** — avalia seus locators do Playwright, não só sua taxa de aprovação |
|
|
176
|
-
| 🔬 | **Forense de runtime** — lê dados reais de execução Playwright/JUnit para detectar `TRUE-FLAKE`, não apenas palpites estáticos |
|
|
177
|
-
| 🚨 | **Regras de integridade de CI** — pega `continue-on-error`, `\|\| true` e outros truques de falso verde |
|
|
178
|
-
| 🐍 | **Todos os quatro bindings do Playwright** — TypeScript, Python, Java, C#/.NET — mais pytest, JUnit/TestNG e workflows de CI |
|
|
179
|
-
| 🔒 | **Local-first** — zero chamadas de rede durante o escaneio, zero telemetria, roda em segundos |
|
|
230
|
+
## O que o Mjölnir encontra
|
|
180
231
|
|
|
181
|
-
|
|
232
|
+
<p align="center">
|
|
233
|
+
<img src="assets/readme/stack.svg" alt="Funciona com a sua stack: as linguagens, frameworks de teste e sistemas de CI cobertos pelas regras, a partir do registro de regras." width="100%" />
|
|
234
|
+
</p>
|
|
182
235
|
|
|
183
|
-
|
|
184
|
-
que dispara na própria fixture negativa não pode ser publicada — esse
|
|
185
|
-
é o firewall de falsos positivos.
|
|
236
|
+
**79 regras** em quatro famílias — higiene de testes, qualidade de testes, Playwright e integridade de CI — para TypeScript e JavaScript, Python, Java, C# e YAML do GitHub Actions. Elas cobrem o Playwright nos quatro bindings, além de pytest, JUnit, TestNG, NUnit, xUnit, MSTest, Jest, Vitest e Mocha, com cobertura inicial para Cypress e Selenium. Nove delas, para mostrar o formato:
|
|
186
237
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
|
191
|
-
|
|
|
192
|
-
| QA-TEST-
|
|
193
|
-
| QA-
|
|
194
|
-
| QA-
|
|
195
|
-
| QA-
|
|
196
|
-
| QA-
|
|
197
|
-
| QA-
|
|
198
|
-
| QA-TEST-010 | Corpo de teste vazio | error |
|
|
238
|
+
| ID | Regra | Severidade | Nível |
|
|
239
|
+
| ------------ | ------------------------------------------------------------------------- | ---------- | ---------- |
|
|
240
|
+
| QA-CI-001 | `continue-on-error` mascara um gate de verificação que falha | error | quarantine |
|
|
241
|
+
| QA-CI-009 | Código de saída dos testes não propagado (`\|` sem pipefail, cadeias `;`) | error | extended |
|
|
242
|
+
| QA-TEST-001 | Teste focado commitado (`.only`, `fit`) | error | quarantine |
|
|
243
|
+
| QA-TEST-003 | Teste sem asserções | error | quarantine |
|
|
244
|
+
| QA-TQUAL-009 | Asserção de promise sem await | error | quarantine |
|
|
245
|
+
| QA-PW-002 | Asserção de locator sem await | error | core |
|
|
246
|
+
| QA-PW-004 | Seletores CSS/XPath frágeis | warning | quarantine |
|
|
247
|
+
| QA-PY-002 | Teste pulado (`skip`, `xfail` não estrito) | warning | core |
|
|
248
|
+
| QA-CS-103 | Método de teste sem asserções | error | core |
|
|
199
249
|
|
|
200
|
-
|
|
250
|
+
O catálogo completo é gerado a partir do registro, nunca mantido à mão: `mjolnir rules --md`, [`docs/rules/`](docs/rules/) ou o [guia do que ele verifica](https://sergey-bar.github.io/Mjolnir/guide/what-it-checks).
|
|
201
251
|
|
|
202
252
|
<details>
|
|
203
|
-
<summary><strong>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
|
253
|
+
<summary><strong>Todas as regras citadas neste README</strong>, em uma tabela</summary>
|
|
254
|
+
|
|
255
|
+
<br />
|
|
256
|
+
|
|
257
|
+
> Regras `quarantine` só rodam com `--strict` e nunca bloqueiam (ficam limitadas a info). A severidade mostrada é a definida pelo autor.
|
|
258
|
+
|
|
259
|
+
| ID | Família | Regra | Severidade | Nível |
|
|
260
|
+
| ------------ | ---------- | -------------------------------------------------------------- | ---------- | ---------- |
|
|
261
|
+
| QA-TEST-001 | Higiene | Teste focado commitado (`.only`, `fit`) | error | quarantine |
|
|
262
|
+
| QA-TEST-002 | Higiene | Teste pulado. Escala para `error` sem um motivo rastreado. | warning | quarantine |
|
|
263
|
+
| QA-TEST-003 | Higiene | Teste sem asserções | error | quarantine |
|
|
264
|
+
| QA-TEST-004 | Higiene | Sleep fixo (`waitForTimeout`, `sleep()`, `delay()`) | warning | extended |
|
|
265
|
+
| QA-TEST-006 | Higiene | Abuso de retry escondendo instabilidade | warning | quarantine |
|
|
266
|
+
| QA-TEST-010 | Higiene | Corpo de teste vazio | error | quarantine |
|
|
267
|
+
| QA-TQUAL-002 | Qualidade | Asserção tautológica | error | quarantine |
|
|
268
|
+
| QA-TQUAL-009 | Qualidade | Asserção de promise sem await | error | quarantine |
|
|
269
|
+
| QA-TQUAL-011 | Qualidade | Testes comentados | warning | extended |
|
|
270
|
+
| QA-PW-002 | Playwright | Asserção de locator sem await | error | core |
|
|
271
|
+
| QA-PW-003 | Playwright | `page.pause()` / `test.only()` commitado | error | core |
|
|
272
|
+
| QA-PW-004 | Playwright | Seletores CSS/XPath frágeis | warning | quarantine |
|
|
273
|
+
| QA-PW-123 | Playwright | URLs de ambiente fixas no código | warning | quarantine |
|
|
274
|
+
| QA-PW-140 | Playwright | Screenshot sem `maxDiffPixelRatio` | warning | core |
|
|
275
|
+
| QA-CI-001 | CI | `continue-on-error` mascara um gate que falha | error | quarantine |
|
|
276
|
+
| QA-CI-002 | CI | `\|\| true` engole códigos de saída | error | extended |
|
|
277
|
+
| QA-CI-005 | CI | Relatório consumido, mas nunca gerado | error | quarantine |
|
|
278
|
+
| QA-CI-007 | CI | Wrappers de retry em volta dos testes | warning | extended |
|
|
279
|
+
| QA-CI-008 | CI | Step que sempre passa mascara falhas | error | quarantine |
|
|
280
|
+
| QA-CI-009 | CI | Código de saída não propagado (`\|` sem pipefail, cadeias `;`) | error | extended |
|
|
281
|
+
| QA-CI-010 | CI | Testes pulados onde deveriam bloquear | error | quarantine |
|
|
282
|
+
| QA-PY-002 | Python | Teste pulado (`skip`, `xfail` não estrito) | warning | core |
|
|
283
|
+
| QA-PY-003 | Python | Função de teste sem asserções | error | quarantine |
|
|
284
|
+
| QA-PY-005 | Python | `time.sleep()` nos testes | warning | extended |
|
|
285
|
+
| QA-PY-012 | Python | Asserção tautológica | error | quarantine |
|
|
286
|
+
| QA-JV-101 | Java | Teste desativado (`@Disabled`) | warning | core |
|
|
287
|
+
| QA-JV-102 | Java | Sleep fixo (`Thread.sleep()`) | warning | extended |
|
|
288
|
+
| QA-JV-103 | Java | Método de teste sem asserções | error | extended |
|
|
289
|
+
| QA-JV-105 | Java | Sleep fixo com `waitForTimeout()` do Playwright | warning | core |
|
|
290
|
+
| QA-JV-106 | Java | Seletor frágil em vez de locator por papel | warning | quarantine |
|
|
291
|
+
| QA-CS-101 | C# | Teste pulado (`[Ignore]`, `[Fact(Skip=)]`) | warning | core |
|
|
292
|
+
| QA-CS-102 | C# | Sleep fixo (`Thread.Sleep` / `Task.Delay`) | warning | core |
|
|
293
|
+
| QA-CS-103 | C# | Método de teste sem asserções | error | core |
|
|
294
|
+
| QA-CS-105 | C# | Sleep fixo com `WaitForTimeoutAsync()` | warning | extended |
|
|
295
|
+
| QA-CS-106 | C# | Seletor frágil em vez de locator por papel | warning | quarantine |
|
|
296
|
+
|
|
297
|
+
O Python também traz QA-PY-001…012 (higiene do pytest) e QA-PY-101…108 (Playwright para Python). Cypress e Selenium têm conjuntos iniciais de três regras cada.
|
|
210
298
|
|
|
211
299
|
</details>
|
|
212
300
|
|
|
213
|
-
|
|
214
|
-
<summary><strong>Playwright 🎭</strong></summary>
|
|
301
|
+
Toda regra é lançada com uma fixture must-fire **e** uma must-not-fire, e uma regra que dispara na própria fixture negativa não pode ser lançada. Esse é o firewall contra falsos positivos; `mjolnir doctor` o aplica na própria CI deste repositório.
|
|
215
302
|
|
|
216
|
-
|
|
217
|
-
| --------- | ----------------------------------------- | -------- |
|
|
218
|
-
| QA-PW-002 | Asserção de locator sem await | error |
|
|
219
|
-
| QA-PW-003 | `page.pause()` / `test.only()` commitados | error |
|
|
220
|
-
| QA-PW-004 | Seletores CSS/XPath frágeis | warning |
|
|
221
|
-
| QA-PW-123 | URLs de ambiente fixas no código | warning |
|
|
303
|
+
### Selector Health Score
|
|
222
304
|
|
|
223
|
-
|
|
305
|
+
`mjolnir doctor:playwright` avalia cada locator pela forma como encontra um elemento: do jeito que um usuário faria (papel, rótulo, texto), por um contrato explícito (`data-testid`) ou por um acidente estrutural (cadeias CSS, XPath). Cada arquivo recebe uma pontuação de 0 a 100:
|
|
224
306
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
| ID | Regra | Severity |
|
|
229
|
-
| --------- | ----------------------------------------------------------------------- | -------- |
|
|
230
|
-
| QA-CI-001 | `continue-on-error` mascara falhas | error |
|
|
231
|
-
| QA-CI-002 | `\|\| true` engole códigos de saída | error |
|
|
232
|
-
| QA-CI-005 | Relatório consumido mas nunca gerado | error |
|
|
233
|
-
| QA-CI-007 | Wrappers de retry em torno de testes | warning |
|
|
234
|
-
| QA-CI-008 | Step sempre bem-sucedido mascara falhas | error |
|
|
235
|
-
| QA-CI-009 | Código de saída do teste não propagado (`\|` sem pipefail, cadeias `;`) | error |
|
|
236
|
-
| QA-CI-010 | Testes pulados onde devem bloquear (guardas skip-on-PR) | error |
|
|
237
|
-
|
|
238
|
-
</details>
|
|
239
|
-
|
|
240
|
-
<details>
|
|
241
|
-
<summary><strong>Python / pytest 🐍</strong></summary>
|
|
242
|
-
|
|
243
|
-
| ID | Regra | Severity |
|
|
244
|
-
| --------- | ------------------------------------------ | -------- |
|
|
245
|
-
| QA-PY-002 | Teste pulado (`skip`, `xfail` não estrito) | warning |
|
|
246
|
-
| QA-PY-003 | Função de teste sem asserções | error |
|
|
247
|
-
| QA-PY-005 | `time.sleep()` em testes | warning |
|
|
248
|
-
| QA-PY-012 | Asserção tautológica | error |
|
|
249
|
-
|
|
250
|
-
20 regras Python no total (QA-PY-001…012 higiene pytest + QA-PY-101…108 Playwright-Python).
|
|
307
|
+
```text
|
|
308
|
+
▍ SELECTOR HEALTH
|
|
251
309
|
|
|
252
|
-
|
|
310
|
+
e2e/login.spec.ts
|
|
311
|
+
[█████████████░░░░░░░] 65 / 100
|
|
312
|
+
role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
|
|
253
313
|
|
|
254
|
-
|
|
255
|
-
|
|
314
|
+
e2e/checkout.spec.ts
|
|
315
|
+
[██████████████████░░] 88 / 100
|
|
316
|
+
role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
|
|
317
|
+
```
|
|
256
318
|
|
|
257
|
-
|
|
258
|
-
| --------- | ------------------------------------------- | -------- |
|
|
259
|
-
| QA-JV-101 | Teste desabilitado (`@Disabled`) | warning |
|
|
260
|
-
| QA-JV-102 | Sleep fixo (`Thread.sleep()`) | warning |
|
|
261
|
-
| QA-JV-103 | Método de teste sem asserções | error |
|
|
262
|
-
| QA-JV-105 | Sleep fixo do Playwright `waitForTimeout()` | warning |
|
|
263
|
-
| QA-JV-106 | Seletor frágil em vez de role locator | warning |
|
|
319
|
+
Isso mede **resiliência, não correção**. `.btn.btn-primary > div:nth-child(2)` passa hoje e continua passando até alguém mexer no markup. Uma pontuação baixa nunca afirma que o teste está quebrado, só que ele depende de um markup que ninguém prometeu manter.
|
|
264
320
|
|
|
265
|
-
|
|
321
|
+
<br />
|
|
266
322
|
|
|
267
|
-
|
|
268
|
-
<summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
|
|
323
|
+
## A pontuação de confiabilidade
|
|
269
324
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
| QA-CS-102 | Sleep fixo (`Thread.Sleep` / `Task.Delay`) | warning |
|
|
274
|
-
| QA-CS-103 | Método de teste sem asserções | error |
|
|
275
|
-
| QA-CS-105 | Sleep fixo `WaitForTimeoutAsync()` | warning |
|
|
276
|
-
| QA-CS-106 | Seletor frágil em vez de role locator | warning |
|
|
325
|
+
<p align="center">
|
|
326
|
+
<img src="assets/readme/score-gauge.svg" alt="A escala de confiabilidade de 0 a 100, com um marcador que percorre cada pontuação: UNWORTHY abaixo de 50, NEEDS WORK de 50 a 79, WORTHY de 80 a 99, FORGED em 100" width="720" />
|
|
327
|
+
</p>
|
|
277
328
|
|
|
278
|
-
|
|
329
|
+
<sub>Cada pontuação de 0 a 100, posicionada pelo `deriveScoreState` real. Gerado por `npm run docs:gauge` e travado contra desvios na CI.</sub>
|
|
279
330
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
>
|
|
288
|
-
> As páginas por regra ficam em [`docs/rules/`](docs/rules/).
|
|
331
|
+
| Pontuação | Veredito |
|
|
332
|
+
| --------- | --------------------------------------------------- |
|
|
333
|
+
| `0 – 49` | **UNWORTHY** |
|
|
334
|
+
| `50 – 79` | **NEEDS WORK** |
|
|
335
|
+
| `80 – 99` | **WORTHY** |
|
|
336
|
+
| `100` | **FORGED** |
|
|
337
|
+
| `null` | **UNKNOWN**: nenhuma declaração de teste encontrada |
|
|
289
338
|
|
|
290
|
-
|
|
339
|
+
**Como é calculada.** A severidade define uma dedução base (`error −8`, `warning −3`, `info −1`) e o nível de evidência a desconta: E2 conta integralmente, E1 pela metade (arredondado para baixo), E0 nada. O total é normalizado pela exposição da suíte, ou seja, deduções por declaração de teste, e não por arquivo. O terminal imprime os mesmos números descontados que a pontuação usou; não há um segundo modelo escondido. Detalhes: [docs/SCORING.md](docs/SCORING.md) e o [guia de pontuação](https://sergey-bar.github.io/Mjolnir/guide/scoring).
|
|
291
340
|
|
|
292
|
-
**
|
|
293
|
-
código OSS real** (≥ 10 findings classificados à mão cada; veja
|
|
294
|
-
[docs/FP-AUDIT.md](docs/FP-AUDIT.md)). As outras 21 são publicadas com
|
|
295
|
-
a estimativa do autor. O rodapé de cada escaneio diz quantas das regras
|
|
296
|
-
_que dispararam_ são medidas; `mjolnir rules --unmeasured` lista as que
|
|
297
|
-
não são; a página `mjolnir explain` de cada regra declara seu status.
|
|
298
|
-
está em quarentena por isso. Fazer esse número crescer é o trabalho contínuo
|
|
299
|
-
do projeto.
|
|
341
|
+
**O que 100 não significa.** Não significa que o software está correto, que a suíte é adequada ou que o produto está livre de defeitos. Significa uma única coisa: **nenhuma das regras avaliadas pelo Mjölnir produziu uma dedução neste scan e neste modelo de evidência.**
|
|
300
342
|
|
|
301
|
-
|
|
343
|
+
<br />
|
|
302
344
|
|
|
303
|
-
|
|
304
|
-
sua taxa de falsos positivos **medida**:
|
|
345
|
+
## O modelo de evidência
|
|
305
346
|
|
|
306
|
-
|
|
307
|
-
| ------------ | ------------------------------------------- | :-------------: | :--------: |
|
|
308
|
-
| `core` | ≤ 10 % de FP medido | ✅ | ✅ |
|
|
309
|
-
| `extended` | ≤ 30 % de FP medido | ✅ | ✅ |
|
|
310
|
-
| `quarantine` | acima de 30 %, ou ainda não medido (n < 10) | ❌ | ✅ |
|
|
347
|
+
Todo achado carrega dois rótulos: quão seguro o Mjölnir está e até onde o achado foi verificado. Essa é a diferença entre uma ferramenta que reporta padrões e uma ferramenta em que você pode condicionar um release.
|
|
311
348
|
|
|
312
|
-
|
|
313
|
-
| --------------- | ----------------- | ---------------------------------------------------------------- |
|
|
314
|
-
| TypeScript / JS | AST do compilador | a mais ampla, a mais medida — majoritariamente `core`/`extended` |
|
|
315
|
-
| Python / pytest | Camada regex | ampla, auditada em corpus — majoritariamente `core`/`extended` |
|
|
316
|
-
| Java | Camada regex | mais novo — majoritariamente `extended`/`quarantine` |
|
|
317
|
-
| C# / .NET | Camada regex | mais novo — majoritariamente `extended`/`quarantine` |
|
|
349
|
+
**Quão seguro — o nível de evidência.**
|
|
318
350
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
351
|
+
| Nível | Nome | Significa | Dedução |
|
|
352
|
+
| ------ | -------------------- | --------------------------------------------------- | -------- |
|
|
353
|
+
| **E2** | Prova determinística | O defeito está presente no código como escrito | Integral |
|
|
354
|
+
| **E1** | Evidência de padrão | Um padrão fortemente ligado ao defeito correspondeu | Metade |
|
|
355
|
+
| **E0** | Observação | Vale saber. Não afirma que algo está errado. | Zero |
|
|
323
356
|
|
|
324
|
-
|
|
357
|
+
A confiança em uma detecção não é a força da prova. Uma regra pode ter certeza de que encontrou o que procurava e ainda assim estar olhando para uma heurística. Achados E1 existem para ser lidos e julgados, nunca aplicados às cegas, e esse limite fica marcado no achado no terminal, no JSON e na passagem para o agente.
|
|
325
358
|
|
|
326
|
-
|
|
359
|
+
**Até onde foi verificado — o nível de confiança.** A maioria dos achados vem da leitura do seu código. Dê ao Mjölnir o relatório de uma execução real de testes e ele poderá confirmar que o código de fato rodou.
|
|
327
360
|
|
|
328
361
|
<p align="center">
|
|
329
|
-
<img src="assets/readme/
|
|
362
|
+
<img src="assets/readme/trust-ladder.svg" alt="A escada de confiança de L0 a L5. L0 a L2 vêm da leitura do código; L3 a L5 precisam do relatório de uma execução real, marcado por uma quebra na escada." width="100%" />
|
|
330
363
|
</p>
|
|
331
364
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
365
|
+
| Nível | Em palavras simples | O que é preciso |
|
|
366
|
+
| ------ | ------------------- | --------------------------------------------------------------------- |
|
|
367
|
+
| **L0** | Anotado | Ler o código |
|
|
368
|
+
| **L1** | Parece o problema | Ler o código: um padrão correspondeu |
|
|
369
|
+
| **L2** | Provado no código | Ler o código: o defeito é estrutural |
|
|
370
|
+
| **L3** | O arquivo rodou | Um relatório de execução mostra que o arquivo do achado foi executado |
|
|
371
|
+
| **L4** | O teste rodou | Um relatório de execução mostra que o teste do achado foi executado |
|
|
372
|
+
| **L5** | A execução concorda | O próprio resultado da execução confirma a classe do defeito |
|
|
335
373
|
|
|
336
|
-
|
|
337
|
-
normalizada pela exposição da suíte (deduções por declaração de teste).
|
|
338
|
-
Deduções ponderadas por evidência significam que sinais fracos custam
|
|
339
|
-
menos. O terminal mostra os mesmos números descontados que a pontuação
|
|
340
|
-
usa — sem caixa-preta. Método completo:
|
|
341
|
-
[docs/SCORING.md](docs/SCORING.md).
|
|
374
|
+
Um scan estático para em L2. Só o relatório de uma execução real (Playwright JSON, Jest ou Vitest JSON, JUnit XML) pode elevar um achado a L3 ou acima, de modo que um achado que nunca foi visto rodando nunca pode afirmar que rodou. Definições: [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md).
|
|
342
375
|
|
|
343
|
-
|
|
376
|
+
### Quanto disso é medido
|
|
344
377
|
|
|
345
|
-
|
|
346
|
-
| ------- | ---------------- |
|
|
347
|
-
| ≥ 80 | ✓ **WORTHY** |
|
|
348
|
-
| 50 – 79 | ⚠ **NEEDS WORK** |
|
|
349
|
-
| < 50 | ✖ **UNWORTHY** |
|
|
378
|
+
**74 de 79 regras têm uma taxa de falsos positivos medida contra código OSS real** (pelo menos 10 achados classificados à mão cada; veja [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). As outras 5 são lançadas com a estimativa do autor e dizem isso, regra por regra, em `mjolnir explain`. `mjolnir rules --unmeasured` as lista, e o rodapé de cada scan informa quantas das regras que de fato _dispararam_ são medidas.
|
|
350
379
|
|
|
351
|
-
|
|
352
|
-
finding na pontuação:
|
|
380
|
+
As taxas continuam públicas quando são ruins. QA-TEST-001 (um `.only` commitado) vai mal na auditoria em repositórios reais e por isso está em quarantine. O número atual de cada regra, incluindo QA-PW-141, está na auditoria.
|
|
353
381
|
|
|
354
|
-
|
|
355
|
-
| ----- | ---------------------- | -------------------- | ------------------------------------------------------ |
|
|
356
|
-
| E2 | Defeito determinístico | Dedução total | `.only` commitado — estruturalmente provável |
|
|
357
|
-
| E1 | Padrão heurístico | Meia dedução | `sleep()` detectado por regex — sinal forte, não prova |
|
|
358
|
-
| E0 | Observação | Zero (só info) | Reportado mas nunca faz gate de CI nem deduz |
|
|
382
|
+
### Níveis de confiança das regras
|
|
359
383
|
|
|
360
|
-
|
|
361
|
-
sistema: findings E2 são prova estrutural; findings E1 são avisos
|
|
362
|
-
corretamente posicionados, não provas formais.
|
|
384
|
+
Os níveis seguem a taxa de falsos positivos medida, não opinião:
|
|
363
385
|
|
|
364
|
-
|
|
365
|
-
|
|
386
|
+
| Nível | FP medido | Comportamento |
|
|
387
|
+
| -------------- | --------------------------------- | -------------------------------------------------- |
|
|
388
|
+
| **core** | ≤ 10% | Relatório padrão, bloqueia |
|
|
389
|
+
| **extended** | ≤ 30% | Relatório padrão, confiança menor |
|
|
390
|
+
| **quarantine** | > 30% ou explicitamente declarado | Só com `--strict`, limitado a info, nunca bloqueia |
|
|
391
|
+
| _não medida_ | n < 10 | Não pode ser promovida a core até ser medida |
|
|
366
392
|
|
|
367
|
-
|
|
393
|
+
As faixas de FP só podem rebaixar um nível — nunca promovem uma regra para fora de `quarantine` se ela foi explicitamente declarada lá. Uma regra explicitamente colocada em quarantine permanece em quarantine independentemente de sua taxa de FP medida.
|
|
368
394
|
|
|
369
|
-
|
|
395
|
+
Promoção, rebaixamento e maturidade por linguagem: [ciclo de vida das regras](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle).
|
|
370
396
|
|
|
371
|
-
|
|
372
|
-
seus locators:
|
|
397
|
+
### Por que isto não é um linter
|
|
373
398
|
|
|
374
|
-
|
|
375
|
-
▚ SELECTOR HEALTH — e2e/checkout.spec.ts
|
|
399
|
+
Linters dizem se o código segue regras. O Mjölnir diz se a sua verificação merece confiança.
|
|
376
400
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
401
|
+
| | Linters (ESLint, SonarQube) | Ferramentas de cobertura | Revisão de código com IA | **Mjölnir** |
|
|
402
|
+
| ------------------------------------------------------------------ | :-------------------------: | :----------------------: | :----------------------: | :--------------: |
|
|
403
|
+
| Pontua o **sistema de verificação**, não o código do produto | Não | Não | Não | Sim |
|
|
404
|
+
| Integridade dos workflows de CI (`continue-on-error`, `\|\| true`) | Não | Não | só o diff | Sim |
|
|
405
|
+
| Avalia a resiliência dos locators do Playwright (Selector Health) | Não | Não | Não | Sim |
|
|
406
|
+
| Lê dados de execução reais para vereditos `TRUE-FLAKE` | Não | Não | Não | Sim |
|
|
407
|
+
| Publica uma taxa de falsos positivos medida por regra | Não | Não | Não | Sim |
|
|
408
|
+
| Aponta testes sem asserções | Sim\* | Não | às vezes | Sim |
|
|
409
|
+
| Detecta sleeps fixos (`waitForTimeout`, `time.sleep`) | Sim\* | Não | às vezes | Sim |
|
|
410
|
+
| Determinístico (mesma entrada, mesma saída) | Sim | Sim | Não | Sim |
|
|
411
|
+
| Custo por scan | grátis | grátis | tokens | **zero** (local) |
|
|
412
|
+
|
|
413
|
+
<sub>\*Coberto por `eslint-plugin-jest` e `eslint-plugin-playwright` (`expect-expect`, `no-wait-for-timeout`) e pelas próprias regras de asserção do SonarQube. As colunas descrevem o comportamento padrão para verificação de suítes de teste; plugins, planos pagos e regras personalizadas mudam algumas respostas. Este é um resumo de posicionamento, não um benchmark.</sub>
|
|
380
414
|
|
|
381
|
-
|
|
382
|
-
XPath afundam a pontuação — eles quebram em qualquer refactor do DOM
|
|
383
|
-
sem dizer qual comportamento regrediu.
|
|
415
|
+
Use revisão com IA também. Ela percebe nuances, intenção e falhas de design que nenhum padrão encontra. O Mjölnir pega o que a revisão com IA deixa passar porque parece intencional: um `.only` commitado, um código de saída engolido, um `continue-on-error` em um job de testes. Isso exige scan, não raciocínio.
|
|
384
416
|
|
|
385
|
-
|
|
417
|
+
<br />
|
|
386
418
|
|
|
387
|
-
##
|
|
419
|
+
## Forense de execução
|
|
388
420
|
|
|
389
|
-
|
|
390
|
-
reais de execução** — relatórios JSON do Playwright e XML do JUnit de
|
|
391
|
-
qualquer runner:
|
|
421
|
+
A análise estática raciocina sobre código que nunca rodou. A forense lê o que realmente aconteceu: Playwright JSON, Jest JSON, Vitest JSON e JUnit XML de qualquer runner.
|
|
392
422
|
|
|
393
423
|
```bash
|
|
394
424
|
mjolnir forensics ./test-results/
|
|
395
425
|
```
|
|
396
426
|
|
|
397
427
|
```text
|
|
398
|
-
|
|
428
|
+
▍ FLAKINESS LEADERBOARD
|
|
399
429
|
|
|
400
430
|
3 tests · 1 failed · 1 flaky · 1 retried
|
|
401
431
|
|
|
@@ -405,300 +435,184 @@ FAILING declines an expired card (e2e/checkout.spec.ts)
|
|
|
405
435
|
████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
|
|
406
436
|
```
|
|
407
437
|
|
|
408
|
-
|
|
409
|
-
teste sortudo. Ele é marcado como `TRUE-FLAKE` independentemente do
|
|
410
|
-
visto verde final.
|
|
438
|
+
`TRUE-FLAKE` não significa que o teste teve retry. Significa que o teste **falhou em pelo menos uma tentativa e depois terminou verde**: uma aprovação por sorte, apontada não importa o que diga o check final. `mjolnir triage` transforma esse histórico em uma proposta de quarentena, e `mjolnir pw-report` resume uma execução. São esses mesmos relatórios de execução que elevam os achados aos níveis de confiança L3 e acima.
|
|
411
439
|
|
|
412
|
-
|
|
440
|
+
<br />
|
|
413
441
|
|
|
414
|
-
##
|
|
442
|
+
## Integridade de CI
|
|
415
443
|
|
|
416
|
-
|
|
417
|
-
verificação pode ser confiada.
|
|
444
|
+
Um teste pode passar enquanto o pipeline ao redor dele não consegue falhar. O Mjölnir também lê os workflows: `continue-on-error`, `|| true`, códigos de saída que nunca se propagam, steps que sempre passam, relatórios consumidos mas nunca gerados e gates pulados justamente nos eventos que deveriam bloquear. Cada achado nomeia o job, o step e a linha, e carrega seu próprio nível de evidência.
|
|
418
445
|
|
|
419
|
-
|
|
420
|
-
| ----------------------------------------------------------------- | :----------------: | :---------------------: | :------------: | :---------: |
|
|
421
|
-
| Integridade de workflows de CI (`continue-on-error`, `\|\| true`) | ❌ | ❌ | raramente | ✅ |
|
|
422
|
-
| Multilinguagem (TS, Python, Java, C#) a partir de uma ferramenta | ❌ | ❌ | ❌ | ✅ |
|
|
423
|
-
| Avalia a resiliência de locators do Playwright (Selector Health) | ❌ | ❌ | raramente | ✅ |
|
|
424
|
-
| Sinaliza testes sem asserções reais | ✅ (plugin)\* | ❌ | às vezes | ✅ |
|
|
425
|
-
| Pega sleeps fixos (`waitForTimeout`, `time.sleep`) | ✅ (plugin)\* | ❌ | às vezes | ✅ |
|
|
426
|
-
| Roda em segundos, zero chamadas de rede durante o escaneio | ✅ | ✅ | — | ✅ |
|
|
446
|
+
Gere o workflow de PR, consultivo por padrão:
|
|
427
447
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
448
|
+
```bash
|
|
449
|
+
mjolnir ci install
|
|
450
|
+
```
|
|
431
451
|
|
|
432
|
-
|
|
452
|
+
Ou adicione a action do Marketplace a um workflow que você já tem:
|
|
433
453
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
454
|
+
```yaml
|
|
455
|
+
- uses: Sergey-Bar/Mjolnir@v1
|
|
456
|
+
with:
|
|
457
|
+
scope: changed
|
|
458
|
+
fail-on: error
|
|
459
|
+
```
|
|
439
460
|
|
|
440
|
-
|
|
441
|
-
de instabilidade autônomo com rótulos de veredito.
|
|
461
|
+
Fixe `@v1` para acompanhar a linha principal, ou uma tag exata (`@v0.5.32`) para um gate reproduzível. [docs/DISTRIBUTION-KIT.md](docs/DISTRIBUTION-KIT.md) cobre o Marketplace, o Smithery e os registros MCP.
|
|
442
462
|
|
|
443
|
-
|
|
463
|
+
Para levar os achados ao GitHub Code Scanning, envie o SARIF (requer `security-events: write` no escopo do workflow ou job):
|
|
444
464
|
|
|
445
|
-
|
|
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
|
+
```
|
|
446
473
|
|
|
447
|
-
|
|
448
|
-
mudança suspeita de teste em um diff; ela não prova que o sistema de
|
|
449
|
-
verificação como um todo é confiável — e só vê o diff que você mostra.
|
|
474
|
+
No GitLab, `--format codequality` grava o relatório do Code Quality que o widget de MR e as anotações do diff leem ([docs/GITLAB-CI.md](docs/GITLAB-CI.md)). Configuração do editor e do pipeline: [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
|
|
450
475
|
|
|
451
|
-
|
|
452
|
-
| -------------------------------------------- | :-------------------------------------: | :-----------------------------------: |
|
|
453
|
-
| Custo por escaneio | Tokens (escala com o tamanho do diff) | **Zero** (local, instalado) |
|
|
454
|
-
| Vê toda a suíte + todas as configs de CI | Só o diff da PR que você mostra | **Tudo, toda vez** |
|
|
455
|
-
| Determinístico (mesma entrada → mesma saída) | ❌ (não determinístico) | **✅** |
|
|
456
|
-
| Pega padrões dormentes por meses | Só se estiver no contexto | **✅** (escaneia todos os arquivos) |
|
|
457
|
-
| Lembra dos findings entre execuções | ❌ (sem memória entre sessões) | **✅** (baseline + diff) |
|
|
458
|
-
| Roda sem gatilho humano | Precisa de uma PR ou prompt | **✅** (hook de CI, roda em segundos) |
|
|
476
|
+
### Atribuição no escopo alterado
|
|
459
477
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
código de saída engolido, um `continue-on-error` em um job de teste.
|
|
464
|
-
Não são bugs que precisam de raciocínio; são fatos que precisam de
|
|
465
|
-
escaneio.
|
|
478
|
+
```bash
|
|
479
|
+
npx mjolnir-qa@latest --scope changed
|
|
480
|
+
```
|
|
466
481
|
|
|
467
|
-
|
|
482
|
+
Os achados são atribuídos às linhas que sua branch adicionou, medidas contra a **merge-base**. O escopo é o mesmo conjunto de arquivos que um scan completo descobre (specs TS/JS e configurações de adaptadores, `test_*.py`, `*Test.java`, `*Tests.cs`, `.github/workflows/*.yml`), mais as alterações não commitadas e não rastreadas, então funciona antes do commit. A base é resolvida como `main → master → origin/main → origin/master → origin/HEAD`; substitua com `--base <ref>`.
|
|
468
483
|
|
|
469
|
-
|
|
484
|
+
Quando a merge-base não pode ser resolvida (um clone raso, um HEAD destacado, um alvo fora do git), os achados passam a ser atribuídos ao arquivo inteiro **e o relatório diz isso.** Um fallback silencioso seria exatamente o tipo de defeito que esta ferramenta existe para pegar.
|
|
470
485
|
|
|
471
|
-
|
|
472
|
-
bloqueante:
|
|
486
|
+
<br />
|
|
473
487
|
|
|
474
|
-
|
|
475
|
-
mjolnir ci install
|
|
476
|
-
```
|
|
488
|
+
## Agentes de IA
|
|
477
489
|
|
|
478
|
-
|
|
490
|
+
Achados só valem alguma coisa se algo agir sobre eles.
|
|
479
491
|
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
- uses: github/codeql-action/upload-sarif@v3
|
|
483
|
-
with:
|
|
484
|
-
sarif_file: mjolnir.sarif
|
|
492
|
+
```text
|
|
493
|
+
SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
|
|
485
494
|
```
|
|
486
495
|
|
|
487
|
-
|
|
488
|
-
[docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
|
|
496
|
+
**A IA escreve a correção. O Mjölnir a verifica.** A prova vem do novo scan, nunca do próprio relato de sucesso do agente.
|
|
489
497
|
|
|
490
|
-
|
|
498
|
+
| Comando | O que o agente recebe |
|
|
499
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
500
|
+
| `mjolnir mcp` | Um servidor [MCP](https://modelcontextprotocol.io) via stdio. `scan`, `explain` e `diff` viram ferramentas chamáveis. |
|
|
501
|
+
| `mjolnir handoff` | Um relatório `--json` salvo vira um plano determinístico em Markdown: o que foi detectado, o limite de evidência de cada achado, o que **não** pode mudar, como verificar. |
|
|
502
|
+
| `mjolnir install` | Grava nas superfícies de agente que seu repo já tem (`.claude/`, `.cursor/`, `.kilo/`, `AGENTS.md`) para que o agente refaça o scan antes de dizer que terminou. |
|
|
491
503
|
|
|
492
|
-
|
|
493
|
-
em relação ao merge-base com `main`. Ele cobre arquivos de teste
|
|
494
|
-
(`*.spec.*`, `*.test.*`) mais arquivos de workflow do GitHub e
|
|
495
|
-
configurações do Playwright no diff. Quando o merge-base não pode ser
|
|
496
|
-
resolvido — clone raso, HEAD detached, alvo sem git, branch padrão
|
|
497
|
-
diferente — ele degrada com honestidade: os findings voltam à
|
|
498
|
-
atribuição por arquivo inteiro e o relatório diz isso. Sobrescreva a ref
|
|
499
|
-
base com `--base <ref>`.
|
|
504
|
+
Adicione-o a um cliente que tenha sua própria CLI:
|
|
500
505
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
O Mjölnir é zero-config. Um `mjolnir.config.json` opcional (ou
|
|
506
|
-
`.mjolnir.json`) na raiz do repo ajusta severidade, gating e escopo —
|
|
507
|
-
ele nunca muda a semântica de detecção.
|
|
506
|
+
```bash
|
|
507
|
+
claude mcp add mjolnir -- npx -y mjolnir-qa@latest mcp
|
|
508
|
+
```
|
|
508
509
|
|
|
509
|
-
|
|
510
|
-
| ------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
511
|
-
| `exclude` | `string[]` | Globs de ignore adicionais (subconjunto do gitignore), além dos padrões embutidos |
|
|
512
|
-
| `gate` | `"advisory" \| "error" \| "warning"` | Quais severidades saem com código diferente de zero (padrão `error`; `advisory` nunca bloqueia) |
|
|
513
|
-
| `severityOverrides` | `{ "<RULE-ID>": severity }` | Reordena os findings de uma regra para o seu repo |
|
|
514
|
-
| `ignore` | `IgnoreEntry[]` | Suprime findings — **`reason` é obrigatório**; as entradas expiram após 90 dias (uma data `expires` explícita, ou a data de modificação do arquivo de config para entradas sem ela) |
|
|
515
|
-
| `plugins` | `string[]` | Pacotes de regras de terceiros (veja o [Modelo de confiança](#modelo-de-confiança)) |
|
|
510
|
+
Ou a qualquer cliente que aceite um bloco `mcpServers`:
|
|
516
511
|
|
|
517
512
|
```json
|
|
518
513
|
{
|
|
519
|
-
"
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
"ignore": [
|
|
523
|
-
{
|
|
524
|
-
"ruleId": "QA-TEST-004",
|
|
525
|
-
"files": ["e2e/legacy-login.spec.ts"],
|
|
526
|
-
"reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
|
|
527
|
-
"expires": "2026-12-31"
|
|
528
|
-
}
|
|
529
|
-
]
|
|
514
|
+
"mcpServers": {
|
|
515
|
+
"mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@latest", "mcp"] }
|
|
516
|
+
}
|
|
530
517
|
}
|
|
531
518
|
```
|
|
532
519
|
|
|
533
|
-
|
|
534
|
-
exclusões de caminhos, mesmo dialeto do `exclude`. Use-o para ruído
|
|
535
|
-
específico da máquina; use `exclude` quando a lista pertence ao
|
|
536
|
-
controle de versão, junto com o resto da configuração.
|
|
537
|
-
- **Overrides de CLI** — `--strict` (incluir regras de quarentena),
|
|
538
|
-
`--width <cols>` e `--ascii` / `--no-ascii` (renderização no
|
|
539
|
-
terminal), `--tone blunt` (mensagens mais secas),
|
|
540
|
-
`--max-duration <sec>` (escaneio parcial limitado).
|
|
541
|
-
- Supressão de regras e ciclo de vida de deprecação:
|
|
542
|
-
[docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
|
|
543
|
-
|
|
544
|
-
As entradas `ignore` também alimentam o comando autônomo
|
|
545
|
-
`mjolnir suppressions`, que lista o que está suprimido no momento e
|
|
546
|
-
quando cada entrada expira.
|
|
547
|
-
|
|
548
|
-
---
|
|
549
|
-
|
|
550
|
-
## 📐 Códigos de saída e contratos
|
|
551
|
-
|
|
552
|
-
Congelados — seguros para construir lógica de CI por cima:
|
|
553
|
-
|
|
554
|
-
| Código de saída | Significado |
|
|
555
|
-
| --------------- | ----------------------------------------------------------------------------------- |
|
|
556
|
-
| `0` | Limpo — nenhum finding no nível do gate ou acima |
|
|
557
|
-
| `1` | Findings no nível do gate ou acima |
|
|
558
|
-
| `2` | Escaneio parcial (orçamento de tempo esgotado, arquivos ilegíveis) — nunca bloqueia |
|
|
559
|
-
| `10` | Erro de uso (flag inválida, alvo ausente) |
|
|
560
|
-
| `20` | Erro interno |
|
|
561
|
-
|
|
562
|
-
O relatório JSON/SARIF é `schemaVersion: 1`. Os IDs de regra
|
|
563
|
-
(`QA-<FAMILY>-NNN`) são imutáveis uma vez publicados e nunca reutilizados.
|
|
564
|
-
|
|
565
|
-
---
|
|
566
|
-
|
|
567
|
-
## Modelo de confiança
|
|
568
|
-
|
|
569
|
-
- **Local-first** — zero chamadas de rede durante o escaneio. Nunca.
|
|
570
|
-
Zero telemetria.
|
|
571
|
-
- **Nenhuma prova falsa** — preferimos dizer "desconhecido" a
|
|
572
|
-
"verificado". Um repo vazio recebe `score: null`, nunca um falso 100.
|
|
573
|
-
- **Honestidade parcial** — se a análise foi interrompida, a saída diz
|
|
574
|
-
isso. Nunca "complete" quando não está.
|
|
575
|
-
- **Firewall de FP** — a detecção roda sobre uma visão do código sem
|
|
576
|
-
comentários/strings (as regras TypeScript usam o AST do compilador):
|
|
577
|
-
um padrão dentro de um comentário de prosa ou de uma string de
|
|
578
|
-
exemplo de documentação é documentação, não um finding.
|
|
579
|
-
- **Medido, não afirmado** — apenas regras com taxa de falsos positivos
|
|
580
|
-
de código OSS real entram nos tiers de destaque (veja
|
|
581
|
-
[Quanto disso é medido](#quanto-disso-é-medido)); o rodapé do
|
|
582
|
-
escaneio e o `mjolnir rules --unmeasured` dizem qual é qual.
|
|
583
|
-
- **Confiança em plugins e porta de execução** — plugins são pacotes
|
|
584
|
-
npm declarados sob
|
|
585
|
-
`"plugins"`; módulos JS vivem em `mjolnir-rules/*.mjs`.
|
|
586
|
-
**Não há sandbox**: o código do plugin roda com todos os
|
|
587
|
-
privilégios do Node, o mesmo modelo de confiança dos plugins ESLint
|
|
588
|
-
ou Vitest. Por isso, a execução de código é **opt-in a cada
|
|
589
|
-
escaneio**: passe `--enable-plugins` (ou defina
|
|
590
|
-
`MJOLNIR_ENABLE_PLUGINS=1`), ou as fontes NÃO são carregadas — um
|
|
591
|
-
aviso sonoro no stderr lista exatamente o que foi pulado. Escanear
|
|
592
|
-
código não confiável nunca o executa. Manifestos de regras JSON
|
|
593
|
-
(`mjolnir-rules/*.json`) não são afetados: eles declaram padrões
|
|
594
|
-
regex e por projeto não executam código. Prefixos de IDs de regras
|
|
595
|
-
core são reservados e rejeitados
|
|
596
|
-
de plugins e regras externas para evitar falsificação.
|
|
597
|
-
- **Regras externas locais ao workspace** (baseadas em pasta, zero
|
|
598
|
-
rede) — um diretório `mjolnir-rules/` ao lado do alvo do escaneio
|
|
599
|
-
carrega regras personalizadas: arquivos JSON declaram padrões regex
|
|
600
|
-
(nenhum código executado), módulos `.mjs`/`.js` exportam `rules`
|
|
601
|
-
(confiança total do Node, como os plugins). Regras externas carregam
|
|
602
|
-
os mesmos metadados de confiança do core; elas nunca podem entrar no
|
|
603
|
-
tier core (core exige uma taxa de FP medida do sidecar de corpus — um
|
|
604
|
-
`tier: "core"` declarado é limitado a `extended`), obedecem aos tetos
|
|
605
|
-
de tier e são verificadas contra deriva:
|
|
606
|
-
`mjolnir rules --md --external` renderiza o catálogo a partir dos
|
|
607
|
-
arquivos carregados (proveniência `external`), e o gerador de matriz
|
|
608
|
-
aceita `--external <root>`.
|
|
609
|
-
|
|
610
|
-
---
|
|
611
|
-
|
|
612
|
-
## 🏗️ Arquitetura
|
|
520
|
+
**A proteção importa mais que a conveniência.** Todo achado em uma passagem carrega seu limite. **E2** diz _determinístico: confira o local e aplique a correção_. **E1** diz _REQUER CONFIRMAÇÃO: a observação sozinha não prova o defeito_. Um agente que corrige E1 às cegas, suprime uma regra ou edita uma regra para aumentar a pontuação está fazendo exatamente o que esta ferramenta existe para pegar, então a passagem diz isso no prompt, ao lado do achado.
|
|
613
521
|
|
|
614
|
-
<
|
|
615
|
-
<summary>Expandir árvore</summary>
|
|
522
|
+
<br />
|
|
616
523
|
|
|
617
|
-
|
|
618
|
-
mjolnir/
|
|
619
|
-
├── src/
|
|
620
|
-
│ ├── engine/ # LanguageAdapter interface + rule runner
|
|
621
|
-
│ ├── adapters/ # typescript · python · java · csharp · github-actions
|
|
622
|
-
│ ├── rules/ # rules across 8 families + the measured-FP table
|
|
623
|
-
│ ├── playwright/ # Selector Health Score engine
|
|
624
|
-
│ ├── discovery/ # workspace, frameworks, ignore resolution
|
|
625
|
-
│ ├── scope/ # git merge-base changed-scope engine
|
|
626
|
-
│ ├── scorer/ # transparent deduction table + prioritization
|
|
627
|
-
│ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
|
|
628
|
-
│ ├── forensics/ # run-data ingestion · flake verdicts · triage
|
|
629
|
-
│ ├── config/ # mjolnir.config.json + suppressions
|
|
630
|
-
│ ├── plugins/ # third-party rule loading (no sandbox)
|
|
631
|
-
│ └── commands/ # every subcommand
|
|
632
|
-
└── tests/
|
|
633
|
-
├── fixtures/ # must-fire / must-not-fire per rule
|
|
634
|
-
└── golden/ # frozen score regression locks
|
|
635
|
-
```
|
|
524
|
+
## Confiança e segurança
|
|
636
525
|
|
|
637
|
-
|
|
526
|
+
**Local-first, zero telemetria.** Nenhuma API com acesso à rede (`fetch`, `http`, `https`, `net`, `dns`, `dgram`, WebSocket) existe em lugar nenhum de `src/`, e [`privacy-network-isolation.spec.ts`](tests/contract/privacy-network-isolation.spec.ts) quebra o build se uma aparecer. Ele também proíbe `eval` e `new Function`. Analisar código não confiável nunca o executa: a análise estática lê o texto-fonte, e a forense interpreta arquivos de relatório que já existem em disco.
|
|
527
|
+
|
|
528
|
+
Duas ressalvas: o próprio `npx` baixa o pacote antes de qualquer coisa rodar, e a garantia cobre `src/`, não plugins de terceiros.
|
|
529
|
+
|
|
530
|
+
**Plugins não rodam em sandbox.** Plugins JS (`mjolnir-rules/*.mjs`, ou pacotes npm listados em `"plugins"`) rodam com todos os privilégios do Node, o mesmo modelo de confiança dos plugins do ESLint ou do Vitest. Carregá-los é opcional **por scan**: sem `--enable-plugins` (ou `MJOLNIR_ENABLE_PLUGINS=1`), suas fontes nunca são carregadas, e um aviso no stderr lista o que foi pulado. Manifestos de regras em JSON não executam código, e os prefixos de ID das regras core são reservados para que nenhum plugin possa se passar por uma delas. Reporte vulnerabilidades por meio do [SECURITY.md](SECURITY.md).
|
|
531
|
+
|
|
532
|
+
**Ele roda sobre si mesmo.** Um motor de confiança de verificação não tem credibilidade se não for ele próprio verificável. Cada execução da CI analisa este repositório com o build que essa mesma execução produziu. O gate falha com qualquer achado de severidade error, e também com um scan **parcial** ou uma **regra que travou**, porque um autoscan truncado que não reporta nada é o falso verde que este projeto existe para pegar. `mjolnir doctor` reaudita a base de regras na mesma execução (firewall de fixtures, honestidade dos níveis, o teto do nível core), e uma verificação INCONCLUSIVE falha exatamente como uma que falhou. Os dois relatórios são enviados como artefatos do build.
|
|
533
|
+
|
|
534
|
+
### Códigos de saída e o contrato de máquina
|
|
638
535
|
|
|
639
|
-
|
|
640
|
-
sem I/O, sem globais. Adicionar um ecossistema = um adaptador + suas
|
|
641
|
-
regras.
|
|
642
|
-
- **TypeScript/Playwright usa o AST do compilador** (ts-morph). Python,
|
|
643
|
-
Java e C# rodam em uma camada regex compartilhada com
|
|
644
|
-
comentários/strings mascarados.
|
|
645
|
-
- Uma camada de AST tree-sitter WASM para Java e C# existe e é o
|
|
646
|
-
próximo passo de precisão — ainda não está ligada ao pipeline de
|
|
647
|
-
escaneio síncrono.
|
|
536
|
+
Congelados, para que você possa construir lógica de CI em cima deles:
|
|
648
537
|
|
|
649
|
-
|
|
538
|
+
| Código de saída | Significado |
|
|
539
|
+
| --------------- | ------------------------------------------------------------------------------- |
|
|
540
|
+
| `0` | Limpo: nenhum achado no nível do gate ou acima |
|
|
541
|
+
| `1` | Achados no nível do gate ou acima |
|
|
542
|
+
| `2` | Scan parcial (orçamento de tempo esgotado, arquivos ilegíveis). Nunca bloqueia. |
|
|
543
|
+
| `10` | Erro de uso (flag inválida, alvo ausente) |
|
|
544
|
+
| `20` | Erro interno |
|
|
650
545
|
|
|
651
|
-
|
|
546
|
+
`2` é deliberadamente diferente de `0`: um scan que não terminou não encontrou "nada". Ele só não terminou de procurar.
|
|
652
547
|
|
|
653
|
-
|
|
654
|
-
| ------------------------------------------------------ | ---------------------------------------------------- |
|
|
655
|
-
| [docs/SCORING.md](docs/SCORING.md) | Normalização da pontuação + ponderação por evidência |
|
|
656
|
-
| [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Taxas de falsos positivos medidas + método |
|
|
657
|
-
| [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Estados de regras, supressão, deprecação |
|
|
658
|
-
| [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | Saída SARIF + configuração de editor/CI |
|
|
659
|
-
| [docs/rules/](docs/rules/) | Catálogo gerado por regra |
|
|
660
|
-
| [CONTRIBUTING.md](CONTRIBUTING.md) | Setup de dev + fluxo de contribuição |
|
|
661
|
-
| [CHANGELOG.md](CHANGELOG.md) | Histórico de releases |
|
|
662
|
-
| [SECURITY.md](SECURITY.md) | Relato de vulnerabilidades |
|
|
548
|
+
Tudo o que uma máquina consome (resultados das ferramentas MCP, `--json`, SARIF 2.1) vem de um único resultado canônico sob um esquema versionado e **somente aditivo** (`schemaVersion: 1`, `contractVersion: 1`), para que nenhum consumidor precise reconstruir significado a partir de texto renderizado. Veja [o contrato de máquina](docs/machine-contract.md). IDs de regra (`QA-<FAMILY>-NNN`) são imutáveis depois de lançados e nunca são reutilizados.
|
|
663
549
|
|
|
664
|
-
|
|
550
|
+
<br />
|
|
665
551
|
|
|
666
|
-
##
|
|
552
|
+
## O que o Mjölnir não pode dizer
|
|
667
553
|
|
|
668
|
-
**
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
554
|
+
- **Ele não roda seus testes.** Um scan limpo não é uma suíte aprovada.
|
|
555
|
+
- **Ele não pode dizer que uma asserção está _errada_.** `expect(total).toBe(41)` parece saudável. O Mjölnir encontra testes que _não podem falhar_ e pipelines que _não podem ficar vermelhos_, não testes que verificam a coisa errada.
|
|
556
|
+
- **Ele não prova a correção de negócio.** Nada aqui diz que o seu produto faz o que o requisito pediu.
|
|
557
|
+
- **Um 100 não é prova de uma boa suíte.** Se a sua suíte cobre o seu risco real é outra questão, e esta ferramenta não a responde.
|
|
558
|
+
- **5 de 79 regras são lançadas com uma estimativa**, não com uma taxa medida. Cada uma diz isso no próprio achado.
|
|
559
|
+
- **E1 não é E2.** Achados heurísticos merecem ser lidos, não aplicados às cegas.
|
|
560
|
+
- **Um repo vazio recebe `null`, nunca 100.**
|
|
561
|
+
- **Um arquivo chamado `*.spec.ts` sem declarações de teste não conta como cobertura.** Um repo cujos únicos arquivos spec contêm imports ou tipos (zero chamadas `it`/`test`) recebe `null`, não 100.
|
|
672
562
|
|
|
673
|
-
|
|
563
|
+
<br />
|
|
674
564
|
|
|
675
|
-
##
|
|
565
|
+
## Documentação
|
|
676
566
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
567
|
+
O site completo de documentação está em <https://sergey-bar.github.io/Mjolnir/>.
|
|
568
|
+
|
|
569
|
+
| Documento | O que tem nele |
|
|
570
|
+
| ------------------------------------------------------ | ------------------------------------------------------------------- |
|
|
571
|
+
| [docs/SCORING.md](docs/SCORING.md) | Normalização da pontuação e ponderação da evidência |
|
|
572
|
+
| [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md) | Vocabulário canônico: uma palavra por conceito |
|
|
573
|
+
| [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Taxas de falsos positivos medidas e o método |
|
|
574
|
+
| [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Estados das regras, níveis, supressão, descontinuação |
|
|
575
|
+
| [docs/VERSIONING.md](docs/VERSIONING.md) | Política de semver, superfícies congeladas, ciclo de descontinuação |
|
|
576
|
+
| [docs/machine-contract.md](docs/machine-contract.md) | O resultado canônico legível por máquina |
|
|
577
|
+
| [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | Saída SARIF e configuração do editor ou da CI |
|
|
578
|
+
| [docs/GITLAB-CI.md](docs/GITLAB-CI.md) | GitLab: relatório do Code Quality, receita de MR, gate |
|
|
579
|
+
| [docs/rules/](docs/rules/) | Catálogo gerado por regra |
|
|
580
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Ambiente de desenvolvimento e fluxo de contribuição |
|
|
581
|
+
| [SUPPORT.md](SUPPORT.md) | Onde perguntar, reportar e obter ajuda |
|
|
582
|
+
| [SECURITY.md](SECURITY.md) | Relato de vulnerabilidades |
|
|
583
|
+
| [CHANGELOG.md](CHANGELOG.md) | Histórico de versões |
|
|
584
|
+
|
|
585
|
+
### Status
|
|
586
|
+
|
|
587
|
+
**Versão 1.** O esquema JSON e os códigos de saída são contratos congelados. TypeScript e Python têm a cobertura medida mais ampla. Java e C# são mais recentes; leia-os pela [tabela de maturidade](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle). O que vem a seguir, sem datas inventadas: [o roadmap público](https://sergey-bar.github.io/Mjolnir/reference/roadmap).
|
|
588
|
+
|
|
589
|
+
### Contribuindo
|
|
590
|
+
|
|
591
|
+
Novas regras são a primeira contribuição mais fácil. Um comando cria o esqueleto da regra com suas fixtures must-fire **e** must-not-fire. A regra gerada falha nas próprias fixtures de propósito até que uma detecção real seja escrita, porque um stub lançado é uma regra que ninguém mediu:
|
|
681
592
|
|
|
682
593
|
```bash
|
|
683
594
|
mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
|
|
684
595
|
```
|
|
685
596
|
|
|
686
|
-
|
|
687
|
-
anti-creep / firewall de fixtures estão no
|
|
688
|
-
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
597
|
+
O ambiente de desenvolvimento, os comandos dos gates permanentes e as leis anti-creep e do firewall de fixtures estão em [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
689
598
|
|
|
690
|
-
|
|
599
|
+
<br />
|
|
691
600
|
|
|
692
601
|
<div align="center">
|
|
693
602
|
|
|
694
|
-
|
|
603
|
+
<img src="assets/readme/closing.svg" alt="Rode no seu repo." width="100%" />
|
|
695
604
|
|
|
696
605
|
```bash
|
|
697
606
|
npx mjolnir-qa@latest
|
|
698
607
|
```
|
|
699
608
|
|
|
700
|
-
|
|
609
|
+
[Leia o guia](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [Site de documentação](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)
|
|
610
|
+
|
|
611
|
+
<br />
|
|
612
|
+
|
|
613
|
+
Não pergunte se os testes passaram.<br />
|
|
614
|
+
Pergunte se a evidência prova que eles merecem confiança.
|
|
701
615
|
|
|
702
|
-
|
|
616
|
+
<sub>Criado por [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · Licença MIT</sub>
|
|
703
617
|
|
|
704
618
|
</div>
|