@educa-corp/sdd-framework 0.9.5 → 0.9.6
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/bin/build.js +11 -1
- package/bin/lint-trace.js +397 -28
- package/bin/self-check.js +183 -12
- package/bin/trace-schema.json +2656 -1981
- package/core/FRAMEWORK_VERSION +1 -1
- package/core/commands/dev-gen-test.md +62 -0
- package/core/commands/generate-code.md +1 -1
- package/core/commands/generate-tech-docs.md +3 -3
- package/core/commands/map-testids.md +88 -11
- package/core/commands/qc-analyze.md +509 -425
- package/core/commands/qc-design-test.md +475 -247
- package/core/commands/qc-plan.md +134 -93
- package/core/commands/qc-review.md +216 -131
- package/core/commands/qc-run-test.md +346 -231
- package/core/commands/validate-traces.md +17 -2
- package/core/rules/workflow.md +40 -0
- package/core/skills/qc/qa-analyst/DOC_GAP.template.md +9 -1
- package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +33 -5
- package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +24 -0
- package/core/skills/qc/qa-planner/test-plan.md +7 -0
- package/core/skills/qc/qa-runner/functional/gui-feature.md +1 -1
- package/core/skills/qc/qa-runner/functional/gui-screen.md +1 -1
- package/core/steps/qc-scope.md +67 -11
- package/core/steps/qc-stamp.md +142 -0
- package/core/steps/report-footer.md +13 -5
- package/core/templates/tech-design.template.md +3 -3
- package/docs/01-getting-started/quickstart.md +4 -3
- package/docs/02-concepts/architecture.md +14 -0
- package/docs/02-concepts/glossary.md +8 -0
- package/docs/02-concepts/overview.md +3 -2
- package/docs/02-concepts/pipeline-steps/04-bdd.md +1 -1
- package/docs/02-concepts/pipeline-steps/05-tech-docs.md +21 -5
- package/docs/02-concepts/pipeline-steps/06-code.md +12 -2
- package/docs/02-concepts/pipeline-steps/08-qc-automation.md +60 -12
- package/docs/02-concepts/pipeline-steps/README.md +4 -3
- package/docs/02-concepts/traceability.md +2 -2
- package/docs/03-guides/architect.md +2 -2
- package/docs/03-guides/developer.md +5 -2
- package/docs/03-guides/tester-qa.md +17 -5
- package/docs/04-reference/commands.md +6 -3
- package/docs/04-reference/trace-schema.md +1 -1
- package/docs/explain/07-generate-tech-docs.md +5 -3
- package/docs/explain/08-review-tech-docs.md +15 -3
- package/docs/explain/09-generate-code.md +30 -4
- package/docs/explain/10-review-code.md +1 -1
- package/docs/explain/11-map-testids.md +72 -70
- package/docs/explain/12-dev-gen-test.md +1 -1
- package/docs/explain/15-qc-analyze.md +14 -2
- package/docs/explain/16-qc-plan.md +5 -1
- package/docs/explain/17-qc-design-test.md +26 -3
- package/docs/explain/18-qc-review.md +6 -2
- package/docs/explain/19-qc-run-test.md +29 -6
- package/docs/explain/20-qc-report.md +5 -2
- package/docs/explain/README.md +4 -1
- package/package.json +1 -1
|
@@ -14,14 +14,15 @@ Code là **hệ quả của spec**. Command biến scenario thành code sao cho:
|
|
|
14
14
|
|
|
15
15
|
## Vị trí & tiền đề
|
|
16
16
|
|
|
17
|
-
- **Vị trí:** Phase Implementation, sau BDD + tech-docs.
|
|
17
|
+
- **Vị trí:** Phase Implementation, sau BDD + tech-docs + [`/map-testids`](11-map-testids.md).
|
|
18
|
+
- **Chạy song song với QC.** Hợp đồng test-id (§4.5.6) đã đóng băng trước bước này, nên FE gắn attribute còn QC dựng test **cùng lúc** trên cùng một bảng — không bên nào chờ bên nào, không bên nào tự đặt id.
|
|
18
19
|
- **Gate vào:** cảnh báo mềm DS1 (BDD chưa approved), DS2 (design-spec), DS3 (tech-doc contract BE), **DS4** (client contract §4.5.4) + **DS5** (FE reuse gate) — DS4/DS5 chỉ khi wire API thật (`integration`/`fe_full`). Xem [Hành vi theo mode](#hành-vi-theo-mode-phase--platform).
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
22
23
|
## Input / Output
|
|
23
24
|
|
|
24
|
-
**Input:** `.feature` (hoặc UC-ID) + tech-design §4 + CLAUDE.md §2/§3/§5 + `.trace/…/{UC-ID}-{platform}.tsv` + `_seams.tsv`.
|
|
25
|
+
**Input:** `.feature` (hoặc UC-ID) + tech-design §4 + **hợp đồng test-id** (`@trace.testid_attr` ở header + §4.5.6 Test Selectors) + CLAUDE.md §2/§3/§5 + `.trace/…/{UC-ID}-{platform}.tsv` + `_seams.tsv`.
|
|
25
26
|
|
|
26
27
|
**Output:** file code (tag `@trace` boundary) + trace row `.tsv` + cập nhật `_seams.tsv`.
|
|
27
28
|
|
|
@@ -64,7 +65,7 @@ Code là **hệ quả của spec**. Command biến scenario thành code sao cho:
|
|
|
64
65
|
| **DS4** — client contract gate (§4.5.4) | ⏭️ cố ý | ✅ | ✅ | — |
|
|
65
66
|
| **DS5** — FE component/service reuse gate | ⏭️ | ✅ | ✅ | — |
|
|
66
67
|
| **Sinh UI** (Figma MCP, component, state) | ✅ | ⏭️ giữ UI cũ | ✅ | — |
|
|
67
|
-
| **Test Selectors** (emit
|
|
68
|
+
| **Test Selectors** (**đọc** §4.5.6 rồi emit, xem dưới) | ✅ | ⏭️ | ✅ | — |
|
|
68
69
|
| **Mock API Layer** | ✅ | ⏭️ | ⏭️ | — |
|
|
69
70
|
| **Integration Phase** (real API adapter) | ⏭️ | ✅ | ✅ | — |
|
|
70
71
|
| **Wire-up API** | dùng **mock** | **lật** mock→real | wire **thẳng** real | — (BE là API) |
|
|
@@ -83,6 +84,29 @@ Code là **hệ quả của spec**. Command biến scenario thành code sao cho:
|
|
|
83
84
|
|
|
84
85
|
---
|
|
85
86
|
|
|
87
|
+
### Test Selectors — ĐỌC hợp đồng, không tự đặt *(đổi ở đợt sửa hợp đồng test-id)*
|
|
88
|
+
|
|
89
|
+
Trước đây lệnh này **tự sinh** test-id khi §4.5.6 rỗng. Đó là lỗi **im lặng**: QC đang viết script theo một bảng khác (hoặc không có bảng nào), và không ai báo cho ai.
|
|
90
|
+
|
|
91
|
+
**Giá trị** test-id lấy từ §4.5.6:
|
|
92
|
+
|
|
93
|
+
| Tình huống | Hành vi |
|
|
94
|
+
|---|---|
|
|
95
|
+
| §4.5.6 **có dòng** | Dùng đúng giá trị trong bảng |
|
|
96
|
+
| §4.5.6 **rỗng** | ⚠️ **Cảnh báo mạnh rồi hỏi Y/N.** Đường đúng là dừng, chạy `/map-testids`. Tiếp tục là **quyết định của dev**, không phải mặc định của máy |
|
|
97
|
+
|
|
98
|
+
**Tên thuộc tính** lấy từ `@trace.testid_attr` ở header tech-doc:
|
|
99
|
+
|
|
100
|
+
| Tình huống | Hành vi |
|
|
101
|
+
|---|---|
|
|
102
|
+
| Header có field | Dùng đúng tên đó (`data-testid` · `data-test` · `testID` · `Key`…) |
|
|
103
|
+
| Header **không có** | Cảnh báo mềm **nêu rõ rủi ro** → fallback theo `active_module`. Không im lặng hardcode |
|
|
104
|
+
| `.feature` cũng khai attr và **lệch** header | In **cả hai** giá trị, để người quyết. Không tự chọn bên nào |
|
|
105
|
+
|
|
106
|
+
> **Vì sao không suy từ platform cho nhanh:** suy từ platform là **phát biểu lại một sự thật đã ghi ở nơi khác**. Nó hỏng đúng ở ca field này sinh ra để phục vụ — web dùng `data-test`/`data-qa` thay vì mặc định, hoặc một PRD trải ba platform với ba thuộc tính khác nhau. Và nó hỏng **im lặng theo kiểu tệ nhất**: test fail `element not found`, trông y hệt một bug sản phẩm, nên QC đi mở bug thay vì sửa selector.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
86
110
|
## Checkpoint & Gate
|
|
87
111
|
|
|
88
112
|
- 🛑 **Comprehension checkpoint** (Code Generation Plan) — điểm dừng chính; Dev xác nhận drift + scope đúng.
|
|
@@ -113,4 +137,6 @@ Code là **hệ quả của spec**. Command biến scenario thành code sao cho:
|
|
|
113
137
|
|
|
114
138
|
## Kết nối
|
|
115
139
|
|
|
116
|
-
**Trước:** [`/review-tech-docs`](08-review-tech-docs.md) · **Sau:** lần đầu → [`/review-code`](10-review-code.md); gen lại → [`/dev-gen-test`](12-dev-gen-test.md).
|
|
140
|
+
**Trước:** [`/map-testids`](11-map-testids.md) → [`/review-tech-docs`](08-review-tech-docs.md) · **Song song:** [`/qc-design-test`](17-qc-design-test.md) · **Sau:** lần đầu → [`/review-code`](10-review-code.md); gen lại → [`/dev-gen-test`](12-dev-gen-test.md).
|
|
141
|
+
|
|
142
|
+
> Test-id sinh ra **không khớp code thật** → sửa bằng `/map-testids --from-code`, đừng sửa tay bảng. Lệnh đó tự hạ `qc_status` → `not_run` và `qc_run_at` → `—`, để QC biết test-script bám selector cũ đã hết hiệu lực.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[← /generate-code](09-generate-code.md) · [Explain Home](README.md) · [Next: /
|
|
1
|
+
[← /generate-code](09-generate-code.md) · [Explain Home](README.md) · [Next: /dev-gen-test →](12-dev-gen-test.md)
|
|
2
2
|
|
|
3
3
|
# 10 · `/review-code` — Review code (read-only, 4 dimension)
|
|
4
4
|
|
|
@@ -1,70 +1,72 @@
|
|
|
1
|
-
[← /
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
- **
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
|
36
|
-
|
|
37
|
-
| **
|
|
38
|
-
| **
|
|
39
|
-
| **
|
|
40
|
-
| **
|
|
41
|
-
| **
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- **
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
- **
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
1
|
+
[← /generate-tech-docs](07-generate-tech-docs.md) · [Explain Home](README.md) · [Next: /review-tech-docs →](08-review-tech-docs.md)
|
|
2
|
+
|
|
3
|
+
> **Số `11` là số file lịch sử, không phải thứ tự chạy.** Lệnh này chạy ở **Phase Design**, giữa `/generate-tech-docs` và `/review-tech-docs` — tức **trước** `/generate-code`. Giữ nguyên tên file để không gãy link cũ.
|
|
4
|
+
|
|
5
|
+
# 11 · `/map-testids` — Dán test-id ổn định cho UI (FE)
|
|
6
|
+
|
|
7
|
+
> **Một câu.** Gắn **test-id ổn định** vào các element có hành động trên UI FE và ghi bản đồ selector vào tech-doc §4.5.6 — làm cầu nối để QC Playwright bám selector không vỡ.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Vấn đề giải quyết
|
|
12
|
+
|
|
13
|
+
Test tự động (Playwright) vỡ khi selector đổi (class/text thay đổi). `/map-testids` chuẩn hoá **test-id ổn định** cho mọi element tương tác, đảm bảo component tái dùng forward được test-id, và ghi map để QC dùng — tách concern "làm UI test được" khỏi "viết test".
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Vị trí & tiền đề
|
|
18
|
+
|
|
19
|
+
- **Vị trí:** Phase **Tech Design**, sau `/generate-tech-docs` và **TRƯỚC** `/review-tech-docs` — tức trước cả `/generate-code`. Chốt hợp đồng test-id ở đây để FE và QC đọc cùng một bản đã đóng băng rồi **chạy song song**.
|
|
20
|
+
- **Hai chế độ:** mặc định (feature mới — nguồn là design-spec + BDD, **không đụng code**) · `--from-code` (brownfield — đọc/patch code đã có, chạy một lần mỗi UC cũ).
|
|
21
|
+
- **Chặn cứng:** chỉ FE/App (platform guard) — BE không có UI.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Input / Output
|
|
26
|
+
|
|
27
|
+
**Input:** design-spec (Component Inventory, màn hình) + step `When` của `.feature` FE + tech-doc §4.5.1 (cây component) + catalog component tái dùng. *Chế độ `--from-code` đọc thêm UI code FE.*
|
|
28
|
+
|
|
29
|
+
**Output:** map §4.5.6 Test Selectors + `@trace.testid_attr` ở header tech-doc. *Chế độ `--from-code` còn patch test-id vào code FE.*
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Các bước xử lý (chi tiết)
|
|
34
|
+
|
|
35
|
+
| Step | Việc |
|
|
36
|
+
|------|------|
|
|
37
|
+
| **0 · Platform guard** | Chỉ FE/App; else STOP |
|
|
38
|
+
| **1 · Thu thập element có action** | Quét UI tìm element người dùng tương tác (nút, ô nhập, link…) |
|
|
39
|
+
| **2 · Phân giải test-id ổn định** | Đặt test-id ổn định (không phụ thuộc text/class dễ đổi) cho mỗi element |
|
|
40
|
+
| **3 · Đảm bảo component tái dùng forward test-id** | Component dùng lại (catalog) phải cho phép truyền test-id xuống — sửa component nếu chưa |
|
|
41
|
+
| **4 · Patch usage site** (chỉ EXTEND) | Gắn test-id vào nơi dùng, chỉ thêm (không viết đè) |
|
|
42
|
+
| **5 · Ghi/làm mới map §4.5.6** | Ghi bảng Test Selectors vào tech-doc để QC bám |
|
|
43
|
+
| **6 · Handoff** | Bàn giao cho QC (`/qc-*`) |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Checkpoint & Gate
|
|
48
|
+
|
|
49
|
+
- Không gate chặn; EXTEND-only khi patch (an toàn).
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Cơ chế đặc biệt
|
|
54
|
+
|
|
55
|
+
- **Test-id ổn định** — chống test vỡ do đổi visual; nguyên tắc "selector là contract QC↔FE".
|
|
56
|
+
- **Forward test-id qua component tái dùng** — sửa gốc component để test-id lan xuống, không hardcode từng chỗ.
|
|
57
|
+
- **Map ở §4.5.6 tech-doc** — QC đọc từ một nguồn, không tự dò.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 👓 Góc nhìn tối ưu
|
|
62
|
+
|
|
63
|
+
- **Lệnh chốt hợp đồng FE↔QC** — vị trí **đã được chốt**: phase Tech Design, trước `/generate-code`. Trước đây vị trí mờ (tài liệu này từng nói 'giữa Tech Design & Code') nên lệnh hay bị bỏ qua; giờ `/generate-tech-docs` trỏ thẳng sang đây, và `/review-tech-docs` T6 không cho APPROVED nếu §4.5.6 rỗng.
|
|
64
|
+
- **Phụ thuộc catalog component tái dùng** — nếu component không forward được prop test-id, Step 3 phát sinh sửa lan rộng.
|
|
65
|
+
- **EXTEND-only** an toàn nhưng nếu test-id cũ sai thì không tự sửa.
|
|
66
|
+
- **Đã vào golden path** — `/generate-tech-docs` → **`/map-testids`** → `/review-tech-docs` (T6 chặn nếu §4.5.6 rỗng). `lint-trace` T15/T16 canh bảng, T17/T18 canh bảng-vs-code.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Kết nối
|
|
71
|
+
|
|
72
|
+
**Trước:** [`/generate-tech-docs`](07-generate-tech-docs.md) · **Sau:** [`/review-tech-docs`](08-review-tech-docs.md), rồi rẽ hai nhánh song song — [`/generate-code`](09-generate-code.md) (FE gắn attribute) ∥ [`/qc-design-test`](17-qc-design-test.md) (QC dựng test theo cùng hợp đồng).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[← /
|
|
1
|
+
[← /review-code](10-review-code.md) · [Explain Home](README.md) · [Next: /dev-run-test →](13-dev-run-test.md)
|
|
2
2
|
|
|
3
3
|
# 12 · `/dev-gen-test` — Sinh bộ tự-kiểm của Dev
|
|
4
4
|
|
|
@@ -26,7 +26,7 @@ QC chính thức cần hiểu yêu cầu **testable** trước khi viết test.
|
|
|
26
26
|
|
|
27
27
|
**Input:** UC-ID + spec (PRD/BDD từ spec repo) + skill `qa-analyst`.
|
|
28
28
|
|
|
29
|
-
**Output (per PRD × nền):** `{qc_dir}/{TICKET-ID}/{platform}/REQUIREMENT_ANALYSIS.md` + `DOC_GAP.md` (11 cột, cột 2 là `UC`) + `{refinement_dir}/{TICKET-ID}-qa-findings.yaml`. Một lần chạy phủ **mọi UC có BDD `approved`** của PRD; UC còn nháp vào bảng *Phạm vi phân tích* với dấu `⏸ Chưa xét` (`--
|
|
29
|
+
**Output (per PRD × nền):** `{qc_dir}/{TICKET-ID}/{platform}/REQUIREMENT_ANALYSIS.md` + `DOC_GAP.md` (11 cột, cột 2 là `UC`) + `{refinement_dir}/{TICKET-ID}-qa-findings.yaml`. Một lần chạy phủ **mọi UC có BDD `approved`** của PRD; UC còn nháp vào bảng *Phạm vi phân tích* với dấu `⏸ Chưa xét` (`--force` để xét luôn).
|
|
30
30
|
|
|
31
31
|
---
|
|
32
32
|
|
|
@@ -37,7 +37,19 @@ QC chính thức cần hiểu yêu cầu **testable** trước khi viết test.
|
|
|
37
37
|
3. **Role qa-analyst** — nạp skill `{qc_skills_dir}/qa-analyst/`.
|
|
38
38
|
4. **Trace mapping (bắt buộc)** — map yêu cầu ↔ scenario ↔ SC.
|
|
39
39
|
5. **DOC_GAP (bắt buộc)** — ghi chỗ tài liệu thiếu/mơ hồ chặn test (blocker 🔴 xử trước ở `/qc-plan`).
|
|
40
|
-
6. **
|
|
40
|
+
6. **Guard — BR-tag** *(mới)* — phép **đếm cơ học** chống bỏ sót business rule:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
A = mọi business rule mà .feature ĐÃ GẮN TAG (@trace.business_rules)
|
|
44
|
+
B = mọi rule bản phân tích VỪA SINH RA (REQUIREMENT_ANALYSIS.md)
|
|
45
|
+
A ∖ B → rule BDD đã nhắc mà phân tích BỎ SÓT
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`A ∖ B` rỗng → in `Guard BR-tag: khớp {n}/{n}`. Không rỗng → **tự bổ sung từ PRD** rồi in danh sách đã bù. **In dòng này kể cả khi sạch** — guard im lặng khi sạch là guard không ai biết nó tồn tại.
|
|
49
|
+
7. **Self-Review** — nạp `skills/qc/_shared/self-review-principles.md`, soát một lượt trước khi in report.
|
|
50
|
+
8. **Output** REQUIREMENT_ANALYSIS.md + DOC_GAP.md.
|
|
51
|
+
> **Self-Review ≠ Guard.** Guard là phép **đếm cơ học**, có hệ quả bắt buộc khi lệch. Self-review là lượt đọc lại **rộng hơn nhưng mềm hơn**, soát ba nhóm lỗi mà phép đếm không bắt được (bịa dữ kiện · lẫn suy đoán với sự thật · bỏ dở giữa chừng). Một bộ nguyên tắc tự soát **không bao giờ** được dùng làm lý do gỡ một Guard — chính file `self-review-principles.md` ghi rõ ranh giới đó ngay ở đầu.
|
|
52
|
+
|
|
41
53
|
|
|
42
54
|
---
|
|
43
55
|
|
|
@@ -32,7 +32,10 @@ Không phải mọi scenario rủi ro ngang nhau. Trạm này xếp ưu tiên te
|
|
|
32
32
|
1. **Role qa-planner** — nạp `{qc_skills_dir}/qa-planner/`.
|
|
33
33
|
2. Đọc analysis + gap → **đánh giá rủi ro** từng vùng.
|
|
34
34
|
3. Nêu **câu hỏi cho dev** (điểm chưa rõ để test đúng).
|
|
35
|
-
4. **
|
|
35
|
+
4. **Self-Review** *(mới)* — nạp `skills/qc/_shared/self-review-principles.md`, soát một lượt trước khi in report.
|
|
36
|
+
5. **Output** TEST_PLAN.md.
|
|
37
|
+
> **Self-Review ≠ Guard.** Guard là phép **đếm cơ học**, có hệ quả bắt buộc khi lệch. Self-review là lượt đọc lại **rộng hơn nhưng mềm hơn**, soát ba nhóm lỗi mà phép đếm không bắt được (bịa dữ kiện · lẫn suy đoán với sự thật · bỏ dở giữa chừng). Một bộ nguyên tắc tự soát **không bao giờ** được dùng làm lý do gỡ một Guard — chính file `self-review-principles.md` ghi rõ ranh giới đó ngay ở đầu.
|
|
38
|
+
|
|
36
39
|
|
|
37
40
|
---
|
|
38
41
|
|
|
@@ -46,6 +49,7 @@ Không phải mọi scenario rủi ro ngang nhau. Trạm này xếp ưu tiên te
|
|
|
46
49
|
|
|
47
50
|
- **Risk-based** — kế hoạch bám rủi ro, không phủ đều.
|
|
48
51
|
- **Câu hỏi cho dev** — kênh QC ↔ Dev có hồ sơ trước khi viết test.
|
|
52
|
+
- **Self-Review dùng chung** — sáu trạm QC nạp **cùng một** file nguyên tắc, không mỗi trạm một bản. Sáu bản sao thì sáu tháng sau sẽ là sáu luật khác nhau, **im lặng**.
|
|
49
53
|
|
|
50
54
|
---
|
|
51
55
|
|
|
@@ -15,12 +15,13 @@ Tách "thiết kế test case" (con người đọc/review được) khỏi "cod
|
|
|
15
15
|
## Vị trí & tiền đề
|
|
16
16
|
|
|
17
17
|
- **Vị trí:** Phase QC (trạm 3), sau `/qc-plan`.
|
|
18
|
+
- **Không cần code.** Trạm này chỉ cần spec + **hợp đồng test-id §4.5.6** (đã chốt ở `/map-testids`, trước `/generate-code`). Nên nó chạy **song song với FE**.
|
|
18
19
|
|
|
19
20
|
---
|
|
20
21
|
|
|
21
22
|
## Input / Output
|
|
22
23
|
|
|
23
|
-
**Input:** TEST_PLAN.md + skill `qa-designer` (chọn layer, nạp MỘT file).
|
|
24
|
+
**Input:** TEST_PLAN.md + skill `qa-designer` (chọn layer, nạp MỘT file) + `.feature` (nguồn scenario cho Guard) + **§4.5.6 Test Selectors**.
|
|
24
25
|
|
|
25
26
|
**Output:** `{qc_dir}/{TICKET-ID}/{platform}/test-cases/*.Test.md` (trace mapping bắt buộc). Gọi theo **từng UC**, ghi vào thư mục test-case dùng chung cấp PRD.
|
|
26
27
|
|
|
@@ -31,13 +32,31 @@ Tách "thiết kế test case" (con người đọc/review được) khỏi "cod
|
|
|
31
32
|
1. **Role qa-designer** — chọn layer, nạp một file skill (không nạp cả bộ → tiết kiệm context).
|
|
32
33
|
2. **Conventions** — theo quy ước test-case của QC team.
|
|
33
34
|
3. **Trace mapping (bắt buộc)** — mỗi test case ↔ SC.
|
|
34
|
-
4. **
|
|
35
|
+
4. **Guard — SC coverage** *(mới)* — phép **đếm cơ học**, không phải lượt đọc lại:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
1. Thu SC — mọi @trace.scenario trong .feature của uc_list (đúng nền).
|
|
39
|
+
LOẠI SC của UC mà qc-scope đã lọc ra (⏸ BDD chưa approved).
|
|
40
|
+
2. Thu V — mọi @trace.verifies trong các file *.Test.md VỪA GHI.
|
|
41
|
+
3. Đếm — mỗi SC ∈ tập bước 1 phải có ≥ 1 TC trỏ tới.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Kết quả | Hành vi |
|
|
45
|
+
|---|---|
|
|
46
|
+
| Mọi SC đều có ≥1 TC | in `Guard SC coverage: khớp {K}/{K}` |
|
|
47
|
+
| Có SC chưa phủ | **viết bù TC ngay**, rồi in `⚠️ Guard SC coverage: {K}/{total} — đã bù {m} SC: {…}` |
|
|
48
|
+
|
|
49
|
+
**In dòng này kể cả khi sạch** — guard im lặng khi sạch là guard không ai biết nó tồn tại, nên cũng không ai phát hiện khi nó hỏng.
|
|
50
|
+
|
|
51
|
+
5. **Self-Review** — nạp `skills/qc/_shared/self-review-principles.md`, soát một lượt trước khi in report.
|
|
52
|
+
6. **Output** `.Test.md`.
|
|
35
53
|
|
|
36
54
|
---
|
|
37
55
|
|
|
38
56
|
## Checkpoint & Gate
|
|
39
57
|
|
|
40
|
-
- Không gate ở đây; gate là `/qc-review` kế tiếp.
|
|
58
|
+
- Không gate chặn người ở đây; gate là `/qc-review` kế tiếp.
|
|
59
|
+
- Nhưng Guard SC coverage **có hệ quả bắt buộc**: thiếu thì lệnh **viết bù** rồi mới báo, không phải chỉ cảnh báo.
|
|
41
60
|
|
|
42
61
|
---
|
|
43
62
|
|
|
@@ -46,6 +65,8 @@ Tách "thiết kế test case" (con người đọc/review được) khỏi "cod
|
|
|
46
65
|
- **Markdown-first** — test case là tài liệu review được trước khi thành code.
|
|
47
66
|
- **Nạp MỘT file skill theo layer** — tối ưu context (chỉ layer cần).
|
|
48
67
|
- **Trace mapping** — giữ test case gắn SC để về sau ghi `qc_status` đúng.
|
|
68
|
+
- **Guard SC coverage KHÔNG có đường thoát.** SC bị gap chặn **vẫn** phải có TC — viết đủ, mang dấu `🚫 Block: [GAP-UC{N}-{nnn}] — lý do`. Gap là thứ được **ghi vào** test case, không phải cái cớ để không viết. Cho phép "bỏ trống có lý do" là dạy hai luật trái nhau trong cùng một lệnh, và cho agent một câu-lý-do-cho-qua.
|
|
69
|
+
- **Guard ≠ Self-Review.** Guard là phép **đếm**, có hệ quả bắt buộc. Self-review là lượt đọc lại rộng hơn nhưng mềm hơn. Không bao giờ dùng self-review làm lý do gỡ Guard.
|
|
49
70
|
|
|
50
71
|
---
|
|
51
72
|
|
|
@@ -53,6 +74,8 @@ Tách "thiết kế test case" (con người đọc/review được) khỏi "cod
|
|
|
53
74
|
|
|
54
75
|
- **Tách design ↔ script** thêm một trạm nhưng cho phép review sớm — đánh đổi giữa số bước và chất lượng gate.
|
|
55
76
|
- **Phụ thuộc convention QC team** — cần đồng bộ khi convention đổi.
|
|
77
|
+
- **Guard đếm sớm, ở chỗ còn sửa được.** `/qc-report` cũng tính design coverage bằng **đúng phép đếm này**, nhưng ở **cuối** — lúc đó chỉ còn kịp báo, không còn kịp viết bù. Cùng một phép đếm, giá trị khác hẳn theo thời điểm.
|
|
78
|
+
- Con số `{K}/{total}` vốn **đã in** ở report từ trước, nhưng **không có phép tính nào đứng sau nó**. Một con số trong báo cáo không chứng minh có phép đo.
|
|
56
79
|
|
|
57
80
|
---
|
|
58
81
|
|
|
@@ -29,8 +29,11 @@ Không chạy test kém. Trạm này chặn: (1) test case chưa đủ tốt tr
|
|
|
29
29
|
## Các bước xử lý (chi tiết)
|
|
30
30
|
|
|
31
31
|
1. **Role qa-reviewer** — nạp `{qc_skills_dir}/qa-reviewer/`.
|
|
32
|
-
2. **Review focus** — kiểm test case (đủ phủ, đúng SC) hoặc script (đúng logic, selector
|
|
33
|
-
3.
|
|
32
|
+
2. **Review focus** — kiểm test case (đủ phủ, đúng SC) hoặc script (đúng logic, **selector bám §4.5.6 chứ không dò DOM**, không fake-pass).
|
|
33
|
+
3. **Self-Review** *(mới)* — nạp `skills/qc/_shared/self-review-principles.md`, soát một lượt trước khi in report.
|
|
34
|
+
4. Verdict: APPROVED → đi tiếp; NEEDS_FIX → sửa rồi review lại.
|
|
35
|
+
> **Self-Review ≠ Guard.** Guard là phép **đếm cơ học**, có hệ quả bắt buộc khi lệch. Self-review là lượt đọc lại **rộng hơn nhưng mềm hơn**, soát ba nhóm lỗi mà phép đếm không bắt được (bịa dữ kiện · lẫn suy đoán với sự thật · bỏ dở giữa chừng). Một bộ nguyên tắc tự soát **không bao giờ** được dùng làm lý do gỡ một Guard — chính file `self-review-principles.md` ghi rõ ranh giới đó ngay ở đầu.
|
|
36
|
+
|
|
34
37
|
|
|
35
38
|
---
|
|
36
39
|
|
|
@@ -44,6 +47,7 @@ Không chạy test kém. Trạm này chặn: (1) test case chưa đủ tốt tr
|
|
|
44
47
|
|
|
45
48
|
- **Một lệnh, hai vai** — review case và review script dùng chung skill, khác focus.
|
|
46
49
|
- **Gate thật của QC** — điểm HITL chính trong dây chuyền tự động.
|
|
50
|
+
- **Review script thì soát cả nguồn selector** — script lấy locator từ §4.5.6 Test Selectors, hay tự dò DOM? Dò DOM là script giòn: dev đổi một class là vỡ, và **không ai báo**.
|
|
47
51
|
|
|
48
52
|
---
|
|
49
53
|
|
|
@@ -36,20 +36,41 @@
|
|
|
36
36
|
1. **Role & stack** — qc-playwright (`stack-profile.yaml`): Python, pytest-playwright fixture, Page Object; mỗi test độc lập; gom theo (role, account) để auth không xen kẽ.
|
|
37
37
|
2. **Skills** — nạp một file skill `qa-runner` theo layer.
|
|
38
38
|
3. **Sinh script** từ `.Test.md`; tag `@trace.verifies={UC-ID}-SC{N}`.
|
|
39
|
-
4. **Chạy**
|
|
39
|
+
4. **Chạy.** Test đỏ **một lần** chưa nói được nó đỏ vì cái gì → **chạy lại riêng test đó, tối đa 2 lần**, rồi mới phân loại thành **ba** nhãn:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
đỏ → đỏ → đỏ ⇒ NHẤT QUÁN → sang bước điều tra: script-bug | product-gap
|
|
43
|
+
đỏ → xanh ⇒ KHÔNG NHẤT QUÁN → flaky
|
|
44
|
+
đỏ → đỏ → xanh ⇒ KHÔNG NHẤT QUÁN → flaky
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
| Nhãn | Khi nào | Hệ quả |
|
|
48
|
+
|---|---|---|
|
|
49
|
+
| `script-bug` | Sai locator / logic test / timing / dữ liệu test | QC tự sửa. **Không** mở bug |
|
|
50
|
+
| `product-gap` | Hành vi thật ≠ spec — defect thật | Mở bug qua `/report-bug`. Giữ `fail` + evidence, **không bao giờ fake-pass** |
|
|
51
|
+
| `flaky` | Không nhất quán ở bước chạy lại — **chưa đủ căn cứ** | Cách ly + ghi **nghi vấn** nguyên nhân. **Không** mở bug từ một lần chạy hên xui |
|
|
52
|
+
|
|
53
|
+
**Điều tra bằng bằng chứng, không đoán** — đọc trace/video/log: timeline, DOM snapshot, network, console **tại thời điểm fail**. Không chắc giữa `script-bug` và `product-gap` → **mời Dev cùng xem trace**.
|
|
54
|
+
|
|
55
|
+
🛑 **Người xác nhận TRƯỚC khi hành động** — lệnh in đề xuất kèm evidence cụ thể rồi **dừng chờ**. **Không ghi `qc_status`** cho scenario nào còn FAIL chưa được xác nhận nhãn.
|
|
40
56
|
5. **Write Trace State — `qc_status`** (kết quả QC chính thức) + `qc_run_at`, `qc_owner`, `qc_blocked_by`, `last_updated`.
|
|
41
57
|
|
|
42
58
|
⚠️ **ĐỌC cột `status` TRƯỚC KHI GHI `pass`** *(GAPS-v4 G55, đối xứng `/dev-run-test`)*: row `DRIFT`/`ORPHANED` + test xanh → **`not_run`**, không bao giờ `pass`. `fail` và `skip` ghi bình thường — chỉ giá trị **khẳng định** cần giấy phép.
|
|
43
59
|
|
|
44
60
|
Và ở lệnh này hậu quả đi **xa hơn** `/dev-run-test`: một `pass` sai còn **đóng một bug** (§Đóng bug đã verify). Nên khi hạ về `not_run`, lệnh **KHÔNG** clear `qc_owner`/`qc_blocked_by` và **KHÔNG** chạy bước đóng bug — đóng bug dựa trên một lần QC chạy trên spec đã đổi là đóng sai.
|
|
45
|
-
|
|
46
|
-
|
|
61
|
+
`flaky` → `qc_status = not_run`, `qc_owner = qc`. Không tạo trạng thái mới: `not_run` đúng nghĩa *"chưa có kết luận"*, và `qc_owner = qc` để nó không rơi vào khoảng không ai nhận.
|
|
62
|
+
6. **Self-Review** *(mới)* — nạp `skills/qc/_shared/self-review-principles.md`, soát một lượt trước khi in report.
|
|
63
|
+
7. **Đóng bug đã verify** — chạy **TRƯỚC** bước clear cột (xem dưới).
|
|
64
|
+
8. **Refresh Panel Mirror** — Living Docs local.
|
|
47
65
|
|
|
48
66
|
---
|
|
49
67
|
|
|
50
68
|
## Checkpoint & Gate
|
|
51
69
|
|
|
52
70
|
- Tiền đề: case đã APPROVED ở `/qc-review`. Script sinh ra → review lại ở `/qc-review` (script) trước PR.
|
|
71
|
+
- 🛑 **Xác nhận nhãn FAIL** — cổng chặn được **thêm vào**, trong khi framework vốn đang giảm số cổng chặn (G41). Lý do: **cả hai hướng sai đều không đảo ngược rẻ.** Gắn nhầm `script-bug` cho lỗi sản phẩm thật là **giấu bug** cho tới khi khách gặp; mở bug từ một lần chạy hên xui là **đốt thời gian dev** và làm mòn niềm tin vào QC.
|
|
72
|
+
|
|
73
|
+
> **Đây KHÔNG phải `retries` trong config test runner.** `retries` tự thử lại rồi báo *"passed on retry"* — nó **che** sự không nhất quán. Ở đây chạy **tách biệt từng lần để quan sát**, vì chính sự không nhất quán mới là thông tin cần.
|
|
53
74
|
|
|
54
75
|
---
|
|
55
76
|
|
|
@@ -57,6 +78,7 @@
|
|
|
57
78
|
|
|
58
79
|
- **`qc_status` là trục authoritative** — khác `dev_selftest`; có evidence.
|
|
59
80
|
- **Không fake-pass** — product-gap giữ nguyên FAIL, đẩy về PO/Dev.
|
|
81
|
+
- **Chạy lại để QUAN SÁT, không để cho qua** — ba nhãn FAIL tách *chưa đủ căn cứ* (`flaky`) ra khỏi *đã đủ căn cứ* (`script-bug` / `product-gap`). Trước đây hai nhãn gộp cả ba tình huống, nên một test hên xui hoặc bị gán bừa `script-bug` (giấu bug), hoặc thành một bug ma gửi cho dev.
|
|
60
82
|
- **Stack QC tách hẳn dev** — `@trace.verifies` nối script ↔ SC.
|
|
61
83
|
- **`active_platform` khoá sổ trace** — `qc_status` ghi đúng `{UC-ID}-{platform}.tsv`.
|
|
62
84
|
- **Chủ sở hữu bước `🟡 Fixed → 🟢 Closed`.** `/report-bug` mở bug (`🟢 Open`), `/fix-bug` đặt `🟡 Fixed`, và **chỉ QC re-verify mới đóng được** — dev không tự đóng bug của mình.
|
|
@@ -80,9 +102,10 @@ Bug report đã đổi phải **commit + push** vào spec repo — file local l
|
|
|
80
102
|
## 👓 Góc nhìn tối ưu
|
|
81
103
|
|
|
82
104
|
- **Trạm nặng nhất của QC** — sinh + chạy + phân loại + ghi trace. Chạy thật phụ thuộc môi trường (browser, data, service lên).
|
|
83
|
-
- **Phân loại script-bug
|
|
84
|
-
- **Selector
|
|
85
|
-
- **Chạy lại tốn tài nguyên** —
|
|
105
|
+
- **Phân loại vẫn phụ thuộc người đọc evidence** — nhưng giờ có **tiêu chí và thứ tự bắt buộc**: chạy lại ×2 → đọc trace/log → đề xuất nhãn → **người xác nhận**. Chỗ mềm còn lại là ranh giới `script-bug` ↔ `product-gap` khi hành vi nằm ở **biên của spec**; đường ra đã ghi rõ là **mời Dev cùng xem trace**, không đoán cho xong.
|
|
106
|
+
- **Selector bám hợp đồng `/map-testids`** — §4.5.6 đã được chốt **trước** `/generate-code`, nên trạm này có bảng selector sẵn. Ca còn lại: §4.5.6 rỗng (dự án cũ chưa từng chạy `/map-testids`) → script quay về dò DOM và **giòn**.
|
|
107
|
+
- **Chạy lại tốn tài nguyên** — ×2 cho mỗi FAIL là chi phí thật. Đánh đổi có chủ đích: rẻ hơn nhiều so với một bug ma gửi cho dev, hoặc một defect thật bị gán `script-bug` rồi chôn.
|
|
108
|
+
- **`flaky` không có cột riêng trong sổ trace** — nó nằm ở `qc_status = not_run` + `qc_owner = qc` + nghi vấn ghi trong report. Cố ý: thêm một giá trị enum mới sẽ kéo theo sửa schema, lint, mọi lệnh đọc cột đó — trong khi `not_run` đã đúng nghĩa *chưa có kết luận*. Cái giá là **không truy được lịch sử flaky bằng máy**, phải đọc report.
|
|
86
109
|
|
|
87
110
|
---
|
|
88
111
|
|
|
@@ -30,8 +30,11 @@ Kết quả chạy cần được trình bày có bằng chứng và **định t
|
|
|
30
30
|
|
|
31
31
|
1. **Role qa-runner/report** — nạp skill report.
|
|
32
32
|
2. **Procedure** — tổng hợp kết quả run (pass/fail per SC), đính evidence.
|
|
33
|
-
3. Tách **product-gap** → định tuyến về PO/Dev (có thể thành `/report-bug`).
|
|
34
|
-
4. **
|
|
33
|
+
3. Tách **product-gap** → định tuyến về PO/Dev (có thể thành `/report-bug`). Scenario mang nhãn **`flaky`** **không** thành bug — nó là *chưa có kết luận*, `qc_status` để `not_run`.
|
|
34
|
+
4. **Self-Review** *(mới)* — nạp `skills/qc/_shared/self-review-principles.md`, soát một lượt trước khi in report.
|
|
35
|
+
5. **Output** report.
|
|
36
|
+
> **Self-Review ≠ Guard.** Guard là phép **đếm cơ học**, có hệ quả bắt buộc khi lệch. Self-review là lượt đọc lại **rộng hơn nhưng mềm hơn**, soát ba nhóm lỗi mà phép đếm không bắt được (bịa dữ kiện · lẫn suy đoán với sự thật · bỏ dở giữa chừng). Một bộ nguyên tắc tự soát **không bao giờ** được dùng làm lý do gỡ một Guard — chính file `self-review-principles.md` ghi rõ ranh giới đó ngay ở đầu.
|
|
37
|
+
|
|
35
38
|
|
|
36
39
|
---
|
|
37
40
|
|
package/docs/explain/README.md
CHANGED
|
@@ -98,12 +98,15 @@ Kết thúc bằng: **Status badge** (✅/❌/⚠️) · **Output Artifacts** (f
|
|
|
98
98
|
- [05 · `/generate-design-spec`](05-generate-design-spec.md)
|
|
99
99
|
- [06 · `/generate-bdd`](06-generate-bdd.md)
|
|
100
100
|
- [07 · `/generate-tech-docs`](07-generate-tech-docs.md)
|
|
101
|
+
- [**11** · `/map-testids`](11-map-testids.md) ← **chốt hợp đồng test-id, TRƯỚC code**
|
|
101
102
|
- [08 · `/review-tech-docs`](08-review-tech-docs.md)
|
|
102
103
|
|
|
104
|
+
> Danh sách này xếp theo **thứ tự chạy**, không theo số file. `/map-testids` giữ số `11` vì lý do lịch sử — giữ tên file để không gãy link cũ.
|
|
105
|
+
> §4.5.6 chốt ở đây là lý do **Phase Implementation** và **Phase QC Automation** chạy được **song song**.
|
|
106
|
+
|
|
103
107
|
### Phase Implementation
|
|
104
108
|
- [09 · `/generate-code`](09-generate-code.md)
|
|
105
109
|
- [10 · `/review-code`](10-review-code.md)
|
|
106
|
-
- [11 · `/map-testids`](11-map-testids.md)
|
|
107
110
|
|
|
108
111
|
### Phase Dev Self-Test
|
|
109
112
|
- [12 · `/dev-gen-test`](12-dev-gen-test.md)
|