mjolnir-qa 2.0.0 → 2.0.2

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/README.uk.md CHANGED
@@ -81,7 +81,7 @@ Mjölnir читає набір тестів, CI-workflow і, якщо він є,
81
81
  Реальне сканування [`examples/demo-repo`](examples/demo-repo), невеликого набору тестів Playwright із CI-workflow. Ось куди пішли його бали:
82
82
 
83
83
  <p align="center">
84
- <img src="assets/readme/terminal-hero.svg" alt="Розбивка вирахувань Mjölnir: WORTHINESS 75/100 NEEDS WORK, оцінка за категоріями, блок вирахувань за серйозністю та список FIX THIS FIRST" width="520" />
84
+ <img src="assets/readme/terminal-hero.svg" alt="Розбивка вирахувань Mjölnir: WORTHINESS 80/100 WORTHY, оцінка за категоріями, блок вирахувань за серйозністю та список FIX THIS FIRST" width="520" />
85
85
  </p>
86
86
 
87
87
  <sub>Згенеровано командою `npm run docs:hero` з реального сканування і захищено від розбіжностей у CI. Повний звіт `--verbose` того самого сканування — [`demo.svg`](assets/readme/demo.svg) (`npm run docs:demo`).</sub>
@@ -312,8 +312,8 @@ e2e/login.spec.ts
312
312
  role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
313
313
 
314
314
  e2e/checkout.spec.ts
315
- [█████████████████░░░] 86 / 100
316
- role/text: 3 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
315
+ [██████████████████░░] 88 / 100
316
+ role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
317
317
  ```
318
318
 
319
319
  Це вимірює **стійкість, а не коректність**. `.btn.btn-primary > div:nth-child(2)` проходить сьогодні й проходитиме, доки хтось не торкнеться розмітки. Низька оцінка ніколи не стверджує, що тест зламаний, — лише що він залежить від розмітки, яку ніхто не обіцяв зберігати.
package/README.vi.md CHANGED
@@ -81,7 +81,7 @@ Mjölnir đọc bộ test, các workflow CI và, nếu bạn có, báo cáo củ
81
81
  Một lần quét thật trên [`examples/demo-repo`](examples/demo-repo), một bộ test Playwright nhỏ có workflow CI. Đây là nơi điểm của nó bị trừ:
82
82
 
83
83
  <p align="center">
84
- <img src="assets/readme/terminal-hero.svg" alt="Bảng phân tích trừ điểm của Mjölnir: WORTHINESS 75/100 NEEDS WORK, điểm theo từng hạng mục, ô trừ điểm theo mức nghiêm trọng và danh sách FIX THIS FIRST" width="520" />
84
+ <img src="assets/readme/terminal-hero.svg" alt="Bảng phân tích trừ điểm của Mjölnir: WORTHINESS 80/100 WORTHY, điểm theo từng hạng mục, ô trừ điểm theo mức nghiêm trọng và danh sách FIX THIS FIRST" width="520" />
85
85
  </p>
86
86
 
87
87
  <sub>Được tạo bởi `npm run docs:hero` từ một lần quét thật và được khóa chống sai lệch trong CI. Báo cáo `--verbose` đầy đủ của cùng lần quét là [`demo.svg`](assets/readme/demo.svg) (`npm run docs:demo`).</sub>
@@ -312,8 +312,8 @@ e2e/login.spec.ts
312
312
  role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
313
313
 
314
314
  e2e/checkout.spec.ts
315
- [█████████████████░░░] 86 / 100
316
- role/text: 3 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
315
+ [██████████████████░░] 88 / 100
316
+ role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
317
317
  ```
318
318
 
319
319
  Điều này đo **độ bền, không phải độ đúng**. `.btn.btn-primary > div:nth-child(2)` qua hôm nay và sẽ tiếp tục qua cho đến khi ai đó động vào markup. Điểm thấp không bao giờ khẳng định test bị hỏng, chỉ nói rằng nó phụ thuộc vào markup mà không ai hứa giữ nguyên.
package/README.zh.md CHANGED
@@ -81,7 +81,7 @@ Mjölnir 读取测试套件、CI workflow,以及(如果有的话)一次真
81
81
  对 [`examples/demo-repo`](examples/demo-repo) 的一次真实扫描,这是一个带 CI workflow 的小型 Playwright 套件。它的分数都扣在了这里:
