mjolnir-qa 0.4.0 → 0.5.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/CHANGELOG.md +259 -28
- package/README.md +209 -72
- package/dist/cli.d.mts +32 -2
- package/dist/cli.mjs +2158 -2208
- package/package.json +11 -8
package/README.md
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<
|
|
4
|
-
╔═══════════╗
|
|
5
|
-
║ ║
|
|
6
|
-
╠═══════════╣ M J Ö L N I R
|
|
7
|
-
║ ║ ║
|
|
8
|
-
╚═════╩═════╝ VERIFICATION TRUST ENGINE
|
|
9
|
-
║
|
|
10
|
-
║
|
|
11
|
-
</pre>
|
|
3
|
+
<img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
|
|
12
4
|
|
|
13
5
|
### Your tests are lying to you. We prove it.
|
|
14
6
|
|
|
15
7
|
**Verification Trust Engine for QA.** Audits test suites and CI pipelines,
|
|
16
8
|
reports a worthiness score, and shows exactly where trust breaks.
|
|
17
9
|
|
|
10
|
+
<sub>"We prove it" is literal for the deterministic findings — a committed `.only`,
|
|
11
|
+
a `continue-on-error` on a test job. The pattern-based rules are labelled
|
|
12
|
+
heuristic, and **15 of 91 carry a false-positive rate measured against real
|
|
13
|
+
OSS code**; `mjolnir rules --unmeasured` names the rest. See
|
|
14
|
+
[docs/FP-AUDIT.md](docs/FP-AUDIT.md).</sub>
|
|
15
|
+
|
|
16
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
17
|
+
[](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
|
|
18
18
|
[](LICENSE)
|
|
19
19
|
[](https://nodejs.org)
|
|
20
|
-
[](#-quickstart)
|
|
21
20
|
|
|
22
21
|
```bash
|
|
23
22
|
npx mjolnir-qa@latest
|
|
@@ -33,14 +32,14 @@ npx mjolnir-qa@latest
|
|
|
33
32
|
|
|
34
33
|
## 🔨 What is Mjölnir?
|
|
35
34
|
|
|
36
|
-
| |
|
|
37
|
-
| --- |
|
|
38
|
-
| ⚖️ | **Worthiness Score** — one number, transparent deduction table, no black box
|
|
39
|
-
| 🎭 | **Selector Health Score** — grades your Playwright locators, not just your pass rate
|
|
40
|
-
| 🔬 | **Runtime forensics** — reads real Playwright/JUnit run data to catch `TRUE-FLAKE`, not just static guesses
|
|
41
|
-
| 🚨 | **CI-integrity rules** — catches `continue-on-error`, `\|\| true`, and other false-green tricks
|
|
42
|
-
| 🐍 | **
|
|
43
|
-
| 🔒 | **Local-first** — zero network calls while scanning, zero telemetry, runs in seconds
|
|
35
|
+
| | |
|
|
36
|
+
| --- | ----------------------------------------------------------------------------------------------------------------- |
|
|
37
|
+
| ⚖️ | **Worthiness Score** — one number, transparent deduction table, no black box |
|
|
38
|
+
| 🎭 | **Selector Health Score** — grades your Playwright locators, not just your pass rate |
|
|
39
|
+
| 🔬 | **Runtime forensics** — reads real Playwright/JUnit run data to catch `TRUE-FLAKE`, not just static guesses |
|
|
40
|
+
| 🚨 | **CI-integrity rules** — catches `continue-on-error`, `\|\| true`, and other false-green tricks |
|
|
41
|
+
| 🐍 | **All four Playwright bindings** — TypeScript, Python, Java, C#/.NET — plus pytest, JUnit/TestNG and CI workflows |
|
|
42
|
+
| 🔒 | **Local-first** — zero network calls while scanning, zero telemetry, runs in seconds |
|
|
44
43
|
|
|
45
44
|
---
|
|
46
45
|
|
|
@@ -49,65 +48,128 @@ npx mjolnir-qa@latest
|
|
|
49
48
|
Linters tell you whether code follows rules.
|
|
50
49
|
Mjölnir tells you whether your verification can be trusted.
|
|
51
50
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
| Runs in seconds, zero network calls
|
|
51
|
+
| | ESLint / SonarQube | Coverage tools | Manual review | **Mjölnir** |
|
|
52
|
+
| -------------------------------------------------------- | :----------------: | :------------: | :-----------: | :---------: |
|
|
53
|
+
| CI workflow integrity (`continue-on-error`, `\|\| true`) | ❌ | ❌ | rarely | ✅ |
|
|
54
|
+
| Cross-language (TS, Python, Java, C#) from one tool | ❌ | ❌ | ❌ | ✅ |
|
|
55
|
+
| Grades Playwright locator resilience (Selector Health) | ❌ | ❌ | rarely | ✅ |
|
|
56
|
+
| Flags tests with no real assertions | ✅ (plugin)\* | ❌ | sometimes | ✅ |
|
|
57
|
+
| Catches hard sleeps (`waitForTimeout`, `time.sleep`) | ✅ (plugin)\* | ❌ | sometimes | ✅ |
|
|
58
|
+
| Runs in seconds, zero network calls while scanning | ✅ | ✅ | — | ✅ |
|
|
59
|
+
|
|
60
|
+
\*`eslint-plugin-jest` (`expect-expect`) and `eslint-plugin-playwright` (`expect-expect`, `no-wait-for-timeout`) cover these for their respective frameworks.
|
|
61
|
+
|
|
62
|
+
**Runtime Analysis** — a separate category from static linting:
|
|
63
|
+
|
|
64
|
+
| | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
|
|
65
|
+
| --------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
|
|
66
|
+
| Reads real run data for `TRUE-FLAKE` verdicts | partial\* | partial (tag) | ✅ |
|
|
67
|
+
| Flaky-triage report from execution history | ❌ | ✅ | ✅ |
|
|
68
|
+
| Integrates with static worthiness score | ❌ | ❌ | ✅ |
|
|
69
|
+
|
|
70
|
+
\*Playwright tracks retries internally but does not produce a standalone flakiness report with verdict labels.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🤖 Why not just use AI code review?
|
|
75
|
+
|
|
76
|
+
AI reviewers are powerful — but they're expensive, intermittent, and reactive.
|
|
77
|
+
Mjölnir is cheap, continuous, and structural. They complement each other, but
|
|
78
|
+
only one of them catches the `continue-on-error` that's been silently hiding
|
|
79
|
+
failures since the repo was created.
|
|
80
|
+
|
|
81
|
+
| | AI code review (Copilot, etc.) | **Mjölnir** |
|
|
82
|
+
| ------------------------------------- | :----------------------------: | :-------------------------: |
|
|
83
|
+
| Cost per scan | Tokens (scales with diff size) | **Zero** (local, installed) |
|
|
84
|
+
| Sees the whole suite + all CI configs | Only the PR diff you show it | **Everything, every time** |
|
|
85
|
+
| Deterministic (same input → same out) | ❌ (non-deterministic) | **✅** |
|
|
86
|
+
| Catches patterns dormant for months | Only if it's in the context | **✅** (scans all files) |
|
|
87
|
+
| Remembers findings between runs | ❌ (no memory across sessions) | **✅** (baseline + diff) |
|
|
88
|
+
| Runs without human triggering | Needs a PR or prompt | **✅** (CI hook, 3 seconds) |
|
|
89
|
+
| Attention budget | Limited by context window | **Unlimited** (every file) |
|
|
90
|
+
|
|
91
|
+
**The honest answer:** Use both. AI catches nuance, intent, and design flaws
|
|
92
|
+
that no regex can find. Mjölnir catches the structural patterns that AI
|
|
93
|
+
overlooks because they look "intentional" — a committed `.only`, a swallowed
|
|
94
|
+
exit code, a `continue-on-error` on a test job. Those aren't bugs that need
|
|
95
|
+
reasoning; they're facts that need scanning. And scanning is what a
|
|
96
|
+
deterministic tool does better, faster, and for free.
|
|
60
97
|
|
|
61
98
|
---
|
|
62
99
|
|
|
63
100
|
## ⚡ Quickstart
|
|
64
101
|
|
|
102
|
+
**The product is one command in CI:**
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx mjolnir-qa@latest --scope changed
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
It scans the test files, Playwright configs and CI workflows touched in the
|
|
109
|
+
branch, and exits non-zero when it finds new problems. Drop that in a PR check
|
|
110
|
+
(`mjolnir ci install` writes the workflow) and you're done. Everything below is
|
|
111
|
+
optional.
|
|
112
|
+
|
|
113
|
+
Run it with no flags for a full-repo report and a WORTHINESS score:
|
|
114
|
+
|
|
65
115
|
```bash
|
|
66
116
|
npx mjolnir-qa@latest
|
|
67
117
|
```
|
|
68
118
|
|
|
69
|
-
|
|
70
|
-
tests, and reports.
|
|
71
|
-
|
|
72
|
-
| Command | What it does |
|
|
73
|
-
| ------------------------------------------------------ | ------------------------------------------------------------------- |
|
|
74
|
-
| `npx mjolnir-qa@latest --scope changed` | Only findings introduced by **your** changes — perfect for PRs |
|
|
75
|
-
| `npx mjolnir-qa@latest --json` | Machine-readable output |
|
|
76
|
-
| `npx mjolnir-qa@latest --format sarif > mjolnir.sarif` | GitHub Code Scanning integration |
|
|
77
|
-
| `npx mjolnir-qa@latest --format mermaid` | Test-architecture diagram — paste into a GitHub comment or a slide |
|
|
78
|
-
| `mjolnir doctor:playwright` | Playwright-only deep scan + Selector Health Score |
|
|
79
|
-
| `mjolnir forensics ./test-results/` | Runtime evidence — retries, true flakes, `FLAKY.md` artifact |
|
|
80
|
-
| `mjolnir triage ./test-results/` | The flaky-triage meeting, in 10 minutes instead of 45 |
|
|
81
|
-
| `mjolnir fix --dry-run` / `fix` | Safe auto-fixes with proof (dry-run first) |
|
|
82
|
-
| `mjolnir debt` | Test debt register — presentable to management |
|
|
83
|
-
| `mjolnir handover` | New-QA-onboarding map of the suite |
|
|
84
|
-
| `mjolnir pw-report ./test-results/` | Playwright run summary — retries / flakes / slowest |
|
|
85
|
-
| `mjolnir badge` | Evidentiary badge (shields.io endpoint JSON) |
|
|
86
|
-
| `mjolnir doctor` | Self-audit — prove Mjölnir's own rule base is worthy |
|
|
87
|
-
| `mjolnir rules` / `rules --md` | Rule catalog with trust metadata (JSON or markdown) |
|
|
88
|
-
| `mjolnir explain <RULE-ID>` | What/why/fix for one rule, with a real example from its own fixture |
|
|
89
|
-
| `mjolnir impact [--since <ref>]` | What changed since a prior commit — fixes and new debt |
|
|
119
|
+
### Everyday
|
|
90
120
|
|
|
91
|
-
|
|
121
|
+
| Command | What it does |
|
|
122
|
+
| ----------------------------------- | ------------------------------------------------ |
|
|
123
|
+
| `mjolnir --scope changed` | Only what your branch introduced — the CI form |
|
|
124
|
+
| `mjolnir` | Full-repo scan + WORTHINESS score |
|
|
125
|
+
| `mjolnir --json` / `--format sarif` | Machine-readable / GitHub Code Scanning |
|
|
126
|
+
| `mjolnir ci install` | Generate the advisory PR workflow |
|
|
127
|
+
| `mjolnir explain <RULE-ID>` | What/why/fix + measured FP rate for one rule |
|
|
128
|
+
| `mjolnir rules --unmeasured` | The rules running on assumption, not measurement |
|
|
129
|
+
| `mjolnir --strict` | Also run quarantine-tier rules (higher FP risk) |
|
|
92
130
|
|
|
93
|
-
|
|
131
|
+
### When something's flaky
|
|
94
132
|
|
|
95
|
-
|
|
96
|
-
|
|
133
|
+
| Command | What it does |
|
|
134
|
+
| ----------------------------------- | --------------------------------------------------- |
|
|
135
|
+
| `mjolnir forensics ./test-results/` | Real run data → `TRUE-FLAKE` verdicts, `FLAKY.md` |
|
|
136
|
+
| `mjolnir triage ./test-results/` | Quarantine proposal from execution history |
|
|
137
|
+
| `mjolnir pw-report ./test-results/` | Playwright run summary — retries / flakes / slowest |
|
|
138
|
+
| `mjolnir doctor:playwright` | Playwright-only deep scan + Selector Health Score |
|
|
97
139
|
|
|
98
|
-
|
|
99
|
-
|
|
140
|
+
<details>
|
|
141
|
+
<summary><strong>Occasional / reporting</strong></summary>
|
|
142
|
+
|
|
143
|
+
| Command | What it does |
|
|
144
|
+
| -------------------------------- | ------------------------------------------------ |
|
|
145
|
+
| `mjolnir fix --dry-run` / `fix` | Safe auto-fixes with proof |
|
|
146
|
+
| `mjolnir baseline` / `diff` | Snapshot findings, then report only new/worsened |
|
|
147
|
+
| `mjolnir impact [--since <ref>]` | What changed since a prior commit |
|
|
148
|
+
| `mjolnir debt` | Test-debt register with a cost model |
|
|
149
|
+
| `mjolnir handover` | New-QA onboarding map of the suite |
|
|
150
|
+
| `mjolnir stats` | Local all-time counters of fixes seen |
|
|
151
|
+
| `mjolnir badge` | shields.io endpoint JSON + snippet |
|
|
152
|
+
| `mjolnir rules` / `rules --md` | Full rule catalog (JSON or Markdown) |
|
|
153
|
+
| `mjolnir doctor` | Self-audit of Mjölnir's own rule base |
|
|
154
|
+
| `mjolnir create-rule <ID>` | Scaffold a new rule + fixtures |
|
|
155
|
+
| `mjolnir --format mermaid` | Test-architecture diagram for a PR comment |
|
|
100
156
|
|
|
101
|
-
|
|
157
|
+
</details>
|
|
102
158
|
|
|
103
|
-
|
|
104
|
-
+8 pts QA-CI-001 · .github/workflows/ci.yml:48
|
|
105
|
-
+3 pts QA-TEST-004 · e2e/checkout.spec.ts:6
|
|
106
|
-
```
|
|
159
|
+
---
|
|
107
160
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
161
|
+
## ⚖️ Worthiness Score
|
|
162
|
+
|
|
163
|
+
<p align="center">
|
|
164
|
+
<img src="assets/readme/terminal-hero.svg" alt="Mjölnir terminal output — WORTHINESS 67/100 NEEDS WORK, a diagnostics-by-category breakdown, and a FIX THIS FIRST list" width="760" />
|
|
165
|
+
</p>
|
|
166
|
+
|
|
167
|
+
<sub>Real output of `npx mjolnir-qa ./examples/demo-repo` in this repo. Regenerated by `npm run docs:hero`; [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts) fails CI if it drifts from what the reporter actually prints.</sub>
|
|
168
|
+
|
|
169
|
+
The score is transparent: error −8, warning −3, info −1, then normalized by
|
|
170
|
+
suite exposure (deductions per test declaration). Evidence-weighted deductions
|
|
171
|
+
mean weak signals cost less. The terminal shows the same discounted numbers the
|
|
172
|
+
score uses — no black box.
|
|
111
173
|
|
|
112
174
|
**Verdicts:**
|
|
113
175
|
|
|
@@ -117,6 +179,29 @@ numbers the score uses — no black box.
|
|
|
117
179
|
| 50 – 79 | ⚠ **NEEDS WORK** |
|
|
118
180
|
| < 50 | ✖ **UNWORTHY** |
|
|
119
181
|
|
|
182
|
+
**Evidence Levels:**
|
|
183
|
+
|
|
184
|
+
Every finding carries an evidence level that determines its weight in the score:
|
|
185
|
+
|
|
186
|
+
| Level | Meaning | Score impact | Example |
|
|
187
|
+
| ----- | -------------------- | ---------------- | ---------------------------------------------------------------------------------- |
|
|
188
|
+
| E2 | Deterministic defect | Full deduction | `.only` committed — structurally provable; downgraded to E1 when confidence is low |
|
|
189
|
+
| E1 | Heuristic pattern | Half deduction | Regex-matched `sleep()` — strong signal, not proof |
|
|
190
|
+
| E0 | Observation | Zero (info only) | Reported but never gates CI or deducts |
|
|
191
|
+
|
|
192
|
+
Most rules are **E1** (heuristic). The tagline "we prove it" refers to this
|
|
193
|
+
evidence-level system — deterministic findings (E2) are structural proof;
|
|
194
|
+
heuristic findings (E1) are correctly-positioned warnings, not formal proofs.
|
|
195
|
+
|
|
196
|
+
**How much of this is measured.** 15 of 91 rules carry a false-positive rate
|
|
197
|
+
measured against real OSS code (≥ 10 hand-classified findings each; see
|
|
198
|
+
[docs/FP-AUDIT.md](docs/FP-AUDIT.md)). The other 76 ship on the author's
|
|
199
|
+
estimate. Every scan footer tells you how many of the rules that _fired_ are
|
|
200
|
+
measured; `mjolnir rules --unmeasured` lists the ones that aren't; every rule's
|
|
201
|
+
`mjolnir explain` page states its status. We publish the rate even when it's
|
|
202
|
+
ugly — QA-JV-103 audits at 50% and is quarantined for it. Growing that 15
|
|
203
|
+
is the project's main open work.
|
|
204
|
+
|
|
120
205
|
---
|
|
121
206
|
|
|
122
207
|
## 📋 The Rules
|
|
@@ -194,9 +279,49 @@ firewall.
|
|
|
194
279
|
| QA-PY-010 | Random/time dependence without freeze | warning |
|
|
195
280
|
| QA-PY-012 | Tautological assertion | error |
|
|
196
281
|
|
|
282
|
+
20 Python rules total (QA-PY-001…012 pytest hygiene + QA-PY-101…108 Playwright-Python).
|
|
283
|
+
|
|
197
284
|
</details>
|
|
198
285
|
|
|
199
|
-
>
|
|
286
|
+
<details>
|
|
287
|
+
<summary><strong>Java / JUnit · TestNG ☕</strong></summary>
|
|
288
|
+
|
|
289
|
+
| ID | Rule | Severity |
|
|
290
|
+
| --------- | ---------------------------------------- | -------- |
|
|
291
|
+
| QA-JV-101 | Disabled test (`@Disabled`) | warning |
|
|
292
|
+
| QA-JV-102 | Hard sleep (`Thread.sleep()`) | warning |
|
|
293
|
+
| QA-JV-103 | Test method with no assertions | error |
|
|
294
|
+
| QA-JV-105 | Playwright `waitForTimeout()` hard sleep | warning |
|
|
295
|
+
| QA-JV-106 | Brittle selector instead of role locator | warning |
|
|
296
|
+
| QA-JV-108 | Hardcoded environment URL in test | warning |
|
|
297
|
+
| QA-JV-111 | Blanket `page.route("**")` mock | warning |
|
|
298
|
+
|
|
299
|
+
</details>
|
|
300
|
+
|
|
301
|
+
<details>
|
|
302
|
+
<summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
|
|
303
|
+
|
|
304
|
+
| ID | Rule | Severity |
|
|
305
|
+
| --------- | ------------------------------------------ | -------- |
|
|
306
|
+
| QA-CS-101 | Skipped test (`[Ignore]`, `[Fact(Skip=)]`) | warning |
|
|
307
|
+
| QA-CS-102 | Hard sleep (`Thread.Sleep` / `Task.Delay`) | warning |
|
|
308
|
+
| QA-CS-103 | Test method with no assertions | error |
|
|
309
|
+
| QA-CS-105 | `WaitForTimeoutAsync()` hard sleep | warning |
|
|
310
|
+
| QA-CS-106 | Brittle selector instead of role locator | warning |
|
|
311
|
+
| QA-CS-108 | Hardcoded environment URL in test | warning |
|
|
312
|
+
| QA-CS-111 | Blanket `page.RouteAsync("**")` mock | warning |
|
|
313
|
+
|
|
314
|
+
</details>
|
|
315
|
+
|
|
316
|
+
**Rule tiers.** Every rule is `core`, `extended`, or `quarantine`, assigned from
|
|
317
|
+
its **measured** false-positive rate ([docs/FP-AUDIT.md](docs/FP-AUDIT.md)):
|
|
318
|
+
`core` ≤ 10 % FP, `extended` ≤ 30 %, `quarantine` above that or not yet measured.
|
|
319
|
+
The default scan runs core + extended; `--strict` adds quarantine. The Java and
|
|
320
|
+
C# families are newer and mostly `extended`/`quarantine` today — they ship,
|
|
321
|
+
they're documented, and they stay out of the headline number until a real
|
|
322
|
+
consumer suite (not a binding-library's own tests) has been audited.
|
|
323
|
+
|
|
324
|
+
> The full live catalog — every rule with tier, confidence, false-positive risk,
|
|
200
325
|
> and autofix availability — is generated from the registry:
|
|
201
326
|
>
|
|
202
327
|
> ```bash
|
|
@@ -285,6 +410,10 @@ Or wire it into GitHub Code Scanning natively via SARIF:
|
|
|
285
410
|
- **FP firewall** — detection runs on a comment/string-free view of the code
|
|
286
411
|
(TypeScript rules use the compiler AST): a pattern inside a prose comment
|
|
287
412
|
or a doc-example string is documentation, not a finding.
|
|
413
|
+
- **Measured, not asserted** — 15 of 91 rules carry a false-positive rate from
|
|
414
|
+
real OSS code; the scan footer, `mjolnir rules --unmeasured`, and every
|
|
415
|
+
`mjolnir explain` page tell you which rules are which.
|
|
416
|
+
[docs/FP-AUDIT.md](docs/FP-AUDIT.md) has the numbers, ugly ones included.
|
|
288
417
|
|
|
289
418
|
---
|
|
290
419
|
|
|
@@ -302,10 +431,12 @@ rejected from plugins to prevent spoofing.
|
|
|
302
431
|
## 🔍 Changed-Scope Coverage
|
|
303
432
|
|
|
304
433
|
`--scope changed` attributes findings to lines added in your branch vs the
|
|
305
|
-
merge-base with `main
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
434
|
+
merge-base with `main` (the base branch is `main`; a repo that uses `master`
|
|
435
|
+
or a shallow clone with no merge-base degrades — see below). It covers test
|
|
436
|
+
files (`*.spec.*`, `*.test.*`) plus GitHub workflow files and Playwright
|
|
437
|
+
configs changed in the diff. When the merge-base can't be resolved — shallow
|
|
438
|
+
clone, detached HEAD, non-git target, different default branch — it degrades
|
|
439
|
+
honestly: findings fall back to full-file attribution and the report says so.
|
|
309
440
|
|
|
310
441
|
---
|
|
311
442
|
|
|
@@ -326,7 +457,7 @@ mjolnir/
|
|
|
326
457
|
│ ├── scorer/ # transparent deduction table
|
|
327
458
|
│ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
|
|
328
459
|
│ ├── forensics/ # run-data ingestion · flake verdicts · triage
|
|
329
|
-
│ ├── commands/ #
|
|
460
|
+
│ ├── commands/ # badge · baseline+diff · create-rule · debt · doctor · explain · fix · handover · impact · init · pr-comment · pw-report · rules · stats
|
|
330
461
|
│ └── integrations/ # CI workflow generator
|
|
331
462
|
└── tests/
|
|
332
463
|
├── fixtures/ # must-fire / must-not-fire per rule
|
|
@@ -335,10 +466,16 @@ mjolnir/
|
|
|
335
466
|
|
|
336
467
|
</details>
|
|
337
468
|
|
|
338
|
-
Multi-language by design: adding
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
469
|
+
Multi-language by design: adding an ecosystem (Ruby/RSpec, Go, PHPUnit…) =
|
|
470
|
+
one adapter + its rules. Playwright itself has exactly four official
|
|
471
|
+
language bindings — TypeScript, Python, Java, .NET — and all four have an
|
|
472
|
+
adapter here.
|
|
473
|
+
TypeScript/Playwright uses the compiler AST (ts-morph); Python, Java, and
|
|
474
|
+
C#/.NET run on a shared comment/string-masked regex layer. A tree-sitter
|
|
475
|
+
WASM AST layer for Java and C# exists (`src/engine/tree-sitter-ast.ts`) and
|
|
476
|
+
is the next precision step — it is not yet wired into the synchronous scan
|
|
477
|
+
pipeline. TypeScript/Playwright and Python are the most battle-tested by
|
|
478
|
+
measured false-positive rate; Java and C# are newer (see **Rule tiers** above).
|
|
342
479
|
|
|
343
480
|
---
|
|
344
481
|
|
|
@@ -352,7 +489,7 @@ npx mjolnir-qa@latest
|
|
|
352
489
|
npm i -g mjolnir-qa
|
|
353
490
|
```
|
|
354
491
|
|
|
355
|
-
Requires Node.js ≥ 22.18. Works on Windows, macOS, and Linux.
|
|
492
|
+
Requires Node.js ≥ 22.18 (required by the tsdown bundler for native ESM support). Works on Windows, macOS, and Linux.
|
|
356
493
|
|
|
357
494
|
---
|
|
358
495
|
|
package/dist/cli.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Mjolnir — canonical types (JSON contract v1, schemaVersion 1).
|
|
4
4
|
*
|
|
5
5
|
* STABILITY: This file is public API. Per Product-MVP.txt §24.2:
|
|
6
6
|
* additive changes only within schemaVersion 1; removing or renaming
|
|
@@ -48,6 +48,15 @@ interface Finding {
|
|
|
48
48
|
* Optional in the JSON contract (additive within schemaVersion 1).
|
|
49
49
|
*/
|
|
50
50
|
evidenceLevel?: EvidenceLevel;
|
|
51
|
+
/**
|
|
52
|
+
* Measured false-positive rate (0..1) for the rule that produced this
|
|
53
|
+
* finding, from hand-classified corpus verdicts — present only when the
|
|
54
|
+
* rule has ≥ 10 classified verdicts. Absent means the rule ships on
|
|
55
|
+
* assumption. Additive within schemaVersion 1.
|
|
56
|
+
*/
|
|
57
|
+
measuredFpRate?: number;
|
|
58
|
+
/** Classified (TP+FP) verdicts behind `measuredFpRate`. */
|
|
59
|
+
measuredFpN?: number;
|
|
51
60
|
/** Repo-relative path with forward slashes, regardless of OS. */
|
|
52
61
|
file: string;
|
|
53
62
|
/** 1-based. */
|
|
@@ -84,6 +93,14 @@ interface ScanResult {
|
|
|
84
93
|
frameworkDetectionUnknown: boolean;
|
|
85
94
|
dimensions: DimensionScore[];
|
|
86
95
|
findings: Finding[];
|
|
96
|
+
/** Number of test files scanned (Phase 5 — reporting only). */
|
|
97
|
+
testFileCount?: number;
|
|
98
|
+
/** Test declarations found — the normalization denominator (Phase 5). */
|
|
99
|
+
testDeclarationCount?: number;
|
|
100
|
+
/** Raw deduction total before normalization (Phase 5 — transparency). */
|
|
101
|
+
rawDeductions?: number;
|
|
102
|
+
/** Number of findings suppressed by active config entries (suppression transparency). */
|
|
103
|
+
suppressionCount?: number;
|
|
87
104
|
analysisStatus: {
|
|
88
105
|
discovery: AnalysisStatus;
|
|
89
106
|
rules: AnalysisStatus;
|
|
@@ -93,6 +110,17 @@ interface ScanResult {
|
|
|
93
110
|
}
|
|
94
111
|
//#endregion
|
|
95
112
|
//#region src/cli.d.ts
|
|
113
|
+
/**
|
|
114
|
+
* Tool version for `mjolnir --version`.
|
|
115
|
+
*
|
|
116
|
+
* A literal, not a package.json read: the shipped artifact is a single
|
|
117
|
+
* bundled `dist/cli.mjs`, so resolving package.json at runtime depends on
|
|
118
|
+
* where the file happens to sit after install. This follows the same
|
|
119
|
+
* discipline as SARIF's `driver.version` — kept in sync by
|
|
120
|
+
* `scripts/sync-sarif-version.cjs` on release and guarded by
|
|
121
|
+
* `tests/version-consistency.spec.ts` locally.
|
|
122
|
+
*/
|
|
123
|
+
declare const CLI_VERSION = "0.5.0";
|
|
96
124
|
interface CliArgs {
|
|
97
125
|
target: string;
|
|
98
126
|
json: boolean;
|
|
@@ -106,6 +134,8 @@ interface CliArgs {
|
|
|
106
134
|
ascii?: boolean;
|
|
107
135
|
/** --tone blunt: opt-in blunter messages (Sprint 9 Task 40). */
|
|
108
136
|
tone?: "blunt";
|
|
137
|
+
/** --strict: include quarantine-tier rules in the scan (Phase 4). */
|
|
138
|
+
strict?: boolean;
|
|
109
139
|
}
|
|
110
140
|
declare function parseArgs(argv: string[]): CliArgs | null;
|
|
111
141
|
declare function runScan(args: CliArgs): ScanResult;
|
|
@@ -231,4 +261,4 @@ declare function runPwReportCommand(argv: string[], io?: {
|
|
|
231
261
|
declare function main(argv?: string[]): number;
|
|
232
262
|
declare function isEntryPoint(): boolean;
|
|
233
263
|
//#endregion
|
|
234
|
-
export { Output, isEntryPoint, main, parseArgs, pathMatchesGlob, runBadgeCommand, runBaselineCommand, runCiInstall, runCreateRuleCommand, runDebtCommand, runDiffCommand, runDoctorCommand, runDoctorPlaywright, runExplainCommand, runFixCommand, runForensicsCommand, runHandoverCommand, runImpactCommand, runInitCommand, runPrCommentCommand, runPwReportCommand, runRulesCommand, runScan, runScanCommand, runStatsCommand, runSuppressions, runTriageCommand };
|
|
264
|
+
export { CLI_VERSION, Output, isEntryPoint, main, parseArgs, pathMatchesGlob, runBadgeCommand, runBaselineCommand, runCiInstall, runCreateRuleCommand, runDebtCommand, runDiffCommand, runDoctorCommand, runDoctorPlaywright, runExplainCommand, runFixCommand, runForensicsCommand, runHandoverCommand, runImpactCommand, runInitCommand, runPrCommentCommand, runPwReportCommand, runRulesCommand, runScan, runScanCommand, runStatsCommand, runSuppressions, runTriageCommand };
|