mjolnir-qa 4.0.0 → 6.0.0

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 DELETED
@@ -1,647 +0,0 @@
1
- <div align="center">
2
-
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
-
5
- <br />
6
-
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.
9
-
10
- <br />
11
-
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
-
20
- ```bash
21
- npx mjolnir-qa@4.0.0
22
- ```
23
-
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-26.
32
-
33
- <!-- Source hash: `de04dfb1677b` -->
34
-
35
- </details>
36
-
37
- </div>
38
-
39
- <br />
40
-
41
- ## Release status (English canonical)
42
-
43
- The published line is `3.0.0`; this working tree is the `4.0.0-rc.1`
44
- candidate. `3.0.0` must not be republished or retagged. The M26–M50 program is
45
- tracked in
46
- [`docs/ROADMAP.yaml`](docs/ROADMAP.yaml); provisional capability contracts
47
- are not automatically enabled or certified. Repository-owned checks pass, but
48
- Trust certification remains `NOT_CERTIFIED` until the protected holdout,
49
- real-world, platform/consumer, remote-workflow, support-matrix, and corpus
50
- evidence gates pass. Run `npm run m26:readiness` before treating any candidate
51
- as releasable. This document does not publish a tag or authorize a release.
52
-
53
- > Machine-assisted canonical text. Translate this block before treating it as localized copy.
54
-
55
- ## Um check verde é uma afirmação, não uma prova
56
-
57
- 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:
58
-
59
- - um `.only` commitado que rodou 3 testes em vez de 900
60
- - `continue-on-error: true` no job que deveria bloquear
61
- - `|| true` depois do comando de testes
62
- - um teste que não verifica nada, ou que tem o corpo vazio
63
- - um wrapper de retry que transforma uma falha real em uma aprovação por sorte
64
- - um relatório que o workflow envia, mas que nunca foi gerado
65
- - um sleep fixo segurando uma condição de corrida
66
-
67
- 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:
68
-
69
- <p align="center">
70
- <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" />
71
- </p>
72
-
73
- <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>
74
-
75
- **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@4.0.0` sem `--strict`) cobre apenas regras core e extended. Adicione `--strict` quando quiser a camada de consultoria também.
76
-
77
- 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:
78
-
79
- | Situação | O que o Mjölnir reporta |
80
- | ---------------------------------------------------------- | ------------------------------------------------------------------- |
81
- | Nenhuma declaração de teste encontrada | Pontuação `null`, exibida como **UNKNOWN**. Nunca um 100 inventado. |
82
- | Nenhuma baseline ou revisão comparável | **UNKNOWN**, com o motivo informado. Nunca um 0 presumido. |
83
- | Scan interrompido (orçamento de tempo, arquivos ilegíveis) | **PARTIAL**, saída `2`. Nunca apresentado como limpo. |
84
-
85
- <p align="center">
86
- <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" />
87
- </p>
88
-
89
- <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>
90
-
91
- <br />
92
-
93
- ## Veja funcionando
94
-
95
- 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:
96
-
97
- <p align="center">
98
- <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" />
99
- </p>
100
-
101
- <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>
102
-
103
- <details>
104
- <summary><strong>Assista</strong> — um scan, a correção que ele imprime e o novo scan que a prova</summary>
105
-
106
- <br />
107
-
108
- <p align="center">
109
- <a href="assets/video/mjolnir-demo.mp4">
110
- <img src="assets/video/mjolnir-demo-poster.png" alt="Um quadro da gravação de demonstração: npx mjolnir-qa@4.0.0 analisando o repositório de demonstração em uma janela de terminal" width="900" />
111
- </a>
112
- </p>
113
-
114
- <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>
115
-
116
- </details>
117
-
118
- ### Um achado, de perto
119
-
120
- 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.
121
-
122
- <p align="center">
123
- <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%" />
124
- </p>
125
-
126
- `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:
127
-
128
- ```text
129
- ▍ QA-CI-001 — continue-on-error masks a failing verification gate
130
-
131
- Severity: error
132
- Confidence: high
133
- Tier: quarantine
134
- Evidence: E2
135
- QA impact: False-green risk (FALSE-GREEN)
136
- Measured FP: 11% (19 hand-classified corpus verdicts)
137
- FP risk: low (author estimate)
138
- Languages: yaml
139
- Frameworks: github-actions, azure-pipelines
140
-
141
- WHAT WAS FOUND (real detector output, not a mockup)
142
- Job `security-scan` runs a verification gate under `continue-on-error: true`.
143
-
144
- WHY IT MATTERS
145
- This job can fail every day and CI will still show green. The checkmark on
146
- this workflow cannot be trusted.
147
-
148
- HOW TO FIX
149
- Remove continue-on-error, or scope it to individual non-blocking steps only.
150
-
151
- Example from this rule's own must-fire fixture: QA-CI-001/must-fire/masked.yml
152
-
153
- WHAT WOULD CHANGE THE VERDICT
154
- - a run report next to the scan target (mjolnir.report.json or test-results/)
155
- corroborating this file lifts its findings to L3–L5
156
- - a documented suppression (mjolnir.config.json) lowers the finding count
157
- without claiming correctness
158
- - quarantine findings run only under --strict and are advisory (E0) — they can
159
- never gate CI
160
-
161
- NEXT ACTION
162
- Fix the first occurrence, then re-run: `mjolnir --scope changed`. Every
163
- occurrence of this rule is listed in the scan output.
164
-
165
- HOW TO VERIFY THE FIX
166
- Re-run `mjolnir` on the changed file(s) — this finding should no longer
167
- appear. `mjolnir --scope changed` scopes the check to just what you touched.
168
-
169
- Docs: mjolnir rules --md (full catalog, this rule included)
170
- ```
171
-
172
- Essa é a unidade de valor: um lugar onde a CI reporta uma aprovação que não mereceu.
173
-
174
- <br />
175
-
176
- ## Início rápido
177
-
178
- ```bash
179
- npx mjolnir-qa@4.0.0
180
- ```
181
-
182
- 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.
183
-
184
- Na CI, analise só o que a branch introduziu, para que uma suíte legada não afogue seu primeiro pull request:
185
-
186
- ```bash
187
- npx mjolnir-qa@4.0.0 --scope changed
188
- ```
189
-
190
- `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 `v3` (ou `npx` puro com `--no-action`). Ele continua consultivo até você decidir que deve bloquear.
191
-
192
- | Comando | O que faz |
193
- | --------------------------------------------- | ------------------------------------------------------------- |
194
- | `mjolnir` | Trust Report: veredito, confiança, próxima ação |
195
- | `mjolnir --scope changed` | Só o que sua branch introduziu (a forma para CI) |
196
- | `mjolnir ci install` | Gera o workflow consultivo de PR (baseado na action) |
197
- | `mjolnir business-case` | ROI estimate: projected savings per finding |
198
- | `mjolnir release-report` | Release readiness: GO, CONDITIONAL GO, or NO-GO |
199
- | `mjolnir release-trust` | 12-dimension release assurance verdict |
200
- | `mjolnir report` | Generate a Playwright-compatible report |
201
- | `mjolnir trend` | Record, show, or diff local quality snapshots |
202
- | `mjolnir policy` | Initialize, validate, or check policy gates |
203
- | `mjolnir quarantine` | Review deterministic proposals (prototype) |
204
- | `mjolnir analyze --cross-file` | Bounded cross-file analysis |
205
- | `mjolnir ci-adapter github .` | Generate CI templates for supported providers |
206
- | `mjolnir dashboard` | Generate a self-contained quality dashboard |
207
- | `mjolnir exec-report` | Executive KPIs and recommendations (advisory) |
208
- | `mjolnir enterprise` | Self-hosted templates (prototype) |
209
- | `mjolnir maturity` | Assess maturity or display maturity levels |
210
- | `mjolnir mutation tests/mutation-report.json` | Analyze mutation reports; never promotes trust |
211
- | `mjolnir mcp` | Read-only MCP tools over stdio |
212
- | `mjolnir explain QA-CI-001` | O quê, por quê e correção, mais a taxa de FP medida |
213
- | `mjolnir why src/a.spec.ts:42` | Por que exatamente esta linha foi apontada. Nunca bloqueia. |
214
- | `mjolnir forensics ./test-results/` | Evidência de runtime de uma execução real |
215
- | `mjolnir trust-report` | Trust Artifact autocontido (md + json) |
216
- | `mjolnir handoff` | Plano de correção para um agente de código |
217
- | `mjolnir --json` / `--format sarif` | Saída legível por máquina, GitHub Code Scanning |
218
- | `mjolnir --format codequality` | Relatório do GitLab Code Quality (artefato do widget de MR) |
219
- | `mjolnir --strict` | Também roda as regras do nível quarantine (maior risco de FP) |
220
-
221
- <details>
222
- <summary><strong>Todos os outros comandos</strong> — triagem de testes instáveis, relatórios, governança</summary>
223
-
224
- <br />
225
-
226
- | Comando | O que faz |
227
- | ----------------------------------- | ----------------------------------------------------------------------------- |
228
- | `mjolnir --classic` | O banner de pontuação anterior ao Trust Report |
229
- | `mjolnir explain verdict` | Por que o veredito do scan salvo é o que é |
230
- | `mjolnir triage ./test-results/` | Triagem guiada. Cada linha termina em uma próxima ação. |
231
- | `mjolnir pw-report ./test-results/` | Resumo da execução do Playwright: retries, instáveis, os mais lentos |
232
- | `mjolnir doctor:playwright` | Scan profundo só de Playwright mais Selector Health Score |
233
- | `mjolnir fix --dry-run` / `fix` | Correções automáticas seguras, cada uma reanalisada para provar que funcionou |
234
- | `mjolnir baseline` / `diff` | Registra os achados e depois reporta só os novos ou piores |
235
- | `mjolnir impact --since <ref>` | O que um commit introduziu e resolveu |
236
- | `mjolnir summary` | Anotações de CI e um resumo do step a partir de um relatório |
237
- | `mjolnir pr-comment` | Um comentário de PR com escopo, em Markdown |
238
- | `mjolnir debt` | Registro de dívida de testes com um modelo de custo |
239
- | `mjolnir handover` | Mapa de integração da suíte para um novo engenheiro de QA |
240
- | `mjolnir init` | Detecta frameworks e imprime um checklist de configuração |
241
- | `mjolnir suppressions` | Lista os achados suprimidos, para governança |
242
- | `mjolnir rules --unmeasured` | As regras que rodam por suposição, não por medição |
243
- | `mjolnir rules --md` | Catálogo completo de regras (JSON ou Markdown) |
244
- | `mjolnir doctor` | Autoauditoria da base de regras do próprio Mjölnir |
245
- | `mjolnir create-rule <ID>` | Cria o esqueleto de uma nova regra e suas fixtures |
246
- | `mjolnir stats` | Contadores locais de todas as correções já vistas |
247
- | `mjolnir badge` | JSON de endpoint do shields.io e snippet |
248
- | `mjolnir --cache` | Novos scans incrementais via um cache local de vereditos |
249
- | `mjolnir --format mermaid` | Diagrama da arquitetura de testes para um comentário de PR |
250
-
251
- `mjolnir help <command>` imprime uso, exemplos e o próximo passo de qualquer um deles.
252
-
253
- </details>
254
-
255
- 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.
256
-
257
- <br />
258
-
259
- ## O que o Mjölnir encontra
260
-
261
- <p align="center">
262
- <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%" />
263
- </p>
264
-
265
- **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:
266
-
267
- | ID | Regra | Severidade | Nível |
268
- | ------------ | ------------------------------------------------------------------------- | ---------- | ---------- |
269
- | QA-CI-001 | `continue-on-error` mascara um gate de verificação que falha | error | quarantine |
270
- | QA-CI-009 | Código de saída dos testes não propagado (`\|` sem pipefail, cadeias `;`) | error | extended |
271
- | QA-TEST-001 | Teste focado commitado (`.only`, `fit`) | error | quarantine |
272
- | QA-TEST-003 | Teste sem asserções | error | quarantine |
273
- | QA-TQUAL-009 | Asserção de promise sem await | error | quarantine |
274
- | QA-PW-002 | Asserção de locator sem await | error | core |
275
- | QA-PW-004 | Seletores CSS/XPath frágeis | warning | quarantine |
276
- | QA-PY-002 | Teste pulado (`skip`, `xfail` não estrito) | warning | core |
277
- | QA-CS-103 | Método de teste sem asserções | error | core |
278
-
279
- 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).
280
-
281
- <details>
282
- <summary><strong>Todas as regras citadas neste README</strong>, em uma tabela</summary>
283
-
284
- <br />
285
-
286
- > Regras `quarantine` só rodam com `--strict` e nunca bloqueiam (ficam limitadas a info). A severidade mostrada é a definida pelo autor.
287
-
288
- | ID | Família | Regra | Severidade | Nível |
289
- | ------------ | ---------- | -------------------------------------------------------------- | ---------- | ---------- |
290
- | QA-TEST-001 | Higiene | Teste focado commitado (`.only`, `fit`) | error | quarantine |
291
- | QA-TEST-002 | Higiene | Teste pulado. Escala para `error` sem um motivo rastreado. | warning | quarantine |
292
- | QA-TEST-003 | Higiene | Teste sem asserções | error | quarantine |
293
- | QA-TEST-004 | Higiene | Sleep fixo (`waitForTimeout`, `sleep()`, `delay()`) | warning | extended |
294
- | QA-TEST-006 | Higiene | Abuso de retry escondendo instabilidade | warning | quarantine |
295
- | QA-TEST-010 | Higiene | Corpo de teste vazio | error | quarantine |
296
- | QA-TQUAL-002 | Qualidade | Asserção tautológica | error | quarantine |
297
- | QA-TQUAL-009 | Qualidade | Asserção de promise sem await | error | quarantine |
298
- | QA-TQUAL-011 | Qualidade | Testes comentados | warning | extended |
299
- | QA-PW-002 | Playwright | Asserção de locator sem await | error | core |
300
- | QA-PW-003 | Playwright | `page.pause()` / `test.only()` commitado | error | core |
301
- | QA-PW-004 | Playwright | Seletores CSS/XPath frágeis | warning | quarantine |
302
- | QA-PW-123 | Playwright | URLs de ambiente fixas no código | warning | quarantine |
303
- | QA-PW-140 | Playwright | Screenshot sem `maxDiffPixelRatio` | warning | core |
304
- | QA-CI-001 | CI | `continue-on-error` mascara um gate que falha | error | quarantine |
305
- | QA-CI-002 | CI | `\|\| true` engole códigos de saída | error | extended |
306
- | QA-CI-005 | CI | Relatório consumido, mas nunca gerado | error | quarantine |
307
- | QA-CI-007 | CI | Wrappers de retry em volta dos testes | warning | extended |
308
- | QA-CI-008 | CI | Step que sempre passa mascara falhas | error | quarantine |
309
- | QA-CI-009 | CI | Código de saída não propagado (`\|` sem pipefail, cadeias `;`) | error | extended |
310
- | QA-CI-010 | CI | Testes pulados onde deveriam bloquear | error | quarantine |
311
- | QA-PY-002 | Python | Teste pulado (`skip`, `xfail` não estrito) | warning | core |
312
- | QA-PY-003 | Python | Função de teste sem asserções | error | quarantine |
313
- | QA-PY-005 | Python | `time.sleep()` nos testes | warning | extended |
314
- | QA-PY-012 | Python | Asserção tautológica | error | quarantine |
315
- | QA-JV-101 | Java | Teste desativado (`@Disabled`) | warning | core |
316
- | QA-JV-102 | Java | Sleep fixo (`Thread.sleep()`) | warning | extended |
317
- | QA-JV-103 | Java | Método de teste sem asserções | error | extended |
318
- | QA-JV-105 | Java | Sleep fixo com `waitForTimeout()` do Playwright | warning | core |
319
- | QA-JV-106 | Java | Seletor frágil em vez de locator por papel | warning | quarantine |
320
- | QA-CS-101 | C# | Teste pulado (`[Ignore]`, `[Fact(Skip=)]`) | warning | core |
321
- | QA-CS-102 | C# | Sleep fixo (`Thread.Sleep` / `Task.Delay`) | warning | core |
322
- | QA-CS-103 | C# | Método de teste sem asserções | error | core |
323
- | QA-CS-105 | C# | Sleep fixo com `WaitForTimeoutAsync()` | warning | extended |
324
- | QA-CS-106 | C# | Seletor frágil em vez de locator por papel | warning | quarantine |
325
-
326
- 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.
327
-
328
- </details>
329
-
330
- 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.
331
-
332
- ### Selector Health Score
333
-
334
- `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:
335
-
336
- ```text
337
- ▍ SELECTOR HEALTH
338
-
339
- e2e/login.spec.ts
340
- [█████████████░░░░░░░] 65 / 100
341
- role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
342
-
343
- e2e/checkout.spec.ts
344
- [██████████████████░░] 88 / 100
345
- role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
346
- ```
347
-
348
- 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.
349
-
350
- <br />
351
-
352
- ## A pontuação de confiabilidade
353
-
354
- <p align="center">
355
- <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" />
356
- </p>
357
-
358
- <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>
359
-
360
- | Pontuação | Veredito |
361
- | --------- | --------------------------------------------------- |
362
- | `0 – 49` | **UNWORTHY** |
363
- | `50 – 79` | **NEEDS WORK** |
364
- | `80 – 99` | **WORTHY** |
365
- | `100` | **FORGED** |
366
- | `null` | **UNKNOWN**: nenhuma declaração de teste encontrada |
367
-
368
- **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).
369
-
370
- **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.**
371
-
372
- <br />
373
-
374
- ## O modelo de evidência
375
-
376
- 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.
377
-
378
- **Quão seguro — o nível de evidência.**
379
-
380
- | Nível | Nome | Significa | Dedução |
381
- | ------ | -------------------- | --------------------------------------------------- | -------- |
382
- | **E2** | Prova determinística | O defeito está presente no código como escrito | Integral |
383
- | **E1** | Evidência de padrão | Um padrão fortemente ligado ao defeito correspondeu | Metade |
384
- | **E0** | Observação | Vale saber. Não afirma que algo está errado. | Zero |
385
-
386
- 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.
387
-
388
- **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.
389
-
390
- <p align="center">
391
- <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%" />
392
- </p>
393
-
394
- | Nível | Em palavras simples | O que é preciso |
395
- | ------ | ------------------- | --------------------------------------------------------------------- |
396
- | **L0** | Anotado | Ler o código |
397
- | **L1** | Parece o problema | Ler o código: um padrão correspondeu |
398
- | **L2** | Provado no código | Ler o código: o defeito é estrutural |
399
- | **L3** | O arquivo rodou | Um relatório de execução mostra que o arquivo do achado foi executado |
400
- | **L4** | O teste rodou | Um relatório de execução mostra que o teste do achado foi executado |
401
- | **L5** | A execução concorda | O próprio resultado da execução confirma a classe do defeito |
402
-
403
- 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).
404
-
405
- ### Quanto disso é medido
406
-
407
- **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.
408
-
409
- 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.
410
-
411
- ### Níveis de confiança das regras
412
-
413
- Os níveis seguem a taxa de falsos positivos medida, não opinião:
414
-
415
- | Nível | FP medido | Comportamento |
416
- | -------------- | --------------------------------- | -------------------------------------------------- |
417
- | **core** | ≤ 10% | Relatório padrão, bloqueia |
418
- | **extended** | ≤ 30% | Relatório padrão, confiança menor |
419
- | **quarantine** | > 30% ou explicitamente declarado | Só com `--strict`, limitado a info, nunca bloqueia |
420
- | _não medida_ | n < 10 | Não pode ser promovida a core até ser medida |
421
-
422
- 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.
423
-
424
- Promoção, rebaixamento e maturidade por linguagem: [ciclo de vida das regras](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle).
425
-
426
- ### Por que isto não é um linter
427
-
428
- Linters dizem se o código segue regras. O Mjölnir diz se a sua verificação merece confiança.
429
-
430
- | | Linters (ESLint, SonarQube) | Ferramentas de cobertura | Revisão de código com IA | **Mjölnir** |
431
- | ------------------------------------------------------------------ | :-------------------------: | :----------------------: | :----------------------: | :--------------: |
432
- | Pontua o **sistema de verificação**, não o código do produto | Não | Não | Não | Sim |
433
- | Integridade dos workflows de CI (`continue-on-error`, `\|\| true`) | Não | Não | só o diff | Sim |
434
- | Avalia a resiliência dos locators do Playwright (Selector Health) | Não | Não | Não | Sim |
435
- | Lê dados de execução reais para vereditos `TRUE-FLAKE` | Não | Não | Não | Sim |
436
- | Publica uma taxa de falsos positivos medida por regra | Não | Não | Não | Sim |
437
- | Aponta testes sem asserções | Sim\* | Não | às vezes | Sim |
438
- | Detecta sleeps fixos (`waitForTimeout`, `time.sleep`) | Sim\* | Não | às vezes | Sim |
439
- | Determinístico (mesma entrada, mesma saída) | Sim | Sim | Não | Sim |
440
- | Custo por scan | grátis | grátis | tokens | **zero** (local) |
441
-
442
- <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>
443
-
444
- 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.
445
-
446
- <br />
447
-
448
- ## Forense de execução
449
-
450
- 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.
451
-
452
- ```bash
453
- mjolnir forensics ./test-results/
454
- ```
455
-
456
- ```text
457
- ▍ FLAKINESS LEADERBOARD
458
-
459
- 3 tests · 1 failed · 1 flaky · 1 retried
460
-
461
- TRUE-FLAKE completes checkout with saved card (e2e/checkout.spec.ts)
462
- ████████████████████ 6.0s · 2 attempts
463
- FAILING declines an expired card (e2e/checkout.spec.ts)
464
- ████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
465
- ```
466
-
467
- `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.
468
-
469
- <br />
470
-
471
- ## Integridade de CI
472
-
473
- 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.
474
-
475
- Gere o workflow de PR, consultivo por padrão:
476
-
477
- ```bash
478
- mjolnir ci install
479
- ```
480
-
481
- Ou adicione a action do Marketplace a um workflow que você já tem:
482
-
483
- ```yaml
484
- - uses: Sergey-Bar/Mjolnir@v3
485
- with:
486
- scope: changed
487
- fail-on: error
488
- ```
489
-
490
- Fixe `@v3` 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.
491
-
492
- Para levar os achados ao GitHub Code Scanning, envie o SARIF (requer `security-events: write` no escopo do workflow ou job):
493
-
494
- ```yaml
495
- - run: npx mjolnir-qa@4.0.0 --format sarif > mjolnir.sarif
496
- continue-on-error: true
497
- - uses: github/codeql-action/upload-sarif@v3
498
- if: ${{ !cancelled() }}
499
- with:
500
- sarif_file: mjolnir.sarif
501
- ```
502
-
503
- 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).
504
-
505
- ### Atribuição no escopo alterado
506
-
507
- ```bash
508
- npx mjolnir-qa@4.0.0 --scope changed
509
- ```
510
-
511
- 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>`.
512
-
513
- 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.
514
-
515
- <br />
516
-
517
- ## Agentes de IA
518
-
519
- Achados só valem alguma coisa se algo agir sobre eles.
520
-
521
- ```text
522
- SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
523
- ```
524
-
525
- **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.
526
-
527
- | Comando | O que o agente recebe |
528
- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
529
- | `mjolnir mcp` | Um servidor [MCP](https://modelcontextprotocol.io) via stdio. `scan`, `explain` e `diff` viram ferramentas chamáveis. |
530
- | `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. |
531
- | `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. |
532
-
533
- Adicione-o a um cliente que tenha sua própria CLI:
534
-
535
- ```bash
536
- claude mcp add mjolnir -- npx -y mjolnir-qa@4.0.0 mcp
537
- ```
538
-
539
- Ou a qualquer cliente que aceite um bloco `mcpServers`:
540
-
541
- ```json
542
- {
543
- "mcpServers": {
544
- "mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@4.0.0", "mcp"] }
545
- }
546
- }
547
- ```
548
-
549
- **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.
550
-
551
- <br />
552
-
553
- ## Confiança e segurança
554
-
555
- **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.
556
-
557
- Duas ressalvas: o próprio `npx` baixa o pacote antes de qualquer coisa rodar, e a garantia cobre `src/`, não plugins de terceiros.
558
-
559
- **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).
560
-
561
- **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.
562
-
563
- ### Códigos de saída e o contrato de máquina
564
-
565
- Congelados, para que você possa construir lógica de CI em cima deles:
566
-
567
- | Código de saída | Significado |
568
- | --------------- | ------------------------------------------------------------------------------- |
569
- | `0` | Limpo: nenhum achado no nível do gate ou acima |
570
- | `1` | Achados no nível do gate ou acima |
571
- | `2` | Scan parcial (orçamento de tempo esgotado, arquivos ilegíveis). Nunca bloqueia. |
572
- | `10` | Erro de uso (flag inválida, alvo ausente) |
573
- | `20` | Erro interno |
574
-
575
- `2` é deliberadamente diferente de `0`: um scan que não terminou não encontrou "nada". Ele só não terminou de procurar.
576
-
577
- 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.
578
-
579
- <br />
580
-
581
- ## O que o Mjölnir não pode dizer
582
-
583
- - **Ele não roda seus testes.** Um scan limpo não é uma suíte aprovada.
584
- - **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.
585
- - **Ele não prova a correção de negócio.** Nada aqui diz que o seu produto faz o que o requisito pediu.
586
- - **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.
587
- - **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.
588
- - **E1 não é E2.** Achados heurísticos merecem ser lidos, não aplicados às cegas.
589
- - **Um repo vazio recebe `null`, nunca 100.**
590
- - **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.
591
-
592
- <br />
593
-
594
- ## Documentação
595
-
596
- O site completo de documentação está em <https://sergey-bar.github.io/Mjolnir/>.
597
-
598
- | Documento | O que tem nele |
599
- | ------------------------------------------------------ | ------------------------------------------------------------------- |
600
- | [docs/SCORING.md](docs/SCORING.md) | Normalização da pontuação e ponderação da evidência |
601
- | [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md) | Vocabulário canônico: uma palavra por conceito |
602
- | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Taxas de falsos positivos medidas e o método |
603
- | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Estados das regras, níveis, supressão, descontinuação |
604
- | [docs/VERSIONING.md](docs/VERSIONING.md) | Política de semver, superfícies congeladas, ciclo de descontinuação |
605
- | [docs/machine-contract.md](docs/machine-contract.md) | O resultado canônico legível por máquina |
606
- | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | Saída SARIF e configuração do editor ou da CI |
607
- | [docs/GITLAB-CI.md](docs/GITLAB-CI.md) | GitLab: relatório do Code Quality, receita de MR, gate |
608
- | [docs/rules/](docs/rules/) | Catálogo gerado por regra |
609
- | [CONTRIBUTING.md](CONTRIBUTING.md) | Ambiente de desenvolvimento e fluxo de contribuição |
610
- | [SUPPORT.md](SUPPORT.md) | Onde perguntar, reportar e obter ajuda |
611
- | [SECURITY.md](SECURITY.md) | Relato de vulnerabilidades |
612
- | [CHANGELOG.md](CHANGELOG.md) | Histórico de versões |
613
-
614
- ### Status
615
-
616
- **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).
617
-
618
- ### Contribuindo
619
-
620
- 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:
621
-
622
- ```bash
623
- mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
624
- ```
625
-
626
- 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).
627
-
628
- <br />
629
-
630
- <div align="center">
631
-
632
- <img src="assets/readme/closing.svg" alt="Rode no seu repo." width="100%" />
633
-
634
- ```bash
635
- npx mjolnir-qa@4.0.0
636
- ```
637
-
638
- [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)
639
-
640
- <br />
641
-
642
- Não pergunte se os testes passaram.<br />
643
- Pergunte se a evidência prova que eles merecem confiança.
644
-
645
- <sub>Criado por [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · Licença MIT</sub>
646
-
647
- </div>