mjolnir-qa 4.0.0 → 5.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 CHANGED
@@ -11,6 +11,8 @@ once shipped, so this file is the record of what changed between versions.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [5.0.0] — 2026-09-27
15
+
14
16
  ### Breaking changes
15
17
 
16
18
  - **`business-case` no longer prints a dollar figure you did not supply.** The
@@ -47,6 +49,18 @@ once shipped, so this file is the record of what changed between versions.
47
49
  The generation timestamp moved out of the visible body into
48
50
  `<meta name="mjolnir-generated-at">`, and `--deterministic` omits it entirely
49
51
  so the artifact is byte-identical and can be diffed in review.
52
+ - **`mjolnir report` no longer publishes a test-run status.** The top-level
53
+ `status` was computed from the findings
54
+ (`partial ? "interrupted" : hasError ? "failed" : "passed"`), so a clean scan
55
+ wrote `{status: "passed", totalTests: 0}` — the first field a Playwright
56
+ consumer reads, asserting a green run over zero executed tests, with the
57
+ contradicting `execution: "STATIC_ANALYSIS"` marker buried in the extension
58
+ block. `failed` was equally dishonest: it implies tests ran and lost. The
59
+ field is now the literal `interrupted` on every path, and what the scan
60
+ actually found is reported separately as
61
+ `mjolnir.scanOutcome` (`clean` / `blocked` / `partial`), which the previous
62
+ `mjolnir.status` field carried. Consumers reading the root `status` will see
63
+ `passed` → `interrupted`; that is the correction, not a regression.
50
64
  - **Score bands are decided in one place.** The dashboard split at 60 while the
51
65
  terminal split at 80, so a score the terminal called UNWORTHY rendered amber
52
66
  in HTML; the contributor handover used 90; `mermaid.ts` and
@@ -55,6 +69,14 @@ once shipped, so this file is the record of what changed between versions.
55
69
 
56
70
  ### Added
57
71
 
72
+ - **`npm run ci:standard` now runs in CI.** `scripts/check-ci-standard.mjs`
73
+ was unit-tested by `tests/integrations/ci-standard.spec.ts` but referenced
74
+ by no workflow, so the invariants it checks — the PR scan's partial-analysis
75
+ handling, the coverage and ratchet gates, and the read-only scan job's
76
+ permissions — were enforced nowhere. It runs as a step in `workflow-lint`,
77
+ next to actionlint, since both are static checks of the repo's own CI
78
+ config.
79
+
58
80
  - **Opt-in Sentry crash reporting.** Set `SENTRY_DSN` and the CLI and the MCP
59
81
  stdio server report their own fatal errors — release-tagged as
60
82
  `mjolnir-qa@<version>`, tagged by surface, and nothing else: no user data
@@ -67,7 +89,11 @@ once shipped, so this file is the record of what changed between versions.
67
89
  the two existing top-level catch blocks rather than `uncaughtException` /
68
90
  `unhandledRejection` handlers, which would have changed the frozen exit-code
69
91
  contract. `npm run sentry:release` creates the release and uploads source maps
70
- (the build now emits them; the published tarball still excludes them).
92
+ (the build now emits them; the published tarball still excludes them). Both
93
+ release pipelines now run it after `npm run build` and before `npm pack`,
94
+ because the debug ids it stamps are written into `dist/` in place: pack first
95
+ and the shipped tarball carries no ids, so the maps uploaded for the release
96
+ match nothing and every stack trace degrades to a bundle frame.
71
97
  - `npm run report:honesty` — no surface may print a zero for a measurement that
72
98
  may be absent. Four reviewed exceptions are recorded for computation inputs,
73
99
  each with a reason and a follow-up.
@@ -93,8 +119,229 @@ once shipped, so this file is the record of what changed between versions.
93
119
  or descriptor to print. It opens no file, touches no clock and formats no
94
120
  document, and a test enforces that.
95
121
 
