mjolnir-qa 0.4.0 → 0.5.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.ja.md ADDED
@@ -0,0 +1,692 @@
1
+ <div align="center">
2
+
3
+ <img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
4
+
5
+ ### あなたのテストは嘘をついています。私たちが証明します。
6
+
7
+ **QA 向け Verification Trust Engine。** Mjölnir はテストスイートと CI
8
+ パイプラインを監査し、信頼性スコアを報告し、信頼がどこで壊れているかを
9
+ 正確に示します。
10
+
11
+ [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=C9A227&labelColor=0B0F17)](https://www.npmjs.com/package/mjolnir-qa)
12
+ [![ci](https://img.shields.io/github/actions/workflow/status/Sergey-Bar/Mjolnir/ci.yml?branch=main&style=flat-square&label=ci&labelColor=0B0F17)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
13
+ [![license](https://img.shields.io/badge/license-MIT-C9A227.svg?style=flat-square&labelColor=0B0F17)](LICENSE)
14
+ [![node](https://img.shields.io/badge/node-%E2%89%A5%2022.18-2E8C7F.svg?style=flat-square&labelColor=0B0F17)](https://nodejs.org)
15
+
16
+ [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) | 日本語 | [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) | [العربية](README.ar.md) | [Bosanski](README.bs.md)
17
+
18
+ > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-04.
19
+
20
+ ```bash
21
+ npx mjolnir-qa@latest
22
+ ```
23
+
24
+ **あなたのテストは信頼に値しますか?**
25
+
26
+ [動作を見る](#-動作を見る) ·
27
+ [クイックスタート](#-クイックスタート) ·
28
+ [何をチェックするか](#-mjölnir-がチェックするもの) ·
29
+ [スコアリング](#スコアの仕組み) ·
30
+ [CI](#-ci-統合) · [設定](#設定) ·
31
+ [ドキュメント](#-ドキュメント)
32
+
33
+ </div>
34
+
35
+ ---
36
+
37
+ ## 🎬 動作を見る
38
+
39
+ <p align="center">
40
+ <img src="assets/readme/demo.svg" alt="デモリポジトリに対する Mjölnir の完全な --verbose レポート: WORTHINESS 75/100 NEEDS WORK、カテゴリ別の診断内訳、FIX THIS FIRST リスト、そして CI・Playwright・テスト衛生・Python ルール全体にわたるルール ID と行番号付きの各検出" width="900" />
41
+ </p>
42
+
43
+ <sub>`npx mjolnir-qa ./examples/demo-repo --verbose` の完全な出力を、
44
+ 本物のレポーターで描画したもの——何ひとつ省いていません。
45
+ `npm run docs:demo` で再生成します。
46
+ [`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
47
+ は、成果物がツールの出力から逸れたら CI を落とします。</sub>
48
+
49
+ **いま何が起きたか:**
50
+
51
+ 1. Mjölnir は Playwright のスペック、その設定、CI ワークフロー、
52
+ Python テストファイルを検出しました——4 言語/フォーマットを 1
53
+ パスで。
54
+ 2. スイートへの信頼を弱める証拠を見つけました——ジョブをマスクする
55
+ `continue-on-error`、終了コードを呑み込む `|| true`、ハードな
56
+ sleep、壊れやすいセレクタ、ハードコードされたステージング URL、
57
+ `networkidle` 待ち。
58
+ 3. それぞれをルール ID・場所・修正方法を備えた具体的な検出に——そして
59
+ PR にゲートをかけられる単一のスコアに変換しました。
60
+
61
+ ### 検出を 1 つ、クローズアップ
62
+
63
+ 上の最初の検出に対して `mjolnir explain QA-CI-001` を実行すると:
64
+
65
+ ```text
66
+ ▚▞ QA-CI-001 — continue-on-error masks a failing verification gate
67
+
68
+ Severity: error
69
+ Confidence: high
70
+ Evidence: E2
71
+ Measured FP: not yet measured — this rule ships on assumption (see docs/FP-AUDIT.md)
72
+
73
+ WHAT WAS FOUND (real detector output, not a mockup)
74
+ Job `security-scan` runs a verification gate under `continue-on-error: true`.
75
+
76
+ WHY IT MATTERS
77
+ This job can fail every day and CI will still show green. The checkmark
78
+ on this workflow cannot be trusted.
79
+
80
+ HOW TO FIX
81
+ Remove continue-on-error, or scope it to individual non-blocking steps only.
82
+ ```
83
+
84
+ これが価値の単位です。スタイルへの指摘ではなく、あなたの CI が
85
+ 「通った」と告げているのに実際には通っていない箇所です。
86
+
87
+ ---
88
+
89
+ ## ⚡ クイックスタート
90
+
91
+ リポジトリに対して実行し、完全なレポートと信頼性スコアを得る:
92
+
93
+ ```bash
94
+ npx mjolnir-qa@latest
95
+ ```
96
+
97
+ **CI では、製品は 1 コマンドです。** ブランチが触ったものだけをスキャン
98
+ し、新しい問題があれば非ゼロで終了します:
99
+
100
+ ```bash
101
+ npx mjolnir-qa@latest --scope changed
102
+ ```
103
+
104
+ それを PR チェックに放り込む——`mjolnir ci install` がワークフローを
105
+ 書き出します——それだけです。ほかはすべてオプションです。
106
+
107
+ | コマンド | 何をするか |
108
+ | ----------------------------------- | ----------------------------------------------------- |
109
+ | `mjolnir` | リポジトリ全体のスキャン + 信頼性スコア |
110
+ | `mjolnir --scope changed` | ブランチが導入したものだけ——CI 形態 |
111
+ | `mjolnir ci install` | アドバイザリな PR ワークフローを生成 |
112
+ | `mjolnir explain QA-CI-001` | 何 / なぜ / 修正方法 + 1 ルールの実測 FP 率 |
113
+ | `mjolnir rules --unmeasured` | 測定ではなく仮定で動いているルール |
114
+ | `mjolnir --json` / `--format sarif` | 機械可読 / GitHub Code Scanning |
115
+ | `mjolnir --strict` | 隔離層(quarantine)のルールも実行(FP リスクが高い) |
116
+
117
+ <details>
118
+ <summary><strong>何かが flaky なとき</strong></summary>
119
+
120
+ | コマンド | 何をするか |
121
+ | ----------------------------------- | ----------------------------------------------------- |
122
+ | `mjolnir forensics ./test-results/` | 実際の実行データ → `TRUE-FLAKE` 判定、`FLAKY.md` |
123
+ | `mjolnir triage ./test-results/` | 実行履歴からの隔離提案 |
124
+ | `mjolnir pw-report ./test-results/` | Playwright 実行サマリー——リトライ / flake / 最遅 |
125
+ | `mjolnir doctor:playwright` | Playwright 専用の深いスキャン + Selector Health Score |
126
+
127
+ </details>
128
+
129
+ <details>
130
+ <summary><strong>たまに / レポート系</strong></summary>
131
+
132
+ | コマンド | 何をするか |
133
+ | ------------------------------- | ----------------------------------------------------- |
134
+ | `mjolnir fix --dry-run` / `fix` | 証拠付きの安全な自動修正 |
135
+ | `mjolnir baseline` / `diff` | 検出のスナップショットを取り、以後は新規/悪化のみ報告 |
136
+ | `mjolnir impact --since <ref>` | 以前のコミット以降に何が変わったか |
137
+ | `mjolnir debt` | コストモデル付きのテスト負債台帳 |
138
+ | `mjolnir handover` | 新しい QA 向けのスイートオンボーディングマップ |
139
+ | `mjolnir stats` | これまでに見た修正のローカル累計カウンタ |
140
+ | `mjolnir badge` | shields.io エンドポイント JSON + スニペット |
141
+ | `mjolnir rules --md` | 完全なルールカタログ(JSON または Markdown) |
142
+ | `mjolnir doctor` | Mjölnir 自身のルールベースの自己監査 |
143
+ | `mjolnir create-rule <ID>` | 新しいルール + フィクスチャのスキャフォールド |
144
+ | `mjolnir --format mermaid` | PR コメント用のテストアーキテクチャ図 |
145
+
146
+ </details>
147
+
148
+ お好みなら `npx` の代わりにグローバルインストールを:
149
+ `npm i -g mjolnir-qa`。Node.js ≥ 22.18 が必要です。Windows、macOS、
150
+ Linux で動作します。
151
+
152
+ ---
153
+
154
+ ## 👥 誰のためのものか
155
+
156
+ - **QA / SDET** — e2e または統合スイートを所有し、スイートが生成する
157
+ 緑のチェックマークが本当に値するものかの証拠を必要としている人。
158
+ - **プラットフォーム / DevEx チーム** — CI の完全性とリリースゲートに
159
+ 責任を持つ人々。`continue-on-error` が赤いパイプラインを静かに緑に
160
+ 塗り替えないことを気にする人々。
161
+ - **OSS メンテナ** — ローカルでも CI でも、ネットワーク呼び出しゼロで
162
+ 動く安価で常時有効な検証ゲートを求めている人。
163
+
164
+ ---
165
+
166
+ ## 🔨 Mjölnir がチェックするもの
167
+
168
+ | | |
169
+ | --- | ----------------------------------------------------------------------------------------------------------------------------- |
170
+ | ⚖️ | **信頼性スコア** — ひとつの数字、透過的な減点テーブル、ブラックボックスなし |
171
+ | 🎭 | **Selector Health Score** — 合格率だけでなく、Playwright ロケータを評価する |
172
+ | 🔬 | **ランタイムフォレンジクス** — 実際の Playwright/JUnit 実行データを読み、静的な推測ではなく `TRUE-FLAKE` を捉える |
173
+ | 🚨 | **CI 完全性ルール** — `continue-on-error`、`\|\| true`、その他の偽グリーンの手口を検出する |
174
+ | 🐍 | **4 つの Playwright バインディングすべて** — TypeScript、Python、Java、C#/.NET — さらに pytest、JUnit/TestNG、CI ワークフロー |
175
+ | 🔒 | **ローカルファースト** — スキャン中のネットワーク呼び出しゼロ、テレメトリゼロ、数秒で実行 |
176
+
177
+ ### ルール
178
+
179
+ すべてのルールは must-fire **と** must-not-fire のフィクスチャを備えて
180
+ 出荷されます。自分自身のネガティブフィクスチャで発火するルールは出荷
181
+ できません——それが false-positive の防火壁です。
182
+
183
+ <details>
184
+ <summary><strong>テスト衛生</strong></summary>
185
+
186
+ | ID | ルール | Severity |
187
+ | ----------- | -------------------------------------------------------- | -------- |
188
+ | QA-TEST-001 | コミットされたフォーカステスト(`.only`、`fit`) | error |
189
+ | QA-TEST-002 | 根拠のないままスキップされたテスト | error |
190
+ | QA-TEST-002 | 記録済みの根拠つきでスキップされたテスト | warning |
191
+ | QA-TEST-003 | アサーションのないテスト | error |
192
+ | QA-TEST-004 | ハードな sleep(`waitForTimeout`、`sleep()`、`delay()`) | warning |
193
+ | QA-TEST-006 | flakiness を隠すリトライの濫用 | warning |
194
+ | QA-TEST-010 | 空のテスト本体 | error |
195
+
196
+ </details>
197
+
198
+ <details>
199
+ <summary><strong>テスト品質</strong></summary>
200
+
201
+ | ID | ルール | Severity |
202
+ | ------------ | --------------------------------------- | -------- |
203
+ | QA-TQUAL-001 | モックのみの検証 | info |
204
+ | QA-TQUAL-002 | トートロジカルなアサーション | error |
205
+ | QA-TQUAL-009 | await されていない promise アサーション | error |
206
+ | QA-TQUAL-011 | コメントアウトされたテスト | warning |
207
+
208
+ </details>
209
+
210
+ <details>
211
+ <summary><strong>Playwright 🎭</strong></summary>
212
+
213
+ | ID | ルール | Severity |
214
+ | --------- | --------------------------------------------- | -------- |
215
+ | QA-PW-002 | await されていないロケータアサーション | error |
216
+ | QA-PW-003 | コミットされた `page.pause()` / `test.only()` | error |
217
+ | QA-PW-004 | 脆弱な CSS/XPath セレクタ | warning |
218
+ | QA-PW-005 | `page.evaluate()` 内のビジネスロジック | info |
219
+ | QA-PW-114 | レガシーな要素ハンドル(`page.$`) | info |
220
+ | QA-PW-118 | `networkidle` 待ち(設計上 flaky) | info |
221
+ | QA-PW-123 | ハードコードされた環境 URL | warning |
222
+
223
+ </details>
224
+
225
+ <details>
226
+ <summary><strong>CI 完全性</strong></summary>
227
+
228
+ | ID | ルール | Severity |
229
+ | --------- | ---------------------------------------------------------------- | -------- |
230
+ | QA-CI-001 | `continue-on-error` が失敗をマスクする | error |
231
+ | QA-CI-002 | `\|\| true` が終了コードを呑み込む | error |
232
+ | QA-CI-005 | レポートが消費されるのに生成されない | error |
233
+ | QA-CI-007 | テストを包むリトライラッパー | warning |
234
+ | QA-CI-008 | 常に成功するステップが失敗をマスクする | error |
235
+ | QA-CI-009 | テストの終了コードが伝播しない(pipefail なしの `\|`、`;` 連結) | error |
236
+ | QA-CI-010 | ブロックすべき場所でテストがスキップされる(skip-on-PR ガード) | error |
237
+
238
+ </details>
239
+
240
+ <details>
241
+ <summary><strong>Python / pytest 🐍</strong></summary>
242
+
243
+ | ID | ルール | Severity |
244
+ | --------- | ------------------------------------------------ | -------- |
245
+ | QA-PY-002 | スキップされたテスト(`skip`、非厳格な `xfail`) | warning |
246
+ | QA-PY-003 | アサーションのないテスト関数 | error |
247
+ | QA-PY-005 | テスト内の `time.sleep()` | warning |
248
+ | QA-PY-006 | 空のテスト本体(`pass`) | info |
249
+ | QA-PY-010 | freeze なしのランダム/時刻依存 | info |
250
+ | QA-PY-012 | トートロジカルなアサーション | error |
251
+
252
+ Python ルールは合計 20 本(QA-PY-001…012 pytest 衛生 + QA-PY-101…108 Playwright-Python)。
253
+
254
+ </details>
255
+
256
+ <details>
257
+ <summary><strong>Java / JUnit · TestNG ☕</strong></summary>
258
+
259
+ | ID | ルール | Severity |
260
+ | --------- | ---------------------------------------------- | -------- |
261
+ | QA-JV-101 | 無効化されたテスト(`@Disabled`) | warning |
262
+ | QA-JV-102 | ハードな sleep(`Thread.sleep()`) | warning |
263
+ | QA-JV-103 | アサーションのないテストメソッド | error |
264
+ | QA-JV-105 | Playwright のハードな sleep `waitForTimeout()` | warning |
265
+ | QA-JV-106 | role ロケータの代わりの脆弱なセレクタ | warning |
266
+ | QA-JV-108 | テストにハードコードされた環境 URL | info |
267
+ | QA-JV-111 | 全域モック `page.route("**")` | info |
268
+
269
+ </details>
270
+
271
+ <details>
272
+ <summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
273
+
274
+ | ID | ルール | Severity |
275
+ | --------- | --------------------------------------------------- | -------- |
276
+ | QA-CS-101 | スキップされたテスト(`[Ignore]`、`[Fact(Skip=)]`) | warning |
277
+ | QA-CS-102 | ハードな sleep(`Thread.Sleep` / `Task.Delay`) | warning |
278
+ | QA-CS-103 | アサーションのないテストメソッド | error |
279
+ | QA-CS-105 | ハードな sleep `WaitForTimeoutAsync()` | warning |
280
+ | QA-CS-106 | role ロケータの代わりの脆弱なセレクタ | warning |
281
+ | QA-CS-108 | テストにハードコードされた環境 URL | info |
282
+ | QA-CS-111 | 全域モック `page.RouteAsync("**")` | info |
283
+
284
+ </details>
285
+
286
+ > 完全なライブカタログ——各ルールのティア、confidence、false-positive
287
+ > リスク、オートフィックス対応状況——はレジストリから生成されます:
288
+ >
289
+ > ```bash
290
+ > mjolnir rules --md
291
+ > ```
292
+ >
293
+ > ルールごとのページは [`docs/rules/`](docs/rules/) にあります。
294
+
295
+ ### どれだけが測定されているか
296
+
297
+ **99 ルールのうち 74 ルールが、実際の OSS コードに対して測定された
298
+ false-positive 率を備えています**(各ルールにつき手作業で分類された
299
+ 検出 ≥ 10 件。[docs/FP-AUDIT.md](docs/FP-AUDIT.md) 参照)。残り 19 ルール
300
+ は作者の推定で出荷されます。すべてのスキャンのフッターは、_発火した_
301
+ ルールのうちいくつが測定済みかを教えてくれます。`mjolnir rules --unmeasured`
302
+ は未測定のものを列挙します。各ルールの `mjolnir explain` ページはその
303
+ 状態を明言します。率は醜くても公開します——QA-CS-103 は 95% で監査され、
304
+ それゆえ隔離されています。この 78 を増やすことが、プロジェクトの継続的
305
+ な仕事です。
306
+
307
+ ### ルールのティアと言語ごとの成熟度
308
+
309
+ すべてのルールは、**測定された** false-positive 率に基づいて `core`、
310
+ `extended`、`quarantine` のいずれかに割り当てられます:
311
+
312
+ | ティア | 意味 | 既定のスキャン | `--strict` |
313
+ | ------------ | ------------------------------- | :------------: | :--------: |
314
+ | `core` | 実測 FP ≤ 10 % | ✅ | ✅ |
315
+ | `extended` | 実測 FP ≤ 30 % | ✅ | ✅ |
316
+ | `quarantine` | 30 % 超、または未測定(n < 10) | ❌ | ✅ |
317
+
318
+ | 言語 | アダプタ | 現在のカバレッジ |
319
+ | --------------- | -------------- | ---------------------------------------------- |
320
+ | TypeScript / JS | コンパイラ AST | 最も広く、最も測定済み——主に `core`/`extended` |
321
+ | Python / pytest | 正規表現層 | 広範、コーパス監査済み——主に `core`/`extended` |
322
+ | Java | 正規表現層 | より新しい——主に `extended`/`quarantine` |
323
+ | C# / .NET | 正規表現層 | より新しい——主に `extended`/`quarantine` |
324
+
325
+ TypeScript と Python が最も広い測定済みカバレッジを持ちます。Java と
326
+ C# は出荷済みでドキュメントもあり、実際のコンシューマスイート(バインディング
327
+ ライブラリ自身のテストではなく)が監査されるまでは、ヘッドラインの数字から
328
+ 外れています。
329
+
330
+ ---
331
+
332
+ ## スコアの仕組み
333
+
334
+ <p align="center">
335
+ <img src="assets/readme/terminal-hero.svg" alt="Mjölnir のターミナル出力——WORTHINESS 75/100 NEEDS WORK、カテゴリ別の診断内訳と FIX THIS FIRST リスト" width="820" />
336
+ </p>
337
+
338
+ <sub>`npm run docs:hero` で再生成されます。
339
+ [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
340
+ は、成果物がレポーターが実際に印字するものから逸れたら CI を落とします。</sub>
341
+
342
+ スコアは透過的です: **error −8、warning −3、info −1**、その後スイートの
343
+ 露出度(テスト宣言あたりの減点)で正規化します。証拠で重みづけされた減点は、
344
+ 弱いシグナルほど安いことを意味します。ターミナルはスコアが使うのと同じ
345
+ 割引後の数字を表示します——ブラックボックスはありません。完全な方法論は
346
+ [docs/SCORING.md](docs/SCORING.md)。
347
+
348
+ **判定**
349
+
350
+ | Score | 判定 |
351
+ | ------- | ---------------- |
352
+ | ≥ 80 | ✓ **WORTHY** |
353
+ | 50 – 79 | ⚠ **NEEDS WORK** |
354
+ | < 50 | ✖ **UNWORTHY** |
355
+
356
+ **証拠レベル** — すべての検出はいずれかを持ち、スコア内での重みを
357
+ 決めます:
358
+
359
+ | レベル | 意味 | スコアへの影響 | 例 |
360
+ | ------ | ---------------------------- | ----------------- | ----------------------------------------------------------- |
361
+ | E2 | 決定論的な欠陥 | 全額減点 | コミットされた `.only` — 構造的に証明可能 |
362
+ | E1 | ヒューリスティックなパターン | 半分の減点 | 正規表現で見つかった `sleep()` — 強いシグナル、証明ではない |
363
+ | E0 | 観察 | ゼロ(info のみ) | 報告されるが CI をゲートすることも減点することもない |
364
+
365
+ ほとんどのルールは **E1** です。「we prove it」という標語はこの仕組みを
366
+ 指します: E2 の検出は構造的な証明であり、E1 の検出は適切に位置づけられた
367
+ 警告であって、形式的な証明ではありません。
368
+
369
+ 空のリポジトリは `null` を返します。偽の 100 を決して返しません —
370
+ [信頼モデル](#信頼モデル) 参照。
371
+
372
+ ---
373
+
374
+ ## 🎭 Selector Health Score
375
+
376
+ Playwright スイート向けの看板指標——あなたのロケータはどれだけ丈夫か:
377
+
378
+ ```text
379
+ ▚▞ SELECTOR HEALTH — e2e/checkout.spec.ts
380
+
381
+ [█████████████████░░░] 83 / 100
382
+ role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
383
+ ```
384
+
385
+ ロールベースのロケータは満点です。CSS クラスチェーンと XPath はスコアを
386
+ 沈めます——どの振る舞いが退行したかを告げずに、あらゆる DOM リファクタで
387
+ 壊れるからです。
388
+
389
+ ---
390
+
391
+ ## 🔬 ランタイム証拠
392
+
393
+ 静的な flakiness 検出は当てずっぽうです。Mjölnir は**実際の実行データ**を
394
+ 読みます——あらゆるランナーの Playwright JSON レポートと JUnit XML
395
+ です:
396
+
397
+ ```bash
398
+ mjolnir forensics ./test-results/
399
+ ```
400
+
401
+ ```text
402
+ ▚▞ FLAKINESS LEADERBOARD
403
+
404
+ 3 tests · 1 failed · 1 flaky · 1 retried
405
+
406
+ TRUE-FLAKE completes checkout with saved card (e2e/checkout.spec.ts)
407
+ ████████████████████ 6.0s · 2 attempts
408
+ FAILING declines an expired card (e2e/checkout.spec.ts)
409
+ ████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
410
+ ```
411
+
412
+ 2 回目以降の試行でしか通らないテストは、通るテストではありません——
413
+ 運の良いテストです。最終的な緑のチェックマークにかかわらず、
414
+ `TRUE-FLAKE` としてフラグが立ちます。
415
+
416
+ ---
417
+
418
+ ## ⚡ Mjölnir はまた別のリンタではありません
419
+
420
+ リンタはコードがルールに従っているかを教えます。Mjölnir は、あなたの
421
+ 検証が信頼できるかを教えます。
422
+
423
+ | | ESLint / SonarQube | カバレッジツール | 手動レビュー | **Mjölnir** |
424
+ | ----------------------------------------------------------- | :----------------: | :--------------: | :----------: | :---------: |
425
+ | CI ワークフローの完全性(`continue-on-error`、`\|\| true`) | ❌ | ❌ | まれ | ✅ |
426
+ | 1 ツールで複数言語(TS、Python、Java、C#) | ❌ | ❌ | ❌ | ✅ |
427
+ | Playwright ロケータの耐性を評価(Selector Health) | ❌ | ❌ | まれ | ✅ |
428
+ | 実質的なアサーションのないテストを検出 | ✅(プラグイン)\* | ❌ | ときどき | ✅ |
429
+ | ハードな sleep を検出(`waitForTimeout`、`time.sleep`) | ✅(プラグイン)\* | ❌ | ときどき | ✅ |
430
+ | 数秒で実行、スキャン中のネットワーク呼び出しゼロ | ✅ | ✅ | — | ✅ |
431
+
432
+ \*`eslint-plugin-jest`(`expect-expect`)と
433
+ `eslint-plugin-playwright`(`expect-expect`、`no-wait-for-timeout`)が
434
+ それぞれのフレームワーク向けにこれをカバーしています。
435
+
436
+ **ランタイム分析**は静的リンティングとは別のカテゴリです:
437
+
438
+ | | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
439
+ | ----------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
440
+ | `TRUE-FLAKE` 判定のために実際の実行データを読む | 一部\* | 一部(タグ) | ✅ |
441
+ | 実行履歴からの flaky トリアージレポート | ❌ | ✅ | ✅ |
442
+ | 静的な信頼性スコアと統合 | ❌ | ❌ | ✅ |
443
+
444
+ \*Playwright はリトライを内部で追跡しますが、判定ラベルつきの独立した
445
+ flakiness レポートは生成しません。
446
+
447
+ ---
448
+
449
+ ## 🤖 なぜ AI コードレビューだけでは足りないのか
450
+
451
+ 問題も層も違います。AI レビューは diff の中の怪しいテスト変更を
452
+ 見つけられますが、検証システム全体が信頼に値すると証明はできません——
453
+ しかも見るのはあなたが見せた diff だけです。
454
+
455
+ | | AI コードレビュー(Copilot など) | **Mjölnir** |
456
+ | ------------------------------------- | :-------------------------------: | :------------------------------------: |
457
+ | スキャンごとのコスト | トークン(diff サイズで増える) | **ゼロ**(ローカル、インストール済み) |
458
+ | スイート全体 + すべての CI 設定を見る | あなたが見せた PR diff のみ | **毎回すべて** |
459
+ | 決定論的(同じ入力 → 同じ出力) | ❌(非決定論的) | **✅** |
460
+ | 数か月眠っていたパターンを検出 | コンテキストにある場合のみ | **✅**(全ファイルをスキャン) |
461
+ | 実行間で検出を記憶 | ❌(セッション間の記憶なし) | **✅**(baseline + diff) |
462
+ | 人間のトリガーなしで動く | PR またはプロンプトが必要 | **✅**(CI フック、3 秒) |
463
+
464
+ **両方使いましょう。** AI は、どんな正規表現も見つけられないニュアンス、
465
+ 意図、設計上の欠陥を捉えます。Mjölnir は、「意図的」に見えるがゆえに
466
+ AI が見逃す構造的パターンを捉えます——コミットされた `.only`、呑み込まれた
467
+ 終了コード、テストジョブ上の `continue-on-error`。これらは推論を要する
468
+ バグではなく、スキャンを要する事実です。
469
+
470
+ ---
471
+
472
+ ## 🤖 CI 統合
473
+
474
+ 1 コマンドで PR ワークフローを生成します——既定ではアドバイザリ、
475
+ 決してブロックしません:
476
+
477
+ ```bash
478
+ mjolnir ci install
479
+ ```
480
+
481
+ または SARIF 経由で GitHub Code Scanning にネイティブに接続します:
482
+
483
+ ```yaml
484
+ - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
485
+ - uses: github/codeql-action/upload-sarif@v3
486
+ with:
487
+ sarif_file: mjolnir.sarif
488
+ ```
489
+
490
+ SARIF のエディタ・パイプライン設定:
491
+ [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md)。
492
+
493
+ ### changed-scope のカバレッジ
494
+
495
+ `--scope changed` は、`main` とのマージベースに対してブランチが追加した
496
+ 行に検出を帰属させます。テストファイル(`*.spec.*`、`*.test.*`)に加え、
497
+ diff 内の GitHub ワークフローファイルと Playwright 設定をカバーします。
498
+ マージベースを解決できない場合——シャロークローン、detached HEAD、
499
+ git 以外のターゲット、既定ブランチの違い——正直に劣化します: 検出は
500
+ ファイル全体への帰属に戻り、レポートはその旨を述べます。ベース参照は
501
+ `--base <ref>` で上書きできます。
502
+
503
+ ---
504
+
505
+ ## 設定
506
+
507
+ Mjölnir はゼロ設定です。リポジトリルートの任意の `mjolnir.config.json`
508
+ (または `.mjolnir.json`)で重大度、ゲーティング、スコープを調整
509
+ できます——検出の意味論は決して変えません。
510
+
511
+ | キー | 型 | 効果 |
512
+ | ------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- |
513
+ | `exclude` | `string[]` | 追加の ignore グロブ(gitignore のサブセット)、内蔵デフォルトの上に重ねる |
514
+ | `gate` | `"advisory" \| "error" \| "warning"` | どの重大度が非ゼロで終了するか(既定 `error`; `advisory` は決してブロックしない) |
515
+ | `severityOverrides` | `{ "<RULE-ID>": severity }` | リポジトリに合わせてルールの検出を再ランク付けする |
516
+ | `ignore` | `IgnoreEntry[]` | 検出を抑制する — **`reason` が必須**; エントリは 90 日で失効します(明示的な `expires` 日付、または未記入の場合は設定ファイルの最終更新時刻) |
517
+ | `plugins` | `string[]` | サードパーティのルールパッケージ([信頼モデル](#信頼モデル) 参照) |
518
+
519
+ ```json
520
+ {
521
+ "gate": "error",
522
+ "exclude": ["legacy/**"],
523
+ "severityOverrides": { "QA-PW-118": "warning" },
524
+ "ignore": [
525
+ {
526
+ "ruleId": "QA-TEST-004",
527
+ "files": ["e2e/legacy-login.spec.ts"],
528
+ "reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
529
+ "expires": "2026-12-31"
530
+ }
531
+ ]
532
+ }
533
+ ```
534
+
535
+ - **`.mjolnirignore`** — パス除外のための素朴な gitignore 風ファイル、
536
+ `exclude` と同じ方言です。マシン単位のノイズにはこちらを; リストが
537
+ 残りの設定とともにバージョン管理に入るべきなら `exclude` を。
538
+ - **CLI 上書き** — `--strict`(隔離層のルールを含める)、`--width <cols>` と
539
+ `--ascii` / `--no-ascii`(ターミナル描画)、`--tone blunt`
540
+ (より直接的なメッセージ)、`--max-duration <sec>`(時間制限つき部分
541
+ スキャン)。
542
+ - ルール抑制と非推奨のライフサイクル:
543
+ [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md)。
544
+
545
+ `ignore` エントリは、単独のコマンド `mjolnir suppressions` も駆動します。
546
+ これは現在中断されているものと、各エントリの失効時期を一覧表示します。
547
+
548
+ ---
549
+
550
+ ## 📐 終了コードと契約
551
+
552
+ 凍結済み — その上に CI ロジックを構築しても安全です:
553
+
554
+ | 終了コード | 意味 |
555
+ | ---------- | ---------------------------------------------------------------------- |
556
+ | `0` | クリーン — ゲート以上の検出なし |
557
+ | `1` | ゲート以上の検出あり |
558
+ | `2` | 部分スキャン(時間予算の消尽、読めないファイル)— 決してブロックしない |
559
+ | `10` | 使用方法の誤り(不正なフラグ、ターゲット欠落) |
560
+ | `20` | 内部エラー |
561
+
562
+ JSON/SARIF レポートは `schemaVersion: 1` です。ルール ID
563
+ (`QA-<FAMILY>-NNN`)は出荷後は不変であり、決して再利用されません。
564
+
565
+ ---
566
+
567
+ ## 信頼モデル
568
+
569
+ - **ローカルファースト** — スキャン中のネットワーク呼び出しゼロ。常に。
570
+ テレメトリゼロ。
571
+ - **偽の証明をしない** — 「検証済み」より「不明」と言うことを選びます。
572
+ 空のリポジトリは `score: null` を受け取り、偽の 100 は決して返しません。
573
+ - **部分的な正直さ** — 分析が中断されたら、出力がその旨を述べます。
574
+ 完了していないのに「complete」とは決して言いません。
575
+ - **FP 防火壁** — 検出はコメント/文字列を除いたコードビュー上で動作
576
+ します(TypeScript ルールはコンパイラ AST を使用): 散文コメント内や
577
+ ドキュメント例の文字列にあるパターンはドキュメントであり、検出では
578
+ ありません。
579
+ - **測定、断言にあらず** — 実際の OSS コードからの false-positive 率を
580
+ 持つルールだけがヘッドラインのティアに出荷されます
581
+ ([どれだけが測定されているか](#どれだけが測定されているか) 参照)。
582
+ スキャンのフッターと `mjolnir rules --unmeasured` がどれがどれかを
583
+ 教えます。
584
+ - **プラグインの信頼** — プラグインは `"plugins"` の下で宣言された npm
585
+ パッケージです。**サンドボックスはありません**: プラグインコードは
586
+ 完全な Node 権限で動作し、ESLint や Vitest のプラグインと同じ信頼
587
+ モデルです。コアルール ID の接頭辞は予約されており、なりすまし防止の
588
+ ためプラグインからは拒否されます。
589
+ - **ワークスペースローカルの外部ルール**(フォルダベース、ネットワーク
590
+ ゼロ)— スキャン対象の隣にある `mjolnir-rules/` ディレクトリがカスタム
591
+ ルールを読み込みます: JSON ファイルは正規表現パターンを宣言し(コードは
592
+ 実行されません)、`.mjs`/`.js` モジュールは `rules` をエクスポート
593
+ します(プラグインと同じ完全な Node 信頼)。外部ルールはコアと同じ
594
+ 信頼メタデータを持ちます; コアティアに出荷されることは決してありません
595
+ (コアにはコーパスサイドカーからの実測 FP 率が必要です — 宣言された
596
+ `tier: "core"` は `extended` にクランプされます)、ティア上限に従い、
597
+ ドリフトの検査を受けます: `mjolnir rules --md --external` は読み込んだ
598
+ ファイルからカタログを描画し(出所 `external`)、マトリクスジェネレータは
599
+ `--external <root>` を受け付けます。
600
+
601
+ ---
602
+
603
+ ## 🏗️ アーキテクチャ
604
+
605
+ <details>
606
+ <summary>ツリーを展開</summary>
607
+
608
+ ```
609
+ mjolnir/
610
+ ├── src/
611
+ │ ├── engine/ # LanguageAdapter interface + rule runner
612
+ │ ├── adapters/ # typescript · python · java · csharp · github-actions
613
+ │ ├── rules/ # rules across 8 families + the measured-FP table
614
+ │ ├── playwright/ # Selector Health Score engine
615
+ │ ├── discovery/ # workspace, frameworks, ignore resolution
616
+ │ ├── scope/ # git merge-base changed-scope engine
617
+ │ ├── scorer/ # transparent deduction table + prioritization
618
+ │ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
619
+ │ ├── forensics/ # run-data ingestion · flake verdicts · triage
620
+ │ ├── config/ # mjolnir.config.json + suppressions
621
+ │ ├── plugins/ # third-party rule loading (no sandbox)
622
+ │ └── commands/ # every subcommand
623
+ └── tests/
624
+ ├── fixtures/ # must-fire / must-not-fire per rule
625
+ └── golden/ # frozen score regression locks
626
+ ```
627
+
628
+ </details>
629
+
630
+ - **ルールは純粋関数です** — `(SourceFileContext) → Finding[]`、I/O なし、
631
+ グローバルなし。新しいエコシステム = 1 つのアダプタ + そのルール。
632
+ - **TypeScript/Playwright はコンパイラ AST を使用します**(ts-morph)。
633
+ Python、Java、C# はコメント/文字列をマスクした共有正規表現層上で動作
634
+ します。
635
+ - Java と C# 向けの tree-sitter WASM AST 層は存在し、次の精度ステップ
636
+ ですが、まだ同期スキャンパイプラインには組み込まれていません。
637
+
638
+ ---
639
+
640
+ ## 📚 ドキュメント
641
+
642
+ | ドキュメント | 内容 |
643
+ | ------------------------------------------------------ | ------------------------------------- |
644
+ | [docs/SCORING.md](docs/SCORING.md) | スコアの正規化 + 証拠の重み付け |
645
+ | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | 実測 false-positive 率 + 手法 |
646
+ | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | ルール状態、抑制、非推奨化 |
647
+ | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | SARIF 出力 + エディタ/CI 設定 |
648
+ | [docs/rules/](docs/rules/) | 生成されたルールごとのカタログ |
649
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | 開発環境 + コントリビューションフロー |
650
+ | [CHANGELOG.md](CHANGELOG.md) | リリース履歴 |
651
+ | [SECURITY.md](SECURITY.md) | 脆弱性の報告 |
652
+
653
+ ---
654
+
655
+ ## 📈 ステータス
656
+
657
+ **v0.5.x · オープンベータ。** JSON スキーマと終了コードは凍結された契約
658
+ です。TypeScript と Python が最も広い実測カバレッジを持ち、Java と C# は
659
+ より新しいものです —
660
+ [ティア表](#ルールのティアと言語ごとの成熟度) を参照して読んでください。
661
+
662
+ ---
663
+
664
+ ## 🤝 コントリビュート
665
+
666
+ 新しいルールが最も簡単な最初の貢献です — 1 コマンドでルールとその
667
+ must-fire **と** must-not-fire フィクスチャをスキャフォールドします
668
+ (生成されたルールは、実際の検出を実装するまで意図的にフィクスチャで
669
+ 失敗します — スタブは出荷できません):
670
+
671
+ ```bash
672
+ mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
673
+ ```
674
+
675
+ 完全な開発環境、常設ゲートのコマンド、アンチクリープ / フィクスチャ
676
+ 防火壁の法則は [CONTRIBUTING.md](CONTRIBUTING.md) にあります。
677
+
678
+ ---
679
+
680
+ <div align="center">
681
+
682
+ **信頼できないテストをリリースするのはやめましょう。**
683
+
684
+ ```bash
685
+ npx mjolnir-qa@latest
686
+ ```
687
+
688
+ **Star ⭐ · Watch 👀 · Contribute 🤝**
689
+
690
+ [Sergey Bar](https://www.linkedin.com/in/sergeybar/) によって構築
691
+
692
+ </div>