mjolnir-qa 2.0.2 → 2.1.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,89 @@ once shipped, so this file is the record of what changed between versions.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [2.1.0] — 2026-09-24
15
+
16
+ ### Added
17
+
18
+ - Added seven milestone commands to the public CLI and root help:
19
+ - `mjolnir ci-integrity` validates GitHub/GitLab/Jenkins scan gates and reports non-blocking or disabled candidates.
20
+ - `mjolnir framework-maturity` reports bounded F0–F5 maturity while preserving human calibration authority.
21
+ - `mjolnir suppression-gate` evaluates reasons, expiry, allowlists, total counts, and matched-finding mass suppression.
22
+ - `mjolnir cross-file` reports duplicate test names, shared imports, circular dependencies, and amplified findings.
23
+ - `mjolnir contract-verify` validates machine-contract fields and binds persisted contracts to a fresh scan.
24
+ - `mjolnir trust-trend` persists, deduplicates, and compares trust snapshots.
25
+ - `mjolnir evidence-graph` builds provenance-bearing evidence graphs and supports file/rule queries.
26
+ - Added a zero-touch PR framework: Conventional Commit enforcement, seeded property tests, merge-result verification, and local/CI command-parity checks.
27
+ - Added dedicated, discoverable property and fuzz suites. Fuzz cases use fixed seeds; property tests remain isolated from default coverage collection.
28
+ - Added CI integrity, suppression, contract, provenance, cross-file, and trust regression suites covering malformed input, partial scans, inactive suppressions, and platform-stable exit behavior.
29
+ - Added stable-only `v1`/`v2` action-tag maintenance. RC tags never move stable consumer tags.
30
+ - Added pinned current corpus revisions and local fixture tree revisions. Baseline counts were not rewritten; corpus drift remains an explicit audit failure.
31
+
32
+ ### Fixed
33
+
34
+ - Fixed false-green milestone engines:
35
+ - machine-contract verification now compares every contract projection, including optional provenance and forensic verdicts;
36
+ - trust snapshots use caller-provided timestamps instead of an embedded wall clock;
37
+ - suppression mass uses actual matched pre-suppression findings and active suppressions;
38
+ - evidence provenance is derived from real file contents;
39
+ - cross-file dependency analysis uses the requested target root;
40
+ - framework maturity uses the supported F5 ceiling.
41
+ - Fixed persisted contract handling: documents use strict runtime schema validation and are verified against a fresh scan rather than self-attesting.
42
+ - Fixed zero-finding and partial-scan reporting so incomplete or unclassified analysis cannot render as a clean, proven, or merge-ready suite.
43
+ - Fixed CI workflow audit parsing to fail closed for dynamic conditions, `continue-on-error`, negated commands, multi-pipe status masking, inactive GitLab rules, advisory `after_script` commands, and missing blocking scans.
44
+ - Fixed the coverage job/ratchet mismatch: merge verification now generates the coverage summary it enforces.
45
+ - Fixed stress determinism by normalizing both analysis and machine-contract duration fields, running real concurrent scans, and making the 10k workflow validate JSON even when findings are advisory.
46
+ - Fixed property/fuzz discovery and workflow trigger/name so required PR checks are actually produced.
47
+ - Fixed root help, command registry, README, and release documentation drift for the new command surface.
48
+
49
+ ### Security
50
+
51
+ - The composite Action and generated CI surfaces use exact released versions, immutable action references, least-privilege permissions, and explicit exit semantics.
52
+ - The composite Action defaults to blocking on findings and partial scans; advisory behavior requires an explicit opt-out.
53
+ - Release publication is isolated from `main`, uses audited artifacts, npm OIDC trusted publishing with provenance, npm 11.5.1+, a `next` RC dist-tag, and verified GitHub prerelease assets.
54
+ - Pull-request shell inputs and workflow-derived values are passed through environment variables instead of direct `${{ }}` interpolation.
55
+ - Machine-contract, suppression-policy, roadmap, and persisted-artifact validation now reject malformed and adversarial inputs rather than fabricating or trusting them.
56
+ - Main-branch deletion and the complete required PR check matrix are enforced by repository ruleset `01`. The repository is solo-maintained, so the owner explicitly chose not to require a second approving review.
57
+
58
+ ### Performance
59
+
60
+ - Centralized deterministic CLI timing normalization and expanded replay, soak, and concurrent stress coverage.
61
+ - Added bounded corpus scans, exact source revisions, and fail-closed baseline provenance checks.
62
+ - Added practical pipeline/command regression tests without changing the frozen 96% branch ratchet.
63
+
64
+ ### Testing
65
+
66
+ - Full instrumented release gate: 408 test files, 10,351 passing tests, one expected failure documenting the outstanding orphan corpus baseline, and five intentional skips.
67
+ - Coverage ratchet at release: 98.58% statements, 96.00% branches, 99.38% functions, and 98.84% lines.
68
+ - Focused gates green: build, lint, typecheck, certification, property, fuzz, stress/soak/concurrency, release/workflow contract tests, pack audit, brand, site, and local/CI parity.
69
+ - Historical failed runs remain historical evidence; they are not retroactively changed.
70
+
71
+ ### Changed
72
+
73
+ - `ci-local` now runs one complete instrumented suite plus property/fuzz/ratchet/audit/brand/site/parity gates instead of silently omitting release checks.
74
+ - Release promotion is explicit and branch/tag based; merging the version PR does not itself publish npm.
75
+ - Suppression counts and governance outputs distinguish configured, active, expired, and matched findings.
76
+ - Rule IDs remain immutable across the 2.x line. Existing detector contracts,
77
+ including `QA-PW-001`, retain their identity while framework maturity and
78
+ evidence quality improve around them.
79
+ - The CLI command registry is shared by help, dispatch, and CI-integrity classification.
80
+
81
+ ### Breaking changes
82
+
83
+ - The package now requires Node.js `>=22.18`.
84
+ - Direct composite-Action consumers now get blocking defaults for findings and partial scans unless they explicitly opt out.
85
+ - Generated CI installation remains opt-in/advisory for first adoption; use `mjolnir ci install --gate error` when an enforcing install is required.
86
+ - Stable release publication no longer occurs automatically from `main`; use the protected release branch and release workflow.
87
+ - The historical `v2.0.3` tag is retained unchanged. This release does not move, delete, or republish that tag.
88
+
89
+ ### Migration
90
+
91
+ 1. Install or invoke `mjolnir-qa@2.1.0` with Node.js 22.18 or newer.
92
+ 2. Replace floating Action versions with `@v2` or the exact `v2.1.0` tag when reproducible enforcement is required.
93
+ 3. Review suppression expiry/allowlist policy before enabling `suppression-gate`; existing entries are policy data, not proof of human validation.
94
+ 4. Run the seven new commands in report mode first and review their JSON before making them release gates.
95
+ 5. Adjudicate remaining corpus count/orphan drift and human/design-partner validation separately; this release does not claim those are closed.
96
+
14
97
  ## [2.0.2] — 2026-09-22