122
+ ### Changed
123
+
124
+ - **Ruleset `01` now enforces 11 required checks instead of 4.** It required
125
+ only the four `build-test` matrix contexts, which meant the repo's entire
126
+ review surface — self-scan, certification, generated-docs-drift, site-build,
127
+ workflow-lint, property, fuzz — could be red while a PR still merged. That
128
+ made every one of those checks advice rather than a gate, and it meant the
129
+ deleted `merge-verify.yml` header was describing a ruleset that never
130
+ existed. The enforced set is now the four matrix entries plus
131
+ `property-tests`, `fuzz`, `site-build`, `workflow-lint`, `self-scan`,
132
+ `certification` and `generated-docs-drift` — every check that can actually
133
+ block. Deliberately still _not_ required: `detector-revision-diff` (advisory
134
+ by design — a hard fail would only manufacture routine revision bumps),
135
+ `scan` / `publish` (the Mjölnir PR report, which reviewers read but which
136
+ duplicates `self-scan` on the `src` tree), and the CodeQL/OSV workflows,
137
+ which report but do not gate. `strict_required_status_checks_policy` and
138
+ `do_not_enforce_on_create` are preserved, so a PR must still be current with
139
+ `main` to merge.
140
+ - **`docs/BRANCH-PROTECTION.md` now states the enforced set instead of an
141
+ aspiration.** It listed eight required checks; three of them were enforced.
142
+ Its verification command also read `branches/main/protection`, which does not
143
+ carry required checks at all on this repo — they live in ruleset `01` — so it
144
+ could not have worked. Both are corrected.
145
+
146
+ ### Removed
147
+
148
+ - **The Snyk webhook is gone.** Snyk posted a `security/snyk (sergey-bar)`
149
+ commit status on every push, duplicating the first-party `osv-scanner.yml`
150
+ (`scan-pr` / `scan-scheduled`) and the Dependabot security updates that are
151
+ already configured. Repo webhooks are now empty. Restore with Snyk's own
152
+ integration settings if it is ever wanted back — the deleted hook pointed at
153
+ `https://api.snyk.io/webhook/github/4ac3f376-3f24-42f7-a2c4-8830700f671d`.
154
+ - **The `merge-verify` workflow is gone.** It re-ran the entire PR gate
155
+ (build, typecheck, lint, coverage, property, fuzz, site, self-scan, docs
156
+ regen) on every push to `main` — roughly doubling CI cost. Its stated
157
+ justification was that "a green PR that merges into a red main is not a
158
+ green PR", but that failure class is already closed by ruleset `01` running
159
+ `strict_required_status_checks_policy`, which refuses to merge a PR that is
160
+ not current with `main`. The file also asserted that ruleset `01` "requires
161
+ the complete PR matrix, property/fuzz, site, workflow-lint, self-scan,
162
+ certification, detector-revision, and generated-docs checks before merge" —
163
+ it did not, and never has. The ruleset requires only the four `build-test`
164
+ matrix contexts. Both the workflow and the claim are removed rather than left
165
+ to mislead a reviewer about what blocks a merge.
166
+ - **The `bench-advisory` CI job is gone.** It spent a full `npm ci` plus a
167
+ 3 000-file benchmark run on every PR to produce a comparison that
168
+ `continue-on-error: true` then discarded, and whose only output was a
169
+ warning nobody could gate on. `npm run bench:scan`, the pinned
170
+ `.mjolnir/bench-baseline.json`, and their schema/comparison tests in
171
+ `tests/adversarial/bench-gate.spec.ts` are untouched — the benchmark is
172
+ still runnable and still tested, it just no longer costs every PR a runner.
173
+ - **Four copies of the soft job time-budget report.** Each of `build-test`,
174
+ `self-scan`, `generated-docs-drift` and `bench-advisory` re-derived its own
175
+ wall-clock minutes into `$GITHUB_STEP_SUMMARY` and printed a warning that,
176
+ by its own comment, "never gates". The jobs already declare
177
+ `timeout-minutes`, which is the hard bound, and GitHub reports job duration
178
+ natively.
179
+
96
180
  ### Fixed
97
181
 
