mjolnir-qa 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +360 -6
- package/README.ar.md +58 -29
- package/README.bn.md +58 -29
- package/README.br.md +58 -29
- package/README.bs.md +58 -29
- package/README.da.md +59 -30
- package/README.de.md +59 -30
- package/README.es.md +58 -29
- package/README.fr.md +59 -30
- package/README.gr.md +58 -29
- package/README.he.md +58 -29
- package/README.it.md +58 -29
- package/README.ja.md +58 -29
- package/README.ko.md +58 -29
- package/README.md +95 -56
- package/README.no.md +58 -29
- package/README.pl.md +58 -29
- package/README.ru.md +58 -29
- package/README.th.md +58 -29
- package/README.tr.md +58 -29
- package/README.uk.md +58 -29
- package/README.vi.md +58 -29
- package/README.zh.md +58 -29
- package/README.zht.md +58 -29
- package/dist/cli.d.mts +218 -14
- package/dist/cli.mjs +1410 -883
- package/dist/mcp/stdio.mjs +1072 -408
- package/dist/scan-pipeline-Bg-46cLS.mjs +2 -0
- package/dist/{scan-pipeline-CAH9_Qgh.mjs → scan-pipeline-CCJdEKNa.mjs} +1443 -809
- package/package.json +52 -8
- package/dist/scan-pipeline-CRe7-MQn.mjs +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -11,12 +11,330 @@ once shipped, so this file is the record of what changed between versions.
|
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
### Breaking changes
|
|
15
|
+
|
|
16
|
+
- **`business-case` no longer prints a dollar figure you did not supply.** The
|
|
17
|
+
`--industry` flag selected from a table of invented incident costs (fintech
|
|
18
|
+
$50 000, healthcare $100 000, …) with no source, and the product of that table
|
|
19
|
+
and a measured false-positive rate was printed as "Expected Savings" and
|
|
20
|
+
"Total potential savings". Pass `--incident-cost <n>` to see the arithmetic;
|
|
21
|
+
the measured FP rates, their sample sizes and the evidence weight behind them
|
|
22
|
+
are always shown. `--industry`, `--history` and `--projected` now exit with a
|
|
23
|
+
reason: `--history` read no history despite promising estimates from scan
|
|
24
|
+
improvements, and `--projected` divided the total by six and called the
|
|
25
|
+
quotient a monthly rate.
|
|
26
|
+
- **`enterprise sso` and `enterprise compliance` no longer write files.** They
|
|
27
|
+
wrote an SSO guide instructing readers to add an `sso` block to
|
|
28
|
+
`mjolnir.config.json` — a key nothing reads — and three auditor-facing SOC 2 /
|
|
29
|
+
HIPAA / PCI-DSS templates mapping controls to capabilities this product does
|
|
30
|
+
not have (SSO/SAML integration, a scan "audit trail", a "privacy scan"). Both
|
|
31
|
+
now refuse with a reason. `enterprise config` emits
|
|
32
|
+
`capability-manifest.json`, whose `notProvided` list records the absences
|
|
33
|
+
instead of inventing a deployment.
|
|
34
|
+
- **The evidence descriptor is now the same on every surface.** The HTML and
|
|
35
|
+
Markdown trust reports showed four bare words (`E2 · deterministic`) where the
|
|
36
|
+
terminal showed the full descriptor. They now show
|
|
37
|
+
`[E2 · deterministic · measured FP 8% · n=14 · trust L3 · runtime: file executed]`.
|
|
38
|
+
A finding with no `evidenceLevel` of its own now derives one from its type and
|
|
39
|
+
confidence instead of defaulting to `E2` — the strongest claim the product can
|
|
40
|
+
make, previously asserted for findings nobody had measured.
|
|
41
|
+
- **Unmeasured counts read "unknown — not measured", not `0`.** The trust
|
|
42
|
+
report, the PR comment and the step summary all rendered
|
|
43
|
+
`testDeclarationCount ?? 0` as "0 tests analyzed in 0 files" for a producer
|
|
44
|
+
that had never measured a declaration. The trust-report JSON twin now emits
|
|
45
|
+
`null` for those fields. A zero is a claim; an absent measurement is not.
|
|
46
|
+
- **The dashboard no longer varies between runs of an unchanged repository.**
|
|
47
|
+
The generation timestamp moved out of the visible body into
|
|
48
|
+
`<meta name="mjolnir-generated-at">`, and `--deterministic` omits it entirely
|
|
49
|
+
so the artifact is byte-identical and can be diffed in review.
|
|
50
|
+
- **Score bands are decided in one place.** The dashboard split at 60 while the
|
|
51
|
+
terminal split at 80, so a score the terminal called UNWORTHY rendered amber
|
|
52
|
+
in HTML; the contributor handover used 90; `mermaid.ts` and
|
|
53
|
+
`monorepo-analysis.ts` each carried their own copy. All of them now read
|
|
54
|
+
`src/reporter/presentation.ts`.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **Opt-in Sentry crash reporting.** Set `SENTRY_DSN` and the CLI and the MCP
|
|
59
|
+
stdio server report their own fatal errors — release-tagged as
|
|
60
|
+
`mjolnir-qa@<version>`, tagged by surface, and nothing else: no user data
|
|
61
|
+
(`sendDefaultPii: false`), no traced spans (`tracesSampleRate: 0`), no
|
|
62
|
+
findings or file contents. With no DSN the SDK is never even imported, so the
|
|
63
|
+
default install gains no dependency, no startup cost, and no network call. A
|
|
64
|
+
tool that reads private repositories must not phone home on its own, so the
|
|
65
|
+
DSN is the only switch. `@sentry/node` is an OPTIONAL peer dependency for the
|
|
66
|
+
same reason: ~1.5 MB that nothing in a code scanner needs. Capture points are
|
|
67
|
+
the two existing top-level catch blocks rather than `uncaughtException` /
|
|
68
|
+
`unhandledRejection` handlers, which would have changed the frozen exit-code
|
|
69
|
+
contract. `npm run sentry:release` creates the release and uploads source maps
|
|
70
|
+
(the build now emits them; the published tarball still excludes them).
|
|
71
|
+
- `npm run report:honesty` — no surface may print a zero for a measurement that
|
|
72
|
+
may be absent. Four reviewed exceptions are recorded for computation inputs,
|
|
73
|
+
each with a reason and a follow-up.
|
|
74
|
+
- `npm run thresholds:parity` — no score-band literal may exist outside the
|
|
75
|
+
threshold registry. It immediately caught a selector-health threshold that
|
|
76
|
+
shared a number with a trust band but not a meaning.
|
|
77
|
+
- `npm run claims:revalidate` — every claim asserted `fixed` must rest on a
|
|
78
|
+
candidate-bound, independent revalidation. It rejects evidence that cites the
|
|
79
|
+
artifact it is meant to prove, and downgrades rather than deleting a claim
|
|
80
|
+
that loses its evidence.
|
|
81
|
+
- `npm run verbs:budget` — the 5.x law, ratcheted at 50 verbs with a 44 target
|
|
82
|
+
for 5.0.
|
|
83
|
+
- `npm run script:paths` — no `package.json` script may name a `tests/`,
|
|
84
|
+
`src/`, `scripts/`, `docs/`, `site/` or `enterprise/` path that does not
|
|
85
|
+
exist. 107 path references are checked today.
|
|
86
|
+
- `npm run m26:gaps:revalidate` — re-runs every gap row's own
|
|
87
|
+
`revalidation_command` against the working tree and records the exit code and
|
|
88
|
+
the commit it ran at.
|
|
89
|
+
- `tests/contract/artifact-determinism.spec.ts` — two runs of the HTML
|
|
90
|
+
artifact over an unchanged repository must be byte-identical.
|
|
91
|
+
- `src/reporter/presentation.ts` — the one module that makes a presentation
|
|
92
|
+
decision. It reads a finding, a score or a palette and returns the word, band
|
|
93
|
+
or descriptor to print. It opens no file, touches no clock and formats no
|
|
94
|
+
document, and a test enforces that.
|
|
95
|
+
|
|
96
|
+
### Fixed
|
|
97
|
+
|
|
98
|
+
- **`frontier:contracts` was reporting 19 suites it never ran.** It named 24
|
|
99
|
+
test files; nineteen had been deleted by the `cc5fcb88` cleanup and its
|
|
100
|
+
follow-up. Vitest treats a missing path as "no tests here" rather than an
|
|
101
|
+
error, so the script exited 0 and printed "57 passed" while nineteen contract
|
|
102
|
+
suites — including every `m3x`/`m4x`/`m5x` frontier contract — silently did
|
|
103
|
+
not execute. A missing test file and a green test file are indistinguishable
|
|
104
|
+
from the outside, so a gate that passes because its subject is absent has
|
|
105
|
+
certified nothing. The list is rebuilt from the 23 contract suites that
|
|
106
|
+
exist (1 110 tests, not 57), and `npm run script:paths` now fails the build if
|
|
107
|
+
any `package.json` script names a path that is gone.
|
|
108
|
+
- The certification ladder's language vocabulary could not name the answer its
|
|
109
|
+
own admission gate produces. `admit()` returns `UNMEASURED` as the supported
|
|
110
|
+
state of any claim not backed by evidence, but `LANGUAGE_STATE_RANK` had no
|
|
111
|
+
word for it — so a language claiming `CERTIFIED` with an empty cohort was
|
|
112
|
+
handed a result its own vocabulary could not record. `UNMEASURED` is now
|
|
113
|
+
expressible in both vocabularies, and the four rule-level states
|
|
114
|
+
(`MEASURED-CORE` … `PROVISIONAL`) are declared in `RULE_ONLY_STATES` as
|
|
115
|
+
explicitly _not_ language outcomes rather than being filtered out by a
|
|
116
|
+
hand-maintained list.
|
|
117
|
+
- The contributor handover reported "Welcome aboard — the suite is in good
|
|
118
|
+
shape" whenever no issues were found, including when no run report had been
|
|
119
|
+
ingested and flakiness was therefore unmeasured. It now says what it did not
|
|
120
|
+
check.
|
|
121
|
+
- The confidence table's row labels were encoded as `"k|v"` strings and split
|
|
122
|
+
back apart, so any value containing a pipe was silently truncated. The rows
|
|
123
|
+
are typed pairs. The table also gained a `<caption>`, a `<thead>` and
|
|
124
|
+
`scope` attributes; it was previously a bare `<tbody>` a screen reader
|
|
125
|
+
announced as six unlabelled rows.
|
|
126
|
+
- `handoff` and `summary` each carried a private colourless score bar that
|
|
127
|
+
rendered 99 and 100 identically. Both now use the canonical `scoreGauge`, and
|
|
128
|
+
the redundant `theme.meter` alias is gone.
|
|
129
|
+
- The gap ledger gained three revalidation statuses
|
|
130
|
+
(`ALREADY_FIXED` / `CONFIRMED_STILL_OPEN` / `STALE_UNVERIFIABLE`). A row may
|
|
131
|
+
no longer be cleared without a revalidation that was actually run at a named
|
|
132
|
+
commit, and `STALE_UNVERIFIABLE` deliberately does not clear a release gate —
|
|
133
|
+
an unverifiable claim must never be able to unblock a release.
|
|
134
|
+
- `m26:github:sync` derived every one of 429 issue dispositions from GitHub's
|
|
135
|
+
own `state` field — a pure function of its input, containing no engineering
|
|
136
|
+
judgement — and `GAP-M26-002` then marked that script `fixed`, citing the
|
|
137
|
+
artifacts it produces. Dispositions now come from
|
|
138
|
+
`docs/issue-dispositions.json`, where each entry must carry a non-empty
|
|
139
|
+
reason and a verification naming a command or a source path, and may not be
|
|
140
|
+
verified by the script that wrote it. An untriaged issue stays open and is
|
|
141
|
+
flagged, never guessed and never silently closed. 215 of 429 are now visibly
|
|
142
|
+
awaiting a human decision, which is the honest count.
|
|
143
|
+
|
|
144
|
+
### Documentation
|
|
145
|
+
|
|
146
|
+
- `PRODUCT-ENHANCEMENT-ANALYSIS.md` is marked `SUPERSEDED-BY: BITTERSWEET` and
|
|
147
|
+
gained a section XII auditing its "all 16 features shipped" claims: six do not
|
|
148
|
+
hold (two shipped fabricated values, two shipped a different capability than
|
|
149
|
+
described, two never shipped). The document is kept as the record of what was
|
|
150
|
+
believed on 2026-09-20, because deleting it would destroy the only evidence
|
|
151
|
+
that the belief was wrong.
|
|
152
|
+
- `docs/RELEASE-TRAINS.md` now records why each of the six scheduled verb
|
|
153
|
+
removals is justified differently, so the deprecation notices do not all send
|
|
154
|
+
the same message to users who acted on different output.
|
|
155
|
+
|
|
156
|
+
## [4.0.0] — 2026-09-26
|
|
157
|
+
|
|
158
|
+
The first release whose reporting surface is checked against the working tree
|
|
159
|
+
rather than against a plan. Every box below is enforced by a gate in
|
|
160
|
+
`npm run certify`.
|
|
161
|
+
|
|
162
|
+
### What you get, relative to 3.0.0
|
|
163
|
+
|
|
164
|
+
**The product no longer reports numbers it did not measure.**
|
|
165
|
+
|
|
166
|
+
- [x] A scan that finished now says it finished. A minified bundle or a lockfile
|
|
167
|
+
in the repository used to downgrade a complete scan to `PARTIAL`, and the
|
|
168
|
+
terminal told you "some files were not analyzed, so the surface is
|
|
169
|
+
unverified" when every discovered test file _had_ been analyzed. Across
|
|
170
|
+
the 37-repository corpus, complete scans went from 13/37 to 29/37.
|
|
171
|
+
- [x] Unmeasured counts read `unknown — not measured`, not `0`. The trust report,
|
|
172
|
+
the PR comment and the step summary all printed "0 tests analyzed in 0
|
|
173
|
+
files" for a producer that had never measured a test declaration. A zero
|
|
174
|
+
is a claim; an absent measurement is not.
|
|
175
|
+
- [x] `handover` no longer tells you "the suite is in good shape" when no run
|
|
176
|
+
report was ingested and flakiness was therefore never checked. It now
|
|
177
|
+
names what it did not check.
|
|
178
|
+
- [x] The HTML dashboard produces the same bytes for the same repository. It
|
|
179
|
+
embedded `new Date()` in its visible body, so it could never be diffed in
|
|
180
|
+
review. `--deterministic` omits the timestamp entirely.
|
|
181
|
+
- [x] The trust report's evidence descriptor is the terminal's, on every surface.
|
|
182
|
+
HTML and Markdown showed four bare words (`E2 · deterministic`) where the
|
|
183
|
+
terminal showed the measured FP rate, the sample size, the trust rung and
|
|
184
|
+
what the runtime actually corroborated.
|
|
185
|
+
- [x] A finding with no evidence level derives one from its own type and
|
|
186
|
+
confidence. It used to default to `E2` — the strongest claim the product
|
|
187
|
+
can make — for findings nobody had measured.
|
|
188
|
+
- [x] The contributor handover no longer derives a dollar figure from a table of
|
|
189
|
+
invented incident costs. `business-case` multiplied a measured
|
|
190
|
+
false-positive rate by unsourced per-industry costs and printed the product
|
|
191
|
+
as "Expected Savings". A cost figure now requires `--incident-cost`, so the
|
|
192
|
+
number is yours. `--history` (which read no history) and `--projected`
|
|
193
|
+
(which divided by six) are gone, with reasons.
|
|
194
|
+
- [x] `mjolnir enterprise` no longer writes a deployment config claiming
|
|
195
|
+
`sso-saml`, an SSO guide telling you to add a config key nothing reads, or
|
|
196
|
+
auditor-facing SOC 2 / HIPAA / PCI-DSS templates mapping controls to
|
|
197
|
+
capabilities this product does not have. `sso` and `compliance` refuse;
|
|
198
|
+
`config` emits a capability manifest whose `notProvided` list records the
|
|
199
|
+
absences.
|
|
200
|
+
- [x] The dependency graph no longer prints a count derived from nothing.
|
|
201
|
+
"Reachable files: N" was always the number of files that went in.
|
|
202
|
+
|
|
203
|
+
**The product now sees things it was blind to.**
|
|
204
|
+
|
|
205
|
+
- [x] Node-native TypeScript tests (`.test.mts`, `.spec.mts`, `.test.cts`,
|
|
206
|
+
`.spec.cts`) are scanned. They were not mis-scored — they were never
|
|
207
|
+
scanned, so every rule was silent on them with no finding and no note.
|
|
208
|
+
Verified with two byte-identical tests: the `.ts` copy produced the
|
|
209
|
+
finding, the `.mts` copy produced nothing at all.
|
|
210
|
+
- [x] The CI matrix installs cleanly on all three platforms. `npm ci` failed on
|
|
211
|
+
every job before a test ran, and then failed again with a missing
|
|
212
|
+
`lightningcss` binary for Linux, because a lockfile regenerated on Windows
|
|
213
|
+
cannot contain the other platforms' optional dependencies.
|
|
214
|
+
|
|
215
|
+
**The gates now catch these instead of the next person.**
|
|
216
|
+
|
|
217
|
+
- [x] `report:honesty` — no surface may print a zero for an absent measurement.
|
|
218
|
+
Four reviewed exceptions, each with a reason and a follow-up.
|
|
219
|
+
- [x] `thresholds:parity` — no score-band literal outside the registry. It
|
|
220
|
+
immediately caught a selector-health threshold that shared a number with a
|
|
221
|
+
trust band but not a meaning.
|
|
222
|
+
- [x] `script:paths` — no `package.json` script may name a path that is missing
|
|
223
|
+
or uncommitted. It found `frontier:contracts` naming 19 test files deleted
|
|
224
|
+
by an earlier cleanup: Vitest treats a missing path as "no tests here", so
|
|
225
|
+
the script exited 0 reporting "57 passed" while nineteen contract suites
|
|
226
|
+
never ran. Rebuilt from the 23 that exist — 1 110 tests, not 57.
|
|
227
|
+
- [x] `lockfile:platforms` — the lockfile must carry the optional binaries for
|
|
228
|
+
every platform CI builds on. The failure is invisible locally by
|
|
229
|
+
construction, so it needed a gate that runs everywhere.
|
|
230
|
+
- [x] `claims:revalidate` — a claim asserted `fixed` must rest on a
|
|
231
|
+
candidate-bound, independent revalidation. It rejects evidence citing the
|
|
232
|
+
artifact it is meant to prove, and downgrades rather than deletes a claim
|
|
233
|
+
that loses its evidence.
|
|
234
|
+
- [x] `verbs:budget` — the 5.x law: one new verb requires one removal or a merge.
|
|
235
|
+
- [x] `m26:gaps:revalidate` — re-runs each gap row's own command and records the
|
|
236
|
+
exit code and the commit it ran at.
|
|
237
|
+
- [x] `release:verify` reports every blocker in one run. It was a `&&` chain, so
|
|
238
|
+
it stopped at the first of four and you met them one per run.
|
|
239
|
+
- [x] The coverage gate is a floor and a ratchet, not one number pretending to
|
|
240
|
+
be both.
|
|
241
|
+
|
|
242
|
+
**Truth in the project's own records.**
|
|
243
|
+
|
|
244
|
+
- [x] The gap ledger was revalidated: all 17 rows had their own
|
|
245
|
+
`revalidation_command` run against this tree. `GAP-M26-005` read
|
|
246
|
+
`fixed` / PASS while its command _fails_. A cleared row can no longer
|
|
247
|
+
exist without a revalidation bound to a named commit, and
|
|
248
|
+
`STALE_UNVERIFIABLE` deliberately cannot unblock a release.
|
|
249
|
+
- [x] **A gap row could be marked fixed while its own revalidation failed.**
|
|
250
|
+
The `exit_code === 0` check was reachable through only one of the four
|
|
251
|
+
combinations the schema allows, so a `fixed` row — or an
|
|
252
|
+
`ALREADY_FIXED` row carrying closure evidence — was accepted with
|
|
253
|
+
`exit_code: 1` recorded in its own revalidation. Three of those four
|
|
254
|
+
routes cleared the row. The test that covered it hid the hole, because
|
|
255
|
+
the fixture only set `closure_evidence` for `fixed`.
|
|
256
|
+
- [x] The 429 GitHub dispositions no longer derive from GitHub's own `state`
|
|
257
|
+
field. A snapshot cannot prove itself; each disposition now needs a reason
|
|
258
|
+
and a verification. 215 issues are visibly awaiting a human decision,
|
|
259
|
+
which is the honest count.
|
|
260
|
+
- [x] `PRODUCT-ENHANCEMENT-ANALYSIS.md` claimed 16 shipped features; six do not
|
|
261
|
+
hold. It is marked `SUPERSEDED-BY` and carries a per-feature audit, kept
|
|
262
|
+
rather than deleted because deleting it would destroy the only evidence
|
|
263
|
+
that the belief was wrong.
|
|
264
|
+
|
|
265
|
+
**Found by the pre-release bug sweep, after the fix list was written.** Both
|
|
266
|
+
were live in 3.0.0 and neither was in the plan.
|
|
267
|
+
|
|
268
|
+
- [x] `mjolnir business-case <path>` answered a path that does not exist with
|
|
269
|
+
exit 0 and a clean report: "Measured: 0 of 0 findings carry a
|
|
270
|
+
corpus-measured FP rate". It called `runScan` directly and so never
|
|
271
|
+
passed through `validateScanTarget` — the check whose own comment says a
|
|
272
|
+
typo'd CI path must be a loud red, never a silent green. Thirteen of the
|
|
273
|
+
fifteen scanning verbs were already loud; this one was not, and a green
|
|
274
|
+
table over a path that was never scanned is the most dangerous output
|
|
275
|
+
this product can produce. Now exit 10.
|
|
276
|
+
- [x] The extended TypeScript test-file regex was probed against 27 shapes:
|
|
277
|
+
all 12 that must match do, all 15 that must not are rejected —
|
|
278
|
+
including `a.min.mts`, `a.spec.cts.bak` and `notatest.mts`.
|
|
279
|
+
- [x] `ships()` in `script:paths` was probed for the failure modes a new gate
|
|
280
|
+
usually has: an empty directory, a directory holding only untracked
|
|
281
|
+
files, and a symlink loop. All resolve correctly and none hangs. A
|
|
282
|
+
first version treated a directory as "tracked" only if `git ls-files`
|
|
283
|
+
listed the directory itself, which it never does — that produced two
|
|
284
|
+
false positives and is fixed.
|
|
285
|
+
|
|
286
|
+
### Known open, deliberately
|
|
287
|
+
|
|
288
|
+
- [ ] `CERTIFICATION_STATES` is not in ladder order, so `rankOf` — the only
|
|
289
|
+
ordering function — ranks `KNOWN` above `TRUST-COMPLETE`, and
|
|
290
|
+
`requiresEvidence` asks `BLOCKED` and `DEGRADED` for a corpus their own
|
|
291
|
+
doc comment says they need none. Two `it.fails` tests record it, so
|
|
292
|
+
reordering the array fails the build. Fixing it moves `rankOf` for every
|
|
293
|
+
state and changes admission outcomes, so it is a contract change, not a
|
|
294
|
+
patch.
|
|
295
|
+
- [ ] 23 corpus count-drifts are unreviewed, the largest being `QA-PY-007`
|
|
296
|
+
firing 1332 times in apache-airflow and 92 now. Not accepted: running
|
|
297
|
+
`--update` without reading them would delete the only evidence that
|
|
298
|
+
detection changed.
|
|
299
|
+
- [ ] 8 of 37 corpus repositories report `PARTIAL` because test-support files
|
|
300
|
+
under `__tests__/` are not scanned. The verdict is honest — an incomplete
|
|
301
|
+
scan is not a pass — and the fix is a design decision about what "the
|
|
302
|
+
surface" means, not a patch.
|
|
303
|
+
- [ ] 215 of 229 GitHub issues are untriaged. Prepared dispositions exist in
|
|
304
|
+
`docs/issue-dispositions.json`; none has been applied, because closing a
|
|
305
|
+
public issue is destructive and is a person's decision.
|
|
306
|
+
- [ ] `BW-022` (one workspace model, real graph edges) is open. The plan claimed
|
|
307
|
+
it is "what makes `impact` honest"; it is not — `impact` never used the
|
|
308
|
+
graph and is honest on its own path. The graph is a no-op on an unshipped
|
|
309
|
+
code path, and the function now reports that instead of implying otherwise.
|
|
310
|
+
|
|
311
|
+
### Upgrade notes
|
|
312
|
+
|
|
313
|
+
- Node-native TypeScript test files are now scanned, so a project using
|
|
314
|
+
`.mts`/`.cts` tests **will see new findings**. That is the fix working, not a
|
|
315
|
+
regression.
|
|
316
|
+
- `business-case` requires `--incident-cost` for any dollar figure, and now
|
|
317
|
+
exits 10 on a target that does not exist instead of printing an empty report.
|
|
318
|
+
- `enterprise sso` and `enterprise compliance` now exit non-zero with a reason.
|
|
319
|
+
- The trust report JSON's `tests.files` and `tests.declarations` are `null`
|
|
320
|
+
rather than `0` when unmeasured.
|
|
321
|
+
|
|
322
|
+
## [4.0.0-rc.1] — 2026-09-25
|
|
323
|
+
|
|
324
|
+
### Breaking changes
|
|
325
|
+
|
|
326
|
+
- The next published version must be a new major line. Generated CI is now
|
|
327
|
+
advisory-first while the direct composite Action remains blocking by default;
|
|
328
|
+
suppression metrics changed from configured to matched findings, and
|
|
329
|
+
zero-finding output no longer implies a clean or green suite. Publishing
|
|
330
|
+
these changes as another `3.0.0` is prohibited.
|
|
331
|
+
|
|
14
332
|
### Changed
|
|
15
333
|
|
|
16
|
-
- **Advisory-first CI adoption** — `mjolnir ci install`
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
or `fail-on`.
|
|
334
|
+
- **Advisory-first generated CI adoption** — `mjolnir ci install` now
|
|
335
|
+
defaults to non-blocking findings and non-blocking partial scans. The direct
|
|
336
|
+
composite Action remains blocking by default. Blocking behavior is explicit
|
|
337
|
+
through `--gate error`, `--gate warning`, or `fail-on`.
|
|
20
338
|
- Suppression counts now report matched findings, not configured entries;
|
|
21
339
|
`suppression-gate` evaluates all-tier pre-suppression findings and enforces
|
|
22
340
|
total-count limits.
|
|
@@ -34,6 +352,44 @@ once shipped, so this file is the record of what changed between versions.
|
|
|
34
352
|
before it ships; and `scripts/check-ci-local-parity.mjs`, which keeps
|
|
35
353
|
`ci.yml`, `merge-verify.yml` and the local gate exercising the same
|
|
36
354
|
command list. All additive — no frozen surface changed.
|
|
355
|
+
- **M26–M50 execution ledger** — added `docs/ROADMAP.yaml`, dated GitHub
|
|
356
|
+
issue/milestone/PR reconciliation, explicit issue dispositions, an
|
|
357
|
+
append-only gap ledger, a finite support matrix, and an external-validation
|
|
358
|
+
record. Approval authority and staged dependency resolution are recorded;
|
|
359
|
+
external evidence remains `BLOCKED`/`NOT_RUN` and cannot be synthesized.
|
|
360
|
+
- **Provisional capability contracts** — added bounded, non-promoting
|
|
361
|
+
contracts for runtime evidence, provider capabilities, QA domain records,
|
|
362
|
+
agent decision receipts, plugin packs, change intelligence, mutation
|
|
363
|
+
sensitivity, adversarial challenges, simulation, language/framework packs,
|
|
364
|
+
cross-repository systems, history, detector lifecycle, research, benchmark,
|
|
365
|
+
scale, UX parity, and Trust OS release proofs. Each has focused hostile,
|
|
366
|
+
stale, foreign, malformed, and recovery coverage.
|
|
367
|
+
- **Release control surfaces** — added exact version-surface synchronization,
|
|
368
|
+
RC-aware changelog validation, candidate manifest refresh/readiness,
|
|
369
|
+
reporter ramp policy, fail-closed M26 audit gates, and current-major-only
|
|
370
|
+
Action tag maintenance.
|
|
371
|
+
- **README release preparation** — canonical and translated README install
|
|
372
|
+
references, release-status blocks, and new command rows are synchronized to
|
|
373
|
+
`3.0.0`; English fallback blocks are explicitly marked for human translation
|
|
374
|
+
review, and the canonical README states the certification boundary.
|
|
375
|
+
- **Release proof hardening** — stable publication now generates and attaches
|
|
376
|
+
an SPDX SBOM, rejects same-version registry artifacts with a different
|
|
377
|
+
integrity digest, updates only the current `v3` Action major, and never
|
|
378
|
+
clobbers release assets.
|
|
379
|
+
- **Support matrix reconciliation** — 136 cells are classified as 90 tested,
|
|
380
|
+
44 explicitly blocked, and 2 not applicable, with evidence paths and revisit
|
|
381
|
+
triggers checked locally.
|
|
382
|
+
|
|
383
|
+
### Fixed
|
|
384
|
+
|
|
385
|
+
- Corpus runs now record complete rule-crash provenance, reject parser
|
|
386
|
+
fallbacks, and support a provenance-only refresh that cannot update counts.
|
|
387
|
+
- QA-PY-004 sanitizes assertion roots before constructing a pattern, removing
|
|
388
|
+
corpus crashes caused by nested call-like targets.
|
|
389
|
+
- Pathological stress runs no longer mask crashes with `|| true`; soak evidence
|
|
390
|
+
no longer claims parent-process RSS as child memory.
|
|
391
|
+
- Exact registry-install smoke can install and verify a published version
|
|
392
|
+
instead of substituting the checkout tarball.
|
|
37
393
|
|
|
38
394
|
## [3.0.0] — 2026-09-24
|
|
39
395
|
|
|
@@ -286,8 +642,6 @@ Complete implementation of the Mjolnir Master Engineering Roadmap & Product Spec
|
|
|
286
642
|
- `src/commands/doctor.ts` gains check 11 (rule metadata contract validation).
|
|
287
643
|
- 4 fingerprint implementations consolidated into `src/engine/finding-identity.ts`.
|
|
288
644
|
|
|
289
|
-
## [Unreleased] — Nordic brand pass
|
|
290
|
-
|
|
291
645
|
### Changed
|
|
292
646
|
|
|
293
647
|
- Terminal report: section headers are marked `▍ TITLE` instead of
|
package/README.ar.md
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
[](https://nodejs.org)
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
npx mjolnir-qa@
|
|
21
|
+
npx mjolnir-qa@3.0.0
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
[شاهده وهو يعمل](#شاهده-وهو-يعمل) · [البدء السريع](#البدء-السريع) · [ما الذي يكتشفه](#ما-الذي-يكتشفه-mjölnir) · [الدرجة](#درجة-الجدارة) · [الأدلة](#نموذج-الأدلة) · [تحليل التشغيلات](#تحليل-تشغيلات-الاختبار) · [CI](#سلامة-ci) · [الوكلاء](#وكلاء-الذكاء-الاصطناعي) · [الأمان](#الثقة-والأمان) · [الحدود](#ما-لا-يستطيع-mjölnir-أن-يخبرك-به) · [التوثيق](#التوثيق)
|
|
@@ -28,9 +28,9 @@ npx mjolnir-qa@latest
|
|
|
28
28
|
|
|
29
29
|
[English](README.md) | [简体中文](README.zh.md) | [繁體中文](README.zht.md) | [한국어](README.ko.md) | [Deutsch](README.de.md) | [Español](README.es.md) | [Français](README.fr.md) | [Italiano](README.it.md) | [Dansk](README.da.md) | [日本語](README.ja.md) | [Polski](README.pl.md) | [Русский](README.ru.md) | [Norsk](README.no.md) | [Português (Brasil)](README.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) | العربية | [Bosanski](README.bs.md)
|
|
30
30
|
|
|
31
|
-
> 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-
|
|
31
|
+
> 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-26.
|
|
32
32
|
|
|
33
|
-
<!-- Source hash:
|
|
33
|
+
<!-- Source hash: `de04dfb1677b` -->
|
|
34
34
|
|
|
35
35
|
</details>
|
|
36
36
|
|
|
@@ -38,6 +38,20 @@ npx mjolnir-qa@latest
|
|
|
38
38
|
|
|
39
39
|
<br />
|
|
40
40
|
|
|
41
|
+
## Release status (English canonical)
|
|
42
|
+
|
|
43
|
+
The published line is `3.0.0`; this working tree is the `4.0.0-rc.1`
|
|
44
|
+
candidate. `3.0.0` must not be republished or retagged. The M26–M50 program is
|
|
45
|
+
tracked in
|
|
46
|
+
[`docs/ROADMAP.yaml`](docs/ROADMAP.yaml); provisional capability contracts
|
|
47
|
+
are not automatically enabled or certified. Repository-owned checks pass, but
|
|
48
|
+
Trust certification remains `NOT_CERTIFIED` until the protected holdout,
|
|
49
|
+
real-world, platform/consumer, remote-workflow, support-matrix, and corpus
|
|
50
|
+
evidence gates pass. Run `npm run m26:readiness` before treating any candidate
|
|
51
|
+
as releasable. This document does not publish a tag or authorize a release.
|
|
52
|
+
|
|
53
|
+
> Machine-assisted canonical text. Translate this block before treating it as localized copy.
|
|
54
|
+
|
|
41
55
|
## علامة الصح الخضراء ادعاء، وليست دليلًا
|
|
42
56
|
|
|
43
57
|
علامة الصح الخضراء تعني أن خط CI لم يفشل. لا تعني أن الاختبارات عملت، ولا أنها كان يمكن أن تفشل. كل واحدة من هذه تمر باللون الأخضر:
|
|
@@ -58,7 +72,7 @@ npx mjolnir-qa@latest
|
|
|
58
72
|
|
|
59
73
|
<sub>كل نتيجة أبلغ عنها فحص العرض لهذا الـ workflow، عند السطر الذي أبلغ عنه. مولَّد بواسطة `npm run docs:readme-brand` من [`demo-report.json`](assets/readme/demo-report.json) ومقفل ضد الانحراف في CI.</sub>
|
|
60
74
|
|
|
61
|
-
**الوضع الصارم.** الكشف الأكثر عدوانية — `.only`، `continue-on-error`، الاختبارات الفارغة، إساءة إعادة المحاولة — تقع في مستوى الحجر الصحي. تعمل فقط مع `--strict` وتُ限定 بخطورة `info`: تُعلم، لكنها لا تُوقف أبدًا. الفحص الافتراضي (`npx mjolnir-qa@
|
|
75
|
+
**الوضع الصارم.** الكشف الأكثر عدوانية — `.only`، `continue-on-error`، الاختبارات الفارغة، إساءة إعادة المحاولة — تقع في مستوى الحجر الصحي. تعمل فقط مع `--strict` وتُ限定 بخطورة `info`: تُعلم، لكنها لا تُوقف أبدًا. الفحص الافتراضي (`npx mjolnir-qa@3.0.0` بدون `--strict`) يغطي القواعد الأساسية والموسعة فقط. أضف `--strict` عندما تريد طبقة الاستشارات أيضًا.
|
|
62
76
|
|
|
63
77
|
يقرأ Mjölnir مجموعة الاختبارات وملفات workflow الخاصة بـ CI، وتقرير تشغيل حقيقي إن وُجد. لا يشغّل اختباراتك، ولا يثبّت اعتمادياتك، ولا ينفّذ الشيفرة التي يفحصها. وعندما لا يملك دليلًا، يقول ذلك بدل أن يختلق ثقة:
|
|
64
78
|
|
|
@@ -93,7 +107,7 @@ npx mjolnir-qa@latest
|
|
|
93
107
|
|
|
94
108
|
<p align="center">
|
|
95
109
|
<a href="assets/video/mjolnir-demo.mp4">
|
|
96
|
-
<img src="assets/video/mjolnir-demo-poster.png" alt="لقطة من تسجيل العرض: npx mjolnir-qa@
|
|
110
|
+
<img src="assets/video/mjolnir-demo-poster.png" alt="لقطة من تسجيل العرض: npx mjolnir-qa@3.0.0 يفحص مستودع العرض في نافذة طرفية" width="900" />
|
|
97
111
|
</a>
|
|
98
112
|
</p>
|
|
99
113
|
|
|
@@ -162,7 +176,7 @@ Docs: mjolnir rules --md (full catalog, this rule included)
|
|
|
162
176
|
## البدء السريع
|
|
163
177
|
|
|
164
178
|
```bash
|
|
165
|
-
npx mjolnir-qa@
|
|
179
|
+
npx mjolnir-qa@3.0.0
|
|
166
180
|
```
|
|
167
181
|
|
|
168
182
|
يفحص الدليل الحالي ويطبع Trust Report: ما الذي وجده، وإلى أي حد يمكنك الوثوق به، ولماذا، وما الخطوة التالية. ويخرج بالرمز `0` عندما لا يُعثر على شيء عند مستوى البوابة أو فوقه.
|
|
@@ -170,24 +184,39 @@ npx mjolnir-qa@latest
|
|
|
170
184
|
في CI، افحص فقط ما أدخله الفرع، حتى لا تُغرق مجموعة اختبارات قديمة أول pull request لك:
|
|
171
185
|
|
|
172
186
|
```bash
|
|
173
|
-
npx mjolnir-qa@
|
|
187
|
+
npx mjolnir-qa@3.0.0 --scope changed
|
|
174
188
|
```
|
|
175
189
|
|
|
176
|
-
يكتب `mjolnir ci install` ذلك كـ workflow لـ GitHub Actions، باستخدام [الـ action](https://github.com/Sergey-Bar/Mjolnir#readme) المثبّت على الوسم الرئيسي `
|
|
177
|
-
|
|
178
|
-
| الأمر
|
|
179
|
-
|
|
|
180
|
-
| `mjolnir`
|
|
181
|
-
| `mjolnir --scope changed`
|
|
182
|
-
| `mjolnir ci install`
|
|
183
|
-
| `mjolnir
|
|
184
|
-
| `mjolnir
|
|
185
|
-
| `mjolnir
|
|
186
|
-
| `mjolnir
|
|
187
|
-
| `mjolnir
|
|
188
|
-
| `mjolnir
|
|
189
|
-
| `mjolnir
|
|
190
|
-
| `mjolnir --
|
|
190
|
+
يكتب `mjolnir ci install` ذلك كـ workflow لـ GitHub Actions، باستخدام [الـ action](https://github.com/Sergey-Bar/Mjolnir#readme) المثبّت على الوسم الرئيسي `v3` (أو `npx` عادي مع `--no-action`). ويبقى استشاريًا إلى أن تقرر أنه يجب أن يمنع الدمج.
|
|
191
|
+
|
|
192
|
+
| الأمر | ما الذي يفعله |
|
|
193
|
+
| --------------------------------------------- | ------------------------------------------------------------ |
|
|
194
|
+
| `mjolnir` | Trust Report: الحكم، ودرجة الثقة، والإجراء التالي |
|
|
195
|
+
| `mjolnir --scope changed` | فقط ما أدخله فرعك (صيغة CI) |
|
|
196
|
+
| `mjolnir ci install` | ينشئ workflow استشاريًا لطلبات الدمج (قائمًا على الـ action) |
|
|
197
|
+
| `mjolnir business-case` | ROI estimate: projected savings per finding |
|
|
198
|
+
| `mjolnir release-report` | Release readiness: GO, CONDITIONAL GO, or NO-GO |
|
|
199
|
+
| `mjolnir release-trust` | 12-dimension release assurance verdict |
|
|
200
|
+
| `mjolnir report` | Generate a Playwright-compatible report |
|
|
201
|
+
| `mjolnir trend` | Record, show, or diff local quality snapshots |
|
|
202
|
+
| `mjolnir policy` | Initialize, validate, or check policy gates |
|
|
203
|
+
| `mjolnir quarantine` | Review deterministic proposals (prototype) |
|
|
204
|
+
| `mjolnir analyze --cross-file` | Bounded cross-file analysis |
|
|
205
|
+
| `mjolnir ci-adapter github .` | Generate CI templates for supported providers |
|
|
206
|
+
| `mjolnir dashboard` | Generate a self-contained quality dashboard |
|
|
207
|
+
| `mjolnir exec-report` | Executive KPIs and recommendations (advisory) |
|
|
208
|
+
| `mjolnir enterprise` | Self-hosted templates (prototype) |
|
|
209
|
+
| `mjolnir maturity` | Assess maturity or display maturity levels |
|
|
210
|
+
| `mjolnir mutation tests/mutation-report.json` | Analyze mutation reports; never promotes trust |
|
|
211
|
+
| `mjolnir mcp` | Read-only MCP tools over stdio |
|
|
212
|
+
| `mjolnir explain QA-CI-001` | ماذا ولماذا وكيف يُصلح، مع معدل FP المقيس |
|
|
213
|
+
| `mjolnir why src/a.spec.ts:42` | لماذا عُلّم هذا السطر بالتحديد. لا يمنع الدمج أبدًا. |
|
|
214
|
+
| `mjolnir forensics ./test-results/` | أدلة وقت التشغيل من تشغيل حقيقي |
|
|
215
|
+
| `mjolnir trust-report` | Trust Artifact مستقل (md + json) |
|
|
216
|
+
| `mjolnir handoff` | خطة معالجة لوكيل برمجة |
|
|
217
|
+
| `mjolnir --json` / `--format sarif` | مخرجات قابلة للقراءة آليًا، GitHub Code Scanning |
|
|
218
|
+
| `mjolnir --format codequality` | تقرير GitLab Code Quality (عنصر لأداة طلب الدمج) |
|
|
219
|
+
| `mjolnir --strict` | يشغّل أيضًا قواعد مستوى quarantine (خطر FP أعلى) |
|
|
191
220
|
|
|
192
221
|
<details>
|
|
193
222
|
<summary><strong>كل الأوامر الأخرى</strong> — فرز الاختبارات غير المستقرة، والتقارير، والحوكمة</summary>
|
|
@@ -452,18 +481,18 @@ mjolnir ci install
|
|
|
452
481
|
أو أضف الـ action من Marketplace إلى workflow لديك بالفعل:
|
|
453
482
|
|
|
454
483
|
```yaml
|
|
455
|
-
- uses: Sergey-Bar/Mjolnir@
|
|
484
|
+
- uses: Sergey-Bar/Mjolnir@v3
|
|
456
485
|
with:
|
|
457
486
|
scope: changed
|
|
458
487
|
fail-on: error
|
|
459
488
|
```
|
|
460
489
|
|
|
461
|
-
ثبّت `@
|
|
490
|
+
ثبّت `@v3` لتتبع الخط الرئيسي، أو وسمًا دقيقًا (`@v0.5.32`) لبوابة قابلة لإعادة الإنتاج. يغطي [docs/DISTRIBUTION-KIT.md](docs/DISTRIBUTION-KIT.md) كلًّا من Marketplace وSmithery وسجلات MCP.
|
|
462
491
|
|
|
463
492
|
لوضع النتائج في GitHub Code Scanning، ارفع SARIF (يتطلب `security-events: write` على مستوى الـ workflow أو الـ job):
|
|
464
493
|
|
|
465
494
|
```yaml
|
|
466
|
-
- run: npx mjolnir-qa@
|
|
495
|
+
- run: npx mjolnir-qa@3.0.0 --format sarif > mjolnir.sarif
|
|
467
496
|
continue-on-error: true
|
|
468
497
|
- uses: github/codeql-action/upload-sarif@v3
|
|
469
498
|
if: ${{ !cancelled() }}
|
|
@@ -476,7 +505,7 @@ mjolnir ci install
|
|
|
476
505
|
### إسناد النتائج إلى نطاق التغييرات
|
|
477
506
|
|
|
478
507
|
```bash
|
|
479
|
-
npx mjolnir-qa@
|
|
508
|
+
npx mjolnir-qa@3.0.0 --scope changed
|
|
480
509
|
```
|
|
481
510
|
|
|
482
511
|
تُسند النتائج إلى الأسطر التي أضافها فرعك، مقيسةً مقابل **merge-base**. النطاق هو مجموعة الملفات نفسها التي يكتشفها الفحص الكامل (ملفات spec لـ TS/JS وإعدادات المحوّلات، `test_*.py`، `*Test.java`، `*Tests.cs`، `.github/workflows/*.yml`)، إضافة إلى التغييرات غير المُثبتة وغير المتتبَّعة، لذا يعمل قبل أن تُجري commit. يُحدَّد الأساس بالترتيب `main → master → origin/main → origin/master → origin/HEAD`؛ ويمكنك تجاوزه بـ `--base <ref>`.
|
|
@@ -504,7 +533,7 @@ SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
|
|
|
504
533
|
أضفه إلى عميل يأتي مع CLI خاص به:
|
|
505
534
|
|
|
506
535
|
```bash
|
|
507
|
-
claude mcp add mjolnir -- npx -y mjolnir-qa@
|
|
536
|
+
claude mcp add mjolnir -- npx -y mjolnir-qa@3.0.0 mcp
|
|
508
537
|
```
|
|
509
538
|
|
|
510
539
|
أو إلى أي عميل يقبل كتلة `mcpServers`:
|
|
@@ -512,7 +541,7 @@ claude mcp add mjolnir -- npx -y mjolnir-qa@latest mcp
|
|
|
512
541
|
```json
|
|
513
542
|
{
|
|
514
543
|
"mcpServers": {
|
|
515
|
-
"mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@
|
|
544
|
+
"mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@3.0.0", "mcp"] }
|
|
516
545
|
}
|
|
517
546
|
}
|
|
518
547
|
```
|
|
@@ -603,7 +632,7 @@ mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
|
|
|
603
632
|
<img src="assets/readme/closing.svg" alt="شغّله على مستودعك." width="100%" />
|
|
604
633
|
|
|
605
634
|
```bash
|
|
606
|
-
npx mjolnir-qa@
|
|
635
|
+
npx mjolnir-qa@3.0.0
|
|
607
636
|
```
|
|
608
637
|
|
|
609
638
|
[اقرأ الدليل](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [موقع التوثيق](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)
|