15
98
 
16
99
  ### Fixed
package/README.md CHANGED
@@ -150,6 +150,17 @@ FP risk: low (author estimate)
150
150
  Languages: yaml
151
151
  Frameworks: github-actions, azure-pipelines
152
152
 
153
+ COPY-READY REVIEW COMMENT
154
+ Advisory finding — this does not block merging: Job `security-scan` runs a
155
+ verification gate under `continue-on-error: true`.
156
+ Why it weakens verification: This job can fail every day and CI will still
157
+ show green. The checkmark on this workflow cannot be trusted.
158
+ Confidence: high, evidence E2, tier quarantine; measured FP 11% (19 verdicts).
159
+ Suggested fix: Remove continue-on-error, or scope it to individual
160
+ non-blocking steps only.
161
+ Verify with: mjolnir --scope changed, then mjolnir explain QA-CI-001 if the
162
+ finding still appears.
163
+
153
164
  WHAT WAS FOUND (real detector output, not a mockup)
154
165
  Job `security-scan` runs a verification gate under `continue-on-error: true`.
155
166
 
@@ -197,30 +208,26 @@ Three steps to trust your release pipeline:
197
208
  2. **Block in CI** — `npx mjolnir-qa@latest --scope changed` — scans only changed lines, blocks PRs with error findings
198
209
  3. **Fix and re-verify** — `mjolnir fix` applies safe auto-fixes, then re-scans to prove each one landed
199
210
 
200
- Add it to your pipeline so it gates releases on error findings:
211
+ Install the advisory PR workflow first, so existing trust debt cannot break
212
+ CI on day one:
201
213
 
202
214
  ```bash
203
- npx mjolnir-qa@latest --scope changed --blocking error
215
+ mjolnir ci install
204
216
  ```
205
217
 
206
- `mjolnir ci install` writes the GitHub Actions workflow with a blocking gate (error severity), pinned to this version:
218
+ After reviewing the findings or baselining existing debt, opt into blocking:
207
219
 