182
+ - **Order in the report no longer depends on the machine that produced it.** 23
183
+ sites in `src/` sorted with a bare `localeCompare`, which resolves against the
184
+ process's default locale. `scan-cache.ts` was the worst: it sorted INSIDE
185
+ `hashDir`, so the order was fed to `hash.update(entry.name)` and became a
186
+ semantic input to the detector fingerprint that `isIncrementalSafe` keys off
187
+ — one repository, two fingerprints, one per locale. All 23 now use
188
+ `compareCodePoints` from `src/lib/compare.ts`, except two whose key is a
189
+ human-readable label, which use a comparator pinned to `en` rather than
190
+ inheriting the environment. `tests/contract/deterministic-ordering.spec.ts`
191
+ fails the build on any unpinned `localeCompare` in `src/`.
192
+ - **`mjolnir bind` can no longer be hijacked by a repository's own `git`.**
193
+ `src/engine/candidate-binding.ts` — called on every scan — ran
194
+ `execFileSync("git", …)` with a bare name. On Windows `CreateProcess` searches
195
+ the current directory before `PATH`, so a committed `git.exe` in an untrusted
196
+ repo chose the `commit` and `tree` that land in `runIdentity` and the evidence
197
+ graph. It is the last bare-name process launch left in `src/`, and
198
+ `tests/contract/no-bare-process-exec.spec.ts` now audits the whole tree.
199
+ - **The coverage exemption ledger can no longer drift silently.** Each
200
+ non-structural entry in `docs/COVERAGE-EXEMPTIONS.json` now carries
201
+ `defectSignatures` — regexes that must still match its file — or an explicit
202
+ `closureState` when the defect it described is gone. A signature that stops
203
+ matching fails the gate, so a code fix forces a ledger edit in the same
204
+ commit. Six entries were already describing defects the current code had
205
+ fixed (`maturity`, `business-case`, `dashboard`, `enterprise`, `exec-report`
206
+ and the `report-playwright` row), and are reclassified accordingly.
207
+ - **Skipped and expected-fail tests now have a price.** Nothing in the
208
+ repository counted them, so the count could grow from zero to hundreds with
209
+ every other signal still green. `docs/SKIP-BUDGET.json` records the current
210
+ counts — 8 skipped tests, 1 skipped file, 3 expected failures — measured by
211
+ `scripts/vitest-skip-budget-reporter.mjs` during the run. They may fall;
212
+ raising them fails `npm run skip:budget` and names the tests that spent the
213
+ budget. A missing or incomplete measurement fails too, so a reporter that
214
+ stops being wired in cannot read as a clean run.
215
+ - **The M26 release gate and the version-drift checks are covered where it
216
+ matters.** Both run inside `certify` and both were excluded from the coverage
217
+ ratchet, so their reject arms — the paths that only execute when something is
218
+ wrong — had no reviewer pressure on them. `tests/ledger/m26-validator-reject-arms.spec.ts`
219
+ is table-driven over every required field, so a field that is added without a
220
+ test fails; `tests/release/version-surface-drift-arms.spec.ts` covers the
221
+ fail-fast arms of the version synchronizer.
222
+ - **One error derivation, one `isRecord`, one crash-isolation path.** The tree
223
+ carried `isRecord` eight times (seven byte-identical), error rendering four
224
+ times under two names, and crash isolation seven times — and the copies
225
+ disagreed, which is the only reason any of this mattered. `String(obj)`
226
+ renders `[object Object]`, so the two _thinner_ error helpers turned a real
227
+ Node failure shape like `throw { code: "EISDIR" }` into a message naming
228
+ nothing — in a doctor detail, an MCP tool result and a `summary` line
229
+ respectively. The richer body survived the collapse, and
230
+ `isRecord` — the predicate every JSON reader uses to decide "this is an
231
+ object I may index into", which is a question a hostile saved report gets
232
+ to ask — is now the exported one in `src/lib/safe-json.ts`. The four
233
+ adapters' duplicated `try { rule.run } catch { onCrash }` is now
234
+ `runRuleIsolated`, because that block is what the `rulesCrashed` count is
235
+ built on and seven copies mean seven chances to lose it.
236
+ The per-adapter _filter chain_ and budget check were deliberately **not**
237
+ folded into the existing `runRulesShared`: the TypeScript adapter injects
238
+ an AST, framework tags, a lazy `codeText` getter, config-only gating and
239
+ `configGateMatches`, and it _aborts the whole file_ on budget exhaustion
240
+ where `runRulesShared` only skips one rule. Routing every adapter through
241
+ it as written would have silently changed which rules run — the exact
242
+ unmeasured claim this program exists to delete.
243
+ `tests/contract/single-error-helper.spec.ts` holds the counts at one, and
244
+ pins the object arm so a future "simplification" cannot drop it.
245
+
246
+ - **A crashed rule is no longer certified as a rule that stayed silent.**
247
+ The doc generator caught a rule THROW while running it against its own
248
+ must-not-fire fixture and returned `null`; the caller read that as
249
+ `fired: false` and committed, into a generated doc page and the
250
+ certification surface, the sentence _"Verified against … — a legitimate,
251
+ similar-looking pattern this rule correctly leaves alone."_ A detector that
252
+ crashes produces exactly the same absence of findings as one that correctly
253
+ abstains, so that claim had no evidence behind it — and it contradicted the
254
+ same function's own docstring, which says the field degrades honestly.
255
+ The outcome is now the tri-state the doctor's own model already defines:
256
+ `FIRED` (a real firewall violation), `DID_NOT_FIRE` (certified), and
257
+ `INCONCLUSIVE` (the rule did not run). An `INCONCLUSIVE` page says so and
258
+ says why, and it never renders the certification sentence. A missing
259
+ fixture is a fourth, separate thing — nothing was attempted — and says
260
+ that instead. The field is typed as a `FixtureOutcome` union rather than a
261
+ boolean, so reintroducing a derived `fired` flag does not typecheck.
262
+
263
+ - **A human-facing table stopped sorting by code unit.** Pinning every
264
+ `localeCompare` to code-unit order (the fix for the ambient-locale drift)
265
+ made the per-rule corpus-occurrence table read
266
+ `SeleniumHQ-selenium` before `microsoft-playwright-dotnet`, because `S`
267
+ sorts before `m`. Stable, and worse to read than the alphabetical order the
268
+ table implies it has. That surface is a table a person chooses repos from,
269
+ so it now uses an **explicitly pinned** locale — readable order, identical
270
+ on every machine, which is the actual defect being avoided.
271
+
272
+ - **Fifteen silent capability losses are now counted, and the count reaches the
273
+ report.** A `catch` in a detection path that returned a clean default made
274
+ the scan exit 0, report `analysisComplete`, and quietly lose the thing that
275
+ made its verdict trustworthy — the reader had no way to tell a whole scan
276
+ from a narrowed one. The worst case was `getCodeOnlyText` returning raw text
277
+ after a throw, which switches OFF the comment/string false-positive firewall
278
+ for that file rather than merely slowing it down. Every such site now records
279
+ a reason in one append-only ledger (`src/engine/degradation-ledger.ts`),
280
+ following the precedent already set by `parserRetryDegradationCount`, and the
281
+ scan result carries `analysisStatus.degradations` — reason-coded counts,
282
+ present only when something was actually lost, alongside a
283
+ `degraded:<reason>:<count>` entry in `reasons`. A non-empty set makes the
284
+ scan `partial`. `truncationReasons` is untouched: a degradation is not
285
+ truncation, and a reader must be able to tell "the scan stopped" from "the
286
+ scan lost a layer".
287
+ - Two distinctions the ledger refuses to blur. **Absent is not degraded:** a
288
+ Python, Java, Go or Rust repository has no `package.json`, and recording
289
+ that would mark every non-Node project partial while training readers to
290
+ ignore the field — so only a manifest that exists and will not parse
291
+ counts. **A no-AST adapter is not a downgrade either:** the same line
292
+ W1.4 draws for the deadline fallback.
293
+ - Two sites outside the original list were found by the new contract spec
294
+ and fixed in the same commit: the tree-sitter Java/C#/Python parses (left
295
+ alone, because the pipeline already counts every `parseAst → undefined` as
296
+ one parse fallback, and counting again would tally one file twice in two
297
+ different fields) and `hashDir`'s `readdirSync`, whose early `return`
298
+ omitted a whole subtree from the detector fingerprint — two rule trees
299
+ differing only inside an unreadable directory then hash identically, which
300
+ is a stale-cache hit wearing a fresh one's clothes.
301
+ - `mjolnir trend show` no longer prints "No trend data yet." and exits clean
302
+ for a history file whose every line failed to parse. The count of
303
+ discarded lines is now reported on stderr, and a history that exists but
304
+ cannot be read is `EXIT_INTERNAL` — the difference between no history and
305
+ unreadable history, which both used to arrive as the same empty array.
306
+ - `mjolnir explain` distinguishes _the rule found nothing_ from _the rule
307
+ never ran_. A rule that THREW on its own fixture produced the same output
308
+ as a correctly silent one, in the one surface whose purpose is to show
309
+ that a rule works. It now says so, with the reason.
310
+ - `tests/contract/no-uncounted-degradation.spec.ts` is the durable half: a
311
+ `catch` in the detection path that RETURNS A VALUE must record a reason,
312
+ rethrow, route to a counted sink, or be exempted with a stated failure
313
+ direction. The rule is about the _return_, not the `catch` — 37 of the 70
314
+ detection-path catches return nothing and cannot lie to a caller, and a
315
+ spec that listed all 70 as individual exemptions would be the same as no
316
+ exemption list at all.
317
+
318
+ - **Scanning a subdirectory no longer reports a framework it read from its
319
+ parent.** `runScan` walks up past the target to find the project root, and
320
+ re-anchors the scan root to the target when the target is a strict
321
+ descendant — but it kept the discovered root's parsed `package.json`. So
322
+ `mjolnir scan monorepo/packages/foo` reported `jest` because
323
+ `monorepo/package.json` said so: a read outside the explicit scan root, and
324
+ a framework verdict about a tree nobody pointed at. Framework detection now
325
+ works from in-root evidence only (config files and the anchor's own
326
+ manifest), and reports `frameworkDetectionUnknown` when that evidence is
327
+ absent — an absent verdict you can see, rather than a parent's you cannot.
328
+ Scanning the project root itself is unchanged. This is the CLI counterpart
329
+ to the containment property the MCP workspace-boundary contract already
330
+ enforced.
331
+ - **A scan that ran out of time no longer loses its AST stage silently.** When a
332
+ scan passes `--max-duration`, the remaining files were analyzed by regex
333
+ instead of AST — a different detection capability, not a slower version of the
334
+ same one, so the same tree produced different findings and a different score.
335
+ The mode was faithfully recorded in the scan cache and reported nowhere; the
336
+ only nearby disclosure, `file-budget`, fired incidentally because the
337
+ per-file rule-loop deadline was usually already spent too. Such a scan now
338
+ carries the truncation reason `ast-budget-fallback` and an
339
+ `analysisStatus.reasons` entry `ast-budget-fallback-files:<n>` saying how many
340
+ files were analyzed by regex, and is honestly `partial`. An adapter that
341
+ declares no AST stage at all (a YAML workflow, for instance) is a declared
342
+ capability envelope and is NOT reported as truncation. `truncationReasons` is
343
+ an open `string[]` by design, so consumers should test for members rather than
344
+ assert the exact array.
98
345
  - **`frontier:contracts` was reporting 19 suites it never ran.** It named 24
