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/CHANGELOG.md
CHANGED
|
@@ -9,29 +9,108 @@ Rule behavior changes (new rules, FP-rate changes against the corpus,
|
|
|
9
9
|
severity changes) are first-class entries here — rule IDs are immutable
|
|
10
10
|
once shipped, so this file is the record of what changed between versions.
|
|
11
11
|
|
|
12
|
-
## [0.
|
|
12
|
+
## [0.5.0] — 2026-08-29
|
|
13
13
|
|
|
14
|
-
###
|
|
14
|
+
### Added — measurement is now visible at the point of use
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
-
|
|
16
|
+
- Only 15 of 91 rules carry a false-positive rate measured against real OSS
|
|
17
|
+
code; that fact previously lived only in `docs/FP-AUDIT.md` and
|
|
18
|
+
`mjolnir doctor`. Now surfaced everywhere a user looks:
|
|
19
|
+
- The scan footer reports how many of the rules that _fired_ are measured.
|
|
20
|
+
- `mjolnir rules --unmeasured` / `--measured` filter the catalog; a new
|
|
21
|
+
"FP (measured)" column in `rules --md`; a "Measured FP rate" row on every
|
|
22
|
+
`docs/rules/` page and in `mjolnir explain`.
|
|
23
|
+
- JSON findings carry `measuredFpRate` and `measuredFpN` (additive —
|
|
24
|
+
`schemaVersion` is still 1).
|
|
25
|
+
- `src/rules/measured-fp.generated.ts` bakes the rates into the shipped
|
|
26
|
+
package (the raw verdicts are not packed); regenerated by
|
|
27
|
+
`npm run fp-audit:generate`, drift-locked by a test, and now the single
|
|
28
|
+
source `mjolnir doctor` reads.
|
|
29
|
+
- Scoring is unchanged — this is visibility only.
|
|
30
|
+
- **Corpus expanded 6 → 13 repos** so the previously-silent rule families
|
|
31
|
+
(QA-TEST, QA-TQUAL, most QA-PW, QA-CI-001) fire on real consumer code:
|
|
32
|
+
added `next-auth`, `vite`, `sveltekit`, `astro`, `TanStack/query`,
|
|
33
|
+
`eslint-plugin-playwright`, `playwright-pytest`. `corpus:sample` and
|
|
34
|
+
`corpus:regression` now scan with `--strict` (quarantine rules were
|
|
35
|
+
invisible to both before). `docs/FP-AUDIT.md` is 15/91 (down from 19 —
|
|
36
|
+
see the dispatch fix below, which retired the leaked cross-language
|
|
37
|
+
verdicts for QA-PW-101/112 and QA-TEST-004/QA-ENV-001 on Java/Python
|
|
38
|
+
repos); the ~250 new corpus findings are queued for classification in
|
|
39
|
+
`tests/corpus/verdicts/`, not counted until read.
|
|
26
40
|
|
|
27
|
-
###
|
|
41
|
+
### Changed — help and README lead with the one command
|
|
28
42
|
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
43
|
+
- `mjolnir --help` and the README quickstart now open with
|
|
44
|
+
`mjolnir --scope changed` as _the_ product, and group the other subcommands
|
|
45
|
+
into Everyday / When-something's-flaky / Occasional instead of a flat list
|
|
46
|
+
of 16 equals. A one-line first-run hint appears after a bare full-repo scan
|
|
47
|
+
with no config. No subcommand removed or renamed.
|
|
33
48
|
|
|
34
|
-
|
|
49
|
+
### Fixed (rule-bug-hunt wave)
|
|
50
|
+
|
|
51
|
+
- **Cross-language dispatch leak**: `appliesTo: "test-files"` mapped to all
|
|
52
|
+
four language adapters, so the 42 TypeScript/Playwright-only rules that
|
|
53
|
+
use it (QA-PW-\*, QA-TEST-\*, QA-TQUAL-\*) ran against `.py`, `.java` and
|
|
54
|
+
`.cs` files too. On the corpus this produced ~140 false positives on
|
|
55
|
+
`microsoft/playwright` Java bindings alone (QA-PW-101, QA-PW-112,
|
|
56
|
+
QA-TEST-004, QA-ENV-001) and inflated several baselines. `legacyAppliesTo`
|
|
57
|
+
now maps `"test-files"` to `["typescript"]` only; cross-language coverage
|
|
58
|
+
is the QA-PY/QA-JV/QA-CS families' job. Regression test added.
|
|
59
|
+
- **QA-PW-103** (missing timeout): no longer fires on assertion strings that
|
|
60
|
+
contain Playwright code as _test data_ (`code: "await page.goto('/x')"` in
|
|
61
|
+
playwright-mcp) — guarded by `isInsideEmbeddedCode`.
|
|
62
|
+
- **QA-TEST-004** (hard sleep): dropped the bare `sleep(N)` pattern and now
|
|
63
|
+
requires `await` and a non-zero argument. `sleep(10).then(...)` and
|
|
64
|
+
`queryFn: () => sleep(10)` are mock-latency, not test-body pauses — this
|
|
65
|
+
cut TanStack Query's count from 1648 to 157.
|
|
66
|
+
- **QA-PW-002** (unawaited assertion): matches only Playwright's 31
|
|
67
|
+
web-first async matchers instead of any `to*` name, so
|
|
68
|
+
`expect(res.status()).toBe(200)` on a variable named `page` is no longer
|
|
69
|
+
flagged.
|
|
70
|
+
- **QA-TQUAL-009** (assertion in unawaited promise chain): the `.then()`
|
|
71
|
+
callback body is now paren-matched instead of grabbing the next `{`, so a
|
|
72
|
+
sibling `.then(res => res.text())` inside an awaited `Promise.all` no
|
|
73
|
+
longer reaches into an unrelated block; the await/return check also sees
|
|
74
|
+
an `await` sitting one line above the `.then(`.
|
|
75
|
+
|
|
76
|
+
### Fixed (rule-bug-hunt wave 2 — CI + Python + order-dependence)
|
|
77
|
+
|
|
78
|
+
- **QA-CI-002** (`|| true` swallows exit code): only fires now when the
|
|
79
|
+
swallowed command is a verification gate. `docker compose down || true`,
|
|
80
|
+
`pkill … || true`, `rm -rf … || true` are ordinary teardown — flagging
|
|
81
|
+
them as FALSE-GREEN was wrong. Gate detection is now shared with QA-CI-001
|
|
82
|
+
(`src/rules/ci/verification-gate.ts`).
|
|
83
|
+
- **QA-CI-009** (exit code not propagated): `playwright` alone was treated as
|
|
84
|
+
a test command, so `npx playwright install --with-deps; npx playwright
|
|
85
|
+
test` (install first, test last) was flagged even though the test's exit
|
|
86
|
+
code IS the step's. Now requires `playwright test`, and skips any
|
|
87
|
+
`setup; <test>` sequence where the test command runs last.
|
|
88
|
+
- **QA-CI-010** (tests skipped where they must block): the condition matcher
|
|
89
|
+
used `[!=]=`, which also matched `==` — so `if: github.event_name ==
|
|
90
|
+
'pull_request'` (run **only** on PRs) was flagged as _skipping_ tests on
|
|
91
|
+
PRs. Now `!=` only, plus positive matches on `== 'push'` / `'schedule'` /
|
|
92
|
+
`'workflow_dispatch'`.
|
|
93
|
+
- **QA-PY-012** (tautological assertion): the patterns lacked the `g` flag,
|
|
94
|
+
so `regex.exec()` never advanced — only the **first** `assert True` and the
|
|
95
|
+
first `assert x == x` in a file were reported; every later one was missed
|
|
96
|
+
(and the loop spun to its 1000-iteration guard each time). Fixed; corpus
|
|
97
|
+
count rose 4 → 5 as the previously-missed assertions surfaced.
|
|
98
|
+
- **QA-PY-009** (commented-out test): `# main()` in a comment ("call main()
|
|
99
|
+
here") was flagged as a disabled test. The `main(` pattern now requires
|
|
100
|
+
the `pytest.main` namespace.
|
|
101
|
+
- **QA-PW-119** (order dependence): three bugs. (1) `let [a, b] = …` /
|
|
102
|
+
`let { page } = …` destructuring was split on `,` into junk names like
|
|
103
|
+
`[a` that were interpolated into `new RegExp(…)` — a crash risk; it is now
|
|
104
|
+
skipped. (2) typed module-level `let x: Foo<T> = …` was invisible to the
|
|
105
|
+
declaration regex (the `<>` broke it) and is now detected. (3) a `before*`
|
|
106
|
+
hook with a destructured param — `beforeEach(async ({ page }) => {` — had
|
|
107
|
+
its body located at the _param_ brace, so assignments in the hook body
|
|
108
|
+
were treated as in-test and flagged; corpus count dropped 45 → 11 on the
|
|
109
|
+
worst-affected repo.
|
|
110
|
+
- **QA-PW-116** (storageState without expiry): the canonical Playwright auth
|
|
111
|
+
pattern — a `setup` project / `*.setup.ts` / `globalSetup` regenerating
|
|
112
|
+
the state each run — is now recognised as a freshness mechanism, not
|
|
113
|
+
flagged.
|
|
35
114
|
|
|
36
115
|
### Fixed (adversarial-audit hardening wave)
|
|
37
116
|
|
|
@@ -54,7 +133,7 @@ once shipped, so this file is the record of what changed between versions.
|
|
|
54
133
|
- **JSON/SARIF truncation removed**: results were silently capped at 50
|
|
55
134
|
findings, including machine consumers. The full finding set is now in
|
|
56
135
|
JSON/SARIF; only terminal display is capped (with an honest count).
|
|
57
|
-
- **`
|
|
136
|
+
- **`mjolnir fix` path containment**: plugin-supplied finding paths can
|
|
58
137
|
no longer write outside the scan root (`../` traversal refused).
|
|
59
138
|
- **Symlinks are no longer followed** during test-file discovery in any
|
|
60
139
|
adapter — prevents scanning outside the repo and link cycles.
|
|
@@ -62,6 +141,80 @@ once shipped, so this file is the record of what changed between versions.
|
|
|
62
141
|
(`QA-JV`, `QA-CS`, `QA-PLUGIN`).
|
|
63
142
|
- `doctor:playwright` bad-usage exit code unified to 10 (was 2).
|
|
64
143
|
|
|
144
|
+
### Fixed — false positives confirmed by reading source, each locked by a fixture
|
|
145
|
+
|
|
146
|
+
Every entry below was verified by opening the cited file and reading the
|
|
147
|
+
surrounding code, not inferred from the rule's description. Each is now locked
|
|
148
|
+
by a `must-not-fire` fixture so the class cannot return silently.
|
|
149
|
+
|
|
150
|
+
- **QA-TQUAL-011** matched a test identifier anywhere inside a comment block,
|
|
151
|
+
so any JSDoc header containing the sequence `test (` fired. Confirmed on
|
|
152
|
+
`tests/package-smoke.spec.ts:2` — `* Package publish integrity smoke test
|
|
153
|
+
(Test Hardening Plan, P0 #2).` Now requires the identifier to be the first
|
|
154
|
+
token on the commented line. Locks:
|
|
155
|
+
`tests/fixtures/QA-TQUAL-011/must-not-fire/prose-mentioning-test.spec.ts`.
|
|
156
|
+
- **QA-PW-004** fired on selectors passed as arguments to the function under
|
|
157
|
+
test. Confirmed on `tests/selector-health.spec.ts:33` —
|
|
158
|
+
`expect(classifyLocator("page.locator('xpath=//div')")).toBe("xpath")`. The
|
|
159
|
+
rule must read raw text to see selector content, so masking cannot fix it;
|
|
160
|
+
it now consults `codeText` as an oracle about the match position instead.
|
|
161
|
+
Locks: `tests/fixtures/QA-PW-004/must-not-fire/selector-as-argument.spec.ts`.
|
|
162
|
+
- **QA-ENV-001**, **QA-PW-123**, **QA-PW-142** fired on code samples embedded
|
|
163
|
+
in strings as test data. Confirmed on
|
|
164
|
+
`tests/rule-sprint8-java-csharp.spec.ts` lines 147, 157, 603 — e.g.
|
|
165
|
+
`text: 'page.navigate("http://localhost:3000/checkout")'`. Now skipped when
|
|
166
|
+
the enclosing string literal holds both a nested quote and call syntax.
|
|
167
|
+
Locks: `tests/fixtures/QA-ENV-001/must-not-fire/code-as-test-data.spec.ts`.
|
|
168
|
+
- **QA-CI-001** fired on `continue-on-error` regardless of what the step did.
|
|
169
|
+
Confirmed on this repo's own workflows: `ci.yml:48` (badge artifact
|
|
170
|
+
generation) and `mjolnir.yml:35` (advisory diff, which carries a comment
|
|
171
|
+
explaining that exit 1 is expected there). Now gated on an allowlist of
|
|
172
|
+
verification commands. Locks:
|
|
173
|
+
`tests/fixtures/QA-CI-001/must-not-fire/reporting-steps.yml`.
|
|
174
|
+
|
|
175
|
+
### Fixed — true positive acted on
|
|
176
|
+
|
|
177
|
+
- **QA-TQUAL-001** on `tests/adapters.spec.ts:110` was correct. The test was
|
|
178
|
+
named "counts skipped files on stat failure", its own comment admitted it
|
|
179
|
+
could not simulate a stat failure, it asserted the skip callback was _not_
|
|
180
|
+
called, and it never asserted on `ctx.testFiles` — the actual output of
|
|
181
|
+
`discoverTestFiles`. The test was rewritten to assert on real output and
|
|
182
|
+
renamed to match what it verifies. The rule was left unchanged.
|
|
183
|
+
|
|
184
|
+
### Changed — BREAKING: scoring
|
|
185
|
+
|
|
186
|
+
- **Normalization denominator is now test declarations, not test files.**
|
|
187
|
+
File count was gameable: adding empty spec files raised the score without
|
|
188
|
+
adding verification.
|
|
189
|
+
- **`SMOOTHING_C` is 1 (Laplace), was 5.** At 5 it tripled the denominator of a
|
|
190
|
+
two-declaration repo, diluting real density away.
|
|
191
|
+
- **Findings may declare `suiteInvalidating: true`**, capping the score at 49
|
|
192
|
+
(UNWORTHY) regardless of exposure. Density can express how much of a suite is
|
|
193
|
+
questionable; it cannot express whether the suite ran at all. Applied to
|
|
194
|
+
QA-TEST-001 and QA-PY-001. Deliberately not applied to QA-PW-003, which
|
|
195
|
+
detects both `test.only()` and `page.pause()` — the flag is per-rule.
|
|
196
|
+
- **A score of 100 now requires zero deductions.** Normalization could
|
|
197
|
+
previously round a real finding up to a perfect score.
|
|
198
|
+
- `NORMALIZATION_K` remains **unfitted**. See `docs/SCORING.md`.
|
|
199
|
+
|
|
200
|
+
### Changed — QA-CI-001 severity
|
|
201
|
+
|
|
202
|
+
- Step-level `continue-on-error` findings are now `error`, previously `warning`.
|
|
203
|
+
The self-scan gate filters on `severity === "error"`, so a warning could never
|
|
204
|
+
fail CI — which is how `continue-on-error` stayed live in this repo's own
|
|
205
|
+
workflows while the tool reported zero errors.
|
|
206
|
+
- Title broadened to "continue-on-error masks a failing verification gate",
|
|
207
|
+
accurate to the allowlist now used.
|
|
208
|
+
|
|
209
|
+
### Removed
|
|
210
|
+
|
|
211
|
+
- **All 49 FABRICATED verdicts removed.** They had been produced by reasoning
|
|
212
|
+
about what each rule's description implied rather than by reading the source
|
|
213
|
+
at the cited file and line — fabricated evidence with a real-looking
|
|
214
|
+
provenance, inside the mechanism built to prevent exactly that.
|
|
215
|
+
Subsequently, 381 verdicts were classified from real source reading via
|
|
216
|
+
corpus:sample (see docs/FP-AUDIT.md).
|
|
217
|
+
|
|
65
218
|
### Changed (adversarial-audit hardening wave)
|
|
66
219
|
|
|
67
220
|
- QA-TQUAL-002 and QA-PW-004 detection now runs on a comment-stripped /
|
|
@@ -79,7 +232,7 @@ once shipped, so this file is the record of what changed between versions.
|
|
|
79
232
|
- Upgrade-Plan-v3 Phase 0.1: expanded the false-positive corpus with two
|
|
80
233
|
additional Python repos (`pytest-dev/pytest`, `psf/requests`) so all
|
|
81
234
|
QA-PY-001..012 rules are exercised against real code via
|
|
82
|
-
`npm run corpus:
|
|
235
|
+
`npm run corpus:regression`.
|
|
83
236
|
- Added `CHANGELOG.md` (this file) per Upgrade-Plan-v3 critical item #3:
|
|
84
237
|
user-visible rule behavior changes get a first-class entry from now on.
|
|
85
238
|
- Upgrade-Plan-v3 Phase 1: five new TypeScript/Playwright rules —
|
|
@@ -93,24 +246,20 @@ once shipped, so this file is the record of what changed between versions.
|
|
|
93
246
|
QA-PY-104 (brittle selectors), QA-PY-105 (UI-driving test without
|
|
94
247
|
assertions), QA-PY-106 (shared page/context across tests), QA-PY-107
|
|
95
248
|
(`networkidle` wait), QA-PY-108 (hardcoded environment URLs).
|
|
96
|
-
|
|
97
249
|
- Upgrade-Plan-v3 Phase 6: Plugin API — declare third-party rule packages
|
|
98
|
-
in `
|
|
250
|
+
in `mjolnir.config.json` (`"plugins": [...]`). Security model: no
|
|
99
251
|
sandbox (same trust as ESLint/Vitest plugins); reserved core rule-ID
|
|
100
252
|
prefixes rejected; load failures degrade honestly as QA-PLUGIN-000
|
|
101
253
|
warnings without affecting exit codes. Plus cross-file duplicate-test-name
|
|
102
254
|
detection (`src/engine/cross-file.ts`).
|
|
103
|
-
|
|
104
|
-
- Upgrade-Plan-v3 Phase 0.2: new `@qa-doctor/playwright-reporter` package
|
|
255
|
+
- Upgrade-Plan-v3 Phase 0.2: new `mjolnir-qa-playwright-reporter` package
|
|
105
256
|
(`packages/playwright-reporter/`) — official Playwright JSON reporter
|
|
106
|
-
wrapper for
|
|
107
|
-
`
|
|
108
|
-
|
|
257
|
+
wrapper for Mjölnir's forensics pipeline; default output
|
|
258
|
+
`mjolnir.report.json` is the CLI's auto-discovery convention.
|
|
109
259
|
- Upgrade-Plan-v3 Phase 3: ts-morph AST precision layer behind the `ast`
|
|
110
260
|
seam (`src/engine/ts-ast.ts`). QA-PW-002 and QA-PW-005 migrated from
|
|
111
261
|
regex to syntax-tree detection (legacy regex kept as fallback). No
|
|
112
262
|
scoring changes — golden lock byte-identical.
|
|
113
|
-
|
|
114
263
|
- Upgrade-Plan-v3 Phases 4+5: new language adapters — Java
|
|
115
264
|
(`src/adapters/java.ts`, rules QA-JV-101..105) and C#/.NET
|
|
116
265
|
(`src/adapters/csharp.ts`, rules QA-CS-101..104). Core Playwright rule
|
|
@@ -118,6 +267,88 @@ once shipped, so this file is the record of what changed between versions.
|
|
|
118
267
|
shared browser state, wait-timeout misuse. Rule-ID registry now accepts
|
|
119
268
|
QA-JV/QA-CS families.
|
|
120
269
|
|
|
270
|
+
### Changed — rule tiers assigned from measured FP rates
|
|
271
|
+
|
|
272
|
+
- Every rule with a measured rate in `docs/FP-AUDIT.md` now carries the tier
|
|
273
|
+
its rate warrants (`core` ≤ 10% FP · `extended` ≤ 30% · `quarantine` above
|
|
274
|
+
that or unmeasured). Demoted to quarantine: QA-CS-102, QA-CS-106, QA-CS-108,
|
|
275
|
+
QA-CS-111, QA-ENV-001, QA-JV-103, QA-JV-106, QA-JV-108, QA-JV-111,
|
|
276
|
+
QA-PY-004, QA-PY-006, QA-PY-007. Set to extended: QA-CS-105, QA-TEST-004.
|
|
277
|
+
Promoted to core: QA-CS-101 (0% FP, n=20), QA-JV-105 (10% FP, n=20).
|
|
278
|
+
Quarantined rules still ship and are still documented — they are opt-in via
|
|
279
|
+
`--strict` rather than shaping the default report.
|
|
280
|
+
- `mjolnir rules` (`--json` and `--md`) now exposes each rule's `tier`, and
|
|
281
|
+
every generated page under `docs/rules/` shows it in the metadata table.
|
|
282
|
+
|
|
283
|
+
### Fixed — documentation claims a `grep` disproved
|
|
284
|
+
|
|
285
|
+
- Every generated rule page told the reader to reproduce corpus counts with
|
|
286
|
+
a `corpus:audit` script. That script had been renamed to `corpus:regression` in
|
|
287
|
+
the Tempering plan and the generator string was never updated — the command
|
|
288
|
+
printed on 91 published pages did not exist. Same dead name in
|
|
289
|
+
`docs/PUBLISHING.md`
|
|
290
|
+
(`corpus:audit:update` → `corpus:regression:update`).
|
|
291
|
+
- **`docs/FP-AUDIT.md` under-reported the rule base as 84 rules when the
|
|
292
|
+
registry holds 91.** The coverage denominator was built by grepping source
|
|
293
|
+
for `id: "QA-…"`, which silently missed the seven rules that the Phase 6
|
|
294
|
+
families declare as positional factory arguments — QA-CS-106/110/111,
|
|
295
|
+
QA-JV-106/110/111 and QA-PY-104, every one of them Java/C#/Python. The
|
|
296
|
+
honesty document was quietly shrinking the newest adapters' coverage. The
|
|
297
|
+
generator now imports the registry directly (and is TypeScript, so the
|
|
298
|
+
`.d.mts` shim is gone); a regression test locks the denominator to
|
|
299
|
+
`RULES.length`.
|
|
300
|
+
- `docs/README.md` described a `docs/plans/` directory that no longer exists
|
|
301
|
+
and called a completed plan "current work".
|
|
302
|
+
- Residual `qa-doctor` naming removed from user-facing CLI output
|
|
303
|
+
(`mjolnir explain`, `mjolnir stats`), from comments that contradicted the
|
|
304
|
+
code they described (`baseline.ts` cited `.qa-doctor/` while writing
|
|
305
|
+
`.mjolnir/`), and from this changelog's own unreleased section.
|
|
306
|
+
- The Playwright reporter package is renamed throughout:
|
|
307
|
+
`mjolnirReporter` / `MJOLNIR_REPORT_FILE` / `mjolnir.report.json`. The
|
|
308
|
+
package is unpublished, so no consumer breaks.
|
|
309
|
+
|
|
310
|
+
### Added — guards
|
|
311
|
+
|
|
312
|
+
- CI now runs `npm run test:coverage`. Its absence is why coverage fell from
|
|
313
|
+
~96% to 92.6% between releases without anyone noticing.
|
|
314
|
+
- `tests/docs-consistency.spec.ts` now asserts that every `npm run <script>`
|
|
315
|
+
referenced in tracked docs and source actually exists in `package.json` —
|
|
316
|
+
the general fix for the dead-command class above, not a one-off patch.
|
|
317
|
+
- ~130 unit tests recovering branch coverage on the code-text maskers, the
|
|
318
|
+
shared position helpers, ignore-pattern resolution, and the per-arm
|
|
319
|
+
behavior of ten Playwright rules plus QA-PY-010.
|
|
320
|
+
|
|
321
|
+
### Known gaps
|
|
322
|
+
|
|
323
|
+
- **19 of 91 rules carry a measured FP rate** (n ≥ 10, from 381 hand-classified
|
|
324
|
+
corpus verdicts). The other 72 ship on an unverified assumption; `mjolnir
|
|
325
|
+
doctor` reports this and will fail once a majority is classified.
|
|
326
|
+
- `NORMALIZATION_K` is unfitted.
|
|
327
|
+
- Statements/branches coverage sits at 94.8%/87.7% against a 95/88 aspiration;
|
|
328
|
+
the enforced floor is 94/87 with the gap documented in `.planning/STATE.md`.
|
|
329
|
+
|
|
330
|
+
## [0.4.0] — 2026-08-27
|
|
331
|
+
|
|
332
|
+
### Changed
|
|
333
|
+
|
|
334
|
+
- **BREAKING: Rebranded from QA Doctor to Mjölnir.** Package name is now
|
|
335
|
+
`mjolnir-qa` (bin: `mjolnir`). Config file: `mjolnir.config.json`.
|
|
336
|
+
Data directory: `.mjolnir/`. Badge: `mjolnir-badge.json`.
|
|
337
|
+
- Score label: "SCORE" → "WORTHINESS".
|
|
338
|
+
- Verdicts: "HEALTHY" → "WORTHY", "CRITICAL" → "UNWORTHY".
|
|
339
|
+
- Environment variable: `QA_DOCTOR_ASCII` → `MJOLNIR_ASCII`.
|
|
340
|
+
- SARIF tool.driver.name: "Mjölnir".
|
|
341
|
+
- Repository: `github.com/Sergey-Bar/Mjolnir`.
|
|
342
|
+
- CLI: all help text, error messages, usage strings reference `mjolnir`.
|
|
343
|
+
- Generated workflows: `mjolnir.yml`, `npx mjolnir-qa@latest`.
|
|
344
|
+
|
|
345
|
+
### Added
|
|
346
|
+
|
|
347
|
+
- `--format mermaid` — test-architecture diagram (Sprint 9).
|
|
348
|
+
- `--tone blunt` — opt-in blunter messages (Sprint 9).
|
|
349
|
+
- Milestones — first flawless scan / first debt reduction announced once.
|
|
350
|
+
- New MJÖLNIR ASCII art logo (minimal Nordic hammer).
|
|
351
|
+
|
|
121
352
|
## [0.3.x] — prior releases
|
|
122
353
|
|
|
123
354
|
See git history; per-rule Trust Metadata `introduced` fields record the
|