208
220
  ```bash
209
221
  mjolnir ci install --gate error
210
222
  ```
211
223
 
212
- Run advisory mode only when you want to preview findings without blocking:
213
-
214
- ```bash
215
- mjolnir ci install --gate advisory
216
- ```
217
-
218
224
  | Command | What it does |
219
225
  | ----------------------------------- | ----------------------------------------------- |
220
226
  | `mjolnir` | Trust Report: verdict, confidence, next action |
221
227
  | `mjolnir --scope changed` | Only what your branch introduced (CI form) |
222
228
  | `mjolnir --blocking error` | Exit 1 on error findings — gate releases |
223
- | `mjolnir ci install --gate error` | Write the blocking PR workflow |
229
+ | `mjolnir ci install` | Write the advisory PR workflow (default) |
230
+ | `mjolnir ci install --gate error` | Opt into the blocking PR workflow |
224
231
  | `mjolnir business-case` | ROI estimate: projected savings per finding |
225
232
  | `mjolnir explain QA-CI-001` | What, why and fix, plus the measured FP rate |
226
233
  | `mjolnir why src/a.spec.ts:42` | Why this exact line was flagged. Never gates. |
@@ -236,30 +243,37 @@ mjolnir ci install --gate advisory
236
243
 
237
244
  <br />
238
245
 
239
- | Command | What it does |
240
- | ----------------------------------- | ---------------------------------------------------- |
241
- | `mjolnir --classic` | The pre-Trust-Report score banner render |
242
- | `mjolnir explain verdict` | Why the saved scan's verdict is what it is |
243
- | `mjolnir triage ./test-results/` | Guided triage. Every row ends in a next action. |
244
- | `mjolnir pw-report ./test-results/` | Playwright run summary: retries, flakes, slowest |
245
- | `mjolnir doctor:playwright` | Playwright-only deep scan plus Selector Health Score |
246
- | `mjolnir fix --dry-run` / `fix` | Safe auto-fixes, each re-scanned to prove it landed |
247
- | `mjolnir baseline` / `diff` | Snapshot findings, then report only new or worse |
248
- | `mjolnir impact --since <ref>` | What a commit introduced and resolved |
249
- | `mjolnir summary` | CI annotations and a step summary from a report |
250
- | `mjolnir pr-comment` | A scoped PR comment, as Markdown |
251
- | `mjolnir debt` | Test-debt register with a cost model |
252
- | `mjolnir handover` | Onboarding map of the suite for a new QA engineer |
253
- | `mjolnir init` | Detect frameworks, print a setup checklist |
254
- | `mjolnir suppressions` | List suppressed findings, for governance |
255
- | `mjolnir rules --unmeasured` | The rules running on assumption, not measurement |
256
- | `mjolnir rules --md` | Full rule catalog (JSON or Markdown) |
257
- | `mjolnir doctor` | Self-audit of Mjölnir's own rule base |
258
- | `mjolnir create-rule <ID>` | Scaffold a new rule and its fixtures |
259
- | `mjolnir stats` | Local all-time counters of fixes seen |
260
- | `mjolnir badge` | shields.io endpoint JSON and snippet |
261
- | `mjolnir --cache` | Incremental re-scans via a local verdict cache |
262
- | `mjolnir --format mermaid` | Test-architecture diagram for a PR comment |
246
+ | Command | What it does |
247
+ | ----------------------------------- | ----------------------------------------------------- |
248
+ | `mjolnir --classic` | The pre-Trust-Report score banner render |
249
+ | `mjolnir explain verdict` | Why the saved scan's verdict is what it is |
250
+ | `mjolnir triage ./test-results/` | Guided triage. Every row ends in a next action. |
251
+ | `mjolnir pw-report ./test-results/` | Playwright run summary: retries, flakes, slowest |
252
+ | `mjolnir doctor:playwright` | Playwright-only deep scan plus Selector Health Score |
253
+ | `mjolnir fix --dry-run` / `fix` | Safe auto-fixes, each re-scanned to prove it landed |
254
+ | `mjolnir baseline` / `diff` | Snapshot findings, then report only new or worse |
255
+ | `mjolnir impact --since <ref>` | What a commit introduced and resolved |
256
+ | `mjolnir summary` | CI annotations and a step summary from a report |
257
+ | `mjolnir pr-comment` | A scoped PR comment, as Markdown |
258
+ | `mjolnir debt` | Test-debt register with a cost model |
259
+ | `mjolnir handover` | Onboarding map of the suite for a new QA engineer |
260
+ | `mjolnir init` | Detect frameworks, print a setup checklist |
261
+ | `mjolnir suppressions` | List suppressed findings, for governance |
262
+ | `mjolnir ci-integrity` | Verify blocking CI scans and suppression policy |
263
+ | `mjolnir framework-maturity` | Inspect bounded maturity with human calibration |
264
+ | `mjolnir suppression-gate` | Enforce expiry, allowlist, and mass-suppression rules |
265
+ | `mjolnir cross-file` | Analyze duplicate, shared, and circular test signals |
266
+ | `mjolnir contract-verify` | Verify a persisted machine contract artifact |
267
+ | `mjolnir trust-trend` | Persist and compare trust snapshots over time |
268
+ | `mjolnir evidence-graph` | Build or query the verification evidence graph |
269
+ | `mjolnir rules --unmeasured` | The rules running on assumption, not measurement |
270
+ | `mjolnir rules --md` | Full rule catalog (JSON or Markdown) |
271
+ | `mjolnir doctor` | Self-audit of Mjölnir's own rule base |
272
+ | `mjolnir create-rule <ID>` | Scaffold a new rule and its fixtures |
273
+ | `mjolnir stats` | Local all-time counters of fixes seen |
274
+ | `mjolnir badge` | shields.io endpoint JSON and snippet |
275
+ | `mjolnir --cache` | Incremental re-scans via a local verdict cache |
276
+ | `mjolnir --format mermaid` | Test-architecture diagram for a PR comment |
263
277
 