99
346
  test files; nineteen had been deleted by the `cc5fcb88` cleanup and its
100
347
  follow-up. Vitest treats a missing path as "no tests here" rather than an
@@ -285,6 +532,27 @@ were live in 3.0.0 and neither was in the plan.
285
532
 
286
533
  ### Known open, deliberately
287
534
 
535
+ - [ ] **Trust certification is not claimed, and this release was authorized
536
+ without it.** `candidate:readiness` reports `BLOCKED` /
537
+ `INCONCLUSIVE` on all ten of its checks — candidate identity is not a
538
+ release candidate, the candidate SHA is not authorized, engineering
539
+ certification is not complete, and external validation, protected holdout
540
+ proof, real-world repository proof, the platform matrix, consumer install
541
+ proof and remote workflow proof are all absent.
542
+ `m26:audit` is likewise unsatisfied. Both ran, both printed, and neither
543
+ blocked the publish, because `vars.STABLE_RELEASE_AUTHORIZED` is `true` —
544
+ the same explicit override 4.0.0 shipped under.
545
+ The distinction is the point: **publication of a package is not the same
546
+ claim as a certification of it.** 5.0.0 asserts that the reporting
547
+ surface is honest, that a silent capability loss is disclosed, and that no
548
+ verdict is published without a measurement behind it. It does not assert
549
+ that a holdout corpus, a platform matrix and an external validation run
550
+ have been completed, because none of them have.
551
+ Consumers are not asked to take that on trust: the npm package publishes
552
+ the candidate manifest, which reads `NOT_CERTIFIED` and
553
+ `NOT_AUTHORIZED`, and every one of those ten blockers is enumerated above
554
+ rather than summarised. Closing them is the work that would make a
555
+ certification claim possible; it is not work this release did.
288
556
  - [ ] `CERTIFICATION_STATES` is not in ladder order, so `rankOf` — the only