82
82
 
83
83
  <p align="center">
84
- <img src="assets/readme/terminal-hero.svg" alt="Mjölnir 的扣分明细:WORTHINESS 75/100 NEEDS WORK、按类别的评分、按严重级别的扣分框,以及 FIX THIS FIRST 列表" width="520" />
84
+ <img src="assets/readme/terminal-hero.svg" alt="Mjölnir 的扣分明细:WORTHINESS 80/100 WORTHY、按类别的评分、按严重级别的扣分框,以及 FIX THIS FIRST 列表" width="520" />
85
85
  </p>
86
86
 
87
87
  <sub>由 `npm run docs:hero` 根据一次真实扫描生成,并在 CI 中锁定以防漂移。同一次扫描的完整 `--verbose` 报告是 [`demo.svg`](assets/readme/demo.svg)(`npm run docs:demo`)。</sub>
@@ -312,8 +312,8 @@ e2e/login.spec.ts
312
312
  role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
313
313
 
314
314
  e2e/checkout.spec.ts
315
- [█████████████████░░░] 86 / 100
316
- role/text: 3 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
315
+ [██████████████████░░] 88 / 100
316
+ role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
317
317
  ```
318
318
 
319
319
  这衡量的是**韧性,而非正确性**。`.btn.btn-primary > div:nth-child(2)` 今天能通过,并会一直通过,直到有人改动标记结构。低分从不声称测试坏了,只说明它依赖于没有人承诺保留的标记结构。
package/README.zht.md CHANGED
@@ -81,7 +81,7 @@ Mjölnir 讀取測試套件、CI workflow,以及(如果有的話)一次真
81
81
  對 [`examples/demo-repo`](examples/demo-repo) 的一次真實掃描,這是一個附帶 CI workflow 的小型 Playwright 套件。它的分數都扣在了這裡:
82
82
 
83
83
  <p align="center">
84
- <img src="assets/readme/terminal-hero.svg" alt="Mjölnir 的扣分明細:WORTHINESS 75/100 NEEDS WORK、依類別的評分、依嚴重程度的扣分框,以及 FIX THIS FIRST 清單" width="520" />
84
+ <img src="assets/readme/terminal-hero.svg" alt="Mjölnir 的扣分明細:WORTHINESS 80/100 WORTHY、依類別的評分、依嚴重程度的扣分框,以及 FIX THIS FIRST 清單" width="520" />
85
85
  </p>
86
86
 
87
87
  <sub>由 `npm run docs:hero` 根據一次真實掃描產生,並在 CI 中鎖定以防漂移。同一次掃描的完整 `--verbose` 報告是 [`demo.svg`](assets/readme/demo.svg)(`npm run docs:demo`)。</sub>
@@ -312,8 +312,8 @@ e2e/login.spec.ts
312
312
  role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
313
313
 
314
314
  e2e/checkout.spec.ts
315
- [█████████████████░░░] 86 / 100
316
- role/text: 3 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
315
+ [██████████████████░░] 88 / 100
316
+ role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
317
317
  ```
318
318
 
319
319
  這衡量的是**韌性,而非正確性**。`.btn.btn-primary > div:nth-child(2)` 今天能通過,並會一直通過,直到有人改動標記結構。低分從不聲稱測試壞了,只說明它依賴於沒有人承諾保留的標記結構。
package/dist/cli.d.mts CHANGED
@@ -80,7 +80,7 @@ interface RuntimeCorroboration {
80
80
  * constrains TRUE-FLAKE derivation, which lives in the analysis, not
81
81
  * in the provenance label.
82
82
  */
83
- source: "playwright-json" | "junit-xml" | "jest-json" | "vitest-json" | "playwright-trace";
83
+ source: "playwright-json" | "junit-xml" | "jest-json" | "vitest-json" | "playwright-trace" | "har";
84
84
  /** Number of tests executed in the finding's file (any level). */
85
85
  testsExecuted: number;
86
86
  /**
@@ -436,6 +436,13 @@ interface ScanResult {
436
436
  sourceCount: number;
437
437
  findingIds: string[];
438
438
  }>;
439
+ /**
440
+ * Aggregate forensic classifications from the discovered runtime
441
+ * report (plan §10.4, WAVE 5). Present only when a runtime report was
442
+ * ingested and produced ≥1 classified verdict — absent otherwise, so
443
+ * the machine contract's `forensicVerdicts` slot is never fabricated.
444
+ */
445
+ forensicVerdicts?: ForensicVerdictSummary;
439
446
  /**
440
447
  * Dependency graph metadata (ECO-005). Present when a dependency
441
448
  * manifest (package.json, pyproject.toml, pom.xml) was found.
@@ -490,6 +497,21 @@ interface TrustSummary {
490
497
  /** Which incompleteness factors applied (audit trail for the cap). */
491
498
  ceilingReasons: string[];
492
499
  }