264
278
  `mjolnir help <command>` prints usage, examples and the next step for any
265
279
  of them.
@@ -556,22 +570,20 @@ propagate, always-success steps, reports consumed but never generated, and
556
570
  gates skipped on the events that should block. Each finding names the job,
557
571
  the step and the line, and carries its own evidence level.
558
572
 
559
- Generate the PR workflow with a blocking gate (error severity) — this is the
560
- default for a reason: findings that survive your pipeline survive your release.
573
+ Generate an advisory PR workflow first. It reports findings without blocking
574
+ and is pinned to this version, so adopting it cannot change gate semantics:
561
575
 
562
576
  ```bash
563
- mjolnir ci install --gate error
577
+ mjolnir ci install
564
578
  ```
565
579
 
566
- The gate is pinned to this version — a new release must not change your gate
567
- semantics without a commit of yours. Switch to advisory only when you want
568
- to preview findings without blocking:
580
+ After reviewing existing debt, opt into an enforcing gate:
569
581
 
570
582
  ```bash
571
- mjolnir ci install --gate advisory
583
+ mjolnir ci install --gate error
572
584
  ```
573
585
 
574
- In your existing workflow, pin the action and gate on error severity:
586
+ In your existing workflow, pin the action and explicitly opt into an error gate:
575
587
 
