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/CHANGELOG.md +1199 -28
- package/README.ar.md +667 -0
- package/README.bn.md +678 -0
- package/README.br.md +706 -0
- package/README.bs.md +690 -0
- package/README.da.md +698 -0
- package/README.de.md +711 -0
- package/README.es.md +709 -0
- package/README.fr.md +714 -0
- package/README.gr.md +705 -0
- package/README.he.md +664 -0
- package/README.it.md +709 -0
- package/README.ja.md +692 -0
- package/README.ko.md +681 -0
- package/README.md +425 -152
- package/README.no.md +696 -0
- package/README.pl.md +699 -0
- package/README.ru.md +701 -0
- package/README.th.md +672 -0
- package/README.tr.md +699 -0
- package/README.uk.md +693 -0
- package/README.vi.md +680 -0
- package/README.zh.md +652 -0
- package/README.zht.md +652 -0
- package/dist/cli.d.mts +469 -22
- package/dist/cli.mjs +9780 -5230
- package/package.json +25 -7
package/README.th.md
ADDED
|
@@ -0,0 +1,672 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="assets/readme/logo.png" alt="Mjölnir — Verification Trust Engine" width="800" />
|
|
4
|
+
|
|
5
|
+
### การทดสอบของคุณโกหกคุณ เราพิสูจน์ให้เห็น
|
|
6
|
+
|
|
7
|
+
**Verification Trust Engine สำหรับ QA** Mjölnir ตรวจสอบชุดทดสอบและ
|
|
8
|
+
CI pipelines รายงานคะแนนความน่าเชื่อถือ และแสดงให้เห็นอย่างแม่นยำว่า
|
|
9
|
+
ความไว้วางใจพังตรงไหน
|
|
10
|
+
|
|
11
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
12
|
+
[](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
[](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)
|
|
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="รายงาน --verbose ฉบับเต็มของ Mjölnir บน demo repo: WORTHINESS 75/100 NEEDS WORK, การแจกแจงการวินิจฉัยตามหมวด, รายการ FIX THIS FIRST และทุก finding พร้อม rule ID และเลขบรรทัด ครอบคลุมกฎ CI, Playwright, สุขอนามัยการทดสอบ และกฎ Python" width="900" />
|
|
41
|
+
</p>
|
|
42
|
+
|
|
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>
|
|
48
|
+
|
|
49
|
+
**เกิดอะไรขึ้นเมื่อครู่:**
|
|
50
|
+
|
|
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 ได้
|
|
58
|
+
|
|
59
|
+
### Finding หนึ่งชิ้น ระยะชิด
|
|
60
|
+
|
|
61
|
+
รัน `mjolnir explain QA-CI-001` กับ finding แรกด้านบน แล้วคุณจะได้:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
▚▞ QA-CI-001 — continue-on-error masks a failing verification gate
|
|
65
|
+
|
|
66
|
+
Severity: error
|
|
67
|
+
Confidence: high
|
|
68
|
+
Evidence: E2
|
|
69
|
+
Measured FP: not yet measured — this rule ships on assumption (see docs/FP-AUDIT.md)
|
|
70
|
+
|
|
71
|
+
WHAT WAS FOUND (real detector output, not a mockup)
|
|
72
|
+
Job `security-scan` runs a verification gate under `continue-on-error: true`.
|
|
73
|
+
|
|
74
|
+
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.
|
|
77
|
+
|
|
78
|
+
HOW TO FIX
|
|
79
|
+
Remove continue-on-error, or scope it to individual non-blocking steps only.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
นี่คือหน่วยของคุณค่า: ไม่ใช่เรื่องสไตล์เล็ก ๆ แต่เป็นจุดที่ CI ของคุณ
|
|
83
|
+
บอกว่าบางอย่างผ่าน ทั้งที่ไม่ได้ผ่าน
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## ⚡ เริ่มเร็ว
|
|
88
|
+
|
|
89
|
+
รันกับ repo เพื่อรายงานฉบับเต็มและคะแนนความน่าเชื่อถือ:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
npx mjolnir-qa@latest
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**ใน CI ผลิตภัณฑ์คือคำสั่งเดียว** มันสแกนเฉพาะสิ่งที่ branch แตะ
|
|
96
|
+
และออกด้วยเลขไม่ใช่ศูนย์เมื่อมีปัญหาใหม่:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx mjolnir-qa@latest --scope changed
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
หย่อนลงใน PR check — `mjolnir ci install` เขียน workflow ให้ — แล้วจบ
|
|
103
|
+
ส่วนที่เหลือเป็นทางเลือกทั้งหมด
|
|
104
|
+
|
|
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>
|
|
117
|
+
|
|
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 |
|
|
124
|
+
|
|
125
|
+
</details>
|
|
126
|
+
|
|
127
|
+
<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 |
|
|
143
|
+
|
|
144
|
+
</details>
|
|
145
|
+
|
|
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
|
+
---
|
|
162
|
+
|
|
163
|
+
## 🔨 Mjölnir ตรวจอะไร
|
|
164
|
+
|
|
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** — ศูนย์การเรียกเครือข่ายระหว่างสแกน ศูนย์เทเลเมทรี รันเสร็จในไม่กี่วินาที |
|
|
173
|
+
|
|
174
|
+
### กฎทั้งหมด
|
|
175
|
+
|
|
176
|
+
ทุกกฎมาพร้อม fixture must-fire **และ** must-not-fire กฎที่ยิงบน
|
|
177
|
+
fixture ลบของตัวเองจะปล่อยไม่ได้ — นั่นคือกำแพงกัน false positive
|
|
178
|
+
|
|
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 |
|
|
191
|
+
|
|
192
|
+
</details>
|
|
193
|
+
|
|
194
|
+
<details>
|
|
195
|
+
<summary><strong>คุณภาพการทดสอบ</strong></summary>
|
|
196
|
+
|
|
197
|
+
| ID | กฎ | Severity |
|
|
198
|
+
| ------------ | -------------------------------------- | -------- |
|
|
199
|
+
| QA-TQUAL-001 | ตรวจยืนยันด้วย mock เท่านั้น | info |
|
|
200
|
+
| QA-TQUAL-002 | assertion พรรคพวกตัวเอง (tautological) | error |
|
|
201
|
+
| QA-TQUAL-009 | assertion ของ promise ที่ไม่ await | error |
|
|
202
|
+
| QA-TQUAL-011 | ทดสอบที่ถูกคอมเมนต์ทิ้งไว้ | warning |
|
|
203
|
+
|
|
204
|
+
</details>
|
|
205
|
+
|
|
206
|
+
<details>
|
|
207
|
+
<summary><strong>Playwright 🎭</strong></summary>
|
|
208
|
+
|
|
209
|
+
| ID | กฎ | Severity |
|
|
210
|
+
| --------- | ----------------------------------------- | -------- |
|
|
211
|
+
| QA-PW-002 | assertion ของ locator ที่ไม่ await | error |
|
|
212
|
+
| QA-PW-003 | `page.pause()` / `test.only()` ถูก commit | error |
|
|
213
|
+
| QA-PW-004 | selector CSS/XPath เปราะ | warning |
|
|
214
|
+
| QA-PW-005 | ตรรกะธุรกิจใน `page.evaluate()` | info |
|
|
215
|
+
| QA-PW-114 | element handles รุ่นเก่า (`page.$`) | info |
|
|
216
|
+
| QA-PW-118 | การรอ `networkidle` (flaky by design) | info |
|
|
217
|
+
| QA-PW-123 | URL สภาพแวดล้อมฝังตาย | warning |
|
|
218
|
+
|
|
219
|
+
</details>
|
|
220
|
+
|
|
221
|
+
<details>
|
|
222
|
+
<summary><strong>ความสมบูรณ์ของ CI</strong></summary>
|
|
223
|
+
|
|
224
|
+
| ID | กฎ | Severity |
|
|
225
|
+
| --------- | ------------------------------------------------------------- | -------- |
|
|
226
|
+
| QA-CI-001 | `continue-on-error` ปกปิดความล้มเหลว | error |
|
|
227
|
+
| QA-CI-002 | `\|\| true` กลืน exit code | error |
|
|
228
|
+
| QA-CI-005 | รายงานถูกใช้แต่ไม่เคยถูกสร้าง | error |
|
|
229
|
+
| QA-CI-007 | ครอบ retry รอบการทดสอบ | warning |
|
|
230
|
+
| QA-CI-008 | step สำเร็จเสมอ ปกปิดความล้มเหลว | error |
|
|
231
|
+
| QA-CI-009 | exit code ของทดสอบไม่ถูกส่งต่อ (`\|` ไม่มี pipefail, โซ่ `;`) | error |
|
|
232
|
+
| QA-CI-010 | ข้ามทดสอบในที่ที่ต้องบล็อก (skip-on-PR guards) | error |
|
|
233
|
+
|
|
234
|
+
</details>
|
|
235
|
+
|
|
236
|
+
<details>
|
|
237
|
+
<summary><strong>Python / pytest 🐍</strong></summary>
|
|
238
|
+
|
|
239
|
+
| ID | กฎ | Severity |
|
|
240
|
+
| --------- | ----------------------------------------- | -------- |
|
|
241
|
+
| QA-PY-002 | ทดสอบถูกข้าม (`skip`, `xfail` ไม่เข้มงวด) | warning |
|
|
242
|
+
| QA-PY-003 | ฟังก์ชันทดสอบไม่มี assertion | error |
|
|
243
|
+
| QA-PY-005 | `time.sleep()` ในการทดสอบ | warning |
|
|
244
|
+
| QA-PY-006 | เนื้อความทดสอบว่าง (`pass`) | info |
|
|
245
|
+
| QA-PY-010 | พึ่งพาความสุ่ม/เวลาโดยไม่ freeze | info |
|
|
246
|
+
| QA-PY-012 | assertion พรรคพวกตัวเอง | error |
|
|
247
|
+
|
|
248
|
+
กฎ Python รวม 20 ข้อ (QA-PY-001…012 สุขอนามัย pytest + QA-PY-101…108 Playwright-Python)
|
|
249
|
+
|
|
250
|
+
</details>
|
|
251
|
+
|
|
252
|
+
<details>
|
|
253
|
+
<summary><strong>Java / JUnit · TestNG ☕</strong></summary>
|
|
254
|
+
|
|
255
|
+
| ID | กฎ | Severity |
|
|
256
|
+
| --------- | ---------------------------------------- | -------- |
|
|
257
|
+
| QA-JV-101 | ทดสอบถูกปิด (`@Disabled`) | warning |
|
|
258
|
+
| QA-JV-102 | hard sleep (`Thread.sleep()`) | warning |
|
|
259
|
+
| QA-JV-103 | วิธีทดสอบไม่มี assertion | error |
|
|
260
|
+
| QA-JV-105 | hard sleep Playwright `waitForTimeout()` | warning |
|
|
261
|
+
| QA-JV-106 | selector เปราะแทน role locator | warning |
|
|
262
|
+
| QA-JV-108 | URL สภาพแวดล้อมฝังตายในทดสอบ | info |
|
|
263
|
+
| QA-JV-111 | mock ครอบคลุมหมด `page.route("**")` | info |
|
|
264
|
+
|
|
265
|
+
</details>
|
|
266
|
+
|
|
267
|
+
<details>
|
|
268
|
+
<summary><strong>C# / .NET — NUnit · xUnit · MSTest 🟣</strong></summary>
|
|
269
|
+
|
|
270
|
+
| ID | กฎ | Severity |
|
|
271
|
+
| --------- | ------------------------------------------ | -------- |
|
|
272
|
+
| QA-CS-101 | ทดสอบถูกข้าม (`[Ignore]`, `[Fact(Skip=)]`) | warning |
|
|
273
|
+
| QA-CS-102 | hard sleep (`Thread.Sleep` / `Task.Delay`) | warning |
|
|
274
|
+
| QA-CS-103 | วิธีทดสอบไม่มี assertion | error |
|
|
275
|
+
| QA-CS-105 | hard sleep `WaitForTimeoutAsync()` | warning |
|
|
276
|
+
| QA-CS-106 | selector เปราะแทน role locator | warning |
|
|
277
|
+
| QA-CS-108 | URL สภาพแวดล้อมฝังตายในทดสอบ | info |
|
|
278
|
+
| QA-CS-111 | mock ครอบคลุมหมด `page.RouteAsync("**")` | info |
|
|
279
|
+
|
|
280
|
+
</details>
|
|
281
|
+
|
|
282
|
+
> แคตตาล็อกสดฉบับเต็ม — ทุกกฎพร้อม tier, confidence, ความเสี่ยง false
|
|
283
|
+
> positive และความพร้อมของ autofix — สร้างจาก registry:
|
|
284
|
+
>
|
|
285
|
+
> ```bash
|
|
286
|
+
> mjolnir rules --md
|
|
287
|
+
> ```
|
|
288
|
+
>
|
|
289
|
+
> หน้าต่อกฎอยู่ใต้ [`docs/rules/`](docs/rules/)
|
|
290
|
+
|
|
291
|
+
### วัดไปแล้วเท่าไร
|
|
292
|
+
|
|
293
|
+
**74 จาก 99 กฎ มีอัตรา false positive ที่วัดกับโค้ด OSS จริง** (อย่างน้อย
|
|
294
|
+
10 findings ที่จัดหมวดด้วยมือต่อกฎ; ดู
|
|
295
|
+
[docs/FP-AUDIT.md](docs/FP-AUDIT.md)) อีก 19 กฎออกมาบนการประเมินของผู้เขียน
|
|
296
|
+
ส่วนท้ายของทุกการสแกนบอกว่ากฎที่ _ยิง_ มีกี่กฎที่วัดแล้ว;
|
|
297
|
+
`mjolnir rules --unmeasured` แสดงกฎที่ยังไม่วัด; หน้า `mjolnir explain`
|
|
298
|
+
ของทุกกฎระบุสถานะ เราเผยแพร่อัตรานี้แม้มันจะน่าเกลียด — QA-CS-103 ตรวจได้
|
|
299
|
+
ที่ 95 % และถูกส่งไปกักกันเพราะเหตุนี้ การทำให้ตัวเลข 78 นั้นโตขึ้นคืองาน
|
|
300
|
+
ต่อเนื่องของโปรเจกต์
|
|
301
|
+
|
|
302
|
+
### Tier ของกฎและความสุกงอมของภาษา
|
|
303
|
+
|
|
304
|
+
ทุกกฎเป็น `core`, `extended` หรือ `quarantine` กำหนดจากอัตรา false
|
|
305
|
+
positive **ที่วัดได้**:
|
|
306
|
+
|
|
307
|
+
| Tier | ความหมาย | สแกนปกติ | `--strict` |
|
|
308
|
+
| ------------ | ----------------------------------- | :------: | :--------: |
|
|
309
|
+
| `core` | ≤ 10 % FP ที่วัดได้ | ✅ | ✅ |
|
|
310
|
+
| `extended` | ≤ 30 % FP ที่วัดได้ | ✅ | ✅ |
|
|
311
|
+
| `quarantine` | สูงกว่า 30 % หรือยังไม่วัด (n < 10) | ❌ | ✅ |
|
|
312
|
+
|
|
313
|
+
| ภาษา | Adapter | ความครอบคลุมวันนี้ |
|
|
314
|
+
| --------------- | -------------- | ------------------------------------------------- |
|
|
315
|
+
| TypeScript / JS | AST คอมไพเลอร์ | กว้างสุด วัดมากสุด — ส่วนใหญ่ `core`/`extended` |
|
|
316
|
+
| Python / pytest | ชั้น regex | กว้าง ตรวจกับ corpus — ส่วนใหญ่ `core`/`extended` |
|
|
317
|
+
| Java | ชั้น regex | ใหม่กว่า — ส่วนใหญ่ `extended`/`quarantine` |
|
|
318
|
+
| C# / .NET | ชั้น regex | ใหม่กว่า — ส่วนใหญ่ `extended`/`quarantine` |
|
|
319
|
+
|
|
320
|
+
TypeScript และ Python มีความครอบคลุมที่วัดได้กว้างที่สุด Java และ C#
|
|
321
|
+
ปล่อยแล้ว มีเอกสาร และยังอยู่นอกตัวเลขพาดหัว จนกว่าชุดทดสอบผู้ใช้จริง
|
|
322
|
+
(ไม่ใช่ทดสอบของไลบรารี binding เอง) จะถูกตรวจ
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## การให้คะแนนทำงานอย่างไร
|
|
327
|
+
|
|
328
|
+
<p align="center">
|
|
329
|
+
<img src="assets/readme/terminal-hero.svg" alt="ผลลัพธ์ terminal ของ Mjölnir — WORTHINESS 75/100 NEEDS WORK, การแจกแจงการวินิจฉัยตามหมวด และรายการ FIX THIS FIRST" width="820" />
|
|
330
|
+
</p>
|
|
331
|
+
|
|
332
|
+
<sub>สร้างใหม่ด้วย `npm run docs:hero`;
|
|
333
|
+
[`tests/hero-asset-reproducibility.spec.ts`](tests/hero-asset-reproducibility.spec.ts)
|
|
334
|
+
จะทำให้ CI ลม หากสินค้าเองเหลื่อมจากสิ่งที่ reporter พิมพ์จริง</sub>
|
|
335
|
+
|
|
336
|
+
คะแนนโปร่งใส: **error −8, warning −3, info −1** แล้ว normalize ด้วย
|
|
337
|
+
exposure ของชุดทดสอบ (การหักต่อการประกาศทดสอบ) การหักที่ถ่วงน้ำหนักด้วย
|
|
338
|
+
หลักฐาน หมายความว่าสัญญาณอ่อนแพงกว่า แสดงผลใน terminal ใช้ตัวเลขที่
|
|
339
|
+
ลดแล้วชุดเดียวกับที่คะแนนใช้ — ไม่มีกล่องดำ วิธีเต็ม:
|
|
340
|
+
[docs/SCORING.md](docs/SCORING.md)
|
|
341
|
+
|
|
342
|
+
**คำพิพากษา**
|
|
343
|
+
|
|
344
|
+
| Score | คำพิพากษา |
|
|
345
|
+
| ------- | ---------------- |
|
|
346
|
+
| ≥ 80 | ✓ **WORTHY** |
|
|
347
|
+
| 50 – 79 | ⚠ **NEEDS WORK** |
|
|
348
|
+
| < 50 | ✖ **UNWORTHY** |
|
|
349
|
+
|
|
350
|
+
**ระดับหลักฐาน** — ทุก finding พกระดับหนึ่ง; มันกำหนดน้ำหนักของ finding
|
|
351
|
+
ในคะแนน:
|
|
352
|
+
|
|
353
|
+
| ระดับ | ความหมาย | ผลต่อคะแนน | ตัวอย่าง |
|
|
354
|
+
| ----- | --------------------- | --------------------- | ----------------------------------------------------- |
|
|
355
|
+
| E2 | ข้อบกพร่องเชิงกำหนด | หักเต็มจำนวน | commit `.only` — พิสูจน์เชิงโครงสร้างได้ |
|
|
356
|
+
| E1 | รูปแบบเชิงเฮิร์ริสติก | หักครึ่งหนึ่ง | `sleep()` ที่ regex เจอ — สัญญาณแข็งแรง ไม่ใช่หลักฐาน |
|
|
357
|
+
| E0 | การสังเกต | ศูนย์ (info เท่านั้น) | รายงานแต่ไม่ gate CI และไม่หักเลย |
|
|
358
|
+
|
|
359
|
+
กฎส่วนใหญ่เป็น **E1** คำสโลแกน «we prove it» อ้างถึงระบบนี้: finding
|
|
360
|
+
E2 คือหลักฐานเชิงโครงสร้าง; finding E1 คือคำเตือนที่วางตำแหน่งถูกต้อง
|
|
361
|
+
ไม่ใช่หลักฐานทางการ
|
|
362
|
+
|
|
363
|
+
repo ว่างจะได้คะแนน `null` ไม่ใช่เลข 100 ปลอม — ดู
|
|
364
|
+
[โมเดลความไว้วางใจ](#โมเดลความไว้วางใจ)
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## 🎭 Selector Health Score
|
|
369
|
+
|
|
370
|
+
ตัวชี้วัดพาดหัวสำหรับชุด Playwright — locator ของคุณทนทานแค่ไหน:
|
|
371
|
+
|
|
372
|
+
```text
|
|
373
|
+
▚▞ SELECTOR HEALTH — e2e/checkout.spec.ts
|
|
374
|
+
|
|
375
|
+
[█████████████████░░░] 83 / 100
|
|
376
|
+
role/text: 2 · testid: 1 · css-chains: 1 ⚠ · xpath: 0
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
locator ที่อิง role ได้คะแนนเต็ม ห่วงโซ่ CSS class และ XPath จมคะแนน —
|
|
380
|
+
มันแตกทุกครั้งที่ refactor DOM โดยไม่บอกว่าพฤติกรรมใดถดถอย
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## 🔬 หลักฐานระดับ runtime
|
|
385
|
+
|
|
386
|
+
การตรวจจับความไม่นิ่งแบบสถิตคือการเดา Mjölnir อ่าน **ข้อมูลการรันจริง** —
|
|
387
|
+
รายงาน JSON ของ Playwright และ XML ของ JUnit จาก runner ใดก็ได้:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
mjolnir forensics ./test-results/
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
```text
|
|
394
|
+
▚▞ FLAKINESS LEADERBOARD
|
|
395
|
+
|
|
396
|
+
3 tests · 1 failed · 1 flaky · 1 retried
|
|
397
|
+
|
|
398
|
+
TRUE-FLAKE completes checkout with saved card (e2e/checkout.spec.ts)
|
|
399
|
+
████████████████████ 6.0s · 2 attempts
|
|
400
|
+
FAILING declines an expired card (e2e/checkout.spec.ts)
|
|
401
|
+
████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
ทดสอบที่ผ่านเฉพาะตั้งแต่ attempt ≥ 2 ไม่ใช่ทดสอบที่ผ่าน — มันเป็น
|
|
405
|
+
ทดสอบที่โชคดี มันถูกติดธง `TRUE-FLAKE` ไม่ว่าเครื่องหมายเขียวสุดท้าย
|
|
406
|
+
จะเป็นอย่างไร
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## ⚡ Mjölnir ไม่ใช่ linter อีกตัว
|
|
411
|
+
|
|
412
|
+
Linter บอกว่าโค้ดทำตามกฎหรือไม่ Mjölnir บอกว่าการตรวจสอบของคุณ
|
|
413
|
+
น่าเชื่อถือหรือไม่
|
|
414
|
+
|
|
415
|
+
| | ESLint / SonarQube | เครื่องมือ coverage | รีวิวด้วยมือ | **Mjölnir** |
|
|
416
|
+
| ------------------------------------------------------------- | :----------------: | :-----------------: | :----------: | :---------: |
|
|
417
|
+
| ความสมบูรณ์ของ CI workflow (`continue-on-error`, `\|\| true`) | ❌ | ❌ | ไม่ค่อย | ✅ |
|
|
418
|
+
| ข้ามภาษา (TS, Python, Java, C#) จากเครื่องมือเดียว | ❌ | ❌ | ❌ | ✅ |
|
|
419
|
+
| ให้เกรดความทนทานของ locator Playwright (Selector Health) | ❌ | ❌ | ไม่ค่อย | ✅ |
|
|
420
|
+
| ติดธงทดสอบไม่มี assertion จริง | ✅ (ปลั๊กอิน)\* | ❌ | บางครั้ง | ✅ |
|
|
421
|
+
| จับ hard sleep (`waitForTimeout`, `time.sleep`) | ✅ (ปลั๊กอิน)\* | ❌ | บางครั้ง | ✅ |
|
|
422
|
+
| รันในไม่กี่วินาที ศูนย์การเรียกเครือข่ายระหว่างสแกน | ✅ | ✅ | — | ✅ |
|
|
423
|
+
|
|
424
|
+
\*`eslint-plugin-jest` (`expect-expect`) และ `eslint-plugin-playwright`
|
|
425
|
+
(`expect-expect`, `no-wait-for-timeout`) ครอบคลุมสิ่งเหล่านี้ให้ framework
|
|
426
|
+
ตามลัพธ์ของมัน
|
|
427
|
+
|
|
428
|
+
**การวิเคราะห์ runtime** เป็นหมวดหมู่แยกจากการ lint แบบสถิต:
|
|
429
|
+
|
|
430
|
+
| | Playwright retry reporter | Allure / ReportPortal | **Mjölnir forensics** |
|
|
431
|
+
| -------------------------------------------- | :-----------------------: | :-------------------: | :-------------------: |
|
|
432
|
+
| อ่านข้อมูลรันจริงเพื่อคำพิพากษา `TRUE-FLAKE` | บางส่วน\* | บางส่วน (tag) | ✅ |
|
|
433
|
+
| รายงาน triage ความไม่นิ่งจากประวัติการรัน | ❌ | ✅ | ✅ |
|
|
434
|
+
| เชื่อมกับคะแนนความน่าเชื่อถือแบบสถิต | ❌ | ❌ | ✅ |
|
|
435
|
+
|
|
436
|
+
\*Playwright ติดตาม retry ภายใน แต่ไม่ผลิตรายงานความไม่นิ่งแบบ
|
|
437
|
+
ยืนเดี่ยวพร้อมป้ายคำพิพากษา
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## 🤖 ทำไมไม่ใช้แค่ AI code review?
|
|
442
|
+
|
|
443
|
+
ปัญหาต่างกัน ชั้นต่างกัน AI review เห็นการเปลี่ยนทดสอบที่น่าสงสัยใน
|
|
444
|
+
diff ได้ แต่มันไม่พิสูจน์ว่าระบบตรวจสอบทั้งหมดน่าไว้วางใจ — และมันเห็น
|
|
445
|
+
แค่ diff ที่คุณให้ดู
|
|
446
|
+
|
|
447
|
+
| | AI code review (Copilot ฯลฯ) | **Mjölnir** |
|
|
448
|
+
| ------------------------------------------- | :--------------------------: | :------------------------------------: |
|
|
449
|
+
| ต้นทุนต่อการสแกน | Tokens (ขยายตามขนาด diff) | **ศูนย์** (ทำงานในเครื่อง ติดตั้งแล้ว) |
|
|
450
|
+
| เห็นทั้งชุดทดสอบ + ทุก config CI | เฉพาะ PR diff ที่คุณให้ดู | **ทุกอย่าง ทุกครั้ง** |
|
|
451
|
+
| กำหนดตาย (input เดียวกัน → output เดียวกัน) | ❌ (ไม่กำหนดตาย) | **✅** |
|
|
452
|
+
| จับรูปแบบที่หลับมาหลายเดือน | เฉพาะถ้าอยู่ในบริบท | **✅** (สแกนทุกไฟล์) |
|
|
453
|
+
| จำ finding ข้ามการรัน | ❌ (ไม่มีความจำข้ามเซสชัน) | **✅** (baseline + diff) |
|
|
454
|
+
| รันโดยไม่ต้องมีคนสั่ง | ต้องมี PR หรือ prompt | **✅** (hook CI, 3 วินาที) |
|
|
455
|
+
|
|
456
|
+
**ใช้ทั้งสอง** AI เก็บรายละเอียดปลีกย่อย เจตนา และข้อบกพร่องเชิงออกแบบ
|
|
457
|
+
ที่ regex หาไม่เจอ Mjölnir เก็บรูปแบบเชิงโครงสร้างที่ AI มองข้ามเพราะ
|
|
458
|
+
มันดู «ตั้งใจ» — `.only` ที่ถูก commit, exit code ที่ถูกกลืน,
|
|
459
|
+
`continue-on-error` บน job ทดสอบ นี่ไม่ใช่บั๊กที่ต้องใช้การใคร่ครวญ;
|
|
460
|
+
นี่คือข้อเท็จจริงที่ต้องใช้การสแกน
|
|
461
|
+
|
|
462
|
+
---
|
|
463
|
+
|
|
464
|
+
## 🤖 การเชื่อมต่อ CI
|
|
465
|
+
|
|
466
|
+
คำสั่งเดียวสร้าง PR workflow — เป็นแบบที่ปรึกษาโดยดีฟอลต์ ไม่เคยบล็อก:
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
mjolnir ci install
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
หรือต่อเข้า GitHub Code Scanning แบบ native ผ่าน SARIF:
|
|
473
|
+
|
|
474
|
+
```yaml
|
|
475
|
+
- run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
|
|
476
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
477
|
+
with:
|
|
478
|
+
sarif_file: mjolnir.sarif
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
การตั้งค่า editor และ pipeline สำหรับ SARIF:
|
|
482
|
+
[docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md)
|
|
483
|
+
|
|
484
|
+
### ความครอบคลุมแบบ changed scope
|
|
485
|
+
|
|
486
|
+
`--scope changed` ผูก finding กับบรรทัดที่ branch คุณเพิ่ม เทียบกับ
|
|
487
|
+
merge-base กับ `main` ครอบคลุมไฟล์ทดสอบ (`*.spec.*`, `*.test.*`) บวก
|
|
488
|
+
ไฟล์ GitHub workflow และ config Playwright ใน diff เมื่อ merge-base
|
|
489
|
+
หาค่าไม่ได้ — shallow clone, detached HEAD, เป้าหมายไม่ใช่ git,
|
|
490
|
+
default branch ต่างกัน — มันลดรูปอย่างซื่อสัตย์: finding กลับไปผูก
|
|
491
|
+
ทั้งไฟล์ และรายงานก็บอก แทนที่ base ref ได้ด้วย `--base <ref>`
|
|
492
|
+
|
|
493
|
+
---
|
|
494
|
+
|
|
495
|
+
## การตั้งค่า
|
|
496
|
+
|
|
497
|
+
Mjölnir เป็น zero-config `mjolnir.config.json` (หรือ `.mjolnir.json`)
|
|
498
|
+
ทางเลือกที่ราก repo ปรับ severity, gating และ scope — ไม่เคยเปลี่ยน
|
|
499
|
+
ความหมายการตรวจจับ
|
|
500
|
+
|
|
501
|
+
| Key | ชนิด | ผล |
|
|
502
|
+
| ------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
503
|
+
| `exclude` | `string[]` | glob ignore เพิ่มเติม (ส่วนย่อยของ gitignore) บนค่าดีฟอลต์ที่มีให้ |
|
|
504
|
+
| `gate` | `"advisory" \| "error" \| "warning"` | ความรุนแรงระดับใดที่ออกด้วยเลขไม่ใช่ศูนย์ (ดีฟอลต์ `error`; `advisory` ไม่เคยบล็อก) |
|
|
505
|
+
| `severityOverrides` | `{ "<RULE-ID>": severity }` | จัดลำดับ finding ของกฎใหม่สำหรับ repo ของคุณ |
|
|
506
|
+
| `ignore` | `IgnoreEntry[]` | กด finding — **`reason` จำเป็น**; รายการหมดอายุใน 90 วัน (วันที่ `expires` ชัดเจน หรือเวลาแก้ไขล่าสุดของไฟล์ config สำหรับรายการที่ไม่ระบุ) |
|
|
507
|
+
| `plugins` | `string[]` | แพ็กเกจกฎบุคคลที่สาม (ดู [โมเดลความไว้วางใจ](#โมเดลความไว้วางใจ)) |
|
|
508
|
+
|
|
509
|
+
```json
|
|
510
|
+
{
|
|
511
|
+
"gate": "error",
|
|
512
|
+
"exclude": ["legacy/**"],
|
|
513
|
+
"severityOverrides": { "QA-PW-118": "warning" },
|
|
514
|
+
"ignore": [
|
|
515
|
+
{
|
|
516
|
+
"ruleId": "QA-TEST-004",
|
|
517
|
+
"files": ["e2e/legacy-login.spec.ts"],
|
|
518
|
+
"reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
|
|
519
|
+
"expires": "2026-12-31"
|
|
520
|
+
}
|
|
521
|
+
]
|
|
522
|
+
}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
- **`.mjolnirignore`** — ไฟล์สไตล์ gitignore เรียบ ๆ สำหรับยกเว้นพาธ
|
|
526
|
+
ภาษาเดียวกับ `exclude` ใช้มันสำหรับสัญญาณรบกวนเฉพาะเครื่อง; ใช้
|
|
527
|
+
`exclude` เมื่อรายการควรอยู่ใน version control ร่วมกับ config ที่เหลือ
|
|
528
|
+
- **CLI overrides** — `--strict` (รวมกฎกักกัน), `--width <cols>` และ
|
|
529
|
+
`--ascii` / `--no-ascii` (เรนเดอร์เทอร์มินัล), `--tone blunt`
|
|
530
|
+
(ข้อความตรงขึ้น), `--max-duration <sec>` (สแกนบางส่วนที่จำกัดเวลา)
|
|
531
|
+
- การกดกฎและวงจรชีวิตการเลิกใช้: [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md)
|
|
532
|
+
|
|
533
|
+
รายการ `ignore` ยังหล่อเลี้ยงคำสั่ง `mjolnir suppressions` แบบเดี่ยว
|
|
534
|
+
ซึ่งแสดงสิ่งที่ถูกกดอยู่ และเมื่อใดรายการแต่ละรายการหมดอายุ
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## 📐 รหัสออก & สัญญา
|
|
539
|
+
|
|
540
|
+
แช่แข็ง — ปลอดภัยที่จะสร้างตรรกะ CI บน:
|
|
541
|
+
|
|
542
|
+
| รหัสออก | ความหมาย |
|
|
543
|
+
| ------- | ----------------------------------------------------- |
|
|
544
|
+
| `0` | สะอาด — ไม่มี finding ที่ระดับเกตหรือสูงกว่า |
|
|
545
|
+
| `1` | มี finding ที่ระดับเกตหรือสูงกว่า |
|
|
546
|
+
| `2` | สแกนบางส่วน (หมดงบเวลา, ไฟล์อ่านไม่ได้) — ไม่เคยบล็อก |
|
|
547
|
+
| `10` | ใช้งานผิด (flag ผิด, ไม่ระบุเป้าหมาย) |
|
|
548
|
+
| `20` | ข้อผิดพลาดภายใน |
|
|
549
|
+
|
|
550
|
+
รายงาน JSON/SARIF คือ `schemaVersion: 1` rule ID (`QA-<FAMILY>-NNN`)
|
|
551
|
+
หลังปล่อยแล้วเปลี่ยนไม่ได้ และไม่เคยถูกนำกลับมาใช้
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## โมเดลความไว้วางใจ
|
|
556
|
+
|
|
557
|
+
- **Local-first** — ศูนย์การเรียกเครือข่ายระหว่างสแกน เด็ดขาด ศูนย์
|
|
558
|
+
เทเลเมทรี
|
|
559
|
+
- **ไม่มีหลักฐานปลอม** — เราพูด «ไม่รู้» มากกว่า «ตรวจแล้ว» repo ว่าง
|
|
560
|
+
ได้ `score: null` ไม่ใช่ 100 ปลอม
|
|
561
|
+
- **ความซื่อสัตย์บางส่วน** — ถ้าการวิเคราะห์ถูกตัดสั้น ผลลัพธ์บอก
|
|
562
|
+
ไม่เคย «เสร็จ» เมื่อไม่ได้เสร็จ
|
|
563
|
+
- **กำแพง FP** — การตรวจจับทำงานบนมุมมองโค้ดที่ปราศจากคอมเมนต์/สตริง
|
|
564
|
+
(กฎ TypeScript ใช้ AST คอมไพเลอร์): รูปแบบในคอมเมนต์ร้อยเรียงหรือ
|
|
565
|
+
สตริงตัวอย่างเอกสาร คือเอกสาร ไม่ใช่ finding
|
|
566
|
+
- **วัด ไม่ใช่อ้าง** — เฉพาะกฎที่มีอัตรา false positive จากโค้ด OSS จริง
|
|
567
|
+
จึงอยู่ใน tier พาดหัว (ดู [วัดไปแล้วเท่าไร](#วัดไปแล้วเท่าไร));
|
|
568
|
+
ส่วนท้ายการสแกนและ `mjolnir rules --unmeasured` บอกว่ากฎไหนสถานะไหน
|
|
569
|
+
- **ความไว้วางใจต่อปลั๊กอิน** — ปลั๊กอินคือแพ็กเกจ npm ประกาศใต้
|
|
570
|
+
`"plugins"` **ไม่มี sandbox**: โค้ดปลั๊กอินรันด้วยสิทธิ์ Node เต็ม
|
|
571
|
+
โมเดลความไว้วางใจเดียวกับปลั๊กอิน ESLint หรือ Vitest คำนำหน้า rule ID
|
|
572
|
+
ของ core สงวนไว้และถูกปฏิเสธจากปลั๊กอิน เพื่อกันการอ้างปลอม
|
|
573
|
+
- **กฎภายนอกประจำ workspace** (อิงโฟลเดอร์ ศูนย์เครือข่าย) — ไดเรกทอรี
|
|
574
|
+
`mjolnir-rules/` ติดกับเป้าสแกนโหลดกฎกำหนดเอง: ไฟล์ JSON ประกาศรูปแบบ
|
|
575
|
+
regex (ไม่รันโค้ด) โมดูล `.mjs`/`.js` export `rules` (ความไว้วางใจ
|
|
576
|
+
Node เต็ม เหมือนปลั๊กอิน) กฎภายนอกพก trust metadata เดียวกับ core;
|
|
577
|
+
ไม่เคยขึ้นไปใน tier core (core ต้องมีอัตรา FP ที่วัดจาก sidecar
|
|
578
|
+
corpus — `tier: "core"` ที่ประกาศมาถูกบีบลงเหลือ `extended`),
|
|
579
|
+
ทำตามเพดาน tier และถูกตรวจเรื่องเหลื่อมล้ำ: `mjolnir rules --md
|
|
580
|
+
--external` เรนเดอร์แคตตาล็อกจากไฟล์ที่โหลด (แหล่งที่มา `external`)
|
|
581
|
+
และตัวสร้างเมทริกซ์รับ `--external <root>`
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## 🏗️ สถาปัตยกรรม
|
|
586
|
+
|
|
587
|
+
<details>
|
|
588
|
+
<summary>ขยายแผนผัง</summary>
|
|
589
|
+
|
|
590
|
+
```
|
|
591
|
+
mjolnir/
|
|
592
|
+
├── src/
|
|
593
|
+
│ ├── engine/ # LanguageAdapter interface + rule runner
|
|
594
|
+
│ ├── adapters/ # typescript · python · java · csharp · github-actions
|
|
595
|
+
│ ├── rules/ # rules across 8 families + the measured-FP table
|
|
596
|
+
│ ├── playwright/ # Selector Health Score engine
|
|
597
|
+
│ ├── discovery/ # workspace, frameworks, ignore resolution
|
|
598
|
+
│ ├── scope/ # git merge-base changed-scope engine
|
|
599
|
+
│ ├── scorer/ # transparent deduction table + prioritization
|
|
600
|
+
│ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
|
|
601
|
+
│ ├── forensics/ # run-data ingestion · flake verdicts · triage
|
|
602
|
+
│ ├── config/ # mjolnir.config.json + suppressions
|
|
603
|
+
│ ├── plugins/ # third-party rule loading (no sandbox)
|
|
604
|
+
│ └── commands/ # every subcommand
|
|
605
|
+
└── tests/
|
|
606
|
+
├── fixtures/ # must-fire / must-not-fire per rule
|
|
607
|
+
└── golden/ # frozen score regression locks
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
</details>
|
|
611
|
+
|
|
612
|
+
- **กฎเป็นฟังก์ชันบริสุทธิ์** — `(SourceFileContext) → Finding[]`,
|
|
613
|
+
ไม่มี I/O ไม่มี global เพิ่มระบบนิเวศใหม่ = หนึ่ง adapter + กฎของมัน
|
|
614
|
+
- **TypeScript/Playwright ใช้ AST คอมไพเลอร์** (ts-morph) Python, Java
|
|
615
|
+
และ C# รันบนชั้น regex ร่วมกันที่ปิดบังคอมเมนต์/สตริง
|
|
616
|
+
- ชั้น AST tree-sitter WASM สำหรับ Java และ C# มีอยู่และเป็นก้าวความ
|
|
617
|
+
แม่นยำถัดไป — ยังไม่ได้เสียบเข้ากับ pipeline สแกนแบบซิงโครนัส
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## 📚 เอกสาร
|
|
622
|
+
|
|
623
|
+
| เอกสาร | มีอะไรในนั้น |
|
|
624
|
+
| ------------------------------------------------------ | ----------------------------------------------- |
|
|
625
|
+
| [docs/SCORING.md](docs/SCORING.md) | การ normalize คะแนน + การถ่วงน้ำหนักด้วยหลักฐาน |
|
|
626
|
+
| [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | อัตรา false positive ที่วัดได้ + วิธีวัด |
|
|
627
|
+
| [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | สถานะกฎ การกด การเลิกใช้ |
|
|
628
|
+
| [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | ผลลัพธ์ SARIF + การตั้งค่า editor/CI |
|
|
629
|
+
| [docs/rules/](docs/rules/) | แคตตาล็อกต่อกฎที่สร้างอัตโนมัติ |
|
|
630
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | การตั้งค่า dev + ขั้นตอนการร่วมพัฒนา |
|
|
631
|
+
| [CHANGELOG.md](CHANGELOG.md) | ประวัติการเผยแพร่ |
|
|
632
|
+
| [SECURITY.md](SECURITY.md) | รายงานช่องโหว่ |
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## 📈 สถานะ
|
|
637
|
+
|
|
638
|
+
**v0.5.x · โอเพนเบตา** JSON schema และรหัสออกเป็นสัญญาแช่แข็ง
|
|
639
|
+
TypeScript และ Python มีความครอบคลุมที่วัดได้กว้างสุด; Java และ C#
|
|
640
|
+
ใหม่กว่า — อ่านผ่าน
|
|
641
|
+
[ตาราง tier](#tier-ของกฎและความสุกงอมของภาษา)
|
|
642
|
+
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
## 🤝 ร่วมพัฒนา
|
|
646
|
+
|
|
647
|
+
กฎใหม่คือรายการแรกที่ง่ายที่สุด — หนึ่งคำสั่งสร้างโครงกฎพร้อม fixture
|
|
648
|
+
must-fire **และ** must-not-fire (กฎที่สร้างให้จงใจล้มเหลวบน fixture
|
|
649
|
+
จนกว่าคุณจะเขียนการตรวจจับจริง — stub ปล่อยไม่ได้):
|
|
650
|
+
|
|
651
|
+
```bash
|
|
652
|
+
mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
การตั้งค่า dev เต็มรูปแบบ คำสั่ง standing gate และกฎหมาย anti-creep /
|
|
656
|
+
กำแพง fixture อยู่ใน [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
660
|
+
<div align="center">
|
|
661
|
+
|
|
662
|
+
**หยุดปล่อยการทดสอบที่คุณไว้วางใจไม่ได้**
|
|
663
|
+
|
|
664
|
+
```bash
|
|
665
|
+
npx mjolnir-qa@latest
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
**Star ⭐ · Watch 👀 · Contribute 🤝**
|
|
669
|
+
|
|
670
|
+
สร้างโดย [Sergey Bar](https://www.linkedin.com/in/sergeybar/)
|
|
671
|
+
|
|
672
|
+
</div>
|