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/README.br.md CHANGED
@@ -1,401 +1,431 @@
1
1
  <div align="center">
2
2
 
3
- <img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
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
- ### Seus testes estão mentindo para você. Nós provamos.
5
+ <br />
6
6
 
7
- **Verification Trust Engine para QA.** O Mjölnir audita suítes de testes
8
- e pipelines de CI, reporta uma pontuação de merecimento e mostra
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
- [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=C19A34&labelColor=0A1119)](https://www.npmjs.com/package/mjolnir-qa)
12
- [![ci](https://img.shields.io/github/actions/workflow/status/Sergey-Bar/Mjolnir/ci.yml?branch=main&style=flat-square&label=ci&labelColor=0A1119)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
13
- [![license](https://img.shields.io/badge/license-MIT-C19A34.svg?style=flat-square&labelColor=0A1119)](LICENSE)
14
- [![node](https://img.shields.io/badge/node-%E2%89%A5%2022.18-37ABBD.svg?style=flat-square&labelColor=0A1119)](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
- > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-08.
12
+ [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=1F6F7C&labelColor=0A1119)](https://www.npmjs.com/package/mjolnir-qa)
13
+ [![downloads](https://img.shields.io/npm/dm/mjolnir-qa.svg?style=flat-square&color=1F6F7C&labelColor=0A1119)](https://www.npmjs.com/package/mjolnir-qa)
14
+ [![ci](https://img.shields.io/github/actions/workflow/status/Sergey-Bar/Mjolnir/ci.yml?branch=main&style=flat-square&label=ci&labelColor=0A1119)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
15
+ [![coverage](https://img.shields.io/codecov/c/github/Sergey-Bar/Mjolnir?style=flat-square&color=1F6F7C&labelColor=0A1119&label=coverage)](https://codecov.io/gh/Sergey-Bar/Mjolnir)
16
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/Sergey-Bar/Mjolnir/badge)](https://scorecard.dev/viewer/?uri=github.com/Sergey-Bar/Mjolnir)
17
+ [![license](https://img.shields.io/badge/license-MIT-1F6F7C.svg?style=flat-square&labelColor=0A1119)](LICENSE)
18
+ [![node](https://img.shields.io/badge/node-%E2%89%A5%2022.18-1F6F7C.svg?style=flat-square&labelColor=0A1119)](https://nodejs.org)
19
19
 
20
20
  ```bash
21
21
  npx mjolnir-qa@latest
22
22
  ```
23
23
 
24
- **Seus testes merecem confiança?**
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
- [Veja funcionando](#-veja-funcionando) ·
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
- ## 🎬 Veja funcionando
92
+ <br />
38
93
 
39
94
  <p align="center">
40
- <img src="assets/readme/demo.svg" alt="O relatório --verbose completo do Mjölnir sobre um repo de demonstração: WORTHINESS 75/100 NEEDS WORK, um detalhamento de diagnósticos por categoria, uma lista FIX THIS FIRST e cada finding com o ID da regra e o número da linha através de CI, Playwright, higiene de testes e regras Python" width="900" />
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>A saída completa de `npx mjolnir-qa ./examples/demo-repo --verbose`,
44
- renderizada pelo reporter real — nada cortado. Regenerada com
45
- `npm run docs:demo`;
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
- **O que acabou de acontecer:**
104
+ ### Um achado, de perto
50
105
 
51
- 1. O Mjölnir descobriu as specs do Playwright, a configuração dele, o
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
- ### Um finding de perto
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
- Execute `mjolnir explain QA-CI-001` no primeiro finding acima e você
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
- ▚ QA-CI-001 — continue-on-error masks a failing verification gate
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
- Measured FP: not yet measured — this rule ships on assumption (see docs/FP-AUDIT.md)
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
- on this workflow cannot be trusted.
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
- Essa é a unidade de valor: não um detalhe de estilo, mas um lugar onde
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
- ## ⚡ Início rápido
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
- Execute contra um repositório para um relatório completo e uma
94
- pontuação de merecimento:
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
- ```bash
97
- npx mjolnir-qa@latest
155
+ Docs: mjolnir rules --md (full catalog, this rule included)
98
156
  ```
99
157
 
100
- **Em CI, o produto é um comando.** Ele escaneia apenas o que a branch
101
- tocou e sai com código diferente de zero diante de problemas novos:
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 --scope changed
165
+ npx mjolnir-qa@latest
105
166
  ```
106
167
 
107
- Coloque isso em um check de PR — `mjolnir ci install` escreve o
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
- | Comando | O que faz |
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
- | Comando | O que faz |
124
- | ----------------------------------- | ----------------------------------------------------------------- |
125
- | `mjolnir forensics ./test-results/` | Dados reais de execução → vereditos `TRUE-FLAKE`, `FLAKY.md` |
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
- </details>
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>Ocasional / relatórios</strong></summary>
134
-
135
- | Comando | O que faz |
136
- | ------------------------------- | ---------------------------------------------------------- |
137
- | `mjolnir fix --dry-run` / `fix` | Correções automáticas seguras com prova |
138
- | `mjolnir baseline` / `diff` | Snapshot de findings, depois reporta só novos/piorados |
139
- | `mjolnir impact --since <ref>` | O que mudou desde um commit anterior |
140
- | `mjolnir debt` | Registro de dívida de testes com um modelo de custo |
141
- | `mjolnir handover` | Mapa de onboarding da suíte para um novo QA |
142
- | `mjolnir stats` | Contadores locais históricos de correções vistas |
143
- | `mjolnir badge` | JSON de endpoint do shields.io + snippet |
144
- | `mjolnir rules --md` | Catálogo completo de regras (JSON ou Markdown) |
145
- | `mjolnir doctor` | Autoauditoria da própria base de regras do Mjölnir |
146
- | `mjolnir create-rule <ID>` | Gera o esqueleto de uma nova regra + fixtures |
147
- | `mjolnir --format mermaid` | Diagrama de arquitetura de testes para um comentário de PR |
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
- Instale globalmente em vez de usar `npx` se preferir:
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
- ## 🔨 O que o Mjölnir verifica
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
- ### As regras
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
- Cada regra vem com fixtures must-fire **e** must-not-fire. Uma regra
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
- <details>
188
- <summary><strong>Higiene de testes</strong></summary>
189
-
190
- | ID | Regra | Severity |
191
- | ----------- | --------------------------------------------------- | -------- |
192
- | QA-TEST-001 | Teste focado commitado (`.only`, `fit`) | error |
193
- | QA-TEST-002 | Teste pulado sem justificativa | error |
194
- | QA-TEST-002 | Teste pulado com justificativa registrada | warning |
195
- | QA-TEST-003 | Teste sem asserções | error |
196
- | QA-TEST-004 | Sleep fixo (`waitForTimeout`, `sleep()`, `delay()`) | warning |
197
- | QA-TEST-006 | Abuso de retry escondendo instabilidade | warning |
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
- </details>
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>Qualidade de testes</strong></summary>
204
-
205
- | ID | Regra | Severity |
206
- | ------------ | ----------------------------- | -------- |
207
- | QA-TQUAL-002 | Asserção tautológica | error |
208
- | QA-TQUAL-009 | Asserção de promise sem await | error |
209
- | QA-TQUAL-011 | Testes comentados | warning |
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
- <details>
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
- | ID | Regra | Severity |
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
- </details>
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
- <details>
226
- <summary><strong>Integridade de CI</strong></summary>
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
- </details>
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
- <details>
255
- <summary><strong>Java / JUnit · TestNG ☕</strong></summary>
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
- | ID | Regra | Severity |
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
- </details>
321
+ <br />
266
322
 
267
- <details>
268
- <summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
323
+ ## A pontuação de confiabilidade
269
324
 
270
- | ID | Regra | Severity |
271
- | --------- | ------------------------------------------ | -------- |
272
- | QA-CS-101 | Teste pulado (`[Ignore]`, `[Fact(Skip=)]`) | warning |
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
- </details>
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
- > O catálogo completo e vivo — cada regra com tier, confidence, risco de
281
- > falso positivo e disponibilidade de autofix — é gerado a partir do
282
- > registro:
283
- >
284
- > ```bash
285
- > mjolnir rules --md
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
- ### Quanto disso é medido
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
- **78 de 99 regras carregam uma taxa de falsos positivos medida contra
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
- ### Tiers de regras e maturidade por linguagem
343
+ <br />
302
344
 
303
- Cada regra é `core`, `extended` ou `quarantine`, atribuído a partir de
304
- sua taxa de falsos positivos **medida**:
345
+ ## O modelo de evidência
305
346
 
306
- | Tier | Significado | Escaneio padrão | `--strict` |
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
- | Linguagem | Adaptador | Cobertura hoje |
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
- TypeScript e Python têm a cobertura medida mais ampla. Java e C# são
320
- publicados, documentados, e ficam fora do número de destaque até que uma
321
- suíte consumidora real (não os próprios testes de uma biblioteca de
322
- binding) seja auditada.
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
- ## Como a pontuação funciona
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/terminal-hero.svg" alt="Saída de terminal do Mjölnir — WORTHINESS 75/100 NEEDS WORK, um detalhamento de diagnósticos por categoria e uma lista FIX THIS FIRST" width="820" />
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
- <sub>Regenerada com `npm run docs:hero`;
333
- [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
334
- faz a CI falhar se ela divergir do que o reporter realmente imprime.</sub>
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
- A pontuação é transparente: **error −8, warning −3, info −1**, depois
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
- **Vereditos**
376
+ ### Quanto disso é medido
344
377
 
345
- | Score | Veredito |
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
- **Níveis de evidência** — cada finding carrega um; ele define o peso do
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
- | Nível | Significado | Impacto na pontuação | Exemplo |
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
- A maioria das regras é **E1**. O lema "we prove it" se refere a este
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
- Um repo vazio pontua `null`, nunca um falso 100 — veja o
365
- [Modelo de confiança](#modelo-de-confiança).
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
- ## 🎭 Selector Health Score
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
- A métrica de destaque para suítes Playwright — quão resilientes são os
372
- seus locators:
397
+ ### Por que isto não é um linter
373
398
 
374
- ```text
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
- [█████████████████░░░] 83 / 100
378
- role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
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
- Locators baseados em role pontuam o máximo. Cadeias de classes CSS e
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
- ## 🔬 Evidência de runtime
419
+ ## Forense de execução
388
420
 
389
- Detecção estática de instabilidade é adivinhação. O Mjölnir lê **dados
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
- ▚ FLAKINESS LEADERBOARD
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
- Um teste que só passa no attempt ≥ 2 não é um teste que passa — é um
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
- ## ⚡ O Mjölnir não é mais um linter
442
+ ## Integridade de CI
415
443
 
416
- Linters dizem se o código segue regras. O Mjölnir diz se a sua
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
- | | ESLint / SonarQube | Ferramentas de coverage | Revisão manual | **Mjölnir** |
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
- \*`eslint-plugin-jest` (`expect-expect`) e `eslint-plugin-playwright`
429
- (`expect-expect`, `no-wait-for-timeout`) cobrem isso para seus
430
- respectivos frameworks.
448
+ ```bash
449
+ mjolnir ci install
450
+ ```
431
451
 
432
- **A análise de runtime** é uma categoria à parte do linting estático:
452
+ Ou adicione a action do Marketplace a um workflow que você já tem:
433
453
 
434
- | | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
435
- | ------------------------------------------------------ | :-----------------------: | :-------------------: | :-------------------: |
436
- | Lê dados reais de execução para vereditos `TRUE-FLAKE` | parcial\* | parcial (tag) | ✅ |
437
- | Relatório de triagem de instabilidade do histórico | ❌ | ✅ | ✅ |
438
- | Integra-se à pontuação de merecimento estática | ❌ | ❌ | ✅ |
454
+ ```yaml
455
+ - uses: Sergey-Bar/Mjolnir@v1
456
+ with:
457
+ scope: changed
458
+ fail-on: error
459
+ ```
439
460
 
440
- \*O Playwright rastreia retries internamente mas não produz um relatório
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
- ## 🤖 Por que não usar apenas revisão de código com IA?
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
- Problema diferente, camada diferente. A revisão com IA pode detectar uma
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
- | | Revisão de código com IA (Copilot etc.) | **Mjölnir** |
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
- **Use ambos.** A IA captura nuance, intenção e defeitos de design que
461
- nenhuma regex encontra. O Mjölnir captura os padrões estruturais que a
462
- IA ignora porque parecem "intencionais" — um `.only` commitado, um
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
- ## 🤖 Integração CI
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
- Um comando gera um workflow de PR — consultivo por padrão, nunca
472
- bloqueante:
486
+ <br />
473
487
 
474
- ```bash
475
- mjolnir ci install
476
- ```
488
+ ## Agentes de IA
477
489
 
478
- Ou conecte-o nativamente ao GitHub Code Scanning via SARIF:
490
+ Achados só valem alguma coisa se algo agir sobre eles.
479
491
 
480
- ```yaml
481
- - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
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
- Configuração de editor e pipeline para SARIF:
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
- ### Cobertura de escopo alterado
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
- `--scope changed` atribui findings às linhas adicionadas na sua branch
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
- ## Configuração
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
- | Key | Tipo | Efeito |
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
- "gate": "error",
520
- "exclude": ["legacy/**"],
521
- "severityOverrides": { "QA-PW-141": "warning" },
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
- - **`.mjolnirignore`** — um arquivo simples no estilo gitignore para
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
- <details>
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
- </details>
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
- - **Regras são funções puras** — `(SourceFileContext) → Finding[]`,
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
- ## 📚 Documentação
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
- | Documento | O que contém |
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
- ## 📈 Status
552
+ ## O que o Mjölnir não pode dizer
667
553
 
668
- **v0.5.x · beta aberto.** O schema JSON e os códigos de saída são
669
- contratos congelados. TypeScript e Python têm a cobertura medida mais
670
- ampla; Java e C# são mais novos — leia-os através da
671
- [tabela de tiers](#tiers-de-regras-e-maturidade-por-linguagem).
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
- ## 🤝 Contribuir
565
+ ## Documentação
676
566
 
677
- Novas regras são a primeira contribuição mais fácil — um comando gera o
678
- esqueleto da regra mais suas fixtures must-fire **e** must-not-fire (a
679
- regra gerada falha nas fixtures de propósito até você implementar
680
- detecção real — um stub não pode ser publicado):
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
- Setup completo de dev, os comandos do gate permanente e as leis
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
- **Pare de publicar testes em que não pode confiar.**
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
- **Star ⭐ · Watch 👀 · Contribute 🤝**
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
- Construído por [Sergey Bar](https://www.linkedin.com/in/sergeybar/)
616
+ <sub>Criado por [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · Licença MIT</sub>
703
617
 
704
618
  </div>