576
588
  ```yaml
577
589
  - uses: Sergey-Bar/Mjolnir@4a588bc62d517bc85fc44c0eae64c6587d3bf70b0
@@ -634,11 +646,11 @@ SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
634
646
  **AI writes the fix. Mjölnir verifies it.** The proof comes from the
635
647
  re-scan, never from the agent's own report of success.
636
648
 
637
- | Command | What the agent gets |
638
- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
639
- | `mjolnir mcp` | An [MCP](https://modelcontextprotocol.io) server over stdio. `scan`, `explain` and `diff` become callable tools. |
640
- | `mjolnir handoff` | A saved `--json` report becomes a deterministic Markdown plan: what was detected, the evidence boundary per finding, what must **not** change, how to verify. |
641
- | `mjolnir install` | Writes into the agent surfaces your repo already has (`.claude/`, `.cursor/`, `.kilo/`, `AGENTS.md`) so the agent re-scans before it claims it is done. |
649
+ | Command | What the agent gets |
650
+ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
651
+ | `mjolnir mcp` | An [MCP](https://modelcontextprotocol.io) server over stdio. `scan`, `explain`, `diff`, `verify`, `forensics`, `triage`, and `pw-report` are read-only callable tools. |
652
+ | `mjolnir handoff` | A saved `--json` report becomes a deterministic Markdown plan: what was detected, the evidence boundary per finding, what must **not** change, how to verify. |
653
+ | `mjolnir install` | Writes into the agent surfaces your repo already has (`.claude/`, `.cursor/`, `.kilo/`, `AGENTS.md`) so the agent re-scans before it claims it is done. |
642
654
 
643
655
  Add it to a client that ships its own CLI:
644
656
 
package/dist/cli.d.mts CHANGED
@@ -1226,6 +1226,8 @@ interface ScanHooks {
1226
1226
  * never on the stdout machine contracts.
1227
1227
  */
1228
1228
  onGateNotice?: (notice: string) => void;
1229
+ onTestFilesDiscovered?: (files: readonly string[]) => void;
1230
+ onPreSuppressionFindings?: (findings: readonly Finding[]) => void;
1229
1231
  }
1230
1232
  /**
1231
1233
  * Workspace fallback for targets with no discoverable project root
@@ -1381,7 +1383,7 @@ declare function runScan$1(args: CliArgs, hooks?: ScanHooks): Promise<ScanResult
1381
1383
  * scripts/sync-sarif-version.cjs and guarded by the version-consistency
1382
1384
  * spec. cli.ts re-exports this as CLI_VERSION.
1383
1385
  */
1384
- declare const ENGINE_VERSION = "2.0.2";
1386
+ declare const ENGINE_VERSION = "2.1.0";
1385
1387
  //#endregion
1386
1388
  //#region src/cli-io.d.ts
1387
1389
  /**
@@ -1623,7 +1625,7 @@ export declare function runAnalyzeCommand(argv: string[], io: {
1623
1625
  export declare function runCiAdapterCommand(argv: string[], io: {
1624
1626
  out: Output;
1625
1627
  err: Output;
1626
- }): Promise<number>;
1628
+ }): number;
1627
1629
  //#endregion
1628
1630
  //#region src/commands/dashboard.d.ts
1629
1631
  export declare function runDashboardCommand(argv: string[], io: {
@@ -1643,6 +1645,36 @@ export declare function runMaturityCommand(argv: string[], io: {
1643
1645
  err: Output;
1644
1646
  }): number;
1645
1647
  //#endregion
1648
+ //#region src/commands/milestone.d.ts
1649
+ export declare function runFrameworkMaturityCommand(argv: string[], io?: {
1650
+ out: Output;
1651
+ err: Output;
1652
+ }): number;
1653
+ export declare function runSuppressionGateCommand(argv: string[], io?: {
1654
+ out: Output;
1655
+ err: Output;
1656
+ }): Promise<number>;
1657
+ export declare function runCrossFileCommand(argv: string[], io?: {
1658
+ out: Output;
1659
+ err: Output;
1660
+ }): Promise<number>;
1661
+ export declare function runContractVerifyCommand(argv: string[], io?: {
1662
+ out: Output;
1663
+ err: Output;
1664
+ }): Promise<number>;
1665
+ export declare function runTrustTrendCommand(argv: string[], io?: {
1666
+ out: Output;
1667
+ err: Output;
1668
+ }): Promise<number>;
1669
+ export declare function runEvidenceGraphCommand(argv: string[], io?: {
1670
+ out: Output;
1671
+ err: Output;
1672
+ }): Promise<number>;
1673
+ export declare function runCIIntegrityCommand(argv: string[], io?: {
1674
+ out: Output;
1675
+ err: Output;
1676
+ }): Promise<number>;
1677
+ //#endregion
1646
1678
  //#region src/cli.d.ts
1647
1679
  export declare const runScan: typeof runScan$1, buildUniversalRules: typeof buildUniversalRules$1, fallbackWorkspace: typeof fallbackWorkspace$1, pathMatchesGlob: typeof pathMatchesGlob$1, isValidFindingRecord: typeof isValidFindingRecord$1, discoverAndParseRuntimeReport: typeof discoverAndParseRuntimeReport$1, KNOWN_RULE_IDS: ReadonlySet<string>, OVERLAP_META_BY_RULE_ID: ReadonlyMap<string, OverlapMeta>, EVIDENCE_OVERRIDES: ReadonlyMap<string, string>, SUITE_INVALIDATING_RULE_IDS: ReadonlySet<string>;
1648
1680
  /** A usage-error detail: the offending token, when one exists. */
@@ -1695,7 +1727,7 @@ export declare function runSuppressions(io?: {
1695
1727
  out: Output;
1696
1728
  err?: Output;
1697
1729
  }): number;
1698
- export declare function printUsage(print: (s: string) => void): void;
1730
+ export declare function printUsage(print: (s: string) => void, width?: number): void;
1699
1731
  export declare function main(argv?: string[], io?: {
1700
1732
  out: Output;
1701
1733
  err: Output;