@educa-corp/sdd-framework 0.9.4 → 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.
Files changed (104) hide show
  1. package/bin/build.js +11 -1
  2. package/bin/lint-trace.js +599 -2
  3. package/bin/self-check.js +195 -0
  4. package/bin/trace-schema.json +2656 -1927
  5. package/core/FRAMEWORK_VERSION +1 -1
  6. package/core/commands/dev-gen-test.md +62 -0
  7. package/core/commands/generate-bdd.md +1 -0
  8. package/core/commands/generate-code.md +39 -2
  9. package/core/commands/generate-tech-docs.md +24 -5
  10. package/core/commands/map-testids.md +164 -7
  11. package/core/commands/qc-analyze.md +163 -9
  12. package/core/commands/qc-design-test.md +294 -2
  13. package/core/commands/qc-plan.md +57 -3
  14. package/core/commands/qc-report.md +76 -60
  15. package/core/commands/qc-review.md +102 -1
  16. package/core/commands/qc-run-test.md +194 -5
  17. package/core/commands/review-tech-docs.md +20 -0
  18. package/core/commands/validate-traces.md +17 -2
  19. package/core/modules/qc-playwright/stack-profile.yaml +1 -1
  20. package/core/rules/data-protection.md +52 -0
  21. package/core/rules/workflow.md +40 -0
  22. package/core/skills/qc/_shared/self-review-principles.md +112 -0
  23. package/core/skills/qc/qa-analyst/DOC_GAP.template.md +9 -1
  24. package/core/skills/qc/qa-designer/shared/duplicate-check-procedure.md +33 -5
  25. package/core/skills/qc/qa-designer/shared/tc-metadata-format.md +24 -0
  26. package/core/skills/qc/qa-planner/test-plan.md +7 -0
  27. package/core/skills/qc/qa-runner/e2e.md +2 -2
  28. package/core/skills/qc/qa-runner/functional/gui-feature.md +9 -3
  29. package/core/skills/qc/qa-runner/functional/gui-screen.md +9 -3
  30. package/core/skills/qc/qa-runner/integration.md +1 -1
  31. package/core/skills/qc/qa-runner/non-functional.md +1 -1
  32. package/core/skills/spec/SKILL.md +1 -1
  33. package/core/steps/context-loader.md +7 -2
  34. package/core/steps/gap-verify.md +67 -0
  35. package/core/steps/qc-scope.md +67 -11
  36. package/core/steps/qc-stamp.md +142 -0
  37. package/core/steps/report-footer.md +15 -7
  38. package/core/templates/feature.template +1 -0
  39. package/core/templates/tech-design.template.md +4 -3
  40. package/docs/01-getting-started/quickstart.md +4 -3
  41. package/docs/02-concepts/architecture.md +14 -0
  42. package/docs/02-concepts/glossary.md +8 -0
  43. package/docs/02-concepts/overview.md +3 -2
  44. package/docs/02-concepts/pipeline-steps/04-bdd.md +1 -1
  45. package/docs/02-concepts/pipeline-steps/05-tech-docs.md +21 -5
  46. package/docs/02-concepts/pipeline-steps/06-code.md +12 -2
  47. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +60 -12
  48. package/docs/02-concepts/pipeline-steps/README.md +4 -3
  49. package/docs/02-concepts/traceability.md +2 -2
  50. package/docs/03-guides/architect.md +2 -2
  51. package/docs/03-guides/developer.md +5 -2
  52. package/docs/03-guides/tester-qa.md +17 -5
  53. package/docs/04-reference/commands.md +7 -4
  54. package/docs/04-reference/trace-schema.md +38 -0
  55. package/docs/explain/07-generate-tech-docs.md +5 -3
  56. package/docs/explain/08-review-tech-docs.md +15 -3
  57. package/docs/explain/09-generate-code.md +30 -4
  58. package/docs/explain/10-review-code.md +1 -1
  59. package/docs/explain/11-map-testids.md +10 -7
  60. package/docs/explain/12-dev-gen-test.md +1 -1
  61. package/docs/explain/15-qc-analyze.md +14 -2
  62. package/docs/explain/16-qc-plan.md +5 -1
  63. package/docs/explain/17-qc-design-test.md +26 -3
  64. package/docs/explain/18-qc-review.md +6 -2
  65. package/docs/explain/19-qc-run-test.md +29 -6
  66. package/docs/explain/20-qc-report.md +5 -2
  67. package/docs/explain/README.md +4 -1
  68. package/docs/plans/qc-surgery/00-nhat-ky.md +497 -0
  69. package/docs/plans/qc-surgery/01-checklist.md +92 -0
  70. package/docs/plans/qc-surgery/02-lo-trinh.md +266 -0
  71. package/docs/plans/qc-surgery/buoc/0-01-testid-attr-co-cho-o.md +157 -0
  72. package/docs/plans/qc-surgery/buoc/0-02-mot-nguon-cho-testid-attr.md +135 -0
  73. package/docs/plans/qc-surgery/buoc/0-03-skill-thoi-day-do-dom.md +167 -0
  74. package/docs/plans/qc-surgery/buoc/0-04-may-canh-hop-dong.md +173 -0
  75. package/docs/plans/qc-surgery/buoc/0-05-don-nhan-cot-va-2b.md +133 -0
  76. package/docs/plans/qc-surgery/buoc/0-06-hop-dong-truoc-code.md +226 -0
  77. package/docs/plans/qc-surgery/buoc/1-01-guard-br-tag.md +156 -0
  78. package/docs/plans/qc-surgery/buoc/1-02-guard-sc-coverage.md +153 -0
  79. package/docs/plans/qc-surgery/buoc/1-03-fail-3-nhan.md +176 -0
  80. package/docs/plans/qc-surgery/buoc/1-04-self-review-dung-chung.md +175 -0
  81. package/docs/plans/qc-surgery/buoc/1-05-spec-la-du-lieu.md +164 -0
  82. package/docs/plans/qc-surgery/buoc/1-06-gap-verify-du-bo.md +162 -0
  83. package/docs/plans/qc-surgery/buoc/README.md +85 -0
  84. package/docs/plans/qc-surgery/exec-d0-b1-testid-attr-header.md +147 -0
  85. package/docs/plans/qc-surgery/exec-d0-b2-thong-nhat-nguon-testid-attr.md +152 -0
  86. package/docs/plans/qc-surgery/exec-d0-b3-sua-skill-probe-dom.md +173 -0
  87. package/docs/plans/qc-surgery/exec-d0-b4-may-canh-4-5-6.md +168 -0
  88. package/docs/plans/qc-surgery/exec-d0-b5-don-nhan-lech.md +196 -0
  89. package/docs/plans/qc-surgery/exec-d0-b6-contract-truoc-code.md +350 -0
  90. package/docs/plans/qc-surgery/exec-d1-b1-guard-br-tag.md +129 -0
  91. package/docs/plans/qc-surgery/exec-d1-b2-guard-sc-coverage.md +159 -0
  92. package/docs/plans/qc-surgery/exec-d1-b3-fail-3-bucket.md +158 -0
  93. package/docs/plans/qc-surgery/exec-d1-b4-self-review-principles.md +145 -0
  94. package/docs/plans/qc-surgery/exec-d1-b5-noi-quy-spec-la-du-lieu.md +156 -0
  95. package/docs/plans/qc-surgery/exec-d1-b6-gap-verify-mo-rong.md +179 -0
  96. package/docs/plans/qc-surgery/exec-d2-b1-tach-qc-review.md +166 -0
  97. package/docs/plans/qc-surgery/exec-d2-b2-tach-qc-run-test-atomic.md +267 -0
  98. package/docs/plans/qc-surgery/exec-d2-b3-qc-automation-assess.md +198 -0
  99. package/docs/plans/qc-surgery/exec-d3-b1-qc-report-gate-decision.md +209 -0
  100. package/docs/plans/qc-surgery/exec-d4-b1-qc-design-testdata.md +146 -0
  101. package/docs/plans/qc-surgery/exec-d4-b2-qc-smoke-test.md +179 -0
  102. package/docs/plans/qc-surgery/exec-d4-b3-qc-metrics-va-lint.md +198 -0
  103. package/docs/plans/qc-surgery/exec-d4-b4-lint-spec-injection.md +199 -0
  104. package/package.json +1 -1