289
557
  ordering function — ranks `KNOWN` above `TRUST-COMPLETE`, and
290
558
  `requiresEvidence` asks `BLOCKED` and `DEGRADED` for a corpus their own
package/README.br.md CHANGED
@@ -18,7 +18,7 @@ e depois pontua até onde o resultado merece confiança, com a evidência de cad
18
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
- npx mjolnir-qa@4.0.0
21
+ npx mjolnir-qa@5.0.0
22
22
  ```
23
23
 
24
24
  [Veja funcionando](#veja-funcionando) · [Início rápido](#início-rápido) · [O que encontra](#o-que-o-mjölnir-encontra) · [Pontuação](#a-pontuação-de-confiabilidade) · [Evidência](#o-modelo-de-evidência) · [Forense](#forense-de-execução) · [CI](#integridade-de-ci) · [Agentes](#agentes-de-ia) · [Segurança](#confiança-e-segurança) · [Limites](#o-que-o-mjölnir-não-pode-dizer) · [Docs](#documentação)
@@ -72,7 +72,7 @@ Nenhum deles deixa o pipeline vermelho, e todos parecem intencionais na revisão
72
72
 
73
73
  <sub>Cada achado que o scan de demonstração reportou para este workflow, na linha reportada. Gerado por `npm run docs:readme-brand` a partir de [`demo-report.json`](assets/readme/demo-report.json) e travado contra desvios na CI.</sub>
74
74
 
75
- **Modo estrito.** As detecções mais agressivas — `.only`, `continue-on-error`, testes vazios, abuso de retry — ficam na quarentena. Só rodam com `--strict` e são limitadas a severidade `info`: elas sinalizam, nunca bloqueiam. O scan padrão (`npx mjolnir-qa@4.0.0` sem `--strict`) cobre apenas regras core e extended. Adicione `--strict` quando quiser a camada de consultoria também.
75
+ **Modo estrito.** As detecções mais agressivas — `.only`, `continue-on-error`, testes vazios, abuso de retry — ficam na quarentena. Só rodam com `--strict` e são limitadas a severidade `info`: elas sinalizam, nunca bloqueiam. O scan padrão (`npx mjolnir-qa@5.0.0` sem `--strict`) cobre apenas regras core e extended. Adicione `--strict` quando quiser a camada de consultoria também.
76
76
 
77
77
  O Mjölnir lê a suíte, os workflows de CI e, se você tiver, o relatório de uma execução real. Ele não roda seus testes, não instala suas dependências e não executa o código que analisa. E quando não tem evidência, ele diz isso em vez de inventar confiança:
78
78
 
@@ -107,7 +107,7 @@ Um scan real de [`examples/demo-repo`](examples/demo-repo), uma pequena suíte P
107
107
 
108
108
  <p align="center">
109
109
  <a href="assets/video/mjolnir-demo.mp4">
110
- <img src="assets/video/mjolnir-demo-poster.png" alt="Um quadro da gravação de demonstração: npx mjolnir-qa@4.0.0 analisando o repositório de demonstração em uma janela de terminal" width="900" />
110
+ <img src="assets/video/mjolnir-demo-poster.png" alt="Um quadro da gravação de demonstração: npx mjolnir-qa@5.0.0 analisando o repositório de demonstração em uma janela de terminal" width="900" />
111
111
  </a>
112
112
  </p>
113
113
 
@@ -176,7 +176,7 @@ Essa é a unidade de valor: um lugar onde a CI reporta uma aprovação que não
176
176
  ## Início rápido
177
177
 
178
178
  ```bash