500
+ /**
501
+ * Aggregate forensic classifications from a runtime report (plan §10.4,
502
+ * WAVE 5). Present on a ScanResult when a runtime report was ingested
503
+ * and produced at least one classified verdict. `inconclusive` is a
504
+ * first-class outcome — the default when evidence is insufficient — and
505
+ * is also counted inside `byVerdict`.
506
+ */
507
+ interface ForensicVerdictSummary {
508
+ /** Total verdicts carrying a forensic classification. */
509
+ classifications: number;
510
+ /** Classification count per verdict label. */
511
+ byVerdict: Record<string, number>;
512
+ /** INCONCLUSIVE outcome count — a first-class result, not a failure. */
513
+ inconclusive: number;
514
+ }
493
515
  //#endregion
494
516
  //#region src/engine/tier-policy.d.ts
495
517
  type Tier = "core" | "extended" | "quarantine";
@@ -552,6 +574,13 @@ interface TestVerdict {
552
574
  */
553
575
  forensic?: ForensicClassification;
554
576
  }
577
+ interface NetworkObservation {
578
+ file: string;
579
+ title: string;
580
+ outcome: "succeeded" | "failed" | "unknown";
581
+ durationMs: number;
582
+ errors?: string[];
583
+ }
555
584
  interface ForensicsReport {
556
585
  forensicsSchemaVersion: number;
557
586
  /**
@@ -563,7 +592,7 @@ interface ForensicsReport {
563
592
  * `playwright-trace`: one record per trace artifact (the per-test
564
593
  * trace convention), action-level facts only.
565
594
  */
566
- source: "playwright-json" | "junit-xml" | "jest-json" | "vitest-json" | "playwright-trace";
595
+ source: "playwright-json" | "junit-xml" | "jest-json" | "vitest-json" | "playwright-trace" | "har";
567
596
  totalTests: number;
568
597
  failed: number;
569
598
  skipped: number;
@@ -571,6 +600,9 @@ interface ForensicsReport {
571
600
  flakyTests: number;
572
601
  totalDurationMs: number;
573
602
  verdicts: TestVerdict[];
603
+ totalNetworkObservations?: number;
604
+ failedNetworkObservations?: number;
605
+ networkObservations?: NetworkObservation[];
574
606
  /**
575
607
  * Whether all discovered report files were successfully ingested.
576
608
  * FALSE when any files were skipped due to size limits, parse failures,
@@ -1055,7 +1087,7 @@ declare function loadConfig(root: string, options?: {
1055
1087
  warnings: string[];
1056
1088
  };
1057
1089
  declare namespace scan_pipeline_d_exports {
1058
- export { AssembleScanResultInput, CliArgs, DiscoveryResult, EVIDENCE_OVERRIDES$1 as EVIDENCE_OVERRIDES, FileAnalysisResult, KNOWN_RULE_IDS$1 as KNOWN_RULE_IDS, OVERLAP_META_BY_RULE_ID$1 as OVERLAP_META_BY_RULE_ID, PostScanResult, SUITE_INVALIDATING_RULE_IDS$1 as SUITE_INVALIDATING_RULE_IDS, ScanHooks, applyPostScanProcessing, assembleScanResult, buildUniversalRules$1 as buildUniversalRules, discoverAndParseRuntimeReport$1 as discoverAndParseRuntimeReport, discoverTestFilesPhase, fallbackWorkspace$1 as fallbackWorkspace, isValidFindingRecord$1 as isValidFindingRecord, pathMatchesGlob$1 as pathMatchesGlob, runFileAnalysisPhase, runScan$1 as runScan, selectAdapter };
1090
+ export { AssembleScanResultInput, CliArgs, DiscoveryResult, EVIDENCE_OVERRIDES$1 as EVIDENCE_OVERRIDES, FileAnalysisResult, KNOWN_RULE_IDS$1 as KNOWN_RULE_IDS, OVERLAP_META_BY_RULE_ID$1 as OVERLAP_META_BY_RULE_ID, PostScanResult, SUITE_INVALIDATING_RULE_IDS$1 as SUITE_INVALIDATING_RULE_IDS, ScanHooks, applyPostScanProcessing, assembleScanResult, buildUniversalRules$1 as buildUniversalRules, discoverAndParseRuntimeReport$1 as discoverAndParseRuntimeReport, discoverTestFilesPhase, fallbackWorkspace$1 as fallbackWorkspace, isValidFindingRecord$1 as isValidFindingRecord, pathMatchesGlob$1 as pathMatchesGlob, runFileAnalysisPhase, runScan$1 as runScan, selectAdapter, summarizeForensicVerdicts };
1059
1091
  }
1060
1092
  /** Registered rule IDs — used to warn on unknown severityOverrides keys (M4). */
1061
1093
  declare const KNOWN_RULE_IDS$1: ReadonlySet<string>;
@@ -1220,11 +1252,11 @@ declare function pathMatchesGlob$1(path: string, glob: string): boolean;
1220
1252
  * Plan §16 + WI-11: locate a runtime run report next to the scan
1221
1253
  * target, using the exact conventions the forensics ingestion already
1222
1254
  * accepts. Zero-config search over conventional artifact names at
1223
- * depth ≤ 2 (src/discovery/evidence-discovery.ts); the FIRST parsable
1224
- * candidate wins (priority: mjolnir-report > playwright-json >
1225
- * test-results-dir > junit-file). Validates each candidate by attempting
1226
- * to parse it and checking that it produces at least one test. Returns
1227
- * the parsed report alongside the path to avoid double-parsing.
1255
+ * depth ≤ 2 (src/discovery/evidence-discovery.ts). The FIRST parsable
1256
+ * candidate with `totalTests > 0` is kept as a fallback; the loop
1257
+ * continues and returns a later candidate when one with
1258
+ * `analysisComplete === true` is found. Returns the parsed report
1259
+ * alongside the path to avoid double-parsing.
1228
1260
  */
1229
1261
  declare function discoverAndParseRuntimeReport$1(scanRoot: string): {
1230
1262
  path: string;
@@ -1272,8 +1304,17 @@ interface PostScanResult {
1272
1304
  suppressionCount: number;
1273
1305
  frameworks: ReturnType<typeof detectFrameworks>;
1274
1306
  runtimeReportPath: string | undefined;
1307
+ /** Aggregate forensic classifications from the ingested runtime report. */
1308
+ forensicVerdicts: ForensicVerdictSummary | undefined;
1275
1309
  config: ReturnType<typeof loadConfig>["config"];
1276
1310
  }
1311
+ /**
1312
+ * Summarize forensic classifications from an ingested runtime report
1313
+ * (plan §10.4, WAVE 5). Returns undefined when no verdict carries a
1314
+ * classification — the machine contract slot stays absent rather than
1315
+ * reporting all-zero counts.
1316
+ */
1317
+ declare function summarizeForensicVerdicts(report: ForensicsReport): ForensicVerdictSummary | undefined;
1277
1318
  declare function applyPostScanProcessing(findings: Finding[], workspace: Workspace, args: CliArgs, hooks: ScanHooks, scanRoot: Workspace, declarationsByFile: Map<string, number>, testDeclarationCount: number, tierByRuleId: Map<string, Tier>, REVISION_BY_RULE_ID: Map<string, number>): PostScanResult;
1278
1319
  interface AssembleScanResultInput {
1279
1320
  findings: Finding[];
@@ -1307,6 +1348,7 @@ interface AssembleScanResultInput {
1307
1348
  suppressionCount: number;
1308
1349
  frameworks: ReturnType<typeof detectFrameworks>;
1309
1350
  runtimeReportPath: string | undefined;
1351
+ forensicVerdicts: ForensicVerdictSummary | undefined;
1310
1352
  config: ReturnType<typeof loadConfig>["config"];
1311
1353
  fileProvenance: Array<{
1312
1354
  path: string;
@@ -1339,7 +1381,7 @@ declare function runScan$1(args: CliArgs, hooks?: ScanHooks): Promise<ScanResult
1339
1381
  * scripts/sync-sarif-version.cjs and guarded by the version-consistency
1340
1382
  * spec. cli.ts re-exports this as CLI_VERSION.
1341
1383
  */
1342
- declare const ENGINE_VERSION = "2.0.0";
1384
+ declare const ENGINE_VERSION = "2.0.2";
1343
1385
  //#endregion
1344
1386
  //#region src/cli-io.d.ts
1345
1387
  /**
@@ -1516,6 +1558,91 @@ export declare function runReleaseTrustCommand(argv: string[], io?: {
1516
1558
  err: Output;
1517
1559
  }): number;
1518
1560
  //#endregion
1561
+ //#region src/commands/business-case.d.ts
1562
+ /**
1563
+ * Entry point for `mjolnir business-case`.
1564
+ *
1565
+ * Flags:
1566
+ * --industry <type> Industry cost profile (default/fintech/healthcare/...)
1567
+ * --history <months> Use git history for the last N months (estimates from
1568
+ * actual scan improvements, not projections)
1569
+ * --projected <months> Show projected savings over N months
1570
+ * --strict Include quarantine-tier findings
1571
+ */
1572
+ export declare function runBusinessCaseCommand(argv: string[], io?: {
1573
+ out: Output;
1574
+ err?: Output;
1575
+ }): Promise<number>;
1576
+ //#endregion
1577
+ //#region src/commands/release-report.d.ts
1578
+ /**
1579
+ * CLI verb: `mjolnir release-report [--since <ref>] [--history <json>] [target]`.
1580
+ */
1581
+ export declare function runReleaseReportCommand(argv: string[], io: {
1582
+ out: Output;
1583
+ err: Output;
1584
+ }): Promise<number>;
1585
+ //#endregion
1586
+ //#region src/commands/report-playwright.d.ts
1587
+ export declare function runReportPlaywrightCommand(argv: string[], io: {
1588
+ out: Output;
1589
+ err: Output;
1590
+ }): Promise<number>;
1591
+ //#endregion
1592
+ //#region src/commands/trend.d.ts
1593
+ export declare function runTrendCommand(argv: string[], io: {
1594
+ out: Output;
1595
+ err: Output;
1596
+ }): Promise<number>;
1597
+ //#endregion
1598
+ //#region src/commands/exec-report.d.ts
1599
+ export declare function runExecReportCommand(argv: string[], io: {
1600
+ out: Output;
1601
+ err: Output;
1602
+ }): Promise<number>;
1603
+ //#endregion
1604
+ //#region src/commands/policy.d.ts
1605
+ export declare function runPolicyCommand(argv: string[], io: {
1606
+ out: Output;
1607
+ err: Output;
1608
+ }): Promise<number>;
1609
+ //#endregion
1610
+ //#region src/commands/quarantine.d.ts
1611
+ export declare function runQuarantineCommand(argv: string[], io: {
1612
+ out: Output;
1613
+ err: Output;
1614
+ }): Promise<number>;
1615
+ //#endregion
1616
+ //#region src/commands/analyze.d.ts
1617
+ export declare function runAnalyzeCommand(argv: string[], io: {
1618
+ out: Output;
1619
+ err: Output;
1620
+ }): number;
1621
+ //#endregion
1622
+ //#region src/commands/ci-adapter.d.ts
1623
+ export declare function runCiAdapterCommand(argv: string[], io: {
1624
+ out: Output;
1625
+ err: Output;
1626
+ }): Promise<number>;
1627
+ //#endregion
1628
+ //#region src/commands/dashboard.d.ts
1629
+ export declare function runDashboardCommand(argv: string[], io: {
1630
+ out: Output;
1631
+ err: Output;
1632
+ }): Promise<number>;
1633
+ //#endregion
1634
+ //#region src/commands/enterprise.d.ts
1635
+ export declare function runEnterpriseCommand(argv: string[], io: {
1636
+ out: Output;
1637
+ err: Output;
1638
+ }): number;
1639
+ //#endregion
1640
+ //#region src/commands/maturity.d.ts
1641
+ export declare function runMaturityCommand(argv: string[], io: {
1642
+ out: Output;
1643
+ err: Output;
1644
+ }): number;
1645
+ //#endregion
1519
1646
  //#region src/cli.d.ts
1520
1647
  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>;
1521
1648
  /** A usage-error detail: the offending token, when one exists. */