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.no.md CHANGED
@@ -1,396 +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. Tester forteller deg hva som besto. Mjölnir forteller deg hva du kan stole på." width="100%" />
4
4
 
5
- ### Testene dine lyver til deg. Vi beviser det.
5
+ <br />
6
6
 
7
- **Verification Trust Engine for QA.** Mjölnir auditor testsuiter og
8
- CI-pipelines, rapporterer en verdighetsscore og viser nøyaktig hvor
9
- tilliten bryter sammen.
7
+ Mjölnir finner tester som ikke kan feile og pipelines som ikke kan bli røde,<br />
8
+ og vurderer deretter hvor langt resultatet er til å stole på, med beviset for hvert poeng.
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 | [Português (Brasil)](README.br.md) | [ไทย](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
- **Er testene dine verd tillit?**
24
+ [Se det i aksjon](#se-det-i-aksjon) · [Kom raskt i gang](#kom-raskt-i-gang) · [Hva det finner](#hva-mjölnir-finner) · [Score](#worthiness-scoren) · [Evidens](#evidensmodellen) · [Kjøringsanalyse](#kjøringsanalyse) · [CI](#ci-integritet) · [Agenter](#ai-agenter) · [Sikkerhet](#tillit-og-sikkerhet) · [Begrensninger](#hva-mjölnir-ikke-kan-fortelle-deg) · [Dokumentasjon](#dokumentasjon)
25
+
26
+ <details>
27
+ <summary>Les på et annet språk — 22 oversettelser</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 | [Português (Brasil)](README.br.md) | [ไทย](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)
25
30
 
26
- [Se det virke](#-se-det-virke) ·
27
- [Rask start](#-rask-start) ·
28
- [Hva den sjekker](#-hva-mjölnir-sjekker) ·
29
- [Scoring](#slik-fungerer-scoren) ·
30
- [CI](#-ci-integrasjon) · [Konfigurasjon](#konfigurasjon) ·
31
- [Dokumentasjon](#-dokumentasjon)
31
+ > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-15.
32
+
33
+ <!-- Source hash: 3541b09e8d04 -->
34
+
35
+ </details>
32
36
 
33
37
  </div>
34
38
 
35
- ---
39
+ <br />
40
+
41
+ ## En grønn hake er en påstand, ikke et bevis
42
+
43
+ En grønn hake betyr at pipelinen ikke feilet. Den betyr ikke at testene kjørte, eller at de kunne ha feilet. Hver eneste av disse går grønt gjennom:
44
+
45
+ - en committet `.only` som kjørte 3 tester i stedet for 900
46
+ - `continue-on-error: true` på jobben som skulle ha blokkert
47
+ - `|| true` etter testkommandoen
48
+ - en test som ikke sjekker noe, eller som har en tom kropp
49
+ - en retry-wrapper som gjør en reell feil om til en heldig bestått
50
+ - en rapport som workflowen laster opp, men aldri har generert
51
+ - en fast sleep som holder sammen en race condition
52
+
53
+ Ingen av dem gjør pipelinen rød, og hver av dem ser tilsiktet ut i review. Derfor overlever de. Her leser Mjölnir et ekte eksempel:
36
54
 
37
- ## 🎬 Se det virke
55
+ <p align="center">
56
+ <img src="assets/readme/scan.svg" alt="Demo-repositoriets CI-workflow, lest linje for linje. Mjölnir markerer hvert funn på linjen det ble rapportert, med regelen, hva som er galt, evidensnivået og den målte falsk-positiv-raten." width="800" />
57
+ </p>
58
+
59
+ <sub>Hvert funn demoskanningen rapporterte for denne workflowen, på linjen det ble rapportert. Generert av `npm run docs:readme-brand` fra [`demo-report.json`](assets/readme/demo-report.json) og låst mot avvik i CI.</sub>
60
+
61
+ **Streng modus.** De mest aggressive deteksjonene — `.only`, `continue-on-error`, tomme tester, misbruk av omkjøringer — lever i karantenenivået. De kjører bare under `--strict` og er begrenset til `info`-alvorlighetsgrad: de flagger, de blokkerer aldri. Standardskanningen (`npx mjolnir-qa@latest` uten `--strict`) dekker bare kjerne- og utvidede regler. Legg til `--strict` når du også vil ha rådgivningslaget.
62
+
63
+ Mjölnir leser testsuiten, CI-workflowene og, hvis du har en, rapporten fra en ekte kjøring. Det kjører ikke testene dine, installerer ikke avhengighetene dine og kjører ikke koden det skanner. Og når det mangler evidens, sier det det i stedet for å finne på tillit:
64
+
65
+ | Situasjon | Hva Mjölnir rapporterer |
66
+ | ------------------------------------------------ | ----------------------------------------------------------- |
67
+ | Ingen testdeklarasjoner funnet | Score `null`, vist som **UNKNOWN**. Aldri en oppdiktet 100. |
68
+ | Ingen baseline eller sammenlignbar revisjon | **UNKNOWN**, med årsaken oppgitt. Aldri en antatt 0. |
69
+ | Skanning avbrutt (tidsbudsjett, uleselige filer) | **PARTIAL**, exit `2`. Aldri presentert som ren. |
38
70
 
39
71
  <p align="center">
40
- <img src="assets/readme/demo.svg" alt="Mjölnirs komplette --verbose-rapport over et demo-repo: WORTHINESS 75/100 NEEDS WORK, en oppdeling av diagnostikk etter kategori, en FIX THIS FIRST-liste og hvert funn med regel-ID og linjenummer på tvers av CI-, Playwright-, testhygiene- og Python-regler" width="900" />
72
+ <img src="assets/readme/how-it-works.svg" alt="Slik fungerer Mjölnir. Det leser testsuiten og CI-pipelinen statisk, og rapporten fra en ekte kjøring når det finnes en. Det vekter hvert funn etter evidensnivå og tillitsnivå, der bare en ekte kjøring kan nå L3 til L5, og gir funn, en worthiness-score og en CI-gate med fryste exitkoder. I agentløkken skriver AI rettelsen, og Mjölnir skanner på nytt for å bevise den." width="880" />
41
73
  </p>
42
74
 
43
- <sub>Det komplette `npx mjolnir-qa ./examples/demo-repo --verbose`-resultatet,
44
- renderet av den ekte reporteren — ingenting klippet vekk. Regenereres
45
- med `npm run docs:demo`;
46
- [`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
47
- får CI til å feile hvis artefakten avviker fra det verktøyet skriver
48
- ut.</sub>
75
+ <sub>Komponert for denne siden og vist i 1:1. Generert av `npm run docs:readme-brand` og låst mot avvik i CI; score, antall og regel-ID kommer fra [`script.demo.json`](assets/video/script.demo.json), [`demo-report.json`](assets/readme/demo-report.json) og regelregisteret, aldri skrevet inn for hånd. Samme bilde som plakat: [`architecture.svg`](assets/readme/architecture.svg).</sub>
76
+
77
+ <br />
78
+
79
+ ## Se det i aksjon
80
+
81
+ En ekte skanning av [`examples/demo-repo`](examples/demo-repo), en liten Playwright-suite med en CI-workflow. Her er hvor poengene ble av:
82
+
83
+ <p align="center">
84
+ <img src="assets/readme/terminal-hero.svg" alt="Mjölnirs oversikt over trekk: WORTHINESS 80/100 WORTHY, scoren per kategori, trekkboksen per alvorlighetsgrad og en FIX THIS FIRST-liste" width="520" />
85
+ </p>
86
+
87
+ <sub>Generert av `npm run docs:hero` fra en ekte skanning og låst mot avvik i CI. Den fullstendige `--verbose`-rapporten fra samme skanning er [`demo.svg`](assets/readme/demo.svg) (`npm run docs:demo`).</sub>
88
+
89
+ <details>
90
+ <summary><strong>Se det</strong> — en skanning, rettelsen den skriver ut, og den nye skanningen som beviser den</summary>
91
+
92
+ <br />
93
+
94
+ <p align="center">
95
+ <a href="assets/video/mjolnir-demo.mp4">
96
+ <img src="assets/video/mjolnir-demo-poster.png" alt="Et bilde fra demoopptaket: npx mjolnir-qa@latest skanner demo-repositoriet i et terminalvindu" width="900" />
97
+ </a>
98
+ </p>
49
99
 
50
- **Hva som nettopp skjedde:**
100
+ <sub>Rendret bilde for bilde fra en ekte skanning av `npm run docs:video`; aldri tatt opp fra skjermen. Velg bildet for å åpne [`mjolnir-demo.mp4`](assets/video/mjolnir-demo.mp4).</sub>
51
101
 
52
- 1. Mjölnir oppdaget Playwright-specs, konfigurasjonen, CI-workflowen og
53
- en Python-testfil — fire språk/formater, ett gjennomløp.
54
- 2. Den fant beviser som svekker tilliten til suiten — en
55
- `continue-on-error` som maskerer en jobb, en `|| true` som svelger en
56
- exit-kode, harde sleeps, en skjør selector, hardkodede staging-URLer,
57
- en `networkidle`-ventetid.
58
- 3. Den gjorde hvert av dem til et konkret funn med regel-ID, plassering
59
- og fiks — og til én score du kan gate en PR på.
102
+ </details>
60
103
 
61
104
  ### Ett funn på nært hold
62
105
 
63
- Kjør `mjolnir explain QA-CI-001` på det første funnet over, og du får:
106
+ Hvert funn svarer på fire spørsmål: hvor det er, hvor sikker Mjölnir er, hvor ofte regelen tar feil, og hvordan det rettes.
107
+
108
+ <p align="center">
109
+ <img src="assets/readme/finding-anatomy.svg" alt="Det første funnet fra demoskanningen, nøyaktig slik terminalen skriver det ut, med de fire delene markert: hvor, hvor sikkert, hvor ofte regelen tar feil, og rettelsen." width="100%" />
110
+ </p>
111
+
112
+ `mjolnir explain QA-CI-001` skriver ut en regels fullstendige tillitsprofil, inkludert den målte falsk-positiv-raten og nivået den raten har gitt den:
64
113
 
65
114
  ```text
66
- ▚ QA-CI-001 — continue-on-error masks a failing verification gate
115
+ ▍ QA-CI-001 — continue-on-error masks a failing verification gate
67
116
 
68
117
  Severity: error
69
118
  Confidence: high
119
+ Tier: quarantine
70
120
  Evidence: E2
71
- 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
72
126
 
73
127
  WHAT WAS FOUND (real detector output, not a mockup)
74
128
  Job `security-scan` runs a verification gate under `continue-on-error: true`.
75
129
 
76
130
  WHY IT MATTERS
77
- This job can fail every day and CI will still show green. The checkmark
78
- 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.
79
133
 
80
134
  HOW TO FIX
81
135
  Remove continue-on-error, or scope it to individual non-blocking steps only.
82
- ```
83
136
 
84
- Det er verdiens enhet: ikke en stilprikke, men et sted der CI-en din
85
- forteller deg at noe besto, selv om det ikke gjorde det.
137
+ Example from this rule's own must-fire fixture: QA-CI-001/must-fire/masked.yml
86
138
 
87
- ---
139
+ WHAT WOULD CHANGE THE VERDICT
140
+ - a run report next to the scan target (mjolnir.report.json or test-results/)
141
+ corroborating this file lifts its findings to L3–L5
142
+ - a documented suppression (mjolnir.config.json) lowers the finding count
143
+ without claiming correctness
144
+ - quarantine findings run only under --strict and are advisory (E0) — they can
145
+ never gate CI
88
146
 
89
- ## ⚡ Rask start
147
+ NEXT ACTION
148
+ Fix the first occurrence, then re-run: `mjolnir --scope changed`. Every
149
+ occurrence of this rule is listed in the scan output.
90
150
 
91
- Kjør den mot et repo for en full rapport og en verdighetsscore:
151
+ HOW TO VERIFY THE FIX
152
+ Re-run `mjolnir` on the changed file(s) — this finding should no longer
153
+ appear. `mjolnir --scope changed` scopes the check to just what you touched.
92
154
 
93
- ```bash
94
- npx mjolnir-qa@latest
155
+ Docs: mjolnir rules --md (full catalog, this rule included)
95
156
  ```
96
157
 
97
- **I CI er produktet én kommando.** Den skanner bare det branchen rørte
98
- og avslutter med ikke-null ved nye problemer:
158
+ Det er verdienheten: ett sted der CI rapporterer en bestått den ikke har gjort seg fortjent til.
159
+
160
+ <br />
161
+
162
+ ## Kom raskt i gang
99
163
 
100
164
  ```bash
101
- npx mjolnir-qa@latest --scope changed
165
+ npx mjolnir-qa@latest
102
166
  ```
103
167
 
104
- Legg det inn som en PR-sjekk — `mjolnir ci install` skriver workflowen —
105
- og du er ferdig. Alt annet er valgfritt.
106
-
107
- | Kommando | Hva den gjør |
108
- | ----------------------------------- | --------------------------------------------------- |
109
- | `mjolnir` | Skann av hele repoet + verdighetsscore |
110
- | `mjolnir --scope changed` | Bare det branchen din innførte — CI-formen |
111
- | `mjolnir ci install` | Genererer den rådgivende PR-workflowen |
112
- | `mjolnir explain QA-CI-001` | Hva / hvorfor / fiks + målt FP-rate for én regel |
113
- | `mjolnir rules --unmeasured` | Reglene som kjører på antagelse, ikke måling |
114
- | `mjolnir --json` / `--format sarif` | Maskinlesbart / GitHub Code Scanning |
115
- | `mjolnir --strict` | Kjør også quarantine-tier-regler (høyere FP-risiko) |
168
+ Det skanner gjeldende mappe og skriver ut Trust Report: hva det fant, hvor langt du kan stole på det, hvorfor, og hva du bør gjøre videre. Det avslutter med `0` når ingenting på eller over gaten ble funnet.
116
169
 
117
- <details>
118
- <summary><strong>Når noe er flaky</strong></summary>
170
+ I CI bør du bare skanne det grenen har introdusert, så en eldre testsuite ikke drukner din første pull request:
119
171
 
120
- | Kommando | Hva den gjør |
121
- | ----------------------------------- | ------------------------------------------------------- |
122
- | `mjolnir forensics ./test-results/` | Ekte kjøringsdata → `TRUE-FLAKE`-dommer, `FLAKY.md` |
123
- | `mjolnir triage ./test-results/` | Karanteneforslag fra utførelseshistorikken |
124
- | `mjolnir pw-report ./test-results/` | Playwright-runoversikt — retries / flakes / de tregeste |
125
- | `mjolnir doctor:playwright` | Dypskann kun Playwright + Selector Health Score |
172
+ ```bash
173
+ npx mjolnir-qa@latest --scope changed
174
+ ```
126
175
 
127
- </details>
176
+ `mjolnir ci install` skriver det som en GitHub Actions-workflow med [action-en](https://github.com/Sergey-Bar/Mjolnir#readme) festet til major-taggen `v1` (eller vanlig `npx` med `--no-action`). Den forblir rådgivende til du bestemmer at den skal blokkere.
177
+
178
+ | Kommando | Hva den gjør |
179
+ | ----------------------------------- | ---------------------------------------------------------- |
180
+ | `mjolnir` | Trust Report: dom, sikkerhet, neste handling |
181
+ | `mjolnir --scope changed` | Bare det grenen din har introdusert (CI-formen) |
182
+ | `mjolnir ci install` | Generer den rådgivende PR-workflowen (action-basert) |
183
+ | `mjolnir explain QA-CI-001` | Hva, hvorfor og rettelse, pluss den målte FP-raten |
184
+ | `mjolnir why src/a.spec.ts:42` | Hvorfor akkurat denne linjen ble markert. Blokkerer aldri. |
185
+ | `mjolnir forensics ./test-results/` | Kjøringsevidens fra en ekte kjøring |
186
+ | `mjolnir trust-report` | Selvstendig Trust-artefakt (md + json) |
187
+ | `mjolnir handoff` | Utbedringsplan for en kodeagent |
188
+ | `mjolnir --json` / `--format sarif` | Maskinlesbar utdata, GitHub Code Scanning |
189
+ | `mjolnir --format codequality` | GitLab Code Quality-rapport (MR-widget-artefakt) |
190
+ | `mjolnir --strict` | Kjør også regler på quarantine-nivå (høyere FP-risiko) |
128
191
 
129
192
  <details>
130
- <summary><strong>Av og til / rapporter</strong></summary>
131
-
132
- | Kommando | Hva den gjør |
133
- | ------------------------------- | -------------------------------------------------------- |
134
- | `mjolnir fix --dry-run` / `fix` | Trygge autofikser med bevis |
135
- | `mjolnir baseline` / `diff` | Øyeblikksbilde av funn, rapporter så bare nye/forverrede |
136
- | `mjolnir impact --since <ref>` | Hva som endret seg siden et tidligere commit |
137
- | `mjolnir debt` | Testgjeldsregister med en kostnadsmodell |
138
- | `mjolnir handover` | Onboarding-kart over suiten for ny QA |
139
- | `mjolnir stats` | Lokale all-time-tellere av sette fikser |
140
- | `mjolnir badge` | shields.io-endepunkt-JSON + snippet |
141
- | `mjolnir rules --md` | Fullstendig regelkatalog (JSON eller Markdown) |
142
- | `mjolnir doctor` | Selvaudit av Mjölnirs egen regelbase |
143
- | `mjolnir create-rule <ID>` | Scaffold en ny regel + fixtures |
144
- | `mjolnir --format mermaid` | Testarkitekturdiagram til en PR-kommentar |
193
+ <summary><strong>Alle andre kommandoer</strong> — triage av ustabile tester, rapportering, styring</summary>
194
+
195
+ <br />
196
+
197
+ | Kommando | Hva den gjør |
198
+ | ----------------------------------- | ------------------------------------------------------------------------- |
199
+ | `mjolnir --classic` | Scorebanneret fra før Trust Report |
200
+ | `mjolnir explain verdict` | Hvorfor dommen for den lagrede skanningen er som den er |
201
+ | `mjolnir triage ./test-results/` | Veiledet triage. Hver rad slutter med en neste handling. |
202
+ | `mjolnir pw-report ./test-results/` | Oppsummering av Playwright-kjøring: retries, ustabile tester, de tregeste |
203
+ | `mjolnir doctor:playwright` | Dypskanning bare for Playwright pluss Selector Health Score |
204
+ | `mjolnir fix --dry-run` / `fix` | Trygge autorettelser, hver skannet på nytt for å bevise at den virket |
205
+ | `mjolnir baseline` / `diff` | Ta et øyeblikksbilde av funn, og rapporter deretter bare nye eller verre |
206
+ | `mjolnir impact --since <ref>` | Hva en commit introduserte og løste |
207
+ | `mjolnir summary` | CI-annotasjoner og en step-oppsummering fra en rapport |
208
+ | `mjolnir pr-comment` | En avgrenset PR-kommentar, som Markdown |
209
+ | `mjolnir debt` | Register over testgjeld med en kostnadsmodell |
210
+ | `mjolnir handover` | Introduksjonskart over suiten for en ny QA-ingeniør |
211
+ | `mjolnir init` | Oppdag rammeverk, skriv ut en sjekkliste for oppsett |
212
+ | `mjolnir suppressions` | List undertrykte funn, for styring |
213
+ | `mjolnir rules --unmeasured` | Reglene som kjører på antakelser, ikke målinger |
214
+ | `mjolnir rules --md` | Fullstendig regelkatalog (JSON eller Markdown) |
215
+ | `mjolnir doctor` | Selvrevisjon av Mjölnirs egen regelbase |
216
+ | `mjolnir create-rule <ID>` | Lag skjelettet til en ny regel og dens fixtures |
217
+ | `mjolnir stats` | Lokale tellere over alle rettelser som noen gang er sett |
218
+ | `mjolnir badge` | shields.io-endepunkt-JSON og snutt |
219
+ | `mjolnir --cache` | Inkrementelle nye skanninger via en lokal hurtigbuffer for dommer |
220
+ | `mjolnir --format mermaid` | Diagram over testarkitekturen for en PR-kommentar |
221
+
222
+ `mjolnir help <command>` skriver ut bruk, eksempler og neste steg for hver av dem.
145
223
 
146
224
  </details>
147
225
 
148
- Installer globalt i stedet for `npx` hvis du foretrekker det:
149
- `npm i -g mjolnir-qa`. Krever Node.js ≥ 22.18. Fungerer på Windows,
150
- macOS og Linux.
151
-
152
- ---
226
+ Krever **Node.js ≥ 22.18** på Windows, macOS eller Linux. Foretrekker du en global installasjon? `npm i -g mjolnir-qa`. Minstekravet kommer fra byggeverktøykjeden (tsdown sikter mot det, og release-pipelinen røyktester mot det); kjøretidsavhengighetene trenger ikke mer enn det.
153
227
 
154
- ## 👥 Hvem er det for?
228
+ <br />
155
229
 
156
- - **QA / SDET** som eier en e2e- eller integrasjonssuite og trenger
157
- bevis for at suiten faktisk fortjener den grønne haken den
158
- produserer.
159
- - **Plattform-/DevEx-team** som har ansvar for CI-integritet og
160
- release gates — folket som bryr seg om at en `continue-on-error`
161
- aldri stille maler en rød pipeline grønn.
162
- - **OSS-maintainere** som vil ha en billig, alltid på verifikasjonsgate
163
- som kjører lokalt og i CI uten nettverkskall.
230
+ ## Hva Mjölnir finner
164
231
 
165
- ---
166
-
167
- ## 🔨 Hva Mjölnir sjekker
232
+ <p align="center">
233
+ <img src="assets/readme/stack.svg" alt="Fungerer med stacken din: språkene, testrammeverkene og CI-systemene reglene dekker, fra regelregisteret." width="100%" />
234
+ </p>
168
235
 
169
- | | |
170
- | --- | ---------------------------------------------------------------------------------------------------------------------------- |
171
- | ⚖️ | **Verdighetsscore** — ett tall, transparent fradragstabell, ingen black box |
172
- | 🎭 | **Selector Health Score** — vurderer Playwright-locatorene dine, ikke bare pass rate |
173
- | 🔬 | **Runtime-forundersøkelse** — leser ekte Playwright/JUnit-kjøringsdata og fanger `TRUE-FLAKE`, ikke bare statiske gjetninger |
174
- | 🚨 | **CI-integritetsregler** — fanger `continue-on-error`, `\|\| true` og andre falskgrønne triks |
175
- | 🐍 | **Alle fire Playwright-bindings** — TypeScript, Python, Java, C#/.NET — pluss pytest, JUnit/TestNG og CI-workflows |
176
- | 🔒 | **Local-first** — null nettverkskall under skanning, null telemetri, kjører på sekunder |
236
+ **79 regler** i fire familier — testhygiene, testkvalitet, Playwright og CI-integritet — på tvers av TypeScript og JavaScript, Python, Java, C# og GitHub Actions-YAML. De dekker Playwright i alle fire bindings, pluss pytest, JUnit, TestNG, NUnit, xUnit, MSTest, Jest, Vitest og Mocha, med startdekning for Cypress og Selenium. Ni av dem, for å vise formen:
177
237
 
178
- ### Reglene
238
+ | ID | Regel | Alvorlighetsgrad | Nivå |
239
+ | ------------ | ---------------------------------------------------------------------- | ---------------- | ---------- |
240
+ | QA-CI-001 | `continue-on-error` skjuler en feilende verifiseringsgate | error | quarantine |
241
+ | QA-CI-009 | Testens exitkode videreformidles ikke (`\|` uten pipefail, `;`-kjeder) | error | extended |
242
+ | QA-TEST-001 | Fokusert test committet (`.only`, `fit`) | error | quarantine |
243
+ | QA-TEST-003 | Test uten assertions | error | quarantine |
244
+ | QA-TQUAL-009 | Promise-assertion uten await | error | quarantine |
245
+ | QA-PW-002 | Locator-assertion uten await | error | core |
246
+ | QA-PW-004 | Skjøre CSS/XPath-selektorer | warning | quarantine |
247
+ | QA-PY-002 | Hoppet over test (`skip`, ikke-streng `xfail`) | warning | core |
248
+ | QA-CS-103 | Testmetode uten assertions | error | core |
179
249
 
180
- Hver regel leveres med både must-fire- **og** must-not-fire-fixtures.
181
- En regel som utløses på sin egen negative fixture, kan ikke skipes —
182
- det er false-positive-brannmuren.
250
+ Den fullstendige katalogen genereres fra registeret, aldri vedlikeholdt for hånd: `mjolnir rules --md`, [`docs/rules/`](docs/rules/) eller [veiledningen om hva det sjekker](https://sergey-bar.github.io/Mjolnir/guide/what-it-checks).
183
251
 
184
252
  <details>
185
- <summary><strong>Testhygiene</strong></summary>
186
-
187
- | ID | Regel | Severity |
188
- | ----------- | ---------------------------------------------------- | -------- |
189
- | QA-TEST-001 | Commitet fokusert test (`.only`, `fit`) | error |
190
- | QA-TEST-002 | Hoppet over test uten begrunnelse | error |
191
- | QA-TEST-002 | Hoppet over test med registrert begrunnelse | warning |
192
- | QA-TEST-003 | Test uten assertions | error |
193
- | QA-TEST-004 | Hardt sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning |
194
- | QA-TEST-006 | Retry-misbruk som skjuler flakiness | warning |
195
- | QA-TEST-010 | Tomt testkropp | error |
253
+ <summary><strong>Alle regler nevnt i denne README-en</strong>, i én tabell</summary>
254
+
255
+ <br />
256
+
257
+ > `quarantine`-regler kjører bare under `--strict` og blokkerer aldri (de er begrenset til info). Alvorlighetsgraden som vises, er forfatterens.
258
+
259
+ | ID | Familie | Regel | Alvorlighetsgrad | Nivå |
260
+ | ------------ | ---------- | ------------------------------------------------------------------- | ---------------- | ---------- |
261
+ | QA-TEST-001 | Hygiene | Fokusert test committet (`.only`, `fit`) | error | quarantine |
262
+ | QA-TEST-002 | Hygiene | Hoppet over test. Eskalerer til `error` uten en sporet begrunnelse. | warning | quarantine |
263
+ | QA-TEST-003 | Hygiene | Test uten assertions | error | quarantine |
264
+ | QA-TEST-004 | Hygiene | Fast sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning | extended |
265
+ | QA-TEST-006 | Hygiene | Misbruk av retries som skjuler ustabilitet | warning | quarantine |
266
+ | QA-TEST-010 | Hygiene | Tom testkropp | error | quarantine |
267
+ | QA-TQUAL-002 | Kvalitet | Tautologisk assertion | error | quarantine |
268
+ | QA-TQUAL-009 | Kvalitet | Promise-assertion uten await | error | quarantine |
269
+ | QA-TQUAL-011 | Kvalitet | Utkommenterte tester | warning | extended |
270
+ | QA-PW-002 | Playwright | Locator-assertion uten await | error | core |
271
+ | QA-PW-003 | Playwright | `page.pause()` / `test.only()` committet | error | core |
272
+ | QA-PW-004 | Playwright | Skjøre CSS/XPath-selektorer | warning | quarantine |
273
+ | QA-PW-123 | Playwright | Hardkodede miljø-URL-er | warning | quarantine |
274
+ | QA-PW-140 | Playwright | Skjermbilde uten `maxDiffPixelRatio` | warning | core |
275
+ | QA-CI-001 | CI | `continue-on-error` skjuler en feilende gate | error | quarantine |
276
+ | QA-CI-002 | CI | `\|\| true` svelger exitkoder | error | extended |
277
+ | QA-CI-005 | CI | Rapport brukt, men aldri generert | error | quarantine |
278
+ | QA-CI-007 | CI | Retry-wrappere rundt tester | warning | extended |
279
+ | QA-CI-008 | CI | Step som alltid lykkes, skjuler feil | error | quarantine |
280
+ | QA-CI-009 | CI | Exitkode videreformidles ikke (`\|` uten pipefail, `;`-kjeder) | error | extended |
281
+ | QA-CI-010 | CI | Tester hoppet over der de må blokkere | error | quarantine |
282
+ | QA-PY-002 | Python | Hoppet over test (`skip`, ikke-streng `xfail`) | warning | core |
283
+ | QA-PY-003 | Python | Testfunksjon uten assertions | error | quarantine |
284
+ | QA-PY-005 | Python | `time.sleep()` i tester | warning | extended |
285
+ | QA-PY-012 | Python | Tautologisk assertion | error | quarantine |
286
+ | QA-JV-101 | Java | Deaktivert test (`@Disabled`) | warning | core |
287
+ | QA-JV-102 | Java | Fast sleep (`Thread.sleep()`) | warning | extended |
288
+ | QA-JV-103 | Java | Testmetode uten assertions | error | extended |
289
+ | QA-JV-105 | Java | Fast sleep med Playwright `waitForTimeout()` | warning | core |
290
+ | QA-JV-106 | Java | Skjør selektor i stedet for rollebasert locator | warning | quarantine |
291
+ | QA-CS-101 | C# | Hoppet over test (`[Ignore]`, `[Fact(Skip=)]`) | warning | core |
292
+ | QA-CS-102 | C# | Fast sleep (`Thread.Sleep` / `Task.Delay`) | warning | core |
293
+ | QA-CS-103 | C# | Testmetode uten assertions | error | core |
294
+ | QA-CS-105 | C# | Fast sleep med `WaitForTimeoutAsync()` | warning | extended |
295
+ | QA-CS-106 | C# | Skjør selektor i stedet for rollebasert locator | warning | quarantine |
296
+
297
+ Python har i tillegg QA-PY-001…012 (pytest-hygiene) og QA-PY-101…108 (Playwright for Python). Cypress og Selenium har startsett på tre regler hver.
196
298
 
197
299
  </details>
198
300
 
199
- <details>
200
- <summary><strong>Testkvalitet</strong></summary>
301
+ Hver regel leveres med en must-fire- **og** en must-not-fire-fixture, og en regel som slår ut på sin egen negative fixture, kan ikke leveres. Det er brannmuren mot falske positiver; `mjolnir doctor` håndhever den i dette repositoriets egen CI.
201
302
 
202
- | ID | Regel | Severity |
203
- | ------------ | ------------------------------- | -------- |
204
- | QA-TQUAL-002 | Tautologisk assertion | error |
205
- | QA-TQUAL-009 | Assertion på promise uten await | error |
206
- | QA-TQUAL-011 | Utkommenterte tester | warning |
303
+ ### Selector Health Score
207
304
 
208
- </details>
305
+ `mjolnir doctor:playwright` vurderer hver locator etter hvordan den finner et element: slik en bruker ville gjort (rolle, etikett, tekst), via en eksplisitt kontrakt (`data-testid`), eller ved et strukturelt tilfelle (CSS-kjeder, XPath). Hver fil får en score fra 0 til 100:
209
306
 
210
- <details>
211
- <summary><strong>Playwright 🎭</strong></summary>
307
+ ```text
308
+ ▍ SELECTOR HEALTH
212
309
 
213
- | ID | Regel | Severity |
214
- | --------- | --------------------------------------- | -------- |
215
- | QA-PW-002 | Locator-assertion uten await | error |
216
- | QA-PW-003 | `page.pause()` / `test.only()` commitet | error |
217
- | QA-PW-004 | Skjøre CSS/XPath-selektorer | warning |
218
- | QA-PW-123 | Hardkodede miljø-URLer | warning |
310
+ e2e/login.spec.ts
311
+ [█████████████░░░░░░░] 65 / 100
312
+ role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
219
313
 
220
- </details>
314
+ e2e/checkout.spec.ts
315
+ [██████████████████░░] 88 / 100
316
+ role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
317
+ ```
221
318
 
222
- <details>
223
- <summary><strong>CI-integritet</strong></summary>
224
-
225
- | ID | Regel | Severity |
226
- | --------- | ------------------------------------------------------------------ | -------- |
227
- | QA-CI-001 | `continue-on-error` maskerer feil | error |
228
- | QA-CI-002 | `\|\| true` svelger exit-koder | error |
229
- | QA-CI-005 | Rapport forbrukes, men genereres aldri | error |
230
- | QA-CI-007 | Retry-wrappers rundt tester | warning |
231
- | QA-CI-008 | Alltid-vellykket step maskerer feil | error |
232
- | QA-CI-009 | Testens exit-kode propageres ikke (`\|` uten pipefail, `;`-kjeder) | error |
233
- | QA-CI-010 | Tester hoppes over der de må blokkere (skip-on-PR-guards) | error |
319
+ Dette måler **robusthet, ikke korrekthet**. `.btn.btn-primary > div:nth-child(2)` består i dag og fortsetter å bestå til noen rører markupen. En lav score påstår aldri at testen er ødelagt, bare at den avhenger av markup ingen har lovet å beholde.
234
320
 
235
- </details>
321
+ <br />
236
322
 
237
- <details>
238
- <summary><strong>Python / pytest 🐍</strong></summary>
323
+ ## Worthiness-scoren
239
324
 
240
- | ID | Regel | Severity |
241
- | --------- | ---------------------------------------------- | -------- |
242
- | QA-PY-002 | Hoppet over test (`skip`, ikke-strikt `xfail`) | warning |
243
- | QA-PY-003 | Testfunksjon uten assertions | error |
244
- | QA-PY-005 | `time.sleep()` i tester | warning |
245
- | QA-PY-012 | Tautologisk assertion | error |
325
+ <p align="center">
326
+ <img src="assets/readme/score-gauge.svg" alt="Worthiness-skalaen fra 0 til 100, med en markør som går gjennom hver score: UNWORTHY under 50, NEEDS WORK fra 50 til 79, WORTHY fra 80 til 99, FORGED ved 100" width="720" />
327
+ </p>
246
328
 
247
- 20 Python-regler totalt (QA-PY-001…012 pytest-hygiene + QA-PY-101…108 Playwright-Python).
329
+ <sub>Hver score fra 0 til 100, plassert av den ekte `deriveScoreState`. Generert av `npm run docs:gauge` og låst mot avvik i CI.</sub>
248
330
 
249
- </details>
331
+ | Score | Dom |
332
+ | --------- | ------------------------------------------- |
333
+ | `0 – 49` | **UNWORTHY** |
334
+ | `50 – 79` | **NEEDS WORK** |
335
+ | `80 – 99` | **WORTHY** |
336
+ | `100` | **FORGED** |
337
+ | `null` | **UNKNOWN**: ingen testdeklarasjoner funnet |
250
338
 
251
- <details>
252
- <summary><strong>Java / JUnit · TestNG ☕</strong></summary>
339
+ **Slik beregnes den.** Alvorlighetsgraden setter et grunntrekk (`error −8`, `warning −3`, `info −1`), og evidensnivået reduserer det: E2 teller fullt, E1 halvt (rundet ned), E0 ingenting. Summen normaliseres etter suitens eksponering, altså trekk per testdeklarasjon i stedet for per fil. Terminalen skriver ut de samme reduserte tallene som scoren brukte; det finnes ingen skjult modell nummer to. Detaljer: [docs/SCORING.md](docs/SCORING.md) og [scoringsveiledningen](https://sergey-bar.github.io/Mjolnir/guide/scoring).
253
340
 
254
- | ID | Regel | Severity |
255
- | --------- | ----------------------------------------- | -------- |
256
- | QA-JV-101 | Deaktivert test (`@Disabled`) | warning |
257
- | QA-JV-102 | Hardt sleep (`Thread.sleep()`) | warning |
258
- | QA-JV-103 | Testmetode uten assertions | error |
259
- | QA-JV-105 | Playwright hardt sleep `waitForTimeout()` | warning |
260
- | QA-JV-106 | Skjør selector i stedet for role-locator | warning |
341
+ **Hva 100 ikke betyr.** Det betyr ikke at programvaren er korrekt, at suiten er tilstrekkelig, eller at produktet er feilfritt. Det betyr én ting: **ingen av Mjölnirs evaluerte regler ga et trekk under denne skanningen og denne evidensmodellen.**
261
342
 
262
- </details>
343
+ <br />
263
344
 
264
- <details>
265
- <summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
345
+ ## Evidensmodellen
266
346
 
267
- | ID | Regel | Severity |
268
- | --------- | ---------------------------------------------- | -------- |
269
- | QA-CS-101 | Hoppet over test (`[Ignore]`, `[Fact(Skip=)]`) | warning |
270
- | QA-CS-102 | Hardt sleep (`Thread.Sleep` / `Task.Delay`) | warning |
271
- | QA-CS-103 | Testmetode uten assertions | error |
272
- | QA-CS-105 | Hardt sleep `WaitForTimeoutAsync()` | warning |
273
- | QA-CS-106 | Skjør selector i stedet for role-locator | warning |
347
+ Hvert funn har to etiketter: hvor sikker Mjölnir er, og hvor langt funnet er sjekket. Det er forskjellen mellom et verktøy som rapporterer mønstre og et verktøy du kan la en release avhenge av.
274
348
 
275
- </details>
349
+ **Hvor sikkert — evidensnivået.**
276
350
 
277
- > Den fulle, levende katalogen — hver regel med tier, confidence,
278
- > false-positive-risiko og autofix-tilgjengelighet — genereres fra
279
- > registret:
280
- >
281
- > ```bash
282
- > mjolnir rules --md
283
- > ```
284
- >
285
- > Sider per regel ligger under [`docs/rules/`](docs/rules/).
286
-
287
- ### Hvor mye er målt
288
-
289
- **78 av 99 regler bærer en false-positive-rate målt mot ekte OSS-kode**
290
- (≥ 10 håndklassifiserte funn hver; se
291
- [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). De andre 21 skiper på
292
- forfatterens estimat. Hver skann-fotnote forteller hvor mange av de
293
- _utløste_ reglene som er målt; `mjolnir rules --unmeasured` lister de
294
- umålte; hver regels `mjolnir explain`-side angir statusen. Vi publiserer
295
- karantene for det. Å få det tallet til å vokse er prosjektets fortsatte
296
- arbeid.
297
-
298
- ### Regel-tiers og språkmodenhet
299
-
300
- Hver regel er `core`, `extended` eller `quarantine`, tildelt ut fra sin
301
- **målte** false-positive-rate:
302
-
303
- | Tier | Betydning | Standardskann | `--strict` |
304
- | ------------ | ---------------------------------------- | :-----------: | :--------: |
305
- | `core` | ≤ 10 % målt FP | ✅ | ✅ |
306
- | `extended` | ≤ 30 % målt FP | ✅ | ✅ |
307
- | `quarantine` | over 30 %, eller ennå ikke målt (n < 10) | ❌ | ✅ |
308
-
309
- | Språk | Adapter | Dekning i dag |
310
- | --------------- | -------------- | ------------------------------------------------ |
311
- | TypeScript / JS | Kompilator-AST | bredeste, mest målte — mest `core`/`extended` |
312
- | Python / pytest | Regex-lag | bredt, corpus-auditeret — mest `core`/`extended` |
313
- | Java | Regex-lag | nyere — mest `extended`/`quarantine` |
314
- | C# / .NET | Regex-lag | nyere — mest `extended`/`quarantine` |
315
-
316
- TypeScript og Python har den bredeste målte dekningen. Java og C# er
317
- skipet, dokumentert og holdes utenfor overskriftstallet til en ekte
318
- forbrukersuite (ikke et binding-biblioteks egne tester) er auditeret.
319
-
320
- ---
321
-
322
- ## Slik fungerer scoren
351
+ | Nivå | Navn | Betyr | Trekk |
352
+ | ------ | -------------------- | ---------------------------------------------------- | ----- |
353
+ | **E2** | Deterministisk bevis | Defekten finnes i koden slik den er skrevet | Fullt |
354
+ | **E1** | Mønsterevidens | Et mønster som er sterkt knyttet til defekten, traff | Halvt |
355
+ | **E0** | Observasjon | Verdt å vite. Ikke en påstand om at noe er galt. | Null |
356
+
357
+ Sikkerhet i en deteksjon er ikke styrken i beviset. En regel kan være sikker på at den fant det den lette etter, og likevel se på en heuristikk. E1-funn er der for å bli lest og vurdert, aldri brukt i blinde, og den grensen står på funnet i terminalen, i JSON-en og i overleveringen til agenten.
358
+
359
+ **Hvor langt det er sjekket — tillitsnivået.** De fleste funn kommer fra å lese koden din. Gi Mjölnir rapporten fra en ekte testkjøring, så kan det bekrefte at koden faktisk kjørte.
323
360
 
324
361
  <p align="center">
325
- <img src="assets/readme/terminal-hero.svg" alt="Mjölnir-terminalutskrift — WORTHINESS 75/100 NEEDS WORK, en oppdeling av diagnostikk etter kategori og en FIX THIS FIRST-liste" width="820" />
362
+ <img src="assets/readme/trust-ladder.svg" alt="Tillitsstigen fra L0 til L5. L0 til L2 kommer fra å lese koden; L3 til L5 krever en ekte kjøringsrapport, markert med et brudd i stigen." width="100%" />
326
363
  </p>
327
364
 
328
- <sub>Regenereres med `npm run docs:hero`;
329
- [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
330
- får CI til å feile hvis artefakten avviker fra det reporteren faktisk
331
- skriver ut.</sub>
365
+ | Nivå | Med vanlige ord | Hva det krever |
366
+ | ------ | -------------------- | -------------------------------------------------- |
367
+ | **L0** | Notert | Å lese koden |
368
+ | **L1** | Ser ut som problemet | Å lese koden: et mønster traff |
369
+ | **L2** | Bevist i koden | Å lese koden: defekten er strukturell |
370
+ | **L3** | Filen kjørte | En kjøringsrapport viser at funnets fil ble kjørt |
371
+ | **L4** | Testen kjørte | En kjøringsrapport viser at funnets test ble kjørt |
372
+ | **L5** | Kjøringen er enig | Kjøringens eget resultat bekrefter defektklassen |
332
373
 
333
- Scoren er transparent: **error −8, warning −3, info −1**, deretter
334
- normalisert etter suitens eksponering (fradrag per testdeklarasjon).
335
- Bevisvektede fradrag betyr at svake signaler koster mindre. Terminalen
336
- viser de samme diskonterte tallene scoren bruker — ingen black box.
337
- Full metode: [docs/SCORING.md](docs/SCORING.md).
374
+ En statisk skanning stopper ved L2. Bare en ekte kjøringsrapport (Playwright JSON, Jest eller Vitest JSON, JUnit XML) kan løfte et funn til L3 eller høyere, så et funn som aldri er sett kjøre, kan aldri påstå at det gjorde det. Definisjoner: [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md).
338
375
 
339
- **Dommer**
376
+ ### Hvor mye av dette som er målt
340
377
 
341
- | Score | Domme |
342
- | ------- | ---------------- |
343
- | ≥ 80 | ✓ **WORTHY** |
344
- | 50 – 79 | ⚠ **NEEDS WORK** |
345
- | < 50 | ✖ **UNWORTHY** |
378
+ **74 av 79 regler har en falsk-positiv-rate målt mot ekte OSS-kode** (minst 10 håndklassifiserte funn hver; se [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). De andre 5 bygger på forfatterens anslag og sier det, regel for regel, i `mjolnir explain`. `mjolnir rules --unmeasured` lister dem, og bunnteksten i hver skanning oppgir hvor mange av reglene som faktisk _slo ut_, som er målt.
346
379
 
347
- **Bevisnivåer** — hvert funn bærer ett; det setter funnets vekt i
348
- scoren:
380
+ Ratene forblir offentlige også når de er dårlige. QA-TEST-001 (en committet `.only`) kommer dårlig ut av revisjonen på ekte repositorier og sitter derfor i quarantine. Det aktuelle tallet for hver regel, inkludert QA-PW-141, står i revisjonen.
349
381
 
350
- | Nivå | Betydning | Score-effekt | Eksempel |
351
- | ---- | --------------------- | --------------- | --------------------------------------------------- |
352
- | E2 | Deterministisk defekt | Fullt fradrag | Commitet `.only` — strukturelt bevisbart |
353
- | E1 | Heuristisk mønster | Halvt fradrag | Regex-truffet `sleep()` — sterkt signal, ikke bevis |
354
- | E0 | Observasjon | Null (kun info) | Rapportert, men gater aldri CI eller trekker fra |
382
+ ### Tillitsnivåer
355
383
 
356
- De fleste regler er **E1**. Slagordet «we prove it» viser til dette
357
- systemet: E2-funn er strukturelt bevis; E1-funn er korrekt plasserte
358
- advarsler, ikke formelle beviser.
384
+ Nivåene følger den målte falsk-positiv-raten, ikke meninger:
359
385
 
360
- Et tomt repo scorer `null`, aldri en falsk 100 — se
361
- [Tillitsmodellen](#tillitsmodellen).
386
+ | Nivå | Målt FP | Oppførsel |
387
+ | -------------- | ------------------------------ | ---------------------------------------------------- |
388
+ | **core** | ≤ 10% | Standardrapport, blokkerer |
389
+ | **extended** | ≤ 30% | Standardrapport, lavere sikkerhet |
390
+ | **quarantine** | > 30% eller eksplisitt erklært | Bare `--strict`, begrenset til info, blokkerer aldri |
391
+ | _ikke målt_ | n < 10 | Kan ikke forfremmes til core før den er målt |
362
392
 
363
- ---
393
+ FP-bånd kan bare degradere et nivå — de forfremmer aldri en regel ut av `quarantine` hvis den var eksplisitt erklært der. En eksplisitt karantenesatt regel forblir i quarantine uavhengig av dens målte FP-rate.
364
394
 
365
- ## 🎭 Selector Health Score
395
+ Forfremmelse, degradering og modenhet per språk: [reglenes livssyklus](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle).
366
396
 
367
- Hovedmetrikken for Playwright-suiter — hvor robuste locatorene dine er:
397
+ ### Hvorfor dette ikke er en linter
368
398
 
369
- ```text
370
- ▚ SELECTOR HEALTH — e2e/checkout.spec.ts
399
+ Lintere forteller deg om koden følger regler. Mjölnir forteller deg om verifiseringen din er til å stole på.
371
400
 
372
- [█████████████████░░░] 83 / 100
373
- role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
374
- ```
401
+ | | Lintere (ESLint, SonarQube) | Dekningsverktøy | AI-kodegjennomgang | **Mjölnir** |
402
+ | -------------------------------------------------------------- | :-------------------------: | :-------------: | :----------------: | :---------------: |
403
+ | Scorer **verifiseringssystemet**, ikke produktkoden | Nei | Nei | Nei | Ja |
404
+ | Integritet i CI-workflows (`continue-on-error`, `\|\| true`) | Nei | Nei | bare diffen | Ja |
405
+ | Vurderer robustheten til Playwright-locators (Selector Health) | Nei | Nei | Nei | Ja |
406
+ | Leser ekte kjøringsdata for `TRUE-FLAKE`-dommer | Nei | Nei | Nei | Ja |
407
+ | Publiserer en målt falsk-positiv-rate per regel | Nei | Nei | Nei | Ja |
408
+ | Markerer tester uten assertions | Ja\* | Nei | noen ganger | Ja |
409
+ | Fanger faste sleeps (`waitForTimeout`, `time.sleep`) | Ja\* | Nei | noen ganger | Ja |
410
+ | Deterministisk (samme input, samme output) | Ja | Ja | Nei | Ja |
411
+ | Kostnad per skanning | gratis | gratis | tokens | **null** (lokalt) |
412
+
413
+ <sub>\*Dekket av `eslint-plugin-jest` og `eslint-plugin-playwright` (`expect-expect`, `no-wait-for-timeout`) og av SonarQubes egne assertion-regler. Kolonnene beskriver standardoppførselen for verifisering av testsuiter; plugins, betalte planer og egne regler endrer noen svar. Dette er en posisjoneringsoversikt, ikke en benchmark.</sub>
375
414
 
376
- Rollebaserte locators får full score. CSS-klassekjeder og XPath senker
377
- scoren — de brekker ved enhver DOM-refaktor uten å fortelle deg hvilken
378
- atferd som har regressert.
415
+ Bruk AI-gjennomgang også. Den fanger nyanser, intensjon og designfeil som ingen mønstre kan finne. Mjölnir fanger det AI-gjennomgangen overser fordi det ser tilsiktet ut: en committet `.only`, en svelget exitkode, en `continue-on-error` på en testjobb. Slikt krever skanning, ikke resonnering.
379
416
 
380
- ---
417
+ <br />
381
418
 
382
- ## 🔬 Runtime-bevis
419
+ ## Kjøringsanalyse
383
420
 
384
- Statisk flakiness-deteksjon er gjetting. Mjölnir leser **ekte
385
- kjøringsdata** — Playwright JSON-rapporter og JUnit-XML fra enhver
386
- runner:
421
+ Statisk analyse resonnerer om kode som aldri har kjørt. Kjøringsanalysen leser hva som faktisk skjedde: Playwright JSON, Jest JSON, Vitest JSON og JUnit XML fra hvilken som helst runner.
387
422
 
388
423
  ```bash
389
424
  mjolnir forensics ./test-results/
390
425
  ```
391
426
 
392
427
  ```text
393
- ▚ FLAKINESS LEADERBOARD
428
+ ▍ FLAKINESS LEADERBOARD
394
429
 
395
430
  3 tests · 1 failed · 1 flaky · 1 retried
396
431
 
@@ -400,293 +435,184 @@ FAILING declines an expired card (e2e/checkout.spec.ts)
400
435
  ████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
401
436
  ```
402
437
 
403
- En test som bare består fra forsøk ≥ 2, er ikke en bestått test — det
404
- er en heldig test. Den merkes `TRUE-FLAKE` uansett den endelige grønne
405
- haken.
438
+ `TRUE-FLAKE` betyr ikke at testen ble kjørt på nytt. Det betyr at testen **feilet minst ett forsøk og deretter endte grønt**: en heldig bestått, markert uansett hva den endelige haken sier. `mjolnir triage` gjør den historikken om til et karanteneforslag, og `mjolnir pw-report` oppsummerer en kjøring. Det er de samme kjøringsrapportene som løfter funn til tillitsnivå L3 og høyere.
439
+
440
+ <br />
441
+
442
+ ## CI-integritet
406
443
 
407
- ---
444
+ En test kan bestå mens pipelinen rundt den ikke kan feile. Mjölnir leser også workflowene: `continue-on-error`, `|| true`, exitkoder som aldri videreformidles, steps som alltid lykkes, rapporter som brukes, men aldri genereres, og gates som hoppes over ved nettopp de hendelsene som burde blokkere. Hvert funn oppgir jobb, step og linje, og har sitt eget evidensnivå.
408
445
 
409
- ## ⚡ Mjölnir er ikke enda en linter
446
+ Generer PR-workflowen, rådgivende som standard:
447
+
448
+ ```bash
449
+ mjolnir ci install
450
+ ```
410
451
 
411
- Lintere forteller deg om koden følger regler. Mjölnir forteller deg om
412
- verifiseringen din kan stoles på.
452
+ Eller legg Marketplace-action-en til en workflow du allerede har:
413
453
 
414
- | | ESLint / SonarQube | Coverage-verktøy | Manuell review | **Mjölnir** |
415
- | -------------------------------------------------------------- | :----------------: | :--------------: | :------------: | :---------: |
416
- | CI-workflow-integritet (`continue-on-error`, `\|\| true`) | ❌ | ❌ | sjelden | ✅ |
417
- | Tverrspråklig (TS, Python, Java, C#) fra ett verktøy | ❌ | ❌ | ❌ | ✅ |
418
- | Vurderer robustheten til Playwright-locators (Selector Health) | ❌ | ❌ | sjelden | ✅ |
419
- | Markerer tester uten ekte assertions | ✅ (plugin)\* | ❌ | av og til | ✅ |
420
- | Fanger harde sleeps (`waitForTimeout`, `time.sleep`) | ✅ (plugin)\* | ❌ | av og til | ✅ |
421
- | Kjører på sekunder, null nettverkskall under skanning | ✅ | ✅ | — | ✅ |
454
+ ```yaml
455
+ - uses: Sergey-Bar/Mjolnir@v1
456
+ with:
457
+ scope: changed
458
+ fail-on: error
459
+ ```
460
+
461
+ Fest `@v1` for å følge major-linjen, eller en eksakt tagg (`@v0.5.32`) for en reproduserbar gate. [docs/DISTRIBUTION-KIT.md](docs/DISTRIBUTION-KIT.md) dekker Marketplace, Smithery og MCP-registrene.
462
+
463
+ For å få funn inn i GitHub Code Scanning, last opp SARIF (krever `security-events: write` på workflow- eller job-nivå):
464
+
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
+ ```
422
473
 
423
- \*`eslint-plugin-jest` (`expect-expect`) og `eslint-plugin-playwright`
424
- (`expect-expect`, `no-wait-for-timeout`) dekker dette for sine
425
- respektive rammeverk.
474
+ På GitLab skriver `--format codequality` Code Quality-rapporten som MR-widgeten og diff-annotasjonene leser ([docs/GITLAB-CI.md](docs/GITLAB-CI.md)). Oppsett av editor og pipeline: [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
426
475
 
427
- **Runtime-analyse** er en egen kategori ved siden av statisk linting:
476
+ ### Tilordning i endret omfang
428
477
 
429
- | | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
430
- | ----------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
431
- | Leser ekte kjøringsdata til `TRUE-FLAKE`-dommer | delvis\* | delvis (tag) | ✅ |
432
- | Flaky-triage-rapport fra utførelseshistorikken | ❌ | ✅ | ✅ |
433
- | Integrerer med den statiske verdighetsscoren | ❌ | ❌ | ✅ |
478
+ ```bash
479
+ npx mjolnir-qa@latest --scope changed
480
+ ```
434
481
 
435
- \*Playwright sporer retries internt, men produserer ikke en selvstendig
436
- flakiness-rapport med dommeetiketter.
482
+ Funn tilordnes linjene grenen din har lagt til, målt mot **merge-base**. Omfanget er det samme filsettet en full skanning finner (TS/JS-specs og adapterkonfigurasjoner, `test_*.py`, `*Test.java`, `*Tests.cs`, `.github/workflows/*.yml`), pluss ikke-committede og usporede endringer, så det fungerer før du committer. Basen løses i rekkefølgen `main → master → origin/main → origin/master → origin/HEAD`; overstyr den med `--base <ref>`.
437
483
 
438
- ---
484
+ Når merge-base ikke kan løses (en shallow clone, et detached HEAD, et mål utenfor git), faller funnene tilbake til tilordning for hele filen, **og rapporten sier det.** En stille fallback ville vært nøyaktig den typen defekt dette verktøyet finnes for å fange.
439
485
 
440
- ## 🤖 Hvorfor ikke bare bruke AI-kodereview?
486
+ <br />
441
487
 
442
- Annet problem, annet lag. AI-review kan spotte en mistenkelig
443
- testendring i en diff; det beviser ikke at verifiseringssystemet som
444
- helhet er troverdig — og det ser bare diffen du viser det.
488
+ ## AI-agenter
445
489
 
446
- | | AI-kodereview (Copilot m.fl.) | **Mjölnir** |
447
- | ------------------------------------------- | :-------------------------------------: | :----------------------------------: |
448
- | Kostnad per skann | Tokens (skalerer med diffstørrelsen) | **Null** (lokal, installert) |
449
- | Ser hele suiten + alle CI-konfigs | Bare PR-diffen du viser | **Alt, hver gang** |
450
- | Deterministisk (samme input → samme output) | ❌ (ikke-deterministisk) | **✅** |
451
- | Fanger mønstre som har sovet i måneder | Bare hvis det er i konteksten | **✅** (skanner alle filer) |
452
- | Husker funn mellom kjøringer | ❌ (ingen hukommelse på tvers av økter) | **✅** (baseline + diff) |
453
- | Kjører uten menneskelig utløser | Krever en PR eller prompt | **✅** (CI-hook, kjører på sekunder) |
490
+ Funn er bare verdt noe hvis noe handler på dem.
454
491
 
455
- **Bruk begge.** AI fanger nyanse, intensjon og designfeil ingen regex
456
- kan finne. Mjölnir fanger de strukturelle mønstrene AI overser fordi de
457
- ser «intensjonelle» ut — et commitet `.only`, en oppslukt exit-kode, en
458
- `continue-on-error` på et testjobb. Det er ikke bugs som krever
459
- resonnering; det er fakta som krever skanning.
492
+ ```text
493
+ SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
494
+ ```
460
495
 
461
- ---
496
+ **AI skriver rettelsen. Mjölnir verifiserer den.** Beviset kommer fra den nye skanningen, aldri fra agentens egen melding om suksess.
462
497
 
463
- ## 🤖 CI-integrasjon
498
+ | Kommando | Hva agenten får |
499
+ | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
500
+ | `mjolnir mcp` | En [MCP](https://modelcontextprotocol.io)-server over stdio. `scan`, `explain` og `diff` blir kallbare verktøy. |
501
+ | `mjolnir handoff` | En lagret `--json`-rapport blir en deterministisk Markdown-plan: hva som ble oppdaget, evidensgrensen for hvert funn, hva som **ikke** må endres, og hvordan det verifiseres. |
502
+ | `mjolnir install` | Skriver inn i agentflatene repoet ditt allerede har (`.claude/`, `.cursor/`, `.kilo/`, `AGENTS.md`), slik at agenten skanner på nytt før den påstår at den er ferdig. |
464
503
 
465
- Én kommando genererer en PR-workflow — rådgivende som standard, aldri
466
- blokkerende:
504
+ Legg det til i en klient som har sin egen CLI:
467
505
 
468
506
  ```bash
469
- mjolnir ci install
507
+ claude mcp add mjolnir -- npx -y mjolnir-qa@latest mcp
470
508
  ```
471
509
 
472
- Eller koble den nativt inn i GitHub Code Scanning via SARIF:
510
+ Eller i en hvilken som helst klient som tar en `mcpServers`-blokk:
473
511
 
474
- ```yaml
475
- - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
476
- - uses: github/codeql-action/upload-sarif@v3
477
- with:
478
- sarif_file: mjolnir.sarif
512
+ ```json
513
+ {
514
+ "mcpServers": {
515
+ "mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@latest", "mcp"] }
516
+ }
517
+ }
479
518
  ```
480
519
 
481
- Editor- og pipeline-oppsett for SARIF:
482
- [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
520
+ **Rekkverket betyr mer enn bekvemmeligheten.** Hvert funn i en overlevering bærer sin grense. **E2** sier _deterministisk: sjekk plasseringen og bruk rettelsen_. **E1** sier _KREVER BEKREFTELSE: observasjonen alene beviser ikke defekten_. En agent som retter E1 i blinde, undertrykker en regel eller redigerer en regel for å heve scoren, gjør nøyaktig det dette verktøyet finnes for å fange, så overleveringen sier det i prompten, rett ved siden av funnet.
483
521
 
484
- ### Changed-scope-dekning
522
+ <br />
485
523
 
486
- `--scope changed` tilskriver funn de linjene branchen din la til
487
- i forhold til merge-base med `main`. Den dekker testfiler (`*.spec.*`,
488
- `*.test.*`) pluss GitHub-workflowfiler og Playwright-konfigurasjoner i
489
- diffen. Når merge-base ikke kan resolve — shallow clone, detached HEAD,
490
- ikke-git-mål, annen default-branch — degraderer den ærlig: funn faller
491
- tilbake til hel-fil-attribuering, og rapporten sier det. Overskriv
492
- base-ref med `--base <ref>`.
524
+ ## Tillit og sikkerhet
493
525
 
494
- ---
526
+ **Local-first, null telemetri.** Det finnes ingen nettverkskapabel API (`fetch`, `http`, `https`, `net`, `dns`, `dgram`, WebSocket) noe sted i `src/`, og [`privacy-network-isolation.spec.ts`](tests/contract/privacy-network-isolation.spec.ts) får bygget til å feile hvis en dukker opp. Den forbyr også `eval` og `new Function`. Å skanne kode du ikke stoler på, kjører den aldri: statisk analyse leser kildetekst, og kjøringsanalysen parser rapportfiler som allerede ligger på disken.
495
527
 
496
- ## Konfigurasjon
528
+ To forbehold: `npx` henter selv pakken før noe kjører, og garantien dekker `src/`, ikke tredjeparts plugins.
497
529
 
498
- Mjölnir er zero-config. En valgfri `mjolnir.config.json` (eller
499
- `.mjolnir.json`) i roten av repoet fininnstiller severity, gating og
500
- scope — den endrer aldri deteksjonssemantikken.
530
+ **Plugins kjører ikke i en sandkasse.** JS-plugins (`mjolnir-rules/*.mjs`, eller npm-pakker oppført under `"plugins"`) kjører med fulle Node-rettigheter, samme tillitsmodell som ESLint- eller Vitest-plugins. Å laste dem er et aktivt valg **per skanning**: uten `--enable-plugins` (eller `MJOLNIR_ENABLE_PLUGINS=1`) lastes kildene deres aldri, og en melding på stderr lister hva som ble hoppet over. JSON-regelmanifester kjører ingen kode, og prefiksene for core-regel-ID-er er reservert, slik at et plugin ikke kan utgi seg for å være en av dem. Rapporter sårbarheter via [SECURITY.md](SECURITY.md).
501
531
 
502
- | Key | Type | Effekt |
503
- | ------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
504
- | `exclude` | `string[]` | Ekstra ignore-globs (gitignore-delmengde), oppå de innebygde defaultene |
505
- | `gate` | `"advisory" \| "error" \| "warning"` | Hvilke severities som avslutter med ikke-null (default `error`; `advisory` blokkerer aldri) |
506
- | `severityOverrides` | `{ "<RULE-ID>": severity }` | Omrangerer en regels funn for repoet ditt |
507
- | `ignore` | `IgnoreEntry[]` | Undertrykker funn — **`reason` er påkrevd**; oppføringer utløper etter 90 dager (en eksplisitt `expires`-dato, eller config-filens last-modified-tid for oppføringer uten) |
508
- | `plugins` | `string[]` | Regelpakker fra tredjepart (se [Tillitsmodellen](#tillitsmodellen)) |
532
+ **Det kjører på seg selv.** En verification trust engine har ingen troverdighet med mindre den selv kan verifiseres. Hver CI-kjøring skanner dette repositoriet med bygget den samme kjøringen produserte. Gaten feiler ved ethvert funn med alvorlighetsgrad error, og også ved en **delvis** skanning eller en **regel som krasjet**, fordi en avkortet selvskanning som ikke rapporterer noe, er nøyaktig det falske grønne dette prosjektet finnes for å fange. `mjolnir doctor` reviderer regelbasen på nytt i samme kjøring (fixture-brannmur, ærlige nivåer, taket for core-nivået), og en INCONCLUSIVE-sjekk feiler akkurat som en feilende sjekk. Begge rapportene lastes opp som byggeartefakter.
509
533
 
510
- ```json
511
- {
512
- "gate": "error",
513
- "exclude": ["legacy/**"],
514
- "severityOverrides": { "QA-PW-141": "warning" },
515
- "ignore": [
516
- {
517
- "ruleId": "QA-TEST-004",
518
- "files": ["e2e/legacy-login.spec.ts"],
519
- "reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
520
- "expires": "2026-12-31"
521
- }
522
- ]
523
- }
524
- ```
534
+ ### Exitkoder og maskinkontrakten
525
535
 
526
- - **`.mjolnirignore`** — en enkel gitignore-lignende fil for
527
- sti-ekskluderinger, samme dialekt som `exclude`. Bruk den for
528
- maskinspesifikk støy; bruk `exclude` når listen hører hjemme i
529
- versjonskontroll sammen med resten av konfigurasjonen.
530
- - **CLI-overrides** — `--strict` (inkluder karantèneregler),
531
- `--width <cols>` og `--ascii` / `--no-ascii` (terminalrendering),
532
- `--tone blunt` (hardere meldinger), `--max-duration <sec>`
533
- (begrenset delvis skanning).
534
- - Regelundertrykkelse og deprecation-levetid:
535
- [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
536
-
537
- `ignore`-oppføringer driver også den selvstendige kommandoen
538
- `mjolnir suppressions`, som lister hva som er undertrykket nå, og når
539
- hver oppføring utløper.
540
-
541
- ---
542
-
543
- ## 📐 Exit-koder & kontrakter
544
-
545
- Frosne — trygge å bygge CI-logikk på:
546
-
547
- | Exit-kode | Betydning |
548
- | --------- | --------------------------------------------------------------------------- |
549
- | `0` | Rent — ingen funn på eller over gaten |
550
- | `1` | Funn på eller over gaten |
551
- | `2` | Delvis skanning (tidsbudsjett brukt opp, ulesebare filer) — blokkerer aldri |
552
- | `10` | Bruksfeil (ugyldig flagg, manglende mål) |
553
- | `20` | Intern feil |
554
-
555
- JSON/SARIF-rapporten er `schemaVersion: 1`. Regel-IDer
556
- (`QA-<FAMILY>-NNN`) er uforanderlige én gang skipet og gjenbrukes
557
- aldri.
558
-
559
- ---
560
-
561
- ## Tillitsmodellen
562
-
563
- - **Local-first** — null nettverkskall under skanning. Ever. Null
564
- telemetri.
565
- - **Ingen falsk bevis** — vi sier heller «ukjent» enn «verifisert». Et
566
- tomt repo får `score: null`, aldri en falsk 100.
567
- - **Delvis ærlighet** — hvis analysen ble avkortet, sier utdataene det.
568
- Aldri «complete» når det ikke er tilfelle.
569
- - **FP-brannmur** — deteksjon kjører på et kommentar-/streng-fritt view
570
- av koden (TypeScript-regler bruker kompilator-AST): et mønster inne i
571
- en prosakommentar eller en doc-eksempelstreng er dokumentasjon, ikke
572
- et funn.
573
- - **Målt, ikke påstått** — bare regler med en false-positive-rate fra
574
- ekte OSS-kode skiper i overskriftstierne (se
575
- [Hvor mye er målt](#hvor-mye-er-målt)); skann-fotnoten og
576
- `mjolnir rules --unmeasured` forteller deg hvilke som er hva.
577
- - **Plugin-tillit og kjøringsport** — plugins er npm-pakker deklarert under
578
- `"plugins"`; JS-moduler bor i `mjolnir-rules/*.mjs`.
579
- Det er **ingen sandbox**: plugin-kode kjører med fulle
580
- Node-privilegier, samme tillitsmodell som ESLint- eller
581
- Vitest-plugins. Derfor er kodekjøring **opt-in ved hver skann**: gi
582
- `--enable-plugins` (eller sett `MJOLNIR_ENABLE_PLUGINS=1`), ellers
583
- lastes kildene IKKE — et høylig stderr-varsel lister nøyaktig hva som
584
- ble hoppet over. Å skanne ukjent kode kjører den aldri. JSON-regelmanifest
585
- (`mjolnir-rules/*.json`) berøres ikke: de deklarerer regex-mønstre og
586
- kjører ingen kode av konstruksjon. Core regel-ID-prefiks er reservert
587
- og avvises fra
588
- plugins og eksterne regler mot spoofing.
589
- - **Workspace-lokale eksterne regler** (mappebaserte, null nettverk) —
590
- en `mjolnir-rules/`-mappe ved siden av skannemålet loader
591
- tilpassede regler: JSON-filer deklarerer regex-mønstre (ingen kode
592
- eksekveres), `.mjs`/`.js`-moduler eksporterer `rules` (full
593
- Node-tillit, som plugins). Eksterne regler bærer samme
594
- trust-metadata som core; de kan aldri skipe i core-tieren (core
595
- krever en målt FP-rate fra corpus-sidecaren — en deklarert
596
- `tier: "core"` klemmes til `extended`), adlyder tier-grenser og
597
- sjekkes for drift: `mjolnir rules --md --external` renderer
598
- katalogen fra de lastede filene (proveniens `external`), og
599
- matrisegeneratoren aksepterer `--external <root>`.
600
-
601
- ---
602
-
603
- ## 🏗️ Arkitektur
536
+ Fryst, så du kan bygge CI-logikk på dem:
604
537
 
605
- <details>
606
- <summary>Utvid treet</summary>
538
+ | Exitkode | Betydning |
539
+ | -------- | --------------------------------------------------------------------------- |
540
+ | `0` | Ren: ingen funn på eller over gaten |
541
+ | `1` | Funn på eller over gaten |
542
+ | `2` | Delvis skanning (tidsbudsjett brukt opp, uleselige filer). Blokkerer aldri. |
543
+ | `10` | Brukerfeil (feil flagg, manglende mål) |
544
+ | `20` | Intern feil |
607
545
 
608
- ```
609
- mjolnir/
610
- ├── src/
611
- │ ├── engine/ # LanguageAdapter interface + rule runner
612
- │ ├── adapters/ # typescript · python · java · csharp · github-actions
613
- │ ├── rules/ # rules across 8 families + the measured-FP table
614
- │ ├── playwright/ # Selector Health Score engine
615
- │ ├── discovery/ # workspace, frameworks, ignore resolution
616
- │ ├── scope/ # git merge-base changed-scope engine
617
- │ ├── scorer/ # transparent deduction table + prioritization
618
- │ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
619
- │ ├── forensics/ # run-data ingestion · flake verdicts · triage
620
- │ ├── config/ # mjolnir.config.json + suppressions
621
- │ ├── plugins/ # third-party rule loading (no sandbox)
622
- │ └── commands/ # every subcommand
623
- └── tests/
624
- ├── fixtures/ # must-fire / must-not-fire per rule
625
- └── golden/ # frozen score regression locks
626
- ```
546
+ `2` er bevisst forskjellig fra `0`: en skanning som ikke ble ferdig, har ikke funnet ingenting. Den er bare ikke ferdig med å lete.
627
547
 
628
- </details>
548
+ Alt en maskin bruker (MCP-verktøyresultater, `--json`, SARIF 2.1), kommer fra ett kanonisk resultat under et versjonert, **bare additivt** skjema (`schemaVersion: 1`, `contractVersion: 1`), så ingen forbruker trenger å gjenskape betydningen fra rendret tekst. Se [maskinkontrakten](docs/machine-contract.md). Regel-ID-er (`QA-<FAMILY>-NNN`) kan ikke endres etter at de er levert, og gjenbrukes aldri.
629
549
 
630
- - **Regler er rene funksjoner** — `(SourceFileContext) → Finding[]`,
631
- ingen I/O, ingen globals. Nye økosystem = én adapter + dens regler.
632
- - **TypeScript/Playwright bruker kompilator-AST** (ts-morph). Python,
633
- Java og C# kjører på et delt regex-lag med maskerte kommentar/strenger.
634
- - Et tree-sitter WASM AST-lag for Java og C# finnes og er neste
635
- presisjonssteg — det er ennå ikke koblet på den synkrone
636
- skanne-pipelinen.
550
+ <br />
637
551
 
638
- ---
552
+ ## Hva Mjölnir ikke kan fortelle deg
639
553
 
640
- ## 📚 Dokumentasjon
554
+ - **Det kjører ikke testene dine.** En ren skanning er ikke en bestått suite.
555
+ - **Det kan ikke fortelle deg at en assertion er _feil_.** `expect(total).toBe(41)` ser sunn ut. Mjölnir finner tester som _ikke kan feile_ og pipelines som _ikke kan bli røde_, ikke tester som sjekker feil ting.
556
+ - **Det beviser ikke forretningsmessig korrekthet.** Ingenting her sier at produktet ditt gjør det kravet ba om.
557
+ - **100 er ikke bevis på en god suite.** Om suiten din dekker den reelle risikoen din, er et annet spørsmål, og det svarer ikke dette verktøyet på.
558
+ - **5 av 79 regler bygger på et anslag**, ikke en målt rate. Hver av dem sier det på sitt eget funn.
559
+ - **E1 er ikke E2.** Heuristiske funn er verdt å lese, ikke verdt å bruke i blinde.
560
+ - **Et tomt repo får `null`, aldri 100.**
561
+ - **En fil som heter `*.spec.ts` uten testdeklarasjoner, teller ikke som dekning.** Et repo der de eneste spec-filene inneholder imports eller typer (null `it`/`test`-kall), får `null`, ikke 100.
641
562
 
642
- | Dokument | Hva som er i det |
643
- | ------------------------------------------------------ | ------------------------------------------- |
644
- | [docs/SCORING.md](docs/SCORING.md) | Score-normalisering + bevisvektning |
645
- | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Målte false-positive-rater + metode |
646
- | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Regeltilstander, undertrykking, deprecation |
647
- | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | SARIF-utdata + editor/CI-oppsett |
648
- | [docs/rules/](docs/rules/) | Generert katalog per regel |
649
- | [CONTRIBUTING.md](CONTRIBUTING.md) | Dev-oppsett + bidragsflyt |
650
- | [CHANGELOG.md](CHANGELOG.md) | Utgivelseshistorikk |
651
- | [SECURITY.md](SECURITY.md) | Sårbarhetsrapportering |
563
+ <br />
652
564
 
653
- ---
565
+ ## Dokumentasjon
654
566
 
655
- ## 📈 Status
567
+ Det fullstendige dokumentasjonsnettstedet finner du på <https://sergey-bar.github.io/Mjolnir/>.
656
568
 
657
- **v0.5.x · åpen beta.** JSON-skjemaet og exit-kodene er frosne
658
- kontrakter. TypeScript og Python har den bredeste målte dekningen; Java
659
- og C# er nyere — les dem gjennom
660
- [tiers-tabellen](#regel-tiers-og-språkmodenhet).
569
+ | Dokument | Hva det inneholder |
570
+ | ------------------------------------------------------ | ------------------------------------------------ |
571
+ | [docs/SCORING.md](docs/SCORING.md) | Normalisering av scoren og vekting av evidens |
572
+ | [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md) | Kanonisk ordforråd: ett ord per begrep |
573
+ | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Målte falsk-positiv-rater og metoden |
574
+ | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | Regeltilstander, nivåer, undertrykking, utfasing |
575
+ | [docs/VERSIONING.md](docs/VERSIONING.md) | Semver-policy, fryste flater, utfasingssyklus |
576
+ | [docs/machine-contract.md](docs/machine-contract.md) | Det kanoniske maskinlesbare resultatet |
577
+ | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | SARIF-utdata og oppsett av editor eller CI |
578
+ | [docs/GITLAB-CI.md](docs/GITLAB-CI.md) | GitLab: Code Quality-rapport, MR-oppskrift, gate |
579
+ | [docs/rules/](docs/rules/) | Generert katalog per regel |
580
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | Utviklingsmiljø og bidragsflyt |
581
+ | [SUPPORT.md](SUPPORT.md) | Hvor du kan spørre, rapportere og få hjelp |
582
+ | [SECURITY.md](SECURITY.md) | Rapportering av sårbarheter |
583
+ | [CHANGELOG.md](CHANGELOG.md) | Versjonshistorikk |
661
584
 
662
- ---
585
+ ### Status
663
586
 
664
- ## 🤝 Bidra
587
+ **Versjon 1.** JSON-skjemaet og exitkodene er fryste kontrakter. TypeScript og Python har den bredeste målte dekningen. Java og C# er nyere; les dem gjennom [modenhetstabellen](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle). Hva som kommer videre, uten oppdiktede datoer: [det offentlige veikartet](https://sergey-bar.github.io/Mjolnir/reference/roadmap).
665
588
 
666
- Nye regler er den enkleste første bidraget — én kommando scaffolder
667
- regelen pluss dens must-fire- **og** must-not-fire-fixtures (den
668
- genererte regelen feiler bevisst fixturene sine til du implementerer
669
- ekte deteksjon — en stub kan ikke skipes):
589
+ ### Bidra
590
+
591
+ Nye regler er det enkleste første bidraget. Én kommando lager skjelettet til regelen med must-fire- **og** must-not-fire-fixtures. Den genererte regelen feiler bevisst sine egne fixtures til ekte deteksjon er skrevet, fordi en stubb som blir levert, er en regel ingen har målt:
670
592
 
671
593
  ```bash
672
594
  mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
673
595
  ```
674
596
 
675
- Full dev-oppsett, standing-gate-kommandoene og anti-creep- /
676
- fixture-brannmur-lovene er i [CONTRIBUTING.md](CONTRIBUTING.md).
597
+ Utviklingsmiljøet, kommandoene for de faste gatene og anti-creep- og fixture-brannmur-lovene står i [CONTRIBUTING.md](CONTRIBUTING.md).
677
598
 
678
- ---
599
+ <br />
679
600
 
680
601
  <div align="center">
681
602
 
682
- **Slutt å skipe tester du ikke kan stole på.**
603
+ <img src="assets/readme/closing.svg" alt="Kjør det på repoet ditt." width="100%" />
683
604
 
684
605
  ```bash
685
606
  npx mjolnir-qa@latest
686
607
  ```
687
608
 
688
- **Star ⭐ · Watch 👀 · Contribute 🤝**
609
+ [Les veiledningen](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [Dokumentasjonsnettsted](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)
610
+
611
+ <br />
612
+
613
+ Ikke spør om testene besto.<br />
614
+ Spør om evidensen beviser at de fortjener tillit.
689
615
 
690
- Bygget av [Sergey Bar](https://www.linkedin.com/in/sergeybar/)
616
+ <sub>Laget av [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · MIT-lisens</sub>
691
617
 
692
618
  </div>