179
- npx mjolnir-qa@4.0.0
179
+ npx mjolnir-qa@5.0.0
180
180
  ```
181
181
 
182
182
  Ele analisa o diretório atual e imprime o Trust Report: o que encontrou, até onde você pode confiar, por quê e o que fazer em seguida. Sai com `0` quando nada foi encontrado no nível do gate ou acima.
@@ -184,7 +184,7 @@ Ele analisa o diretório atual e imprime o Trust Report: o que encontrou, até o
184
184
  Na CI, analise só o que a branch introduziu, para que uma suíte legada não afogue seu primeiro pull request:
185
185
 
186
186
  ```bash
187
- npx mjolnir-qa@4.0.0 --scope changed
187
+ npx mjolnir-qa@5.0.0 --scope changed
188
188
  ```
189
189
 
190
190
  `mjolnir ci install` grava isso como um workflow do GitHub Actions, usando a [action](https://github.com/Sergey-Bar/Mjolnir#readme) fixada na tag principal `v3` (ou `npx` puro com `--no-action`). Ele continua consultivo até você decidir que deve bloquear.
@@ -492,7 +492,7 @@ Fixe `@v3` para acompanhar a linha principal, ou uma tag exata (`@v0.5.32`) para
492
492
  Para levar os achados ao GitHub Code Scanning, envie o SARIF (requer `security-events: write` no escopo do workflow ou job):
493
493
 
494
494
  ```yaml
