mjolnir-qa 1.0.9 → 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.th.md CHANGED
@@ -1,386 +1,431 @@
1
1
  <div align="center">
2
2
 
3
- <img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
3
+ <img src="assets/readme/hero.svg" alt="Mjölnir เทสต์บอกคุณว่าอะไรผ่าน Mjölnir บอกคุณว่าอะไรเชื่อถือได้" width="100%" />
4
4
 
5
- ### การทดสอบของคุณโกหกคุณ เราพิสูจน์ให้เห็น
5
+ <br />
6
6
 
7
- **Verification Trust Engine สำหรับ QA** Mjölnir ตรวจสอบชุดทดสอบและ
8
- CI pipelines รายงานคะแนนความน่าเชื่อถือ และแสดงให้เห็นอย่างแม่นยำว่า
9
- ความไว้วางใจพังตรงไหน
7
+ Mjölnir ค้นหาเทสต์ที่ไม่มีวันล้มเหลวและไปป์ไลน์ที่ไม่มีวันเป็นสีแดง<br />
8
+ แล้วให้คะแนนว่าผลลัพธ์เชื่อถือได้แค่ไหน พร้อมหลักฐานของทุกคะแนน
10
9
 
11
- [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=C19A34&labelColor=0A1119)](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=0A1119)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
13
- [![license](https://img.shields.io/badge/license-MIT-C19A34.svg?style=flat-square&labelColor=0A1119)](LICENSE)
14
- [![node](https://img.shields.io/badge/node-%E2%89%A5%2022.18-37ABBD.svg?style=flat-square&labelColor=0A1119)](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) | [日本語](README.ja.md) | [Polski](README.pl.md) | [Русский](README.ru.md) | [Norsk](README.no.md) | [Português (Brasil)](README.br.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)
10
+ <br />
17
11
 
18
- > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-08.
12
+ [![npm](https://img.shields.io/npm/v/mjolnir-qa.svg?style=flat-square&color=1F6F7C&labelColor=0A1119)](https://www.npmjs.com/package/mjolnir-qa)
13
+ [![downloads](https://img.shields.io/npm/dm/mjolnir-qa.svg?style=flat-square&color=1F6F7C&labelColor=0A1119)](https://www.npmjs.com/package/mjolnir-qa)
14
+ [![ci](https://img.shields.io/github/actions/workflow/status/Sergey-Bar/Mjolnir/ci.yml?branch=main&style=flat-square&label=ci&labelColor=0A1119)](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
15
+ [![coverage](https://img.shields.io/codecov/c/github/Sergey-Bar/Mjolnir?style=flat-square&color=1F6F7C&labelColor=0A1119&label=coverage)](https://codecov.io/gh/Sergey-Bar/Mjolnir)
16
+ [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/Sergey-Bar/Mjolnir/badge)](https://scorecard.dev/viewer/?uri=github.com/Sergey-Bar/Mjolnir)
17
+ [![license](https://img.shields.io/badge/license-MIT-1F6F7C.svg?style=flat-square&labelColor=0A1119)](LICENSE)
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
21
  npx mjolnir-qa@latest
22
22
  ```
23
23
 
24
- **การทดสอบของคุณคู่ควรแก่ความไว้วางใจหรือไม่?**
24
+ [ดูการทำงานจริง](#ดูการทำงานจริง) · [เริ่มต้นอย่างรวดเร็ว](#เริ่มต้นอย่างรวดเร็ว) · [สิ่งที่ตรวจพบ](#สิ่งที่-mjölnir-ตรวจพบ) · [คะแนน](#คะแนนความน่าเชื่อถือ) · [หลักฐาน](#แบบจำลองหลักฐาน) · [นิติวิเคราะห์การรัน](#นิติวิเคราะห์ขณะรัน) · [CI](#ความสมบูรณ์ของ-ci) · [เอเจนต์](#เอเจนต์-ai) · [ความปลอดภัย](#ความเชื่อถือและความปลอดภัย) · [ข้อจำกัด](#สิ่งที่-mjölnir-บอกคุณไม่ได้) · [เอกสาร](#เอกสารประกอบ)
25
+
26
+ <details>
27
+ <summary>อ่านในภาษาอื่น — 22 ภาษา</summary>
28
+
29
+ [English](README.md) | [简体中文](README.zh.md) | [繁體中文](README.zht.md) | [한국어](README.ko.md) | [Deutsch](README.de.md) | [Español](README.es.md) | [Français](README.fr.md) | [Italiano](README.it.md) | [Dansk](README.da.md) | [日本語](README.ja.md) | [Polski](README.pl.md) | [Русский](README.ru.md) | [Norsk](README.no.md) | [Português (Brasil)](README.br.md) | ไทย | [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)
30
+
31
+ > 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-15.
32
+
33
+ <!-- Source hash: 3541b09e8d04 -->
25
34
 
26
- [ดูมันทำงาน](#-ดูมันทำงาน) ·
27
- [เริ่มเร็ว](#-เริ่มเร็ว) ·
28
- [มันตรวจอะไร](#-mjölnir-ตรวจอะไร) ·
29
- [การให้คะแนน](#การให้คะแนนทำงานอย่างไร) ·
30
- [CI](#-การเชื่อมต่อ-ci) · [การตั้งค่า](#การตั้งค่า) ·
31
- [เอกสาร](#-เอกสาร)
35
+ </details>
32
36
 
33
37
  </div>
34
38
 
35
- ---
39
+ <br />
40
+
41
+ ## เครื่องหมายถูกสีเขียวคือคำกล่าวอ้าง ไม่ใช่ข้อพิสูจน์
42
+
43
+ เครื่องหมายถูกสีเขียวหมายความว่าไปป์ไลน์ไม่ล้มเหลว ไม่ได้หมายความว่าเทสต์ถูกรันจริง หรือว่าเทสต์มีโอกาสล้มเหลวได้ ทุกกรณีต่อไปนี้ผ่านเป็นสีเขียวทั้งสิ้น:
44
+
45
+ - `.only` ที่ถูกคอมมิตไว้ ทำให้รันเทสต์เพียง 3 ตัวแทนที่จะเป็น 900 ตัว
46
+ - `continue-on-error: true` บน job ที่ควรทำหน้าที่เป็นด่านกั้น
47
+ - `|| true` ต่อท้ายคำสั่งรันเทสต์
48
+ - เทสต์ที่ไม่ได้ตรวจสอบอะไรเลย หรือมีเนื้อหาว่างเปล่า
49
+ - ตัวครอบการรันซ้ำที่เปลี่ยนความล้มเหลวจริงให้กลายเป็นการผ่านแบบฟลุก
50
+ - รายงานที่ workflow อัปโหลดแต่ไม่เคยถูกสร้างขึ้นมาจริง
51
+ - sleep แบบตายตัวที่ประคอง race condition เอาไว้
52
+
53
+ ไม่มีข้อใดทำให้ไปป์ไลน์เป็นสีแดง และทุกข้อดูเหมือนตั้งใจเมื่ออยู่ในการรีวิว นั่นคือเหตุผลที่มันรอดมาได้ นี่คือ Mjölnir กำลังอ่านกรณีจริง:
54
+
55
+ <p align="center">
56
+ <img src="assets/readme/scan.svg" alt="CI workflow ของรีโพสาธิต อ่านทีละบรรทัด Mjölnir ทำเครื่องหมายแต่ละข้อค้นพบที่บรรทัดที่รายงาน พร้อมกฎ สิ่งที่ผิด ระดับหลักฐาน และอัตราผลบวกลวงที่วัดได้" width="800" />
57
+ </p>
58
+
59
+ <sub>ทุกข้อค้นพบที่การสแกนสาธิตรายงานสำหรับ workflow นี้ ณ บรรทัดที่รายงาน สร้างโดย `npm run docs:readme-brand` จาก [`demo-report.json`](assets/readme/demo-report.json) และถูกล็อกไม่ให้คลาดเคลื่อนใน CI</sub>
60
+
61
+ **โหมดเข้มงวด.** การตรวจจับที่รุนแรงที่สุด — `.only`, `continue-on-error`, การทดสอบว่าง, การใช้ retry ในทางที่ผิด — อยู่ในชั้นกักกัน ทำงานเฉพาะภายใต้ `--strict` และจำกัดที่ความรุนแรง `info`: ตั้งค่าสถานะ แต่ไม่เคยบล็อก การสแกนเริ่มต้น (`npx mjolnir-qa@latest` โดยไม่มี `--strict`) ครอบคลุมเฉพาะกฎหลักและกฎขยาย เพิ่ม `--strict` เมื่อคุณต้องการชั้นที่ปรึกษาด้วย
62
+
63
+ Mjölnir อ่านชุดเทสต์ CI workflow และรายงานจากการรันจริงหากคุณมี มันไม่รันเทสต์ของคุณ ไม่ติดตั้ง dependency และไม่รันโค้ดที่มันสแกน และเมื่อไม่มีหลักฐาน มันจะบอกตรง ๆ แทนที่จะแต่งความมั่นใจขึ้นมา:
64
+
65
+ | สถานการณ์ | สิ่งที่ Mjölnir รายงาน |
66
+ | ------------------------------------------------- | -------------------------------------------------------------- |
67
+ | ไม่พบการประกาศเทสต์ | คะแนน `null` แสดงเป็น **UNKNOWN** ไม่มีวันเป็น 100 ที่แต่งขึ้น |
68
+ | ไม่มี baseline หรือรีวิชันที่เปรียบเทียบได้ | **UNKNOWN** พร้อมระบุเหตุผล ไม่มีวันสมมติเป็น 0 |
69
+ | การสแกนถูกตัดจบกลางคัน (งบเวลา ไฟล์ที่อ่านไม่ได้) | **PARTIAL** รหัสออก `2` ไม่มีวันแสดงว่าสะอาด |
70
+
71
+ <p align="center">
72
+ <img src="assets/readme/how-it-works.svg" alt="Mjölnir ทำงานอย่างไร มันอ่านชุดเทสต์และไปป์ไลน์ CI แบบสถิต และอ่านรายงานจากการรันจริงเมื่อมี มันถ่วงน้ำหนักทุกข้อค้นพบตามระดับหลักฐานและระดับความเชื่อถือ โดยมีเพียงการรันจริงเท่านั้นที่ไปถึง L3 ถึง L5 ได้ แล้วสร้างข้อค้นพบ คะแนนความน่าเชื่อถือ และด่าน CI ที่ใช้รหัสออกซึ่งถูกตรึงไว้ ในลูปของเอเจนต์ AI เขียนการแก้ไข แล้ว Mjölnir สแกนซ้ำเพื่อพิสูจน์" width="880" />
73
+ </p>
74
+
75
+ <sub>จัดทำขึ้นสำหรับหน้านี้และแสดงในขนาด 1:1 สร้างโดย `npm run docs:readme-brand` และถูกล็อกไม่ให้คลาดเคลื่อนใน CI คะแนน จำนวน และ ID ของกฎมาจาก [`script.demo.json`](assets/video/script.demo.json), [`demo-report.json`](assets/readme/demo-report.json) และทะเบียนกฎ ไม่เคยพิมพ์ด้วยมือ ภาพเดียวกันในแบบโปสเตอร์: [`architecture.svg`](assets/readme/architecture.svg)</sub>
76
+
77
+ <br />
78
+
79
+ ## ดูการทำงานจริง
36
80
 
37
- ## 🎬 ดูมันทำงาน
81
+ การสแกนจริงของ [`examples/demo-repo`](examples/demo-repo) ซึ่งเป็นชุดเทสต์ Playwright ขนาดเล็กที่มี CI workflow คะแนนของมันหายไปตรงนี้:
38
82
 
39
83
  <p align="center">
40
- <img src="assets/readme/demo.svg" alt="รายงาน --verbose ฉบับเต็มของ Mjölnir บน demo repo: WORTHINESS 75/100 NEEDS WORK, การแจกแจงการวินิจฉัยตามหมวด, รายการ FIX THIS FIRST และทุก finding พร้อม rule ID และเลขบรรทัด ครอบคลุมกฎ CI, Playwright, สุขอนามัยการทดสอบ และกฎ Python" width="900" />
84
+ <img src="assets/readme/terminal-hero.svg" alt="รายละเอียดการหักคะแนนของ Mjölnir: WORTHINESS 80/100 WORTHY คะแนนแยกตามหมวดหมู่ กล่องการหักคะแนนตามความรุนแรง และรายการ FIX THIS FIRST" width="520" />
41
85
  </p>
42
86
 
43
- <sub>ผลลัพธ์ฉบับเต็มของ `npx mjolnir-qa ./examples/demo-repo --verbose`
44
- เรนเดอร์จาก reporter จริง — ไม่ตัดทอนอะไรเลย สร้างใหม่ด้วย
45
- `npm run docs:demo`;
46
- [`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
47
- จะทำให้ CI ล้ม หากสินค้าเองเหลื่อมจากสิ่งที่เครื่องมือพิมพ์</sub>
87
+ <sub>สร้างโดย `npm run docs:hero` จากการสแกนจริง และถูกล็อกไม่ให้คลาดเคลื่อนใน CI รายงาน `--verbose` ฉบับเต็มของการสแกนเดียวกันคือ [`demo.svg`](assets/readme/demo.svg) (`npm run docs:demo`)</sub>
48
88
 
49
- **เกิดอะไรขึ้นเมื่อครู่:**
89
+ <details>
90
+ <summary><strong>ดูวิดีโอ</strong> — การสแกน การแก้ไขที่มันพิมพ์ออกมา และการสแกนซ้ำที่พิสูจน์การแก้ไขนั้น</summary>
50
91
 
51
- 1. Mjölnir ค้นพบ Playwright specs, config, CI workflow และไฟล์ทดสอบ
52
- Python — สี่ภาษา/ฟอร์แมต ในหนึ่งรอบ
53
- 2. มันพบหลักฐานที่บั่นทอนความไว้วางใจต่อชุดทดสอบ — `continue-on-error`
54
- ที่ปกปิด job, `|| true` ที่กลืน exit code, hard sleep, selector เปราะ,
55
- URL staging ฝังตาย, การรอ `networkidle`
56
- 3. มันเปลี่ยนแต่ละเรื่องเป็น finding ที่จับต้องได้ พร้อม rule ID,
57
- ตำแหน่ง และวิธีแก้ — และเป็นคะแนนเดียวที่คุณ gate PR ได้
92
+ <br />
58
93
 
59
- ### Finding หนึ่งชิ้น ระยะชิด
94
+ <p align="center">
95
+ <a href="assets/video/mjolnir-demo.mp4">
96
+ <img src="assets/video/mjolnir-demo-poster.png" alt="เฟรมหนึ่งจากวิดีโอสาธิต: npx mjolnir-qa@latest กำลังสแกนรีโพสาธิตในหน้าต่างเทอร์มินัล" width="900" />
97
+ </a>
98
+ </p>
60
99
 
61
- รัน `mjolnir explain QA-CI-001` กับ finding แรกด้านบน แล้วคุณจะได้:
100
+ <sub>เรนเดอร์ทีละเฟรมจากการสแกนจริงด้วย `npm run docs:video` ไม่เคยอัดหน้าจอ เลือกเฟรมเพื่อเปิด [`mjolnir-demo.mp4`](assets/video/mjolnir-demo.mp4)</sub>
101
+
102
+ </details>
103
+
104
+ ### ข้อค้นพบหนึ่งข้อแบบใกล้ชิด
105
+
106
+ ทุกข้อค้นพบตอบคำถามสี่ข้อ: อยู่ที่ไหน Mjölnir มั่นใจแค่ไหน กฎนี้ผิดบ่อยแค่ไหน และแก้อย่างไร
107
+
108
+ <p align="center">
109
+ <img src="assets/readme/finding-anatomy.svg" alt="ข้อค้นพบแรกของการสแกนสาธิต ตรงตามที่เทอร์มินัลพิมพ์ออกมา พร้อมทำเครื่องหมายสี่ส่วน: ตำแหน่ง ความมั่นใจ ความถี่ที่กฎผิด และการแก้ไข" width="100%" />
110
+ </p>
111
+
112
+ `mjolnir explain QA-CI-001` พิมพ์ประวัติความน่าเชื่อถือทั้งหมดของกฎ รวมถึงอัตราผลบวกลวงที่วัดได้และระดับที่อัตรานั้นทำให้กฎได้รับ:
62
113
 
63
114
  ```text
64
- ▚ QA-CI-001 — continue-on-error masks a failing verification gate
115
+ ▍ QA-CI-001 — continue-on-error masks a failing verification gate
65
116
 
66
117
  Severity: error
67
118
  Confidence: high
119
+ Tier: quarantine
68
120
  Evidence: E2
69
- Measured FP: not yet measured — this rule ships on assumption (see docs/FP-AUDIT.md)
121
+ QA impact: False-green risk (FALSE-GREEN)
122
+ Measured FP: 11% (19 hand-classified corpus verdicts)
123
+ FP risk: low (author estimate)
124
+ Languages: yaml
125
+ Frameworks: github-actions, azure-pipelines
70
126
 
71
127
  WHAT WAS FOUND (real detector output, not a mockup)
72
128
  Job `security-scan` runs a verification gate under `continue-on-error: true`.
73
129
 
74
130
  WHY IT MATTERS
75
- This job can fail every day and CI will still show green. The checkmark
76
- on this workflow cannot be trusted.
131
+ This job can fail every day and CI will still show green. The checkmark on
132
+ this workflow cannot be trusted.
77
133
 
78
134
  HOW TO FIX
79
135
  Remove continue-on-error, or scope it to individual non-blocking steps only.
80
- ```
81
136
 
82
- นี่คือหน่วยของคุณค่า: ไม่ใช่เรื่องสไตล์เล็ก ๆ แต่เป็นจุดที่ CI ของคุณ
83
- บอกว่าบางอย่างผ่าน ทั้งที่ไม่ได้ผ่าน
137
+ Example from this rule's own must-fire fixture: QA-CI-001/must-fire/masked.yml
84
138
 
85
- ---
139
+ WHAT WOULD CHANGE THE VERDICT
140
+ - a run report next to the scan target (mjolnir.report.json or test-results/)
141
+ corroborating this file lifts its findings to L3–L5
142
+ - a documented suppression (mjolnir.config.json) lowers the finding count
143
+ without claiming correctness
144
+ - quarantine findings run only under --strict and are advisory (E0) — they can
145
+ never gate CI
86
146
 
87
- ## ⚡ เริ่มเร็ว
147
+ NEXT ACTION
148
+ Fix the first occurrence, then re-run: `mjolnir --scope changed`. Every
149
+ occurrence of this rule is listed in the scan output.
88
150
 
89
- รันกับ repo เพื่อรายงานฉบับเต็มและคะแนนความน่าเชื่อถือ:
151
+ HOW TO VERIFY THE FIX
152
+ Re-run `mjolnir` on the changed file(s) — this finding should no longer
153
+ appear. `mjolnir --scope changed` scopes the check to just what you touched.
90
154
 
91
- ```bash
92
- npx mjolnir-qa@latest
155
+ Docs: mjolnir rules --md (full catalog, this rule included)
93
156
  ```
94
157
 
95
- **ใน CI ผลิตภัณฑ์คือคำสั่งเดียว** มันสแกนเฉพาะสิ่งที่ branch แตะ
96
- และออกด้วยเลขไม่ใช่ศูนย์เมื่อมีปัญหาใหม่:
158
+ นี่คือหน่วยของคุณค่า: จุดหนึ่งที่ CI รายงานว่าผ่านทั้งที่ไม่ได้ผ่านจริง
159
+
160
+ <br />
161
+
162
+ ## เริ่มต้นอย่างรวดเร็ว
97
163
 
98
164
  ```bash
99
- npx mjolnir-qa@latest --scope changed
165
+ npx mjolnir-qa@latest
100
166
  ```
101
167
 
102
- หย่อนลงใน PR check — `mjolnir ci install` เขียน workflow ให้ — แล้วจบ
103
- ส่วนที่เหลือเป็นทางเลือกทั้งหมด
168
+ มันสแกนไดเรกทอรีปัจจุบันและพิมพ์ Trust Report: สิ่งที่พบ เชื่อถือได้แค่ไหน เพราะอะไร และควรทำอะไรต่อ มันออกด้วยรหัส `0` เมื่อไม่พบสิ่งใดที่ระดับด่านหรือสูงกว่า
104
169
 
105
- | คำสั่ง | มันทำอะไร |
106
- | ----------------------------------- | ---------------------------------------------------- |
107
- | `mjolnir` | สแกนทั้ง repo + คะแนนความน่าเชื่อถือ |
108
- | `mjolnir --scope changed` | เฉพาะสิ่งที่ branch คุณแนะนำ — รูปแบบ CI |
109
- | `mjolnir ci install` | สร้าง CI workflow แบบที่ปรึกษาสำหรับ PR |
110
- | `mjolnir explain QA-CI-001` | อะไร / ทำไม / วิธีแก้ + อัตรา FP ที่วัดได้ของกฎเดียว |
111
- | `mjolnir rules --unmeasured` | กฎที่ทำงานด้วยข้อสมมติ ไม่ใช่การวัด |
112
- | `mjolnir --json` / `--format sarif` | เครื่องอ่านได้ / GitHub Code Scanning |
113
- | `mjolnir --strict` | รันกฎ tier quarantine ด้วย (ความเสี่ยง FP สูงกว่า) |
114
-
115
- <details>
116
- <summary><strong>เมื่ออะไรบางอย่าง flaky</strong></summary>
170
+ ใน CI ให้สแกนเฉพาะสิ่งที่ branch นำเข้ามา เพื่อไม่ให้ชุดเทสต์เก่าท่วม pull request แรกของคุณ:
117
171
 
118
- | คำสั่ง | มันทำอะไร |
119
- | ----------------------------------- | -------------------------------------------------- |
120
- | `mjolnir forensics ./test-results/` | ข้อมูลรันจริง → คำพิพากษา `TRUE-FLAKE`, `FLAKY.md` |
121
- | `mjolnir triage ./test-results/` | ข้อเสนอการกักกันจากประวัติการรัน |
122
- | `mjolnir pw-report ./test-results/` | สรุปการรัน Playwright — retry / flake / ช้าสุด |
123
- | `mjolnir doctor:playwright` | สแกนลึกเฉพาะ Playwright + Selector Health Score |
172
+ ```bash
173
+ npx mjolnir-qa@latest --scope changed
174
+ ```
124
175
 
125
- </details>
176
+ `mjolnir ci install` เขียนสิ่งนี้เป็น GitHub Actions workflow โดยใช้ [action](https://github.com/Sergey-Bar/Mjolnir#readme) ที่ปักไว้กับแท็กหลัก `v1` (หรือใช้ `npx` ธรรมดาด้วย `--no-action`) มันจะอยู่ในโหมดให้คำแนะนำจนกว่าคุณจะตัดสินใจให้มันบล็อก
177
+
178
+ | คำสั่ง | สิ่งที่ทำ |
179
+ | ----------------------------------- | -------------------------------------------------------- |
180
+ | `mjolnir` | Trust Report: คำตัดสิน ความมั่นใจ ขั้นตอนถัดไป |
181
+ | `mjolnir --scope changed` | เฉพาะสิ่งที่ branch ของคุณนำเข้ามา (รูปแบบสำหรับ CI) |
182
+ | `mjolnir ci install` | สร้าง PR workflow แบบให้คำแนะนำ (ใช้ action) |
183
+ | `mjolnir explain QA-CI-001` | อะไร ทำไม และวิธีแก้ พร้อมอัตรา FP ที่วัดได้ |
184
+ | `mjolnir why src/a.spec.ts:42` | เหตุผลที่บรรทัดนี้ถูกทำเครื่องหมาย ไม่บล็อกเลย |
185
+ | `mjolnir forensics ./test-results/` | หลักฐานรันไทม์จากการรันจริง |
186
+ | `mjolnir trust-report` | Trust Artifact แบบครบในตัว (md + json) |
187
+ | `mjolnir handoff` | แผนการแก้ไขสำหรับเอเจนต์เขียนโค้ด |
188
+ | `mjolnir --json` / `--format sarif` | ผลลัพธ์ที่เครื่องอ่านได้, GitHub Code Scanning |
189
+ | `mjolnir --format codequality` | รายงาน GitLab Code Quality (อาร์ติแฟกต์สำหรับวิดเจ็ต MR) |
190
+ | `mjolnir --strict` | รันกฎระดับ quarantine ด้วย (ความเสี่ยง FP สูงกว่า) |
126
191
 
127
192
  <details>
128
- <summary><strong>ใช้เป็นครั้งคราว / รายงาน</strong></summary>
129
-
130
- | คำสั่ง | มันทำอะไร |
131
- | ------------------------------- | ----------------------------------------------------- |
132
- | `mjolnir fix --dry-run` / `fix` | แก้อัตโนมัติอย่างปลอดภัย พร้อมหลักฐาน |
133
- | `mjolnir baseline` / `diff` | บันทึก snapshot ของ finding แล้วรายงานเฉพาะใหม่/แย่ลง |
134
- | `mjolnir impact --since <ref>` | อะไรเปลี่ยนไปตั้งแต่ commit ก่อนหน้า |
135
- | `mjolnir debt` | ทะเบียนหนี้การทดสอบ พร้อมโมเดลต้นทุน |
136
- | `mjolnir handover` | แผนที่ onboarding ชุดทดสอบสำหรับ QA หน้าใหม่ |
137
- | `mjolnir stats` | ตัวนับตลอดกาลในเครื่อง ของ fix ที่เคยเห็น |
138
- | `mjolnir badge` | JSON endpoint ของ shields.io + snippet |
139
- | `mjolnir rules --md` | แคตตาล็อกกฎเต็มรูปแบบ (JSON หรือ Markdown) |
140
- | `mjolnir doctor` | ตรวจตรวามของฐานกฎของ Mjölnir เอง |
141
- | `mjolnir create-rule <ID>` | สร้างโครงกฎใหม่ + fixtures |
142
- | `mjolnir --format mermaid` | แผนภาพสถาปัตยกรรมการทดสอบสำหรับคอมเมนต์ PR |
193
+ <summary><strong>คำสั่งอื่นทั้งหมด</strong> — คัดแยกเทสต์ไม่เสถียร การรายงาน การกำกับดูแล</summary>
194
+
195
+ <br />
196
+
197
+ | คำสั่ง | สิ่งที่ทำ |
198
+ | ----------------------------------- | --------------------------------------------------------------------- |
199
+ | `mjolnir --classic` | แบนเนอร์คะแนนแบบก่อนมี Trust Report |
200
+ | `mjolnir explain verdict` | เหตุผลที่คำตัดสินของการสแกนที่บันทึกไว้เป็นเช่นนั้น |
201
+ | `mjolnir triage ./test-results/` | การคัดแยกแบบมีขั้นตอน ทุกแถวจบด้วยขั้นตอนถัดไป |
202
+ | `mjolnir pw-report ./test-results/` | สรุปการรัน Playwright: การรันซ้ำ เทสต์ไม่เสถียร เทสต์ที่ช้าที่สุด |
203
+ | `mjolnir doctor:playwright` | สแกนเชิงลึกเฉพาะ Playwright พร้อม Selector Health Score |
204
+ | `mjolnir fix --dry-run` / `fix` | การแก้ไขอัตโนมัติที่ปลอดภัย แต่ละรายการถูกสแกนซ้ำเพื่อพิสูจน์ว่าได้ผล |
205
+ | `mjolnir baseline` / `diff` | บันทึกสแนปช็อตของข้อค้นพบ แล้วรายงานเฉพาะที่ใหม่หรือแย่ลง |
206
+ | `mjolnir impact --since <ref>` | สิ่งที่คอมมิตหนึ่งนำเข้ามาและแก้ไขไป |
207
+ | `mjolnir summary` | คำอธิบายประกอบ CI และสรุป step จากรายงาน |
208
+ | `mjolnir pr-comment` | คอมเมนต์ PR ที่จำกัดขอบเขต เป็น Markdown |
209
+ | `mjolnir debt` | ทะเบียนหนี้ทางเทสต์พร้อมแบบจำลองต้นทุน |
210
+ | `mjolnir handover` | แผนที่แนะนำชุดเทสต์สำหรับวิศวกร QA คนใหม่ |
211
+ | `mjolnir init` | ตรวจหาเฟรมเวิร์กและพิมพ์รายการตรวจสอบการตั้งค่า |
212
+ | `mjolnir suppressions` | แสดงรายการข้อค้นพบที่ถูกระงับ เพื่อการกำกับดูแล |
213
+ | `mjolnir rules --unmeasured` | กฎที่ทำงานจากการสันนิษฐาน ไม่ใช่จากการวัด |
214
+ | `mjolnir rules --md` | แค็ตตาล็อกกฎฉบับเต็ม (JSON หรือ Markdown) |
215
+ | `mjolnir doctor` | การตรวจสอบตัวเองของฐานกฎของ Mjölnir |
216
+ | `mjolnir create-rule <ID>` | สร้างโครงของกฎใหม่และ fixture ของมัน |
217
+ | `mjolnir stats` | ตัวนับสะสมในเครื่องของการแก้ไขทั้งหมดที่เคยพบ |
218
+ | `mjolnir badge` | JSON สำหรับ endpoint ของ shields.io และโค้ดตัวอย่าง |
219
+ | `mjolnir --cache` | สแกนซ้ำแบบเพิ่มทีละส่วนผ่านแคชคำตัดสินในเครื่อง |
220
+ | `mjolnir --format mermaid` | แผนภาพสถาปัตยกรรมเทสต์สำหรับคอมเมนต์ PR |
221
+
222
+ `mjolnir help <command>` พิมพ์วิธีใช้ ตัวอย่าง และขั้นตอนถัดไปของทุกคำสั่ง
143
223
 
144
224
  </details>
145
225
 
146
- ติดตั้งแบบ global แทน `npx` หากคุณชอบ: `npm i -g mjolnir-qa`
147
- ต้องใช้ Node.js ≥ 22.18 ทำงานบน Windows, macOS และ Linux
148
-
149
- ---
150
-
151
- ## 👥 สำหรับใคร?
152
-
153
- - **QA / SDET** เจ้าของชุด e2e หรือ integration ที่ต้องการหลักฐานว่า
154
- ชุดทดสอบสมควรได้เครื่องหมายเขียวที่มันผลิตจริง
155
- - **ทีม Platform / DevEx** ผู้รับผิดชอบความสมบูรณ์ของ CI และ release
156
- gates — คนที่ใส่ใจว่า `continue-on-error` จะไม่หลอกเปลี่ยน pipeline
157
- แดงให้เขียวอย่างเงียบ ๆ
158
- - **ผู้ดูแล OSS** ที่อยากได้เกตตรวจสอบที่ถูก เปิดตลอดเวลา รันได้ทั้ง
159
- ในเครื่องและใน CI โดยไม่มีการเรียกเครือข่าย
160
-
161
- ---
226
+ ต้องใช้ **Node.js ≥ 22.18** บน Windows, macOS หรือ Linux อยากติดตั้งแบบ global หรือไม่? `npm i -g mjolnir-qa` เวอร์ชันขั้นต่ำนี้มาจากชุดเครื่องมือ build (tsdown กำหนดเป้าหมายไว้ที่เวอร์ชันนี้ และไปป์ไลน์รีลีสทำ smoke test กับเวอร์ชันนี้) dependency ตอนรันไม่ต้องการมากกว่านั้น
162
227
 
163
- ## 🔨 Mjölnir ตรวจอะไร
228
+ <br />
164
229
 
165
- | | |
166
- | --- | --------------------------------------------------------------------------------------------------------------- |
167
- | ⚖️ | **คะแนนความน่าเชื่อถือ** — ตัวเลขเดียว ตารางหักโปร่งใส ไม่มีกล่องดำ |
168
- | 🎭 | **Selector Health Score** — ให้เกรด locator ของ Playwright คุณ ไม่ใช่แค่อัตราผ่าน |
169
- | 🔬 | **นิติวิทยาศาสตร์ runtime** — อ่านข้อมูลรันจริงของ Playwright/JUnit เพื่อจับ `TRUE-FLAKE` ไม่ใช่แค่เดาแบบสถิต |
170
- | 🚨 | **กฎความสมบูรณ์ของ CI** — จับ `continue-on-error`, `\|\| true` และเทคนิคเขียวลวงอื่น ๆ |
171
- | 🐍 | **ทั้งสี่ Playwright bindings** — TypeScript, Python, Java, C#/.NET — บวก pytest, JUnit/TestNG และ CI workflows |
172
- | 🔒 | **Local-first** — ศูนย์การเรียกเครือข่ายระหว่างสแกน ศูนย์เทเลเมทรี รันเสร็จในไม่กี่วินาที |
230
+ ## สิ่งที่ Mjölnir ตรวจพบ
173
231
 
174
- ### กฎทั้งหมด
232
+ <p align="center">
233
+ <img src="assets/readme/stack.svg" alt="ใช้งานได้กับสแตกของคุณ: ภาษา เฟรมเวิร์กเทสต์ และระบบ CI ที่กฎครอบคลุม จากทะเบียนกฎ" width="100%" />
234
+ </p>
175
235
 
176
- ทุกกฎมาพร้อม fixture must-fire **และ** must-not-fire กฎที่ยิงบน
177
- fixture ลบของตัวเองจะปล่อยไม่ได้ — นั่นคือกำแพงกัน false positive
236
+ **79 กฎ** ในสี่ตระกูล ได้แก่ สุขอนามัยของเทสต์ คุณภาพของเทสต์ Playwright และความสมบูรณ์ของ CI ครอบคลุม TypeScript และ JavaScript, Python, Java, C# และ YAML ของ GitHub Actions รองรับ Playwright ครบทั้งสี่ binding รวมถึง pytest, JUnit, TestNG, NUnit, xUnit, MSTest, Jest, Vitest และ Mocha พร้อมการรองรับเบื้องต้นสำหรับ Cypress และ Selenium นี่คือเก้ากฎเพื่อให้เห็นภาพ:
178
237
 
179
- <details>
180
- <summary><strong>สุขอนามัยการทดสอบ</strong></summary>
181
-
182
- | ID | กฎ | Severity |
183
- | ----------- | --------------------------------------------------- | -------- |
184
- | QA-TEST-001 | ทดสอบแบบโฟกัสถูก commit (`.only`, `fit`) | error |
185
- | QA-TEST-002 | ข้ามทดสอบโดยไม่มีเหตุผล | error |
186
- | QA-TEST-002 | ข้ามทดสอบโดยมีเหตุผลที่ถูกบันทึก | warning |
187
- | QA-TEST-003 | ทดสอบไม่มี assertion | error |
188
- | QA-TEST-004 | hard sleep (`waitForTimeout`, `sleep()`, `delay()`) | warning |
189
- | QA-TEST-006 | ใช้ retry เกินควร ซ่อนความไม่นิ่ง | warning |
190
- | QA-TEST-010 | เนื้อความทดสอบว่าง | error |
238
+ | ID | กฎ | ความรุนแรง | ระดับ |
239
+ | ------------ | ------------------------------------------------------------------- | ---------- | ---------- |
240
+ | QA-CI-001 | `continue-on-error` ปิดบังด่านตรวจสอบที่ล้มเหลว | error | quarantine |
241
+ | QA-CI-009 | รหัสออกของเทสต์ไม่ถูกส่งต่อ (`\|` โดยไม่มี pipefail, สายคำสั่ง `;`) | error | extended |
242
+ | QA-TEST-001 | คอมมิตเทสต์ที่โฟกัสไว้ (`.only`, `fit`) | error | quarantine |
243
+ | QA-TEST-003 | เทสต์ที่ไม่มี assertion | error | quarantine |
244
+ | QA-TQUAL-009 | assertion ของ promise ที่ไม่ได้ await | error | quarantine |
245
+ | QA-PW-002 | assertion ของ locator ที่ไม่ได้ await | error | core |
246
+ | QA-PW-004 | selector CSS/XPath ที่เปราะบาง | warning | quarantine |
247
+ | QA-PY-002 | เทสต์ที่ถูกข้าม (`skip`, `xfail` ที่ไม่เข้มงวด) | warning | core |
248
+ | QA-CS-103 | เมธอดเทสต์ที่ไม่มี assertion | error | core |
191
249
 
192
- </details>
250
+ แค็ตตาล็อกฉบับเต็มสร้างจากทะเบียน ไม่เคยดูแลด้วยมือ: `mjolnir rules --md`, [`docs/rules/`](docs/rules/) หรือ [คู่มือสิ่งที่ตรวจสอบ](https://sergey-bar.github.io/Mjolnir/guide/what-it-checks)
193
251
 
194
252
  <details>
195
- <summary><strong>คุณภาพการทดสอบ</strong></summary>
196
-
197
- | ID | กฎ | Severity |
198
- | ------------ | -------------------------------------- | -------- |
199
- | QA-TQUAL-002 | assertion พรรคพวกตัวเอง (tautological) | error |
200
- | QA-TQUAL-009 | assertion ของ promise ที่ไม่ await | error |
201
- | QA-TQUAL-011 | ทดสอบที่ถูกคอมเมนต์ทิ้งไว้ | warning |
253
+ <summary><strong>ทุกกฎที่กล่าวถึงใน README นี้</strong> ในตารางเดียว</summary>
254
+
255
+ <br />
256
+
257
+ > กฎ `quarantine` รันเฉพาะภายใต้ `--strict` และไม่บล็อกเลย (ถูกจำกัดไว้ที่ info) ความรุนแรงที่แสดงคือค่าที่ผู้เขียนกำหนด
258
+
259
+ | ID | ตระกูล | กฎ | ความรุนแรง | ระดับ |
260
+ | ------------ | ---------- | ---------------------------------------------------------------- | ---------- | ---------- |
261
+ | QA-TEST-001 | สุขอนามัย | คอมมิตเทสต์ที่โฟกัสไว้ (`.only`, `fit`) | error | quarantine |
262
+ | QA-TEST-002 | สุขอนามัย | เทสต์ที่ถูกข้าม จะยกระดับเป็น `error` หากไม่มีเหตุผลที่ติดตามได้ | warning | quarantine |
263
+ | QA-TEST-003 | สุขอนามัย | เทสต์ที่ไม่มี assertion | error | quarantine |
264
+ | QA-TEST-004 | สุขอนามัย | sleep แบบตายตัว (`waitForTimeout`, `sleep()`, `delay()`) | warning | extended |
265
+ | QA-TEST-006 | สุขอนามัย | การใช้การรันซ้ำอย่างผิดวิธีเพื่อซ่อนความไม่เสถียร | warning | quarantine |
266
+ | QA-TEST-010 | สุขอนามัย | เนื้อหาเทสต์ว่างเปล่า | error | quarantine |
267
+ | QA-TQUAL-002 | คุณภาพ | assertion ที่เป็นจริงเสมอ | error | quarantine |
268
+ | QA-TQUAL-009 | คุณภาพ | assertion ของ promise ที่ไม่ได้ await | error | quarantine |
269
+ | QA-TQUAL-011 | คุณภาพ | เทสต์ที่ถูกคอมเมนต์ทิ้งไว้ | warning | extended |
270
+ | QA-PW-002 | Playwright | assertion ของ locator ที่ไม่ได้ await | error | core |
271
+ | QA-PW-003 | Playwright | คอมมิต `page.pause()` / `test.only()` ไว้ | error | core |
272
+ | QA-PW-004 | Playwright | selector CSS/XPath ที่เปราะบาง | warning | quarantine |
273
+ | QA-PW-123 | Playwright | URL ของสภาพแวดล้อมที่ฝังไว้ในโค้ด | warning | quarantine |
274
+ | QA-PW-140 | Playwright | ภาพหน้าจอที่ไม่มี `maxDiffPixelRatio` | warning | core |
275
+ | QA-CI-001 | CI | `continue-on-error` ปิดบังด่านที่ล้มเหลว | error | quarantine |
276
+ | QA-CI-002 | CI | `\|\| true` กลืนรหัสออก | error | extended |
277
+ | QA-CI-005 | CI | รายงานถูกใช้แต่ไม่เคยถูกสร้าง | error | quarantine |
278
+ | QA-CI-007 | CI | ตัวครอบการรันซ้ำรอบเทสต์ | warning | extended |
279
+ | QA-CI-008 | CI | step ที่สำเร็จเสมอปิดบังความล้มเหลว | error | quarantine |
280
+ | QA-CI-009 | CI | รหัสออกไม่ถูกส่งต่อ (`\|` โดยไม่มี pipefail, สายคำสั่ง `;`) | error | extended |
281
+ | QA-CI-010 | CI | เทสต์ถูกข้ามในจุดที่ต้องบล็อก | error | quarantine |
282
+ | QA-PY-002 | Python | เทสต์ที่ถูกข้าม (`skip`, `xfail` ที่ไม่เข้มงวด) | warning | core |
283
+ | QA-PY-003 | Python | ฟังก์ชันเทสต์ที่ไม่มี assertion | error | quarantine |
284
+ | QA-PY-005 | Python | `time.sleep()` ในเทสต์ | warning | extended |
285
+ | QA-PY-012 | Python | assertion ที่เป็นจริงเสมอ | error | quarantine |
286
+ | QA-JV-101 | Java | เทสต์ที่ถูกปิดใช้งาน (`@Disabled`) | warning | core |
287
+ | QA-JV-102 | Java | sleep แบบตายตัว (`Thread.sleep()`) | warning | extended |
288
+ | QA-JV-103 | Java | เมธอดเทสต์ที่ไม่มี assertion | error | extended |
289
+ | QA-JV-105 | Java | sleep แบบตายตัวด้วย `waitForTimeout()` ของ Playwright | warning | core |
290
+ | QA-JV-106 | Java | selector ที่เปราะบางแทน locator ตามบทบาท | warning | quarantine |
291
+ | QA-CS-101 | C# | เทสต์ที่ถูกข้าม (`[Ignore]`, `[Fact(Skip=)]`) | warning | core |
292
+ | QA-CS-102 | C# | sleep แบบตายตัว (`Thread.Sleep` / `Task.Delay`) | warning | core |
293
+ | QA-CS-103 | C# | เมธอดเทสต์ที่ไม่มี assertion | error | core |
294
+ | QA-CS-105 | C# | sleep แบบตายตัวด้วย `WaitForTimeoutAsync()` | warning | extended |
295
+ | QA-CS-106 | C# | selector ที่เปราะบางแทน locator ตามบทบาท | warning | quarantine |
296
+
297
+ Python ยังมี QA-PY-001…012 (สุขอนามัยของ pytest) และ QA-PY-101…108 (Playwright สำหรับ Python) Cypress และ Selenium มีชุดเริ่มต้นอย่างละสามกฎ
202
298
 
203
299
  </details>
204
300
 
205
- <details>
206
- <summary><strong>Playwright 🎭</strong></summary>
301
+ ทุกกฎมาพร้อม fixture แบบ must-fire **และ** must-not-fire และกฎที่ทำงานกับ fixture เชิงลบของตัวเองจะไม่สามารถปล่อยได้ นี่คือไฟร์วอลล์กันผลบวกลวง `mjolnir doctor` บังคับใช้สิ่งนี้ใน CI ของรีโพนี้เอง
207
302
 
208
- | ID | กฎ | Severity |
209
- | --------- | ----------------------------------------- | -------- |
210
- | QA-PW-002 | assertion ของ locator ที่ไม่ await | error |
211
- | QA-PW-003 | `page.pause()` / `test.only()` ถูก commit | error |
212
- | QA-PW-004 | selector CSS/XPath เปราะ | warning |
213
- | QA-PW-123 | URL สภาพแวดล้อมฝังตาย | warning |
303
+ ### Selector Health Score
214
304
 
215
- </details>
305
+ `mjolnir doctor:playwright` ให้คะแนน locator แต่ละตัวตามวิธีที่มันหาองค์ประกอบ: แบบที่ผู้ใช้หา (บทบาท ป้ายกำกับ ข้อความ) ผ่านสัญญาที่ชัดเจน (`data-testid`) หรือด้วยความบังเอิญเชิงโครงสร้าง (สาย CSS, XPath) แต่ละไฟล์ได้คะแนนตั้งแต่ 0 ถึง 100:
216
306
 
217
- <details>
218
- <summary><strong>ความสมบูรณ์ของ CI</strong></summary>
219
-
220
- | ID | กฎ | Severity |
221
- | --------- | ------------------------------------------------------------- | -------- |
222
- | QA-CI-001 | `continue-on-error` ปกปิดความล้มเหลว | error |
223
- | QA-CI-002 | `\|\| true` กลืน exit code | error |
224
- | QA-CI-005 | รายงานถูกใช้แต่ไม่เคยถูกสร้าง | error |
225
- | QA-CI-007 | ครอบ retry รอบการทดสอบ | warning |
226
- | QA-CI-008 | step สำเร็จเสมอ ปกปิดความล้มเหลว | error |
227
- | QA-CI-009 | exit code ของทดสอบไม่ถูกส่งต่อ (`\|` ไม่มี pipefail, โซ่ `;`) | error |
228
- | QA-CI-010 | ข้ามทดสอบในที่ที่ต้องบล็อก (skip-on-PR guards) | error |
229
-
230
- </details>
231
-
232
- <details>
233
- <summary><strong>Python / pytest 🐍</strong></summary>
234
-
235
- | ID | กฎ | Severity |
236
- | --------- | ----------------------------------------- | -------- |
237
- | QA-PY-002 | ทดสอบถูกข้าม (`skip`, `xfail` ไม่เข้มงวด) | warning |
238
- | QA-PY-003 | ฟังก์ชันทดสอบไม่มี assertion | error |
239
- | QA-PY-005 | `time.sleep()` ในการทดสอบ | warning |
240
- | QA-PY-012 | assertion พรรคพวกตัวเอง | error |
241
-
242
- กฎ Python รวม 20 ข้อ (QA-PY-001…012 สุขอนามัย pytest + QA-PY-101…108 Playwright-Python)
307
+ ```text
308
+ ▍ SELECTOR HEALTH
243
309
 
244
- </details>
310
+ e2e/login.spec.ts
311
+ [█████████████░░░░░░░] 65 / 100
312
+ role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
245
313
 
246
- <details>
247
- <summary><strong>Java / JUnit · TestNG ☕</strong></summary>
314
+ e2e/checkout.spec.ts
315
+ [██████████████████░░] 88 / 100
316
+ role/text: 4 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
317
+ ```
248
318
 
249
- | ID | กฎ | Severity |
250
- | --------- | ---------------------------------------- | -------- |
251
- | QA-JV-101 | ทดสอบถูกปิด (`@Disabled`) | warning |
252
- | QA-JV-102 | hard sleep (`Thread.sleep()`) | warning |
253
- | QA-JV-103 | วิธีทดสอบไม่มี assertion | error |
254
- | QA-JV-105 | hard sleep Playwright `waitForTimeout()` | warning |
255
- | QA-JV-106 | selector เปราะแทน role locator | warning |
319
+ สิ่งนี้วัด **ความทนทาน ไม่ใช่ความถูกต้อง** `.btn.btn-primary > div:nth-child(2)` ผ่านในวันนี้ และจะผ่านต่อไปจนกว่าจะมีคนแตะ markup คะแนนต่ำไม่เคยอ้างว่าเทสต์พัง เพียงบอกว่ามันพึ่งพา markup ที่ไม่มีใครสัญญาว่าจะคงไว้
256
320
 
257
- </details>
321
+ <br />
258
322
 
259
- <details>
260
- <summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
323
+ ## คะแนนความน่าเชื่อถือ
261
324
 
262
- | ID | กฎ | Severity |
263
- | --------- | ------------------------------------------ | -------- |
264
- | QA-CS-101 | ทดสอบถูกข้าม (`[Ignore]`, `[Fact(Skip=)]`) | warning |
265
- | QA-CS-102 | hard sleep (`Thread.Sleep` / `Task.Delay`) | warning |
266
- | QA-CS-103 | วิธีทดสอบไม่มี assertion | error |
267
- | QA-CS-105 | hard sleep `WaitForTimeoutAsync()` | warning |
268
- | QA-CS-106 | selector เปราะแทน role locator | warning |
325
+ <p align="center">
326
+ <img src="assets/readme/score-gauge.svg" alt="สเกลความน่าเชื่อถือจาก 0 ถึง 100 พร้อมตัวชี้ที่กวาดผ่านทุกคะแนน: UNWORTHY ต่ำกว่า 50, NEEDS WORK ตั้งแต่ 50 ถึง 79, WORTHY ตั้งแต่ 80 ถึง 99, FORGED ที่ 100" width="720" />
327
+ </p>
269
328
 
270
- </details>
329
+ <sub>ทุกคะแนนตั้งแต่ 0 ถึง 100 วางตำแหน่งโดย `deriveScoreState` ตัวจริง สร้างโดย `npm run docs:gauge` และถูกล็อกไม่ให้คลาดเคลื่อนใน CI</sub>
271
330
 
272
- > แคตตาล็อกสดฉบับเต็ม — ทุกกฎพร้อม tier, confidence, ความเสี่ยง false
273
- > positive และความพร้อมของ autofix — สร้างจาก registry:
274
- >
275
- > ```bash
276
- > mjolnir rules --md
277
- > ```
278
- >
279
- > หน้าต่อกฎอยู่ใต้ [`docs/rules/`](docs/rules/)
331
+ | คะแนน | คำตัดสิน |
332
+ | --------- | -------------------------------- |
333
+ | `0 – 49` | **UNWORTHY** |
334
+ | `50 – 79` | **NEEDS WORK** |
335
+ | `80 – 99` | **WORTHY** |
336
+ | `100` | **FORGED** |
337
+ | `null` | **UNKNOWN**: ไม่พบการประกาศเทสต์ |
280
338
 
281
- ### วัดไปแล้วเท่าไร
339
+ **วิธีคำนวณ** ความรุนแรงกำหนดการหักคะแนนพื้นฐาน (`error −8`, `warning −3`, `info −1`) และระดับหลักฐานจะลดทอนมันลง: E2 หักเต็ม E1 หักครึ่ง (ปัดลง) E0 ไม่หักเลย ผลรวมถูกปรับให้เป็นมาตรฐานตามขนาดของชุดเทสต์ คือหักต่อการประกาศเทสต์แต่ละรายการ ไม่ใช่ต่อไฟล์ เทอร์มินัลพิมพ์ตัวเลขที่ลดทอนแล้วชุดเดียวกับที่คะแนนใช้ ไม่มีแบบจำลองที่สองซ่อนอยู่ รายละเอียด: [docs/SCORING.md](docs/SCORING.md) และ [คู่มือการให้คะแนน](https://sergey-bar.github.io/Mjolnir/guide/scoring)
282
340
 
283
- **78 จาก 99 กฎ มีอัตรา false positive ที่วัดกับโค้ด OSS จริง** (อย่างน้อย
284
- 10 findings ที่จัดหมวดด้วยมือต่อกฎ; ดู
285
- [docs/FP-AUDIT.md](docs/FP-AUDIT.md)) อีก 21 กฎออกมาบนการประเมินของผู้เขียน
286
- ส่วนท้ายของทุกการสแกนบอกว่ากฎที่ _ยิง_ มีกี่กฎที่วัดแล้ว;
287
- `mjolnir rules --unmeasured` แสดงกฎที่ยังไม่วัด; หน้า `mjolnir explain`
288
- ที่ 95 % และถูกส่งไปกักกันเพราะเหตุนี้ การทำให้ตัวเลขนั้นโตขึ้นคืองาน
289
- ต่อเนื่องของโปรเจกต์
341
+ **สิ่งที่ 100 ไม่ได้หมายถึง** ไม่ได้หมายความว่าซอฟต์แวร์ถูกต้อง ชุดเทสต์เพียงพอ หรือผลิตภัณฑ์ไม่มีข้อบกพร่อง มันหมายถึงเพียงสิ่งเดียว: **ไม่มีกฎใดที่ Mjölnir ประเมินทำให้เกิดการหักคะแนนภายใต้การสแกนนี้และแบบจำลองหลักฐานนี้**
290
342
 
291
- ### Tier ของกฎและความสุกงอมของภาษา
343
+ <br />
292
344
 
293
- ทุกกฎเป็น `core`, `extended` หรือ `quarantine` กำหนดจากอัตรา false
294
- positive **ที่วัดได้**:
345
+ ## แบบจำลองหลักฐาน
295
346
 
296
- | Tier | ความหมาย | สแกนปกติ | `--strict` |
297
- | ------------ | ----------------------------------- | :------: | :--------: |
298
- | `core` | ≤ 10 % FP ที่วัดได้ | ✅ | ✅ |
299
- | `extended` | ≤ 30 % FP ที่วัดได้ | ✅ | ✅ |
300
- | `quarantine` | สูงกว่า 30 % หรือยังไม่วัด (n < 10) | ❌ | ✅ |
347
+ ทุกข้อค้นพบมีป้ายกำกับสองอย่าง: Mjölnir มั่นใจแค่ไหน และข้อค้นพบถูกตรวจสอบไปไกลแค่ไหน นี่คือความต่างระหว่างเครื่องมือที่รายงานรูปแบบ กับเครื่องมือที่คุณใช้เป็นด่านก่อนปล่อยรีลีสได้
301
348
 
302
- | ภาษา | Adapter | ความครอบคลุมวันนี้ |
303
- | --------------- | -------------- | ------------------------------------------------- |
304
- | TypeScript / JS | AST คอมไพเลอร์ | กว้างสุด วัดมากสุด — ส่วนใหญ่ `core`/`extended` |
305
- | Python / pytest | ชั้น regex | กว้าง ตรวจกับ corpus — ส่วนใหญ่ `core`/`extended` |
306
- | Java | ชั้น regex | ใหม่กว่า — ส่วนใหญ่ `extended`/`quarantine` |
307
- | C# / .NET | ชั้น regex | ใหม่กว่า — ส่วนใหญ่ `extended`/`quarantine` |
349
+ **มั่นใจแค่ไหน — ระดับหลักฐาน**
308
350
 
309
- TypeScript และ Python มีความครอบคลุมที่วัดได้กว้างที่สุด Java และ C#
310
- ปล่อยแล้ว มีเอกสาร และยังอยู่นอกตัวเลขพาดหัว จนกว่าชุดทดสอบผู้ใช้จริง
311
- (ไม่ใช่ทดสอบของไลบรารี binding เอง) จะถูกตรวจ
351
+ | ระดับ | ชื่อ | ความหมาย | การหักคะแนน |
352
+ | ------ | ------------------------ | -------------------------------------------- | ----------- |
353
+ | **E2** | การพิสูจน์แบบกำหนดแน่นอน | ข้อบกพร่องมีอยู่ในโค้ดตามที่เขียนไว้ | เต็ม |
354
+ | **E1** | หลักฐานจากรูปแบบ | รูปแบบที่ผูกกับข้อบกพร่องอย่างแน่นแฟ้นตรงกัน | ครึ่ง |
355
+ | **E0** | ข้อสังเกต | ควรรู้ไว้ ไม่ใช่การอ้างว่ามีอะไรผิด | ศูนย์ |
312
356
 
313
- ---
357
+ ความมั่นใจในการตรวจจับไม่ใช่ความแข็งแรงของการพิสูจน์ กฎหนึ่งอาจมั่นใจว่าตรงกับสิ่งที่มองหา แต่ก็ยังอาจกำลังมองฮิวริสติกอยู่ ข้อค้นพบ E1 มีไว้ให้อ่านและใช้วิจารณญาณ ไม่ใช่นำไปใช้อย่างไม่ไตร่ตรอง และขอบเขตนี้ถูกประทับไว้บนข้อค้นพบในเทอร์มินัล ใน JSON และในการส่งต่อให้เอเจนต์
314
358
 
315
- ## การให้คะแนนทำงานอย่างไร
359
+ **ตรวจสอบไปไกลแค่ไหน — ระดับความเชื่อถือ** ข้อค้นพบส่วนใหญ่มาจากการอ่านโค้ดของคุณ ให้รายงานจากการรันเทสต์จริงแก่ Mjölnir แล้วมันจะยืนยันได้ว่าโค้ดถูกรันจริง
316
360
 
317
361
  <p align="center">
318
- <img src="assets/readme/terminal-hero.svg" alt="ผลลัพธ์ terminal ของ Mjölnir — WORTHINESS 75/100 NEEDS WORK, การแจกแจงการวินิจฉัยตามหมวด และรายการ FIX THIS FIRST" width="820" />
362
+ <img src="assets/readme/trust-ladder.svg" alt="บันไดความเชื่อถือจาก L0 ถึง L5 L0 ถึง L2 มาจากการอ่านโค้ด L3 ถึง L5 ต้องใช้รายงานการรันจริง ซึ่งแสดงด้วยรอยขาดบนบันได" width="100%" />
319
363
  </p>
320
364
 
321
- <sub>สร้างใหม่ด้วย `npm run docs:hero`;
322
- [`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
323
- จะทำให้ CI ลม หากสินค้าเองเหลื่อมจากสิ่งที่ reporter พิมพ์จริง</sub>
365
+ | ระดับ | พูดง่าย ๆ | สิ่งที่ต้องมี |
366
+ | ------ | ----------------- | -------------------------------------------- |
367
+ | **L0** | บันทึกไว้ | อ่านโค้ด |
368
+ | **L1** | ดูเหมือนเป็นปัญหา | อ่านโค้ด: รูปแบบตรงกัน |
369
+ | **L2** | พิสูจน์แล้วในโค้ด | อ่านโค้ด: ข้อบกพร่องเป็นเชิงโครงสร้าง |
370
+ | **L3** | ไฟล์ถูกรัน | รายงานการรันแสดงว่าไฟล์ของข้อค้นพบถูกรัน |
371
+ | **L4** | เทสต์ถูกรัน | รายงานการรันแสดงว่าเทสต์ของข้อค้นพบถูกรัน |
372
+ | **L5** | การรันยืนยัน | ผลลัพธ์ของการรันเองยืนยันประเภทของข้อบกพร่อง |
324
373
 
325
- คะแนนโปร่งใส: **error −8, warning −3, info −1** แล้ว normalize ด้วย
326
- exposure ของชุดทดสอบ (การหักต่อการประกาศทดสอบ) การหักที่ถ่วงน้ำหนักด้วย
327
- หลักฐาน หมายความว่าสัญญาณอ่อนแพงกว่า แสดงผลใน terminal ใช้ตัวเลขที่
328
- ลดแล้วชุดเดียวกับที่คะแนนใช้ — ไม่มีกล่องดำ วิธีเต็ม:
329
- [docs/SCORING.md](docs/SCORING.md)
374
+ การสแกนแบบสถิตหยุดที่ L2 มีเพียงรายงานการรันจริง (Playwright JSON, Jest หรือ Vitest JSON, JUnit XML) เท่านั้นที่ยกข้อค้นพบขึ้นไปถึง L3 หรือสูงกว่าได้ ดังนั้นข้อค้นพบที่ไม่เคยถูกเห็นว่ารันจริงจะอ้างไม่ได้เลยว่ามันถูกรัน นิยาม: [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md)
330
375
 
331
- **คำพิพากษา**
376
+ ### มีการวัดไปมากแค่ไหน
332
377
 
333
- | Score | คำพิพากษา |
334
- | ------- | ---------------- |
335
- | ≥ 80 | ✓ **WORTHY** |
336
- | 50 – 79 | ⚠ **NEEDS WORK** |
337
- | < 50 | ✖ **UNWORTHY** |
378
+ **74 จาก 79 กฎมีอัตราผลบวกลวงที่วัดกับโค้ด OSS จริง** (อย่างน้อย 10 ข้อค้นพบที่จัดประเภทด้วยมือต่อกฎ ดู [docs/FP-AUDIT.md](docs/FP-AUDIT.md)) อีก 5 กฎปล่อยออกมาด้วยค่าประมาณของผู้เขียนและบอกไว้ชัดเจนทีละกฎใน `mjolnir explain` `mjolnir rules --unmeasured` แสดงรายการกฎเหล่านั้น และท้ายการสแกนทุกครั้งจะรายงานว่ามีกฎกี่ข้อในบรรดาที่ _ทำงานจริง_ ที่ผ่านการวัดแล้ว
338
379
 
339
- **ระดับหลักฐาน** — ทุก finding พกระดับหนึ่ง; มันกำหนดน้ำหนักของ finding
340
- ในคะแนน:
380
+ อัตราต่าง ๆ ยังคงเปิดเผยแม้จะแย่ QA-TEST-001 (`.only` ที่ถูกคอมมิต) ได้ผลตรวจสอบไม่ดีบนรีโพจริงจึงถูกจัดไว้ใน quarantine ตัวเลขล่าสุดของทุกกฎ รวมถึง QA-PW-141 อยู่ในผลการตรวจสอบ
341
381
 
342
- | ระดับ | ความหมาย | ผลต่อคะแนน | ตัวอย่าง |
343
- | ----- | --------------------- | --------------------- | ----------------------------------------------------- |
344
- | E2 | ข้อบกพร่องเชิงกำหนด | หักเต็มจำนวน | commit `.only` — พิสูจน์เชิงโครงสร้างได้ |
345
- | E1 | รูปแบบเชิงเฮิร์ริสติก | หักครึ่งหนึ่ง | `sleep()` ที่ regex เจอ — สัญญาณแข็งแรง ไม่ใช่หลักฐาน |
346
- | E0 | การสังเกต | ศูนย์ (info เท่านั้น) | รายงานแต่ไม่ gate CI และไม่หักเลย |
382
+ ### ระดับความเชื่อถือของกฎ
347
383
 
348
- กฎส่วนใหญ่เป็น **E1** คำสโลแกน «we prove it» อ้างถึงระบบนี้: finding
349
- E2 คือหลักฐานเชิงโครงสร้าง; finding E1 คือคำเตือนที่วางตำแหน่งถูกต้อง
350
- ไม่ใช่หลักฐานทางการ
384
+ ระดับเป็นไปตามอัตราผลบวกลวงที่วัดได้ ไม่ใช่ความเห็น:
351
385
 
352
- repo ว่างจะได้คะแนน `null` ไม่ใช่เลข 100 ปลอม — ดู
353
- [โมเดลความไว้วางใจ](#โมเดลความไว้วางใจ)
386
+ | ระดับ | FP ที่วัดได้ | พฤติกรรม |
387
+ | -------------- | ------------------------------ | --------------------------------------------- |
388
+ | **core** | ≤ 10% | รายงานค่าเริ่มต้น บล็อกได้ |
389
+ | **extended** | ≤ 30% | รายงานค่าเริ่มต้น ความมั่นใจต่ำกว่า |
390
+ | **quarantine** | > 30% หรือประกาศไว้อย่างชัดเจน | เฉพาะ `--strict` จำกัดไว้ที่ info ไม่บล็อกเลย |
391
+ | _ยังไม่ได้วัด_ | n < 10 | เลื่อนขึ้นเป็น core ไม่ได้จนกว่าจะวัด |
354
392
 
355
- ---
393
+ ช่วง FP สามารถลดระดับ tier ได้เท่านั้น — จะไม่เลื่อนระดับกฎออกจาก `quarantine` หากกฎนั้นถูกประกาศไว้ที่นั่นอย่างชัดเจน กฎที่ถูก quarantined อย่างชัดเจนจะยังคงอยู่ใน quarantine โดยไม่คำนึงถึงอัตรา FP ที่วัดได้
356
394
 
357
- ## 🎭 Selector Health Score
395
+ การเลื่อนระดับ การลดระดับ และความพร้อมรายภาษา: [วงจรชีวิตของกฎ](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle)
358
396
 
359
- ตัวชี้วัดพาดหัวสำหรับชุด Playwright — locator ของคุณทนทานแค่ไหน:
397
+ ### ทำไมนี่จึงไม่ใช่ linter
360
398
 
361
- ```text
362
- ▚ SELECTOR HEALTH — e2e/checkout.spec.ts
399
+ Linter บอกคุณว่าโค้ดทำตามกฎหรือไม่ Mjölnir บอกคุณว่าการตรวจสอบของคุณเชื่อถือได้หรือไม่
363
400
 
364
- [█████████████████░░░] 83 / 100
365
- role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
366
- ```
401
+ | | Linter (ESLint, SonarQube) | เครื่องมือวัด coverage | รีวิวโค้ดด้วย AI | **Mjölnir** |
402
+ | ------------------------------------------------------------- | :------------------------: | :--------------------: | :--------------: | :-------------------: |
403
+ | ให้คะแนน **ระบบการตรวจสอบ** ไม่ใช่โค้ดผลิตภัณฑ์ | ไม่ | ไม่ | ไม่ | ใช่ |
404
+ | ความสมบูรณ์ของ CI workflow (`continue-on-error`, `\|\| true`) | ไม่ | ไม่ | เฉพาะ diff | ใช่ |
405
+ | ให้คะแนนความทนทานของ locator ใน Playwright (Selector Health) | ไม่ | ไม่ | ไม่ | ใช่ |
406
+ | อ่านข้อมูลการรันจริงเพื่อตัดสิน `TRUE-FLAKE` | ไม่ | ไม่ | ไม่ | ใช่ |
407
+ | เผยแพร่อัตราผลบวกลวงที่วัดได้ของแต่ละกฎ | ไม่ | ไม่ | ไม่ | ใช่ |
408
+ | ทำเครื่องหมายเทสต์ที่ไม่มี assertion | ใช่\* | ไม่ | บางครั้ง | ใช่ |
409
+ | จับ sleep แบบตายตัว (`waitForTimeout`, `time.sleep`) | ใช่\* | ไม่ | บางครั้ง | ใช่ |
410
+ | กำหนดแน่นอน (อินพุตเดียวกัน เอาต์พุตเดียวกัน) | ใช่ | ใช่ | ไม่ | ใช่ |
411
+ | ต้นทุนต่อการสแกน | ฟรี | ฟรี | โทเค็น | **ศูนย์** (ในเครื่อง) |
367
412
 
368
- locator ที่อิง role ได้คะแนนเต็ม ห่วงโซ่ CSS class และ XPath จมคะแนน —
369
- มันแตกทุกครั้งที่ refactor DOM โดยไม่บอกว่าพฤติกรรมใดถดถอย
413
+ <sub>\*ครอบคลุมโดย `eslint-plugin-jest` และ `eslint-plugin-playwright` (`expect-expect`, `no-wait-for-timeout`) และโดยกฎ assertion ของ SonarQube เอง คอลัมน์ต่าง ๆ อธิบายพฤติกรรมเริ่มต้นสำหรับการตรวจสอบชุดเทสต์ ปลั๊กอิน แพ็กเกจแบบเสียเงิน และกฎที่กำหนดเองจะเปลี่ยนบางคำตอบ นี่เป็นบทสรุปการวางตำแหน่ง ไม่ใช่ benchmark</sub>
370
414
 
371
- ---
415
+ ใช้การรีวิวด้วย AI ด้วย มันจับรายละเอียดปลีกย่อย เจตนา และข้อบกพร่องด้านการออกแบบที่ไม่มีรูปแบบใดหาเจอ ส่วน Mjölnir จับสิ่งที่การรีวิวด้วย AI มองข้ามเพราะดูเหมือนตั้งใจ: `.only` ที่ถูกคอมมิต รหัสออกที่ถูกกลืน `continue-on-error` บน job เทสต์ สิ่งเหล่านี้ต้องการการสแกน ไม่ใช่การใช้เหตุผล
372
416
 
373
- ## 🔬 หลักฐานระดับ runtime
417
+ <br />
374
418
 
375
- การตรวจจับความไม่นิ่งแบบสถิตคือการเดา Mjölnir อ่าน **ข้อมูลการรันจริง** —
376
- รายงาน JSON ของ Playwright และ XML ของ JUnit จาก runner ใดก็ได้:
419
+ ## นิติวิเคราะห์ขณะรัน
420
+
421
+ การวิเคราะห์แบบสถิตให้เหตุผลเกี่ยวกับโค้ดที่ไม่เคยรัน นิติวิเคราะห์อ่านสิ่งที่เกิดขึ้นจริง: Playwright JSON, Jest JSON, Vitest JSON และ JUnit XML จาก runner ใดก็ได้
377
422
 
378
423
  ```bash
379
424
  mjolnir forensics ./test-results/
380
425
  ```
381
426
 
382
427
  ```text
383
- ▚ FLAKINESS LEADERBOARD
428
+ ▍ FLAKINESS LEADERBOARD
384
429
 
385
430
  3 tests · 1 failed · 1 flaky · 1 retried
386
431
 
@@ -390,279 +435,184 @@ FAILING declines an expired card (e2e/checkout.spec.ts)
390
435
  ████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
391
436
  ```
392
437
 
393
- ทดสอบที่ผ่านเฉพาะตั้งแต่ attempt ≥ 2 ไม่ใช่ทดสอบที่ผ่าน — มันเป็น
394
- ทดสอบที่โชคดี มันถูกติดธง `TRUE-FLAKE` ไม่ว่าเครื่องหมายเขียวสุดท้าย
395
- จะเป็นอย่างไร
438
+ `TRUE-FLAKE` ไม่ได้หมายความว่าเทสต์ถูกรันซ้ำ แต่หมายความว่าเทสต์ **ล้มเหลวอย่างน้อยหนึ่งครั้งแล้วจบลงเป็นสีเขียว** คือการผ่านแบบฟลุก ซึ่งจะถูกทำเครื่องหมายไม่ว่าเครื่องหมายถูกสุดท้ายจะบอกอะไร `mjolnir triage` เปลี่ยนประวัตินั้นเป็นข้อเสนอให้กักกัน และ `mjolnir pw-report` สรุปการรัน รายงานการรันชุดเดียวกันนี้คือสิ่งที่ยกข้อค้นพบขึ้นสู่ระดับความเชื่อถือ L3 ขึ้นไป
439
+
440
+ <br />
396
441
 
397
- ---
442
+ ## ความสมบูรณ์ของ CI
443
+
444
+ เทสต์หนึ่งอาจผ่าน ขณะที่ไปป์ไลน์รอบตัวมันไม่มีทางล้มเหลวได้ Mjölnir อ่าน workflow ด้วย: `continue-on-error`, `|| true` รหัสออกที่ไม่เคยถูกส่งต่อ step ที่สำเร็จเสมอ รายงานที่ถูกใช้แต่ไม่เคยถูกสร้าง และด่านที่ถูกข้ามในเหตุการณ์ที่ควรบล็อก แต่ละข้อค้นพบระบุ job, step และบรรทัด พร้อมระดับหลักฐานของตัวเอง
445
+
446
+ สร้าง PR workflow ซึ่งเป็นแบบให้คำแนะนำโดยค่าเริ่มต้น:
447
+
448
+ ```bash
449
+ mjolnir ci install
450
+ ```
451
+
452
+ หรือเพิ่ม action จาก Marketplace ลงใน workflow ที่คุณมีอยู่แล้ว:
453
+
454
+ ```yaml
455
+ - uses: Sergey-Bar/Mjolnir@v1
456
+ with:
457
+ scope: changed
458
+ fail-on: error
459
+ ```
398
460
 
399
- ## ⚡ Mjölnir ไม่ใช่ linter อีกตัว
461
+ ปัก `@v1` เพื่อติดตามสายเวอร์ชันหลัก หรือปักแท็กที่แน่นอน (`@v0.5.32`) เพื่อด่านที่ทำซ้ำได้ [docs/DISTRIBUTION-KIT.md](docs/DISTRIBUTION-KIT.md) ครอบคลุม Marketplace, Smithery และทะเบียน MCP
400
462
 
401
- Linter บอกว่าโค้ดทำตามกฎหรือไม่ Mjölnir บอกว่าการตรวจสอบของคุณ
402
- น่าเชื่อถือหรือไม่
463
+ หากต้องการส่งข้อค้นพบเข้า GitHub Code Scanning ให้อัปโหลด SARIF (ต้องมี `security-events: write` ที่ระดับ workflow หรือ job):
403
464
 
404
- | | ESLint / SonarQube | เครื่องมือ coverage | รีวิวด้วยมือ | **Mjölnir** |
405
- | ------------------------------------------------------------- | :----------------: | :-----------------: | :----------: | :---------: |
406
- | ความสมบูรณ์ของ CI workflow (`continue-on-error`, `\|\| true`) | ❌ | ❌ | ไม่ค่อย | ✅ |
407
- | ข้ามภาษา (TS, Python, Java, C#) จากเครื่องมือเดียว | ❌ | ❌ | ❌ | ✅ |
408
- | ให้เกรดความทนทานของ locator Playwright (Selector Health) | ❌ | ❌ | ไม่ค่อย | ✅ |
409
- | ติดธงทดสอบไม่มี assertion จริง | ✅ (ปลั๊กอิน)\* | ❌ | บางครั้ง | ✅ |
410
- | จับ hard sleep (`waitForTimeout`, `time.sleep`) | ✅ (ปลั๊กอิน)\* | ❌ | บางครั้ง | ✅ |
411
- | รันในไม่กี่วินาที ศูนย์การเรียกเครือข่ายระหว่างสแกน | ✅ | ✅ | — | ✅ |
465
+ ```yaml
466
+ - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
467
+ continue-on-error: true
468
+ - uses: github/codeql-action/upload-sarif@v3
469
+ if: ${{ !cancelled() }}
470
+ with:
471
+ sarif_file: mjolnir.sarif
472
+ ```
412
473
 
413
- \*`eslint-plugin-jest` (`expect-expect`) และ `eslint-plugin-playwright`
414
- (`expect-expect`, `no-wait-for-timeout`) ครอบคลุมสิ่งเหล่านี้ให้ framework
415
- ตามลัพธ์ของมัน
474
+ บน GitLab `--format codequality` เขียนรายงาน Code Quality ที่วิดเจ็ต MR และคำอธิบายประกอบ diff อ่าน ([docs/GITLAB-CI.md](docs/GITLAB-CI.md)) การตั้งค่าเอดิเตอร์และไปป์ไลน์: [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md)
416
475
 
417
- **การวิเคราะห์ runtime** เป็นหมวดหมู่แยกจากการ lint แบบสถิต:
476
+ ### การระบุที่มาในขอบเขตที่เปลี่ยนแปลง
418
477
 
419
- | | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
420
- | -------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
421
- | อ่านข้อมูลรันจริงเพื่อคำพิพากษา `TRUE-FLAKE` | บางส่วน\* | บางส่วน (tag) | ✅ |
422
- | รายงาน triage ความไม่นิ่งจากประวัติการรัน | ❌ | ✅ | ✅ |
423
- | เชื่อมกับคะแนนความน่าเชื่อถือแบบสถิต | ❌ | ❌ | ✅ |
478
+ ```bash
479
+ npx mjolnir-qa@latest --scope changed
480
+ ```
424
481
 
425
- \*Playwright ติดตาม retry ภายใน แต่ไม่ผลิตรายงานความไม่นิ่งแบบ
426
- ยืนเดี่ยวพร้อมป้ายคำพิพากษา
482
+ ข้อค้นพบถูกระบุไปยังบรรทัดที่ branch ของคุณเพิ่มเข้ามา โดยวัดเทียบกับ **merge-base** ขอบเขตคือชุดไฟล์เดียวกับที่การสแกนเต็มค้นพบ (spec ของ TS/JS และการตั้งค่า adapter, `test_*.py`, `*Test.java`, `*Tests.cs`, `.github/workflows/*.yml`) รวมกับการเปลี่ยนแปลงที่ยังไม่คอมมิตและที่ไม่ได้ติดตาม จึงใช้ได้ตั้งแต่ก่อนคอมมิต ฐานถูกหาตามลำดับ `main → master → origin/main → origin/master → origin/HEAD` และแทนที่ได้ด้วย `--base <ref>`
427
483
 
428
- ---
484
+ เมื่อหา merge-base ไม่ได้ (shallow clone, detached HEAD, เป้าหมายอยู่นอก git) ข้อค้นพบจะถอยกลับไปใช้การระบุที่มาทั้งไฟล์ **และรายงานจะบอกไว้** การถอยกลับแบบเงียบ ๆ ก็คือข้อบกพร่องประเภทเดียวกับที่เครื่องมือนี้มีไว้จับ
429
485
 
430
- ## 🤖 ทำไมไม่ใช้แค่ AI code review?
486
+ <br />
431
487
 
432
- ปัญหาต่างกัน ชั้นต่างกัน AI review เห็นการเปลี่ยนทดสอบที่น่าสงสัยใน
433
- diff ได้ แต่มันไม่พิสูจน์ว่าระบบตรวจสอบทั้งหมดน่าไว้วางใจ — และมันเห็น
434
- แค่ diff ที่คุณให้ดู
488
+ ## เอเจนต์ AI
435
489
 
436
- | | AI code review (Copilot ฯลฯ) | **Mjölnir** |
437
- | ------------------------------------------- | :--------------------------: | :------------------------------------: |
438
- | ต้นทุนต่อการสแกน | Tokens (ขยายตามขนาด diff) | **ศูนย์** (ทำงานในเครื่อง ติดตั้งแล้ว) |
439
- | เห็นทั้งชุดทดสอบ + ทุก config CI | เฉพาะ PR diff ที่คุณให้ดู | **ทุกอย่าง ทุกครั้ง** |
440
- | กำหนดตาย (input เดียวกัน → output เดียวกัน) | ❌ (ไม่กำหนดตาย) | **✅** |
441
- | จับรูปแบบที่หลับมาหลายเดือน | เฉพาะถ้าอยู่ในบริบท | **✅** (สแกนทุกไฟล์) |
442
- | จำ finding ข้ามการรัน | ❌ (ไม่มีความจำข้ามเซสชัน) | **✅** (baseline + diff) |
443
- | รันโดยไม่ต้องมีคนสั่ง | ต้องมี PR หรือ prompt | **✅** (hook CI, รันในไม่กี่วินาที) |
490
+ ข้อค้นพบจะมีค่าก็ต่อเมื่อมีสิ่งใดลงมือทำตามมัน
444
491
 
445
- **ใช้ทั้งสอง** AI เก็บรายละเอียดปลีกย่อย เจตนา และข้อบกพร่องเชิงออกแบบ
446
- ที่ regex หาไม่เจอ Mjölnir เก็บรูปแบบเชิงโครงสร้างที่ AI มองข้ามเพราะ
447
- มันดู «ตั้งใจ» — `.only` ที่ถูก commit, exit code ที่ถูกกลืน,
448
- `continue-on-error` บน job ทดสอบ นี่ไม่ใช่บั๊กที่ต้องใช้การใคร่ครวญ;
449
- นี่คือข้อเท็จจริงที่ต้องใช้การสแกน
492
+ ```text
493
+ SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
494
+ ```
450
495
 
451
- ---
496
+ **AI เขียนการแก้ไข Mjölnir ตรวจสอบมัน** ข้อพิสูจน์มาจากการสแกนซ้ำ ไม่ใช่จากรายงานความสำเร็จของเอเจนต์เอง
452
497
 
453
- ## 🤖 การเชื่อมต่อ CI
498
+ | คำสั่ง | สิ่งที่เอเจนต์ได้รับ |
499
+ | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
500
+ | `mjolnir mcp` | เซิร์ฟเวอร์ [MCP](https://modelcontextprotocol.io) ผ่าน stdio `scan`, `explain` และ `diff` กลายเป็นเครื่องมือที่เรียกใช้ได้ |
501
+ | `mjolnir handoff` | รายงาน `--json` ที่บันทึกไว้กลายเป็นแผน Markdown แบบกำหนดแน่นอน: สิ่งที่ตรวจพบ ขอบเขตหลักฐานของแต่ละข้อค้นพบ สิ่งที่ **ห้าม** เปลี่ยน และวิธีตรวจสอบ |
502
+ | `mjolnir install` | เขียนลงในพื้นที่สำหรับเอเจนต์ที่รีโพของคุณมีอยู่แล้ว (`.claude/`, `.cursor/`, `.kilo/`, `AGENTS.md`) เพื่อให้เอเจนต์สแกนซ้ำก่อนจะบอกว่าทำเสร็จแล้ว |
454
503
 
455
- คำสั่งเดียวสร้าง PR workflow — เป็นแบบที่ปรึกษาโดยดีฟอลต์ ไม่เคยบล็อก:
504
+ เพิ่มลงในไคลเอนต์ที่มี CLI ของตัวเอง:
456
505
 
457
506
  ```bash
458
- mjolnir ci install
507
+ claude mcp add mjolnir -- npx -y mjolnir-qa@latest mcp
459
508
  ```
460
509
 
461
- หรือต่อเข้า GitHub Code Scanning แบบ native ผ่าน SARIF:
510
+ หรือในไคลเอนต์ใดก็ได้ที่รับบล็อก `mcpServers`:
462
511
 
463
- ```yaml
464
- - run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
465
- - uses: github/codeql-action/upload-sarif@v3
466
- with:
467
- sarif_file: mjolnir.sarif
512
+ ```json
513
+ {
514
+ "mcpServers": {
515
+ "mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@latest", "mcp"] }
516
+ }
517
+ }
468
518
  ```
469
519
 
470
- การตั้งค่า editor และ pipeline สำหรับ SARIF:
471
- [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md)
520
+ **ราวกันตกสำคัญกว่าความสะดวก** ทุกข้อค้นพบในการส่งต่อมีขอบเขตของตัวเอง **E2** บอกว่า _กำหนดแน่นอน: ตรวจสอบตำแหน่งแล้วใช้การแก้ไข_ **E1** บอกว่า _ต้องยืนยัน: ข้อสังเกตเพียงอย่างเดียวไม่ได้พิสูจน์ข้อบกพร่อง_ เอเจนต์ที่แก้ E1 อย่างไม่ไตร่ตรอง ระงับกฎ หรือแก้ไขกฎเพื่อดันคะแนน กำลังทำสิ่งที่เครื่องมือนี้มีไว้จับพอดี ดังนั้นการส่งต่อจึงบอกไว้ใน prompt ข้างข้อค้นพบนั้นเลย
472
521
 
473
- ### ความครอบคลุมแบบ changed scope
522
+ <br />
474
523
 
475
- `--scope changed` ผูก finding กับบรรทัดที่ branch คุณเพิ่ม เทียบกับ
476
- merge-base กับ `main` ครอบคลุมไฟล์ทดสอบ (`*.spec.*`, `*.test.*`) บวก
477
- ไฟล์ GitHub workflow และ config Playwright ใน diff เมื่อ merge-base
478
- หาค่าไม่ได้ — shallow clone, detached HEAD, เป้าหมายไม่ใช่ git,
479
- default branch ต่างกัน — มันลดรูปอย่างซื่อสัตย์: finding กลับไปผูก
480
- ทั้งไฟล์ และรายงานก็บอก แทนที่ base ref ได้ด้วย `--base <ref>`
524
+ ## ความเชื่อถือและความปลอดภัย
481
525
 
482
- ---
526
+ **ในเครื่องเป็นหลัก ไม่มีการเก็บข้อมูลการใช้งาน** ไม่มี API ที่เชื่อมต่อเครือข่ายได้ (`fetch`, `http`, `https`, `net`, `dns`, `dgram`, WebSocket) อยู่ที่ใดใน `src/` และ [`privacy-network-isolation.spec.ts`](tests/contract/privacy-network-isolation.spec.ts) จะทำให้ build ล้มเหลวหากมีสักตัวปรากฏขึ้น มันยังห้าม `eval` และ `new Function` ด้วย การสแกนโค้ดที่ไม่น่าเชื่อถือจะไม่รันโค้ดนั้นเลย: การวิเคราะห์แบบสถิตอ่านข้อความซอร์ส และนิติวิเคราะห์แยกวิเคราะห์ไฟล์รายงานที่มีอยู่บนดิสก์แล้ว
483
527
 
484
- ## การตั้งค่า
528
+ ข้อควรทราบสองข้อ: `npx` เองดาวน์โหลดแพ็กเกจก่อนที่อะไรจะรัน และการรับประกันนี้ครอบคลุม `src/` ไม่รวมปลั๊กอินจากบุคคลที่สาม
485
529
 
486
- Mjölnir เป็น zero-config `mjolnir.config.json` (หรือ `.mjolnir.json`)
487
- ทางเลือกที่ราก repo ปรับ severity, gating และ scope — ไม่เคยเปลี่ยน
488
- ความหมายการตรวจจับ
530
+ **ปลั๊กอินไม่ได้รันใน sandbox** ปลั๊กอิน JS (`mjolnir-rules/*.mjs` หรือแพ็กเกจ npm ที่ระบุไว้ใต้ `"plugins"`) รันด้วยสิทธิ์ Node เต็มรูปแบบ ซึ่งเป็นแบบจำลองความเชื่อถือเดียวกับปลั๊กอินของ ESLint หรือ Vitest การโหลดปลั๊กอินต้องเลือกเปิดเอง **ในทุกการสแกน**: หากไม่มี `--enable-plugins` (หรือ `MJOLNIR_ENABLE_PLUGINS=1`) ซอร์สของปลั๊กอินจะไม่ถูกโหลดเลย และประกาศบน stderr จะแสดงรายการสิ่งที่ถูกข้าม manifest ของกฎที่เป็น JSON ไม่รันโค้ดใด ๆ และคำนำหน้า ID ของกฎ core ถูกสงวนไว้ เพื่อไม่ให้ปลั๊กอินปลอมตัวเป็นกฎเหล่านั้นได้ รายงานช่องโหว่ผ่าน [SECURITY.md](SECURITY.md)
489
531
 
490
- | Key | ชนิด | ผล |
491
- | ------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
492
- | `exclude` | `string[]` | glob ignore เพิ่มเติม (ส่วนย่อยของ gitignore) บนค่าดีฟอลต์ที่มีให้ |
493
- | `gate` | `"advisory" \| "error" \| "warning"` | ความรุนแรงระดับใดที่ออกด้วยเลขไม่ใช่ศูนย์ (ดีฟอลต์ `error`; `advisory` ไม่เคยบล็อก) |
494
- | `severityOverrides` | `{ "<RULE-ID>": severity }` | จัดลำดับ finding ของกฎใหม่สำหรับ repo ของคุณ |
495
- | `ignore` | `IgnoreEntry[]` | กด finding — **`reason` จำเป็น**; รายการหมดอายุใน 90 วัน (วันที่ `expires` ชัดเจน หรือเวลาแก้ไขล่าสุดของไฟล์ config สำหรับรายการที่ไม่ระบุ) |
496
- | `plugins` | `string[]` | แพ็กเกจกฎบุคคลที่สาม (ดู [โมเดลความไว้วางใจ](#โมเดลความไว้วางใจ)) |
532
+ **มันรันกับตัวเอง** เอนจินความเชื่อถือในการตรวจสอบจะไม่มีความน่าเชื่อถือเลย หากตัวมันเองตรวจสอบไม่ได้ ทุกการรัน CI สแกนรีโพนี้ด้วย build ที่การรันเดียวกันนั้นสร้างขึ้น ด่านจะล้มเหลวเมื่อพบข้อค้นพบระดับ error ใด ๆ และเมื่อการสแกนเป็นแบบ **บางส่วน** หรือมี **กฎที่พัง** เพราะการสแกนตัวเองที่ถูกตัดจบและไม่รายงานอะไรเลย ก็คือสีเขียวปลอมที่โปรเจกต์นี้มีไว้จับ `mjolnir doctor` ตรวจสอบฐานกฎซ้ำในการรันเดียวกัน (ไฟร์วอลล์ fixture ความซื่อตรงของระดับ เพดานของระดับ core) และการตรวจที่ได้ผล INCONCLUSIVE จะล้มเหลวเหมือนกับการตรวจที่ล้มเหลวทุกประการ รายงานทั้งสองถูกอัปโหลดเป็นอาร์ติแฟกต์ของ build
497
533
 
498
- ```json
499
- {
500
- "gate": "error",
501
- "exclude": ["legacy/**"],
502
- "severityOverrides": { "QA-PW-141": "warning" },
503
- "ignore": [
504
- {
505
- "ruleId": "QA-TEST-004",
506
- "files": ["e2e/legacy-login.spec.ts"],
507
- "reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
508
- "expires": "2026-12-31"
509
- }
510
- ]
511
- }
512
- ```
534
+ ### รหัสออกและสัญญาสำหรับเครื่อง
513
535
 
514
- - **`.mjolnirignore`** — ไฟล์สไตล์ gitignore เรียบ ๆ สำหรับยกเว้นพาธ
515
- ภาษาเดียวกับ `exclude` ใช้มันสำหรับสัญญาณรบกวนเฉพาะเครื่อง; ใช้
516
- `exclude` เมื่อรายการควรอยู่ใน version control ร่วมกับ config ที่เหลือ
517
- - **CLI overrides** — `--strict` (รวมกฎกักกัน), `--width <cols>` และ
518
- `--ascii` / `--no-ascii` (เรนเดอร์เทอร์มินัล), `--tone blunt`
519
- (ข้อความตรงขึ้น), `--max-duration <sec>` (สแกนบางส่วนที่จำกัดเวลา)
520
- - การกดกฎและวงจรชีวิตการเลิกใช้: [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md)
521
-
522
- รายการ `ignore` ยังหล่อเลี้ยงคำสั่ง `mjolnir suppressions` แบบเดี่ยว
523
- ซึ่งแสดงสิ่งที่ถูกกดอยู่ และเมื่อใดรายการแต่ละรายการหมดอายุ
524
-
525
- ---
526
-
527
- ## 📐 รหัสออก & สัญญา
528
-
529
- แช่แข็ง — ปลอดภัยที่จะสร้างตรรกะ CI บน:
530
-
531
- | รหัสออก | ความหมาย |
532
- | ------- | ----------------------------------------------------- |
533
- | `0` | สะอาด — ไม่มี finding ที่ระดับเกตหรือสูงกว่า |
534
- | `1` | มี finding ที่ระดับเกตหรือสูงกว่า |
535
- | `2` | สแกนบางส่วน (หมดงบเวลา, ไฟล์อ่านไม่ได้) — ไม่เคยบล็อก |
536
- | `10` | ใช้งานผิด (flag ผิด, ไม่ระบุเป้าหมาย) |
537
- | `20` | ข้อผิดพลาดภายใน |
538
-
539
- รายงาน JSON/SARIF คือ `schemaVersion: 1` rule ID (`QA-<FAMILY>-NNN`)
540
- หลังปล่อยแล้วเปลี่ยนไม่ได้ และไม่เคยถูกนำกลับมาใช้
541
-
542
- ---
543
-
544
- ## โมเดลความไว้วางใจ
545
-
546
- - **Local-first** — ศูนย์การเรียกเครือข่ายระหว่างสแกน เด็ดขาด ศูนย์
547
- เทเลเมทรี
548
- - **ไม่มีหลักฐานปลอม** — เราพูด «ไม่รู้» มากกว่า «ตรวจแล้ว» repo ว่าง
549
- ได้ `score: null` ไม่ใช่ 100 ปลอม
550
- - **ความซื่อสัตย์บางส่วน** — ถ้าการวิเคราะห์ถูกตัดสั้น ผลลัพธ์บอก
551
- ไม่เคย «เสร็จ» เมื่อไม่ได้เสร็จ
552
- - **กำแพง FP** — การตรวจจับทำงานบนมุมมองโค้ดที่ปราศจากคอมเมนต์/สตริง
553
- (กฎ TypeScript ใช้ AST คอมไพเลอร์): รูปแบบในคอมเมนต์ร้อยเรียงหรือ
554
- สตริงตัวอย่างเอกสาร คือเอกสาร ไม่ใช่ finding
555
- - **วัด ไม่ใช่อ้าง** — เฉพาะกฎที่มีอัตรา false positive จากโค้ด OSS จริง
556
- จึงอยู่ใน tier พาดหัว (ดู [วัดไปแล้วเท่าไร](#วัดไปแล้วเท่าไร));
557
- ส่วนท้ายการสแกนและ `mjolnir rules --unmeasured` บอกว่ากฎไหนสถานะไหน
558
- - **ความไว้วางใจต่อปลั๊กอินและประตูการรันโค้ด** — ปลั๊กอินคือแพ็กเกจ npm ประกาศใต้
559
- `"plugins"`; โมดูล JS อยู่ใน `mjolnir-rules/*.mjs`
560
- **ไม่มี sandbox**: โค้ดปลั๊กอินรันด้วยสิทธิ์ Node เต็ม
561
- โมเดลความไว้วางใจเดียวกับปลั๊กอิน ESLint หรือ Vitest ด้วยเหตุนี้
562
- การรันโค้ดจึงเป็น **opt-in ในทุกการสแกน**: ส่ง `--enable-plugins`
563
- (หรือตั้ง `MJOLNIR_ENABLE_PLUGINS=1`) ไม่งั้นซอร์สจะไม่ถูกโหลด —
564
- แจ้งเตือนบน stderr อย่างชัดเจนว่าข้ามอะไรไปบ้าง การสแกนโค้ดที่ไม่
565
- น่าเชื่อถือไม่เคยรันมัน ไฟล์ JSON rule manifest (`mjolnir-rules/*.json`)
566
- ไม่ได้รับผลกระทบ: ประกาศ regex pattern และไม่รันโค้ดโดยการออกแบบ
567
- คำนำหน้า rule ID ของ core สงวนไว้และถูกปฏิเสธจากปลั๊กอินและกฎภายนอก
568
- เพื่อกันการอ้างปลอม
569
- - **กฎภายนอกประจำ workspace** (อิงโฟลเดอร์ ศูนย์เครือข่าย) — ไดเรกทอรี
570
- `mjolnir-rules/` ติดกับเป้าสแกนโหลดกฎกำหนดเอง: ไฟล์ JSON ประกาศรูปแบบ
571
- regex (ไม่รันโค้ด) โมดูล `.mjs`/`.js` export `rules` (ความไว้วางใจ
572
- Node เต็ม เหมือนปลั๊กอิน) กฎภายนอกพก trust metadata เดียวกับ core;
573
- ไม่เคยขึ้นไปใน tier core (core ต้องมีอัตรา FP ที่วัดจาก sidecar
574
- corpus — `tier: "core"` ที่ประกาศมาถูกบีบลงเหลือ `extended`),
575
- ทำตามเพดาน tier และถูกตรวจเรื่องเหลื่อมล้ำ: `mjolnir rules --md
576
- --external` เรนเดอร์แคตตาล็อกจากไฟล์ที่โหลด (แหล่งที่มา `external`)
577
- และตัวสร้างเมทริกซ์รับ `--external <root>`
578
-
579
- ---
580
-
581
- ## 🏗️ สถาปัตยกรรม
536
+ ถูกตรึงไว้ คุณจึงสร้างตรรกะ CI บนมันได้:
582
537
 
583
- <details>
584
- <summary>ขยายแผนผัง</summary>
538
+ | รหัสออก | ความหมาย |
539
+ | ------- | -------------------------------------------------------- |
540
+ | `0` | สะอาด: ไม่มีข้อค้นพบที่ระดับด่านหรือสูงกว่า |
541
+ | `1` | มีข้อค้นพบที่ระดับด่านหรือสูงกว่า |
542
+ | `2` | การสแกนบางส่วน (หมดงบเวลา ไฟล์ที่อ่านไม่ได้) ไม่บล็อกเลย |
543
+ | `10` | ข้อผิดพลาดในการใช้งาน (แฟล็กผิด ไม่ได้ระบุเป้าหมาย) |
544
+ | `20` | ข้อผิดพลาดภายใน |
585
545
 
586
- ```
587
- mjolnir/
588
- ├── src/
589
- │ ├── engine/ # LanguageAdapter interface + rule runner
590
- │ ├── adapters/ # typescript · python · java · csharp · github-actions
591
- │ ├── rules/ # rules across 8 families + the measured-FP table
592
- │ ├── playwright/ # Selector Health Score engine
593
- │ ├── discovery/ # workspace, frameworks, ignore resolution
594
- │ ├── scope/ # git merge-base changed-scope engine
595
- │ ├── scorer/ # transparent deduction table + prioritization
596
- │ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
597
- │ ├── forensics/ # run-data ingestion · flake verdicts · triage
598
- │ ├── config/ # mjolnir.config.json + suppressions
599
- │ ├── plugins/ # third-party rule loading (no sandbox)
600
- │ └── commands/ # every subcommand
601
- └── tests/
602
- ├── fixtures/ # must-fire / must-not-fire per rule
603
- └── golden/ # frozen score regression locks
604
- ```
546
+ `2` ถูกแยกจาก `0` โดยเจตนา: การสแกนที่ยังไม่เสร็จไม่ได้ "ไม่พบอะไรเลย" มันแค่ยังค้นหาไม่เสร็จ
605
547
 
606
- </details>
548
+ ทุกสิ่งที่เครื่องใช้ (ผลลัพธ์จากเครื่องมือ MCP, `--json`, SARIF 2.1) มาจากผลลัพธ์มาตรฐานเดียวภายใต้ schema ที่มีเวอร์ชันและ **ขยายได้ด้วยการเพิ่มเท่านั้น** (`schemaVersion: 1`, `contractVersion: 1`) จึงไม่มีผู้ใช้รายใดต้องสร้างความหมายขึ้นใหม่จากข้อความที่เรนเดอร์แล้ว ดู [สัญญาสำหรับเครื่อง](docs/machine-contract.md) ID ของกฎ (`QA-<FAMILY>-NNN`) เปลี่ยนไม่ได้เมื่อปล่อยแล้วและไม่ถูกนำกลับมาใช้ซ้ำ
607
549
 
608
- - **กฎเป็นฟังก์ชันบริสุทธิ์** — `(SourceFileContext) → Finding[]`,
609
- ไม่มี I/O ไม่มี global เพิ่มระบบนิเวศใหม่ = หนึ่ง adapter + กฎของมัน
610
- - **TypeScript/Playwright ใช้ AST คอมไพเลอร์** (ts-morph) Python, Java
611
- และ C# รันบนชั้น regex ร่วมกันที่ปิดบังคอมเมนต์/สตริง
612
- - ชั้น AST tree-sitter WASM สำหรับ Java และ C# มีอยู่และเป็นก้าวความ
613
- แม่นยำถัดไป — ยังไม่ได้เสียบเข้ากับ pipeline สแกนแบบซิงโครนัส
550
+ <br />
614
551
 
615
- ---
552
+ ## สิ่งที่ Mjölnir บอกคุณไม่ได้
616
553
 
617
- ## 📚 เอกสาร
554
+ - **มันไม่รันเทสต์ของคุณ** การสแกนที่สะอาดไม่ใช่ชุดเทสต์ที่ผ่าน
555
+ - **มันบอกไม่ได้ว่า assertion _ผิด_** `expect(total).toBe(41)` ดูปกติดี Mjölnir หาเทสต์ที่ _ล้มเหลวไม่ได้_ และไปป์ไลน์ที่ _เป็นสีแดงไม่ได้_ ไม่ใช่เทสต์ที่ตรวจสอบผิดเรื่อง
556
+ - **มันไม่ได้พิสูจน์ความถูกต้องทางธุรกิจ** ไม่มีสิ่งใดในที่นี้บอกว่าผลิตภัณฑ์ของคุณทำตามที่ข้อกำหนดต้องการ
557
+ - **100 ไม่ใช่ข้อพิสูจน์ว่าชุดเทสต์ดี** ชุดเทสต์ของคุณครอบคลุมความเสี่ยงจริงหรือไม่เป็นอีกคำถามหนึ่ง และเครื่องมือนี้ไม่ได้ตอบคำถามนั้น
558
+ - **5 จาก 79 กฎปล่อยออกมาด้วยค่าประมาณ** ไม่ใช่อัตราที่วัดได้ แต่ละกฎบอกไว้บนข้อค้นพบของตัวเอง
559
+ - **E1 ไม่ใช่ E2** ข้อค้นพบเชิงฮิวริสติกควรค่าแก่การอ่าน ไม่ใช่นำไปใช้อย่างไม่ไตร่ตรอง
560
+ - **รีโพว่างได้คะแนน `null` ไม่มีวันได้ 100**
561
+ - **ไฟล์ชื่อ `*.spec.ts` ที่ไม่มีการประกาศเทสต์ไม่นับเป็น coverage** รีโพที่ไฟล์ spec มีเพียง import หรือ type (ไม่มีการเรียก `it`/`test` เลย) ได้คะแนน `null` ไม่ใช่ 100
618
562
 
619
- | เอกสาร | มีอะไรในนั้น |
620
- | ------------------------------------------------------ | ----------------------------------------------- |
621
- | [docs/SCORING.md](docs/SCORING.md) | การ normalize คะแนน + การถ่วงน้ำหนักด้วยหลักฐาน |
622
- | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | อัตรา false positive ที่วัดได้ + วิธีวัด |
623
- | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | สถานะกฎ การกด การเลิกใช้ |
624
- | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | ผลลัพธ์ SARIF + การตั้งค่า editor/CI |
625
- | [docs/rules/](docs/rules/) | แคตตาล็อกต่อกฎที่สร้างอัตโนมัติ |
626
- | [CONTRIBUTING.md](CONTRIBUTING.md) | การตั้งค่า dev + ขั้นตอนการร่วมพัฒนา |
627
- | [CHANGELOG.md](CHANGELOG.md) | ประวัติการเผยแพร่ |
628
- | [SECURITY.md](SECURITY.md) | รายงานช่องโหว่ |
563
+ <br />
629
564
 
630
- ---
565
+ ## เอกสารประกอบ
631
566
 
632
- ## 📈 สถานะ
567
+ เว็บไซต์เอกสารฉบับเต็มอยู่ที่ <https://sergey-bar.github.io/Mjolnir/>
633
568
 
634
- **v0.5.x · โอเพนเบตา** JSON schema และรหัสออกเป็นสัญญาแช่แข็ง
635
- TypeScript และ Python มีความครอบคลุมที่วัดได้กว้างสุด; Java และ C#
636
- ใหม่กว่า — อ่านผ่าน
637
- [ตาราง tier](#tier-ของกฎและความสุกงอมของภาษา)
569
+ | เอกสาร | เนื้อหา |
570
+ | ------------------------------------------------------ | -------------------------------------------------- |
571
+ | [docs/SCORING.md](docs/SCORING.md) | การปรับคะแนนให้เป็นมาตรฐานและการถ่วงน้ำหนักหลักฐาน |
572
+ | [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md) | คำศัพท์มาตรฐาน: หนึ่งคำต่อหนึ่งแนวคิด |
573
+ | [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | อัตราผลบวกลวงที่วัดได้และวิธีการ |
574
+ | [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | สถานะของกฎ ระดับ การระงับ การเลิกใช้ |
575
+ | [docs/VERSIONING.md](docs/VERSIONING.md) | นโยบาย semver อินเทอร์เฟซที่ถูกตรึง รอบการเลิกใช้ |
576
+ | [docs/machine-contract.md](docs/machine-contract.md) | ผลลัพธ์มาตรฐานที่เครื่องอ่านได้ |
577
+ | [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | เอาต์พุต SARIF และการตั้งค่าเอดิเตอร์หรือ CI |
578
+ | [docs/GITLAB-CI.md](docs/GITLAB-CI.md) | GitLab: รายงาน Code Quality สูตรสำหรับ MR ด่าน |
579
+ | [docs/rules/](docs/rules/) | แค็ตตาล็อกรายกฎที่สร้างอัตโนมัติ |
580
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | การตั้งค่าสำหรับพัฒนาและขั้นตอนการมีส่วนร่วม |
581
+ | [SUPPORT.md](SUPPORT.md) | ที่สำหรับถาม รายงาน และขอความช่วยเหลือ |
582
+ | [SECURITY.md](SECURITY.md) | การรายงานช่องโหว่ |
583
+ | [CHANGELOG.md](CHANGELOG.md) | ประวัติการออกรุ่น |
638
584
 
639
- ---
585
+ ### สถานะ
640
586
 
641
- ## 🤝 ร่วมพัฒนา
587
+ **เวอร์ชัน 1** schema ของ JSON และรหัสออกเป็นสัญญาที่ถูกตรึงไว้ TypeScript และ Python มีการครอบคลุมที่วัดได้กว้างที่สุด Java และ C# ใหม่กว่า ให้อ่านผ่าน [ตารางความพร้อม](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle) สิ่งที่จะมาต่อไป โดยไม่มีวันที่ที่แต่งขึ้น: [แผนงานสาธารณะ](https://sergey-bar.github.io/Mjolnir/reference/roadmap)
642
588
 
643
- กฎใหม่คือรายการแรกที่ง่ายที่สุด — หนึ่งคำสั่งสร้างโครงกฎพร้อม fixture
644
- must-fire **และ** must-not-fire (กฎที่สร้างให้จงใจล้มเหลวบน fixture
645
- จนกว่าคุณจะเขียนการตรวจจับจริง — stub ปล่อยไม่ได้):
589
+ ### การมีส่วนร่วม
590
+
591
+ กฎใหม่คือการมีส่วนร่วมครั้งแรกที่ง่ายที่สุด คำสั่งเดียวสร้างโครงของกฎพร้อม fixture แบบ must-fire **และ** must-not-fire กฎที่สร้างขึ้นจะล้มเหลวกับ fixture ของตัวเองโดยเจตนาจนกว่าจะมีการเขียนการตรวจจับจริง เพราะโครงเปล่าที่ถูกปล่อยออกไปคือกฎที่ไม่มีใครวัด:
646
592
 
647
593
  ```bash
648
594
  mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
649
595
  ```
650
596
 
651
- การตั้งค่า dev เต็มรูปแบบ คำสั่ง standing gate และกฎหมาย anti-creep /
652
- กำแพง fixture อยู่ใน [CONTRIBUTING.md](CONTRIBUTING.md)
597
+ การตั้งค่าสำหรับพัฒนา คำสั่งด่านถาวร และกฎ anti-creep กับไฟร์วอลล์ fixture อยู่ใน [CONTRIBUTING.md](CONTRIBUTING.md)
653
598
 
654
- ---
599
+ <br />
655
600
 
656
601
  <div align="center">
657
602
 
658
- **หยุดปล่อยการทดสอบที่คุณไว้วางใจไม่ได้**
603
+ <img src="assets/readme/closing.svg" alt="ลองรันกับรีโพของคุณ" width="100%" />
659
604
 
660
605
  ```bash
661
606
  npx mjolnir-qa@latest
662
607
  ```
663
608
 
664
- **Star ⭐ · Watch 👀 · Contribute 🤝**
609
+ [อ่านคู่มือ](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [เว็บไซต์เอกสาร](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)
610
+
611
+ <br />
612
+
613
+ อย่าถามว่าเทสต์ผ่านหรือไม่<br />
614
+ ให้ถามว่าหลักฐานพิสูจน์ได้หรือไม่ว่าเทสต์เหล่านั้นสมควรได้รับความเชื่อถือ
665
615
 
666
- สร้างโดย [Sergey Bar](https://www.linkedin.com/in/sergeybar/)
616
+ <sub>สร้างโดย [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · สัญญาอนุญาต MIT</sub>
667
617
 
668
618
  </div>