@@ -0,0 +1,209 @@
1
+ ---
2
+ buoc: Đợt 3 — Bước 1
3
+ title: Nâng cấp /qc-report — coverage kép, 8 ngưỡng, verdict
4
+ phu_thuoc: d2-b2 (CỨNG)
5
+ trang_thai: chưa làm
6
+ ---
7
+
8
+ # Đợt 3 · Bước 1 — Từ "báo cáo" thành "phán quyết"
9
+
10
+ ← [`01-checklist.md`](01-checklist.md) · [`02-lo-trinh.md`](02-lo-trinh.md)
11
+
12
+ > ⚠️ **Phụ thuộc cứng vào `/qc-run-manualtest`** (d2-b2). Làm trước là biến lệnh giá trị nhất
13
+ > của cả đề xuất thành lệnh không ai dùng được — xem §6.
14
+
15
+ ## 1. Vì sao
16
+
17
+ Đây là phần giá trị nhất trong toàn bộ đề xuất của chị QC, và nó giải quyết ba câu hỏi mà
18
+ `/qc-report` hiện không trả lời được.
19
+
20
+ ### 1.1 "Coverage bao nhiêu?" — hiện là một số, đáng ra là hai
21
+
22
+ Hai câu hỏi rất khác nhau bị gộp vào một chữ:
23
+
24
+ ```
25
+ Đã VIẾT test case cho bao nhiêu % scenario? → design coverage = 100%
26
+ Đã CHẠY và có kết quả bao nhiêu % scenario? → execution coverage = 40%
27
+ ```
28
+
29
+ Báo "coverage 100%" khi mới chạy 40% là **báo cáo sai** — và nó sai theo hướng nguy hiểm: người
30
+ đọc kết luận đã kiểm xong.
31
+
32
+ ### 1.2 "Được release chưa?" — hiện không có ai trả lời
33
+
34
+ `/qc-report` hiện in ra kết quả rồi hết. Người đọc tự quyết định. Nghe có vẻ đúng vai (QC không
35
+ quyết định release), nhưng thực tế nó đẩy một quyết định kỹ thuật thành một quyết định cảm tính:
36
+ *"38/42 pass, 2 fail, 2 skip — thế là được hay không?"*
37
+
38
+ Cái thiếu không phải quyền quyết định, mà là **ngưỡng khai báo trước**. Có ngưỡng thì QC đưa ra
39
+ tín hiệu kỹ thuật rõ ràng (PASS/FAIL/INCOMPLETE), Lead/PM vẫn giữ quyền quyết định cuối.
40
+
41
+ ### 1.3 "Không có test nào fail" ≠ "tốt"
42
+
43
+ Đây là lỗ hổng logic nghiêm trọng nhất. Một PRD chạy 0 test sẽ có: 0 fail, 0 bug, không gì đỏ.
44
+ Nếu verdict dựa trên "có fail hay không" thì nó **PASS**.
45
+
46
+ Framework đã học chính bài này ở phía dev — `bin/trace-schema.json` →
47
+ `positive_assertion_guards` (G55):
48
+
49
+ > *"AI KHẲNG ĐỊNH MỘT GIÁ TRỊ DƯƠNG THÌ PHẢI KIỂM RẰNG MÌNH ĐƯỢC PHÉP KHẲNG ĐỊNH."*
50
+
51
+ Bước này là **mệnh đề đối ngẫu ở cấp báo cáo**: không được kết luận PASS chỉ vì không có tin
52
+ xấu.
53
+
54
+ ## 2. Tình trạng hiện tại
55
+
56
+ `commands/qc-report.tmpl` — 217 dòng, tổng hợp kết quả từ `/qc-run-test`, liệt kê bug, in báo
57
+ cáo. Không có:
58
+
59
+ - Phân biệt design vs execution coverage.
60
+ - Ngưỡng nào.
61
+ - Verdict nào.
62
+ - Risk matrix nào.
63
+
64
+ Và số liệu nó tổng hợp lấy từ một lần chạy `/qc-run-test`, nên không phân biệt được *"SC này
65
+ chưa chạy"* với *"SC này chạy rồi và pass"* ở cấp báo cáo — thông tin đó có trong sổ trace nhưng
66
+ không được đưa lên thành chỉ số.
67
+
68
+ ## 3. Sẽ đổi thành gì
69
+
70
+ ### 3.1 Hai số coverage, không gộp
71
+
72
+ ```
73
+ Design coverage = số SC có ≥1 TC-approved trỏ tới / tổng số SC (đếm từ .feature, trừ ORPHANED)
74
+ Execution coverage = số SC có qc_status ∈ {pass, fail} / tổng số SC
75
+ ```
76
+
77
+ In **cạnh nhau**, kèm ghi chú rõ **không được gộp**:
78
+
79
+ ```
80
+ Coverage : Design 100% · Execution 90% ← KHÔNG gộp hai số này
81
+ ```
82
+
83
+ Chú ý: `design coverage` là **cùng phép đếm** với Guard SC coverage ở
84
+ [`exec-d1-b2`](exec-d1-b2-guard-sc-coverage.md). Khác nhau ở thời điểm: guard đếm **lúc thiết
85
+ kế** (còn kịp viết bù), báo cáo đếm **ở cuối** (chỉ còn kịp báo). Đó là lý do d1-b2 làm trước.
86
+
87
+ ### 3.2 Cờ `INVERSION`
88
+
89
+ ```
90
+ Design coverage < Execution coverage → 🔴 INVERSION
91
+ ```
92
+
93
+ Nghĩa: có SC **đã chạy** mà **không có test case approved** đứng sau. Bất thường — hoặc trace
94
+ matrix sai, hoặc có test chạy ngoài quy trình. Phải kiểm lại, không được bỏ qua.
95
+
96
+ ### 3.3 Tám ngưỡng khai báo được
97
+
98
+ ```
99
+ coverage_min = 85 # % execution coverage tổng, tối thiểu
100
+ p0_pass_rate_min = 100 # % P0 pass / P0 ĐÃ CHẠY (không tính not_run vào mẫu)
101
+ p1_pass_rate_min = 95
102
+ overall_pass_rate_min = 90
103
+ skip_rate_max = 5 # % skip / tổng SC
104
+ critical_risk_max = 0 # số SC risk CRITICAL còn tồn đọng
105
+ high_risk_max = 3
106
+ not_run_p0_max = 0 # số SC P0 not_run — giữ 0: P0 chưa chạy là rủi ro chưa đánh giá được
107
+ ```
108
+
109
+ Override qua `$ARGUMENTS` (`--coverage-min=80`…), hoặc hỏi **một lần** cho `{TICKET-ID}` nếu
110
+ chưa từng đặt trong phiên.
111
+
112
+ Chú ý cách tính `p0_pass_rate_min`: mẫu số là *P0 **đã chạy***, không phải *tổng P0*. Nếu tính
113
+ trên tổng thì một P0 chưa chạy sẽ làm tỷ lệ tụt và bị hiểu là "có test đỏ" — sai bản chất. Việc
114
+ "P0 chưa chạy" do ngưỡng #8 canh riêng. Hai chuyện khác nhau, hai ngưỡng khác nhau.
115
+
116
+ ### 3.4 Risk matrix — Severity × Impact × Test-type
117
+
118
+ Với mỗi SC còn `fail` hoặc `not_run`, tính điểm rủi ro tồn đọng, xếp
119
+ `CRITICAL / HIGH / MEDIUM / LOW`. Đầu vào: severity của bug đã file, `Priority` của TC, loại test
120
+ (smoke/functional/integration/e2e). Ngưỡng #6, #7 dùng số này.
121
+
122
+ ### 3.5 Verdict — ba trạng thái, không có trung gian
123
+
124
+ ```
125
+ ≥1 ô "⚠️ THIẾU DỮ LIỆU" → INCOMPLETE (chạy lại phần thiếu trước khi ra verdict)
126
+ ≥1 ô ❌ → FAIL
127
+ mọi ô ✅ → PASS
128
+ ```
129
+
130
+ **Thiếu dữ liệu thì ghi "thiếu dữ liệu", không tự ước lượng.** Đây là điều khoản chống chính lỗi
131
+ "số liệu ước lượng" ở [`exec-d1-b4`](exec-d1-b4-self-review-principles.md) nhóm 3.
132
+
133
+ Và điều khoản trung tâm:
134
+
135
+ > **KHÔNG BAO GIỜ ra PASS khi execution coverage thấp hoặc 0, dù 0 FAIL thật.**
136
+ > Ngưỡng #1 (`coverage_min`), #5 (`skip_rate_max`), #8 (`not_run_p0_max`) tự chặn ca này:
137
+ > coverage 0% « 85 · skip 100% » 5 · not-run P0 » 0 → verdict tự động rơi về **FAIL**.
138
+
139
+ ### 3.6 Vai trò — QC đưa tín hiệu, Lead/PM quyết định
140
+
141
+ Verdict là **tín hiệu kỹ thuật**, không phải quyết định release. Report phải nói rõ điều đó, và
142
+ ghi cả bộ ngưỡng đã dùng để người đọc biết verdict được tính trên cơ sở nào:
143
+
144
+ ```
145
+ Ngưỡng dùng: coverage≥85% | P0=100% | P1≥95% | overall≥90% | skip≤5% |
146
+ critical≤0 | high≤3 | p0-not-run≤0
147
+ ```
148
+
149
+ ## 4. Sửa file nào
150
+
151
+ | File | Việc |
152
+ |---|---|
153
+ | `commands/qc-report.tmpl` | Viết lại: thêm §Coverage (design vs execution) · §Risk Matrix · §Gate Decision (8 ngưỡng + verdict) · giữ phần liệt kê bug và handoff product-gap |
154
+ | `skills/qc/qa-script-runner/report.md` | **Mới** (thay `qa-runner/report/report.md` cho phần automation) — khuôn report theo stack mới: Playwright HTML Report + Trace Viewer (web) · WDIO + Allure (mobile) |
155
+ | `skills/qc/qa-runner/report/report.md` | **Giữ** — phần report cho `/qc-run-manualtest` |
156
+ | `steps/report-footer.md` | Bảng Next sau `/qc-report` |
157
+ | `docs/explain/20-qc-report.md`, `docs/02-concepts/pipeline-steps/08-qc-automation.md` | Cập nhật |
158
+
159
+ Nguồn: `D:\base\qcframework_proposal\command\qc-report.md` (§Bước 2 Coverage · §Bước 3 Risk
160
+ Matrix · §Bước 4 Gate Decision). Gỡ comment provenance, thay gate cắt tay, và **sửa tham chiếu
161
+ skill treo** `qa-script-runner/report/coverage-evaluator.md` → file này không tồn tại (chỉ có
162
+ `report.md`); hoặc tạo file đó, hoặc sửa tham chiếu. Không sửa thì `self-check.js:1235`
163
+ (R16(d)) fail build.
164
+
165
+ ## 5. Kiểm thế nào để biết đã xong
166
+
167
+ ```bash
168
+ node bin/build.js && node bin/self-check.js && node test/run.js
169
+ grep -n "coverage-evaluator" commands/qc-report.tmpl # → hoặc 0, hoặc file đó phải tồn tại
170
+ ```
171
+
172
+ Kiểm bằng **bốn ca**, và ca 4 là phép thử quyết định của cả đợt mổ:
173
+
174
+ | Ca | Dựng thế nào | Kỳ vọng |
175
+ |---|---|---|
176
+ | **1 — PASS** | PRD chạy đủ, mọi ngưỡng đạt | `VERDICT: PASS`, in đủ 8 ô ✅ |
177
+ | **2 — FAIL vì fail thật** | 1 test đỏ nhất quán, đã xác nhận `product-gap` | `VERDICT: FAIL`, ngưỡng #2 hoặc #4 ❌ |
178
+ | **3 — FAIL vì chưa chạy** | Không chạy `/qc-run-script` lần nào | `VERDICT: FAIL` (**không** phải PASS dù 0 fail). Ngưỡng #1, #5, #8 phải ❌ |
179
+ | **4 — PRD có test tay** | PRD có ≥1 SC `Automatable: N`, trong đó ≥1 là **P0**. Chạy `/qc-run-script` **và** `/qc-run-manualtest` | `VERDICT: PASS`. Execution coverage phải **đạt** |
180
+
181
+ **Ca 3** kiểm điều khoản "Untested ≠ Pass". Nếu nó ra PASS thì lỗ hổng logic vẫn còn.
182
+
183
+ **Ca 4** kiểm việc `/qc-run-manualtest` đã bịt được lỗ hổng. Nếu nó ra FAIL/INCOMPLETE thì
184
+ hoặc `/qc-run-manualtest` chưa ghi trace đúng, hoặc công thức execution coverage chưa tính SC
185
+ manual. **Không được xử lý bằng cách hạ ngưỡng** — đó là bỏ qua vấn đề chứ không sửa.
186
+
187
+ Thêm ca 5 nếu dựng được: tạo tình huống `INVERSION` (một SC có `qc_status = pass` mà không TC
188
+ approved nào trỏ tới) → phải hiện cờ 🔴.
189
+
190
+ ## 6. Nếu bỏ qua thì hỏng gì
191
+
192
+ **Bỏ cả bước:** `/qc-report` vẫn là bản tổng hợp mỏng. Câu "được release chưa?" vẫn trả lời bằng
193
+ cảm tính, và "coverage 100%" vẫn là con số gộp hai thứ khác nhau.
194
+
195
+ **Làm bước này TRƯỚC d2-b2 (`/qc-run-manualtest`) — đây là cái phải tránh:**
196
+
197
+ ```
198
+ PRD nào có ≥1 SC phải test tay
199
+ → SC đó mãi not_run (không trạm nào ghi)
200
+ → execution coverage không bao giờ đạt 85
201
+ → nếu SC đó là P0 thì ngưỡng #8 cũng trượt
202
+ → VERDICT: FAIL vĩnh viễn, không có cách sửa
203
+ ```
204
+
205
+ Và điều sẽ xảy ra sau đó là điều hợp lý duy nhất còn lại cho đội QC: **hạ `coverage_min` xuống 0
206
+ và `not_run_p0_max` lên vô cùng** để verdict xanh. Lúc đó cả 8 ngưỡng thành trang trí, và ta đã
207
+ làm một lệnh phán quyết mà phán quyết của nó bị vô hiệu hoá ngay từ ngày đầu.
208
+
209
+ Vì vậy thứ tự d2-b2 → d3-b1 **không phải sở thích**, nó là điều kiện để bước này có nghĩa.
@@ -0,0 +1,146 @@
1
+ ---
2
+ buoc: Đợt 4 — Bước 1
3
+ title: Thêm /qc-design-testdata — kế hoạch dữ liệu test cho phần automation
4
+ phu_thuoc: d2-b3
5
+ trang_thai: chưa làm
6
+ ---
7
+
8
+ # Đợt 4 · Bước 1 — Dữ liệu test dùng chung là nguồn gốc phổ biến nhất của test chập chờn
9
+
10
+ ← [`01-checklist.md`](01-checklist.md) · [`02-lo-trinh.md`](02-lo-trinh.md)
11
+
12
+ ## 1. Vì sao
13
+
14
+ Kể một chuyện quen:
15
+
16
+ Hai test dùng cùng một tài khoản `qa_student_01`. Test A đổi mật khẩu tài khoản đó. Test B đăng
17
+ nhập bằng mật khẩu cũ. Chạy tuần tự thì B đỏ. Chạy song song thì tuỳ thứ tự — đỏ hoặc xanh.
18
+
19
+ Ai điều tra sẽ thấy test B "chập chờn", gắn nhãn `flaky`, quarantine, rồi tuần sau nó lại nổ. Vì
20
+ nguyên nhân không nằm trong test B — nó nằm ở chỗ **hai test cùng sở hữu một tài khoản mà không
21
+ ai khai điều đó ra**.
22
+
23
+ Đây là loại lỗi có đặc điểm riêng: nó **không sửa được bằng cách sửa test**. Phải sửa **quyết
24
+ định về dữ liệu** — tài khoản nào dùng riêng, tài khoản nào dùng chung, chạy xong có dọn không.
25
+ Và quyết định đó hiện không được ghi ở đâu.
26
+
27
+ Bốn câu hỏi cần trả lời trước khi viết script, không phải sau:
28
+
29
+ | Câu hỏi | Nếu không trả lời |
30
+ |---|---|
31
+ | Dữ liệu này lấy ở đâu? | Hard-code vào test, đổi môi trường là vỡ hết |
32
+ | Có dùng chung với test khác không? | Chuyện ở trên |
33
+ | Chạy xong có phải dọn không? | DB test phình dần, đến lúc test đỏ vì trùng khoá |
34
+ | Có chứa mật khẩu/PII thật không? | Credential lọt vào git |
35
+
36
+ ## 2. Tình trạng hiện tại
37
+
38
+ Test data hiện là **một field mô tả trong test case**. Kiểm
39
+ `skills/qc/qa-designer/shared/tc-metadata-format.md` — có field `Test Data`, dạng văn xuôi kiểu
40
+ *"tài khoản học sinh đã kích hoạt"*.
41
+
42
+ Field đó **đủ cho test tay** (người đọc tự hiểu, tự chuẩn bị) nhưng **không đủ cho automation**:
43
+ nó không nói tài khoản nào, ai sở hữu, có dùng chung không, dọn thế nào.
44
+
45
+ Và `modules/qc-playwright/stack-profile.yaml` có thư mục `test_data/` với ghi chú *"JSON
46
+ datasets"* — tức là chỗ chứa thì có, còn **kế hoạch** thì không.
47
+
48
+ ## 3. Sẽ đổi thành gì
49
+
50
+ ### 3.1 Lệnh mới `/qc-design-testdata`
51
+
52
+ Chạy **sau** `/qc-automation-assess` (cần biết TC nào `Automatable: Y`) và **trước**
53
+ `/qc-design-script`. Ghi **một** file `TEST_DATA_PLAN.md` cho cả PRD, vào `qc_artifact_dir`.
54
+
55
+ **Chỉ phục vụ automation.** Test data cho test tay vẫn nằm ở field `Test Data` của `.Test.md`,
56
+ độc lập, không tham chiếu qua lại. Lý do tách: người chạy tay tự xoay được dữ liệu; script thì
57
+ không — nó cần địa chỉ chính xác.
58
+
59
+ ### 3.2 Chín cột của `TEST_DATA_PLAN.md`
60
+
61
+ | Cột | Ý nghĩa | Vì sao cần |
62
+ |---|---|---|
63
+ | `TD-xxx` | ID, trace được tới TC/SC | Để biết dữ liệu nào phục vụ test nào |
64
+ | **Type** | `Account` / `Boundary Value` / `Negative Value` / `Seed/Reference Data` / `Env Config` | Phân loại để biết cách chuẩn bị |
65
+ | **Dùng bởi** | `{UC-ID}-SC{N}` / `TC_xxx` | **Cột quan trọng nhất** — nhìn là biết dữ liệu bị dùng ở mấy chỗ |
66
+ | **Nguồn** | `Static fixture` / `Factory` (sinh runtime) / `DB seed` / `Env var` (secret) | Script biết lấy ở đâu |
67
+ | **Cách ly** | `Dedicated` / `Pool` / `Stateless` | Đây là cột chặn đúng chuyện ở §1 |
68
+ | **Vòng đời** | `Persistent` / `Ephemeral` | Biết có được sửa hay không |
69
+ | **Cleanup** | Có/không + cách dọn | Chặn DB phình |
70
+ | **Nhạy cảm** | Có chứa PII/credential không → **bắt buộc** qua `Env.*`/`CONFIG` | Chặn credential vào git |
71
+ | **Owner & refresh** | Ai bảo trì, khi nào cần làm mới | Tài khoản test hết hạn thì ai biết |
72
+
73
+ Hai cột **Dùng bởi** + **Cách ly** là cặp giải quyết vấn đề ở §1: nhìn thấy một tài khoản
74
+ `Dedicated` mà cột "Dùng bởi" có 3 TC là **mâu thuẫn tự lộ ra** — hoặc nó phải là `Pool`, hoặc
75
+ phải tách thành 3 tài khoản.
76
+
77
+ ### 3.3 Nối với nội quy bảo vệ dữ liệu
78
+
79
+ Cột **Nhạy cảm** không chỉ là ghi chú. Nếu một dòng đánh dấu có chứa credential thì cột
80
+ **Nguồn** **bắt buộc** phải là `Env var`, không được là `Static fixture`. Đây là kiểm được bằng
81
+ máy (một phép so hai cột) — cân nhắc thêm vào `bin/lint-spec.js` (d4-b4) hoặc kiểm ngay trong
82
+ lệnh.
83
+
84
+ Nối với `rules/data-protection.md` (đã mở rộng ở d1-b5): agent không được in giá trị secret vào
85
+ `TEST_DATA_PLAN.md` — chỉ ghi **tên biến môi trường**, không ghi giá trị.
86
+
87
+ ### 3.4 Escape hatch — không thiết kế trước
88
+
89
+ Nếu sau này phát hiện một tài khoản/dữ liệu bị dùng lại ở **≥2 PRD khác nhau**, mới cân nhắc
90
+ tách phần đó ra một registry dùng chung (tránh sửa N nơi khi tài khoản đổi). **Không làm trước
91
+ khi thấy dấu hiệu thật** — đúng ý chị QC đã ghi trong đề xuất, và đúng nguyên tắc không dựng hạ
92
+ tầng cho vấn đề chưa có.
93
+
94
+ ## 4. Sửa file nào
95
+
96
+ | File | Việc |
97
+ |---|---|
98
+ | `commands/qc-design-testdata.tmpl` | **Mới** — `{{include:steps/gate.md}}` + `{{include:steps/qc-scope.md}}` + nhãn `*Checkpoint:*` |
99
+ | `skills/qc/qa-testdata/test-data-plan.md` | **Mới** — khuôn 9 cột, cách chọn giá trị mỗi cột, ví dụ |
100
+ | `commands/qc-design-script.tmpl` | Đọc `TEST_DATA_PLAN.md`; thiếu file → dừng, báo chạy bước này trước |
101
+ | `steps/report-footer.md` | Bảng Phase + Next |
102
+ | `bin/qc-base-map.json` | Entry cho skill mới |
103
+ | `docs/04-reference/commands.md` | Thêm lệnh |
104
+
105
+ Nguồn: `D:\base\qcframework_proposal\command\qc-design-testdata.md` +
106
+ `skills\qc\qa-testdata\test-data-plan.md`. **Sửa `test-data-plan.md` đang gọi `TC_<FEATURE>.md`**
107
+ → `.Test.md` (nằm trong 14 file cần dọn).
108
+
109
+ ### Cân nhắc gộp
110
+
111
+ Chính chị QC đề xuất *"cân nhắc gộp `qc-automation-assess` + `qc-design-testdata` thành 1 lệnh
112
+ nếu đội QC thực tế thấy 2 bước tách biệt là thừa cho case đơn giản"*. Nếu chọn gộp, phần này
113
+ thành một mục trong `/qc-design-script` thay vì một lệnh — **quyết định sau khi chạy thật 2–3
114
+ PRD**, không quyết trước.
115
+
116
+ ## 5. Kiểm thế nào để biết đã xong
117
+
118
+ ```bash
119
+ node bin/build.js && node bin/self-check.js && node test/run.js
120
+ grep -n "TC_<FEATURE>" skills/qc/qa-testdata/test-data-plan.md # → 0 kết quả
121
+ ```
122
+
123
+ Kiểm bằng tay:
124
+
125
+ 1. `/qc-design-testdata {TICKET-ID}` → `TEST_DATA_PLAN.md` có đủ 9 cột, chỉ phủ TC
126
+ `Automatable: Y`.
127
+ 2. **Ca mâu thuẫn cách ly:** dựng tình huống một tài khoản `Dedicated` mà cột "Dùng bởi" có 2 TC
128
+ → lệnh phải chỉ ra mâu thuẫn, không im lặng ghi.
129
+ 3. **Ca nhạy cảm:** một dòng đánh `Nhạy cảm = có` mà `Nguồn = Static fixture` → phải báo lỗi,
130
+ đòi đổi sang `Env var`.
131
+ 4. **Ca không ghi giá trị secret:** kiểm `TEST_DATA_PLAN.md` không chứa mật khẩu/token thật, chỉ
132
+ chứa tên biến.
133
+ 5. `/qc-design-script` khi **chưa** có `TEST_DATA_PLAN.md` → phải dừng, báo chạy bước này trước.
134
+
135
+ ## 6. Nếu bỏ qua thì hỏng gì
136
+
137
+ Không có gì vỡ ngay — đây là lý do bước này ở Đợt 4, không phải Đợt 1. Script vẫn viết được, vẫn
138
+ chạy được, dữ liệu vẫn hard-code hoặc dùng chung ngầm.
139
+
140
+ Cái vỡ đến muộn và khó truy: **tỷ lệ test chập chờn tăng dần theo số test**. Với 20 test thì hiếm
141
+ khi đụng nhau; với 200 test dùng chung một pool tài khoản thì đụng liên tục. Và mỗi lần đụng,
142
+ `/qc-run-script` sẽ gắn nhãn `flaky` rồi quarantine — tức là **triệu chứng được xử lý, nguyên
143
+ nhân thì không**, và số test bị quarantine chỉ tăng.
144
+
145
+ Chỉ số **flaky rate trend** ở d4-b3 sẽ cho thấy điều đó bằng số. Nếu đường đó đi lên đều mà
146
+ không rõ vì sao, thì bước này là chỗ đầu tiên nên xem.
@@ -0,0 +1,179 @@
1
+ ---
2
+ buoc: Đợt 4 — Bước 2
3
+ title: Thêm smoke suite — chạy nhanh tính năng lõi khi có build mới
4
+ phu_thuoc: d2-b2
5
+ trang_thai: chưa làm
6
+ can_chot: TÊN LỆNH (không được nhầm /dev-smoke-test)
7
+ ---
8
+
9
+ # Đợt 4 · Bước 2 — Cổng nhanh trước khi chạy hết regression
10
+
11
+ ← [`01-checklist.md`](01-checklist.md) · [`02-lo-trinh.md`](02-lo-trinh.md)
12
+
13
+ > ⚠️ **Chưa chốt tên lệnh.** Xem §3.1 — phải chốt trước khi viết, vì `/dev-smoke-test` đã tồn
14
+ > tại với nghĩa khác hẳn.
15
+
16
+ ## 1. Vì sao
17
+
18
+ Hai tình huống mà pipeline hiện không có câu trả lời nhanh:
19
+
20
+ **a) Có build mới, cần biết ngay tính năng lõi còn sống không.** Cách duy nhất hiện tại: chạy
21
+ `/qc-run-script` cho **từng UC**. Một PRD 5 UC × vài chục test = rất lâu, và phần lớn thời gian
22
+ dành cho test không phải tính năng lõi.
23
+
24
+ **b) Gấp trước bàn giao, chưa kịp chạy đủ.** Cần một tín hiệu go/no-go trong 5 phút thay vì báo
25
+ cáo đầy đủ trong 2 giờ.
26
+
27
+ Cả hai cần cùng một thứ: **chạy riêng tập test của tính năng lõi**, phạm vi linh hoạt (1 feature
28
+ / 1 domain / toàn app), và ra một kết luận đi/không-đi.
29
+
30
+ Điều kiện để làm được: phải biết test nào là "lõi". Cái đó đã có — `Priority: P0` trong test
31
+ case, và `/qc-design-script` (d2-b2) gắn tag tự động:
32
+
33
+ ```
34
+ P0 → @smoke + @regression
35
+ P1/P2 → @regression
36
+ ```
37
+
38
+ Nên bước này là **thu hoạch** của việc gắn tag ở d2-b2, không phải hạ tầng mới.
39
+
40
+ ## 2. Tình trạng hiện tại
41
+
42
+ **Không có lệnh nào chạy theo tag.** `/qc-run-test` luôn khoá **một UC**, chạy toàn bộ test của
43
+ UC đó.
44
+
45
+ **Đã có một lệnh tên gần giống, nghĩa khác hẳn** — `commands/dev-smoke-test.tmpl:1-3`:
46
+
47
+ > *"# /dev-smoke-test — Smoke Test Service hoặc App đang chạy*
48
+ > *Dùng khi service/app **đang chạy sẵn**. Khác `/dev-run-test` (không cần live server)."*
49
+
50
+ Tức `/dev-smoke-test` là **của dev**, kiểm một service đang chạy có sống không (health check,
51
+ gọi vài endpoint). Không liên quan gì tới tag `@smoke` của bộ test QC.
52
+
53
+ Hai lệnh cùng chữ "smoke test" với hai nghĩa khác nhau trong cùng một framework là mời gọi gọi
54
+ sai lệnh — đúng loại lỗi mà việc tách `/qc-review` (d2-b1) vừa xử lý.
55
+
56
+ ## 3. Sẽ đổi thành gì
57
+
58
+ ### 3.1 Chốt tên trước — 3 phương án
59
+
60
+ | Phương án | Ưu | Nhược |
61
+ |---|---|---|
62
+ | `/qc-smoke-run` | Ngắn, giữ chữ "smoke" mà đội QC quen | Vẫn gần `/dev-smoke-test`, đọc nhanh dễ lẫn |
63
+ | `/qc-run-smoke` | Cùng họ với `/qc-run-script`, `/qc-run-manualtest` — nhìn là biết nhóm "chạy test" | Dài hơn một chút |
64
+ | `/qc-gate-check` | Không lẫn với gì; nói đúng mục đích (cổng nhanh go/no-go) | Mất chữ "smoke" mà đội QC đã quen dùng |
65
+
66
+ **Nghiêng về `/qc-run-smoke`**: nó xếp cùng nhóm với hai lệnh chạy test khác, nên khi gõ `/qc-run`
67
+ là thấy đủ ba lựa chọn — `script` (chạy tự động), `manualtest` (chạy tay), `smoke` (chạy nhanh
68
+ tập lõi). Không tự quyết, **cần chốt với anh + chị QC**.
69
+
70
+ ### 3.2 Phạm vi linh hoạt — khác mọi lệnh QC khác
71
+
72
+ | `$ARGUMENTS` | Phạm vi |
73
+ |---|---|
74
+ | `{domain}/{prd-slug}` | 1 feature |
75
+ | `{domain}` | cả domain |
76
+ | rỗng hoặc `all` | toàn app |
77
+
78
+ Đây là điểm **khác biệt có chủ ý**: mọi lệnh QC khác khoá một PRD/UC. Lệnh này không — vì câu hỏi
79
+ nó trả lời là *"build này có sống không"*, không phải *"PRD này đã kiểm xong chưa"*.
80
+
81
+ Nên nó **không dùng** `steps/qc-scope.md` như 11 lệnh kia (`qc-scope` chốt `TICKET-ID` +
82
+ `active_platform` + `uc_list`). Cần cách phân giải phạm vi riêng — và phải viết rõ vì sao, để
83
+ người sau không "sửa cho đồng bộ".
84
+
85
+ ### 3.3 Chỉ chạy script ĐÃ CÓ
86
+
87
+ Không tự sinh script mới. Chỉ chạy file đã qua `/qc-design-script` + `/qc-review-script` verdict
88
+ `APPROVED`. Không có script `@smoke` nào trong phạm vi → **báo rõ là chưa có**, đừng báo xanh:
89
+
90
+ ```
91
+ ⚠️ Không tìm thấy test @smoke nào trong phạm vi {scope}.
92
+ Chưa có nghĩa là "sạch" — nghĩa là chưa có gì để kiểm.
93
+ Chạy /qc-design-script cho các UC có TC Priority P0 trước.
94
+ ```
95
+
96
+ Câu này quan trọng: "0 test chạy, 0 fail" **không phải** go. Cùng logic "Untested ≠ Pass" của
97
+ Đợt 3.
98
+
99
+ ### 3.4 Retry + 3 loại như d1-b3, nhưng rút gọn
100
+
101
+ Cùng cơ chế phân loại (`script-bug` / `product-gap` / `flaky`), nhưng **1 lần chạy lại** thay vì
102
+ 2 — mục đích của lệnh là nhanh.
103
+
104
+ Đánh đổi phải nói ra: 1 lần chạy lại thì độ chắc chắn thấp hơn. Nên kết quả của lệnh này
105
+ **không** thay `qc_status` chính thức. Xem §3.6.
106
+
107
+ ### 3.5 `product-gap` → báo bug NGAY
108
+
109
+ Khác `/qc-run-script` (đợi xác nhận hết mọi fail rồi mới file bug): ở đây, `product-gap` được xác
110
+ nhận thì gọi `/report-bug` **ngay lập tức**, không đợi chạy hết phạm vi. Severity đề xuất mặc
111
+ định Critical, nhãn `🔥 Smoke-fail`.
112
+
113
+ Vì sao: mục đích chính của lệnh là **báo sớm cho dev**. Đợi chạy hết toàn app rồi mới báo là mất
114
+ đúng cái giá trị đó.
115
+
116
+ ### 3.6 Không thay `/qc-run-script`
117
+
118
+ ```
119
+ Output: Smoke Test Summary — go / no-go ← bản tóm tắt nhẹ, gắn với lần chạy này
120
+ KHÔNG ghi qc_status chính thức vào sổ trace ← đó là việc của /qc-run-script + /qc-run-manualtest
121
+ ```
122
+
123
+ Lý do: `qc_status` là kết quả QC **chính thức**, và nó phải dựa trên một lần chạy đầy đủ với
124
+ retry ×2. Smoke chỉ là cổng nhanh trước đó.
125
+
126
+ Nếu ghi `qc_status` từ smoke thì Đợt 3 sẽ tính execution coverage trên dữ liệu chạy rút gọn —
127
+ tức là báo cáo "đã kiểm 85%" trên một tập test P0 mà thôi. Đó là làm sai chính chỉ số vừa xây.
128
+
129
+ ### 3.7 Ai quyết định
130
+
131
+ 🔴 no-go → **báo Lead/PM**, QC không tự quyết định hoãn hay tiếp tục release. QC đưa tín hiệu kỹ
132
+ thuật; quyết định là của Lead/PM — cùng nguyên tắc với verdict của Đợt 3.
133
+
134
+ ## 4. Sửa file nào
135
+
136
+ | File | Việc |
137
+ |---|---|
138
+ | `commands/{tên-đã-chốt}.tmpl` | **Mới** — `{{include:steps/gate.md}}`; **không** include `qc-scope` (xem §3.2); nhãn `*Checkpoint:*` |
139
+ | `skills/qc/qa-script-runner/smoke.md` | **Mới** — cách chạy theo tag, khuôn Smoke Test Summary |
140
+ | `steps/report-footer.md` | Bảng Next — thêm lệnh này vào nhóm utility, ghi rõ nó **ngoài** luồng tuần tự |
141
+ | `docs/04-reference/commands.md` | Thêm lệnh, **ghi rõ khác gì `/dev-smoke-test`** |
142
+ | `bin/qc-base-map.json` | Entry cho skill mới |
143
+
144
+ Nguồn: `D:\base\qcframework_proposal\command\qc-smoke-test.md` +
145
+ `skills\qc\qa-script-runner\smoke.md`. Gỡ comment provenance, thay gate cắt tay, đổi tên lệnh
146
+ theo §3.1.
147
+
148
+ ## 5. Kiểm thế nào để biết đã xong
149
+
150
+ ```bash
151
+ node bin/build.js && node bin/self-check.js && node test/run.js
152
+ ls core/commands/{tên-đã-chốt}.md
153
+ ```
154
+
155
+ Kiểm bằng tay — **ca 3 và 4 là quan trọng nhất**:
156
+
157
+ | Ca | Dựng thế nào | Kỳ vọng |
158
+ |---|---|---|
159
+ | 1 | Chạy phạm vi 1 feature có test `@smoke` | Chỉ chạy test `@smoke`, không chạy `@regression` khác |
160
+ | 2 | Chạy phạm vi 1 domain, rồi `all` | Phạm vi mở rộng đúng |
161
+ | **3** | Phạm vi **không có** test `@smoke` nào | Phải báo *"chưa có gì để kiểm"*, **không** báo go |
162
+ | **4** | Sau khi chạy smoke thành công, mở sổ trace | `qc_status` **KHÔNG** bị ghi bởi lệnh này |
163
+ | 5 | Ép 1 test `@smoke` fail nhất quán, xác nhận `product-gap` | `/report-bug` được gọi **ngay**, severity Critical, nhãn `🔥 Smoke-fail` |
164
+
165
+ Ca 4 là chỗ dễ làm sai nhất: rất tự nhiên để lệnh "ghi luôn kết quả cho tiện", và làm vậy là phá
166
+ chỉ số của Đợt 3.
167
+
168
+ ## 6. Nếu bỏ qua thì hỏng gì
169
+
170
+ Không có gì vỡ — đây là utility, không nằm trong luồng tuần tự. Đội QC vẫn làm việc được, chỉ là
171
+ mỗi lần có build mới thì phải chạy `/qc-run-script` cho từng UC.
172
+
173
+ Cái mất là **thu hoạch của việc gắn tag `@smoke` ở d2-b2**: tag được gắn, được lưu trong script,
174
+ và không lệnh nào dùng. Tức là d2-b2 làm một việc không ai tiêu thụ — và sáu tháng sau sẽ có
175
+ người hỏi "cái tag này để làm gì?" rồi gỡ nó đi.
176
+
177
+ Rủi ro thứ hai nếu làm mà **không chốt tên**: hai lệnh "smoke test" với hai nghĩa. Người gọi sai
178
+ lệnh sẽ nhận một kết quả trông hợp lý nhưng trả lời câu hỏi khác — `/dev-smoke-test` báo "service
179
+ sống" không có nghĩa "tính năng lõi đúng".