495
- - run: npx mjolnir-qa@4.0.0 --format sarif > mjolnir.sarif
495
+ - run: npx mjolnir-qa@5.0.0 --format sarif > mjolnir.sarif
496
496
  continue-on-error: true
497
497
  - uses: github/codeql-action/upload-sarif@v3
498
498
  if: ${{ !cancelled() }}
@@ -505,7 +505,7 @@ No GitLab, `--format codequality` grava o relatório do Code Quality que o widge
505
505
  ### Atribuição no escopo alterado
506
506
 
507
507
  ```bash
508
- npx mjolnir-qa@4.0.0 --scope changed
508
+ npx mjolnir-qa@5.0.0 --scope changed
509
509
  ```
510
510
 
511
511
  Os achados são atribuídos às linhas que sua branch adicionou, medidas contra a **merge-base**. O escopo é o mesmo conjunto de arquivos que um scan completo descobre (specs TS/JS e configurações de adaptadores, `test_*.py`, `*Test.java`, `*Tests.cs`, `.github/workflows/*.yml`), mais as alterações não commitadas e não rastreadas, então funciona antes do commit. A base é resolvida como `main → master → origin/main → origin/master → origin/HEAD`; substitua com `--base <ref>`.
@@ -533,7 +533,7 @@ SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
533
533
  Adicione-o a um cliente que tenha sua própria CLI:
534
534
 
535
535
  ```bash
536
- claude mcp add mjolnir -- npx -y mjolnir-qa@4.0.0 mcp
536
+ claude mcp add mjolnir -- npx -y mjolnir-qa@5.0.0 mcp
537
537
  ```
538
538
 
539
539
  Ou a qualquer cliente que aceite um bloco `mcpServers`:
@@ -541,7 +541,7 @@ Ou a qualquer cliente que aceite um bloco `mcpServers`:
541
541
  ```json
542
542
  {
543
543
  "mcpServers": {
544
- "mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@4.0.0", "mcp"] }
544
+ "mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@5.0.0", "mcp"] }
545
545
  }
546
546
  }
547
547
  ```
@@ -632,7 +632,7 @@ O ambiente de desenvolvimento, os comandos dos gates permanentes e as leis anti-
632
632
  <img src="assets/readme/closing.svg" alt="Rode no seu repo." width="100%" />
633
633
 
634
634
  ```bash
635
- npx mjolnir-qa@4.0.0
635
+ npx mjolnir-qa@5.0.0
636
636
  ```
637
637
 
638
638
  [Leia o guia](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [Site de documentação](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)
package/README.md CHANGED
@@ -18,7 +18,7 @@ when verification isn't earning its keep.
18
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
- npx mjolnir-qa@4.0.0
21
+ npx mjolnir-qa@5.0.0
22
22
  ```
23
23
 
24
24
  [See it work](#see-it-work) · [Quickstart](#quickstart) · [What it finds](#what-mjölnir-finds) · [Score](#the-worthiness-score) · [Evidence](#the-evidence-model) · [Forensics](#runtime-forensics) · [CI](#ci-integrity) · [Agents](#ai-agents) · [Security](#trust-and-security) · [Limits](#what-mjölnir-cannot-tell-you) · [Docs](#documentation)
@@ -67,7 +67,7 @@ reported. Generated by `npm run docs:readme-brand` from
67
67
  **Strict mode.** The most aggressive detections — `.only`, `continue-on-error`,
68
68
  empty tests, retry abuse — live in the quarantine tier. They run only
69
69
  under `--strict` and are capped to `info` severity: they flag, they never
70
- gate. The default scan (`npx mjolnir-qa@4.0.0` without `--strict`)
70
+ gate. The default scan (`npx mjolnir-qa@5.0.0` without `--strict`)
71
71
  covers core and extended rules only. Add `--strict` when you want the
72
72
  advisory layer too.
73
73
 
@@ -127,7 +127,7 @@ CI. The full `--verbose` report of the same scan is
127
127
 
128
128
  <p align="center">
129
129
  <a href="assets/video/mjolnir-demo.mp4">
130
- <img src="assets/video/mjolnir-demo-poster.png" alt="A frame of the demo recording: npx mjolnir-qa@4.0.0 scanning the demo repository in a terminal window" width="900" />
130
+ <img src="assets/video/mjolnir-demo-poster.png" alt="A frame of the demo recording: npx mjolnir-qa@5.0.0 scanning the demo repository in a terminal window" width="900" />
131
131
  </a>
132
132
  </p>
133
133
 
@@ -211,13 +211,13 @@ That is the unit of value: one place where CI reports a pass it did not earn.
211
211
  ## Quickstart
212
212
 
213
213
  ```bash
214
- npx mjolnir-qa@4.0.0
214
+ npx mjolnir-qa@5.0.0
215
215
  ```
216
216
 
217
217
  Three steps to trust your release pipeline:
218
218
 
219
- 1. **Scan** — `npx mjolnir-qa@4.0.0` — scans the current directory, prints the Trust Report, exits `1` if findings at the gate
220
- 2. **Block in CI** — `npx mjolnir-qa@4.0.0 --scope changed` — scans only changed lines, blocks PRs with error findings
219
+ 1. **Scan** — `npx mjolnir-qa@5.0.0` — scans the current directory, prints the Trust Report, exits `1` if findings at the gate
220
+ 2. **Block in CI** — `npx mjolnir-qa@5.0.0 --scope changed` — scans only changed lines, blocks PRs with error findings
221
221
  3. **Fix and re-verify** — `mjolnir fix` applies safe auto-fixes, then re-scans to prove each one landed
222
222
 
223
223
  Install the advisory PR workflow first, so existing trust debt cannot break
@@ -627,14 +627,14 @@ In your existing workflow, pin the action and explicitly opt into an error gate:
627
627
  The `--blocking error` flag does the same in any CI pipeline:
628
628
 
629
629
  ```bash
630
- npx mjolnir-qa@4.0.0 --scope changed --blocking error
630
+ npx mjolnir-qa@5.0.0 --scope changed --blocking error
631
631
  ```
632
632
 
633
633
  To put findings in GitHub Code Scanning, upload SARIF (requires
634
634
  `security-events: write` at workflow or job scope):
635
635
 
636
636
  ```yaml
637
- - run: npx mjolnir-qa@4.0.0 --format sarif > mjolnir.sarif
637
+ - run: npx mjolnir-qa@5.0.0 --format sarif > mjolnir.sarif
638
638
  continue-on-error: true
639
639
  - uses: github/codeql-action/upload-sarif@v3
640
640
  if: ${{ !cancelled() }}
@@ -649,7 +649,7 @@ Editor and pipeline setup: [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md
649
649
  ### Changed-scope attribution
650
650
 
651
651
  ```bash
652
- npx mjolnir-qa@4.0.0 --scope changed
652
+ npx mjolnir-qa@5.0.0 --scope changed
653
653
  ```
654
654
 
655
655
  Findings are attributed to the lines your branch added, measured against
@@ -687,7 +687,7 @@ re-scan, never from the agent's own report of success.
687
687
  Add it to a client that ships its own CLI:
688
688
 
689
689
  ```bash
690
- claude mcp add mjolnir -- npx -y mjolnir-qa@4.0.0 mcp
690
+ claude mcp add mjolnir -- npx -y mjolnir-qa@5.0.0 mcp
691
691
  ```
692
692
 
693
693
  Or to any client that takes an `mcpServers` block:
@@ -697,7 +697,7 @@ Or to any client that takes an `mcpServers` block:
697
697
  "mcpServers": {
698
698
  "mjolnir": {
699
699
  "command": "npx",
700
- "args": ["-y", "mjolnir-qa@4.0.0", "mcp"]
700
+ "args": ["-y", "mjolnir-qa@5.0.0", "mcp"]
701
701
  }
702
702
  }
703
703
  }
@@ -839,7 +839,7 @@ fixture-firewall laws are in [CONTRIBUTING.md](CONTRIBUTING.md).
839
839
  <img src="assets/readme/closing.svg" alt="Run it on your repo." width="100%" />
840
840
 
841
841
  ```bash
842
- npx mjolnir-qa@4.0.0
842
+ npx mjolnir-qa@5.0.0
843
843
  ```
844
844
 
845
845
  [Read the guide](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [Docs site](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)