@educa-corp/sdd-framework 0.9.1 → 0.9.3

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 (69) hide show
  1. package/bin/qc-base-map.json +595 -0
  2. package/bin/self-check.js +146 -0
  3. package/core/FRAMEWORK_VERSION +1 -1
  4. package/core/commands/propose-scenario.md +1 -1
  5. package/core/commands/qc-analyze.md +398 -37
  6. package/core/commands/qc-design-test.md +141 -2
  7. package/core/commands/qc-plan.md +159 -10
  8. package/core/commands/qc-review.md +134 -1
  9. package/core/commands/qc-run-test.md +135 -2
  10. package/core/commands/refine-prd.md +47 -20
  11. package/core/commands/report-bug.md +1 -1
  12. package/core/commands/review-context.md +27 -1
  13. package/core/modules/qc-playwright/stack-profile.yaml +3 -3
  14. package/core/skills/qc/qa-analyst/DOC_GAP.template.md +147 -0
  15. package/core/skills/qc/qa-analyst/acceptance-criteria.md +5 -3
  16. package/core/skills/qc/qa-analyst/business-rules.md +39 -5
  17. package/core/skills/qc/qa-analyst/data-flow.md +6 -4
  18. package/core/skills/qc/qa-analyst/exhaustive-gap-scanner.md +174 -0
  19. package/core/skills/qc/qa-analyst/spec-breakdown.md +10 -8
  20. package/core/skills/qc/qa-analyst/spec-issue-reporter.md +112 -0
  21. package/core/skills/qc/qa-designer/e2e/journey.md +3 -3
  22. package/core/skills/qc/qa-designer/exploratory/charter.md +1 -1
  23. package/core/skills/qc/qa-designer/exploratory/explore-to-functional.md +2 -2
  24. package/core/skills/qc/qa-designer/functional/api.md +3 -3
  25. package/core/skills/qc/qa-designer/functional/gui-feature.md +3 -3
  26. package/core/skills/qc/qa-designer/functional/gui-screen.md +3 -3
  27. package/core/skills/qc/qa-designer/integration/api.md +3 -3
  28. package/core/skills/qc/qa-designer/integration/db.md +3 -3
  29. package/core/skills/qc/qa-designer/integration/gui.md +3 -3
  30. package/core/skills/qc/qa-designer/integration/kafka.md +3 -3
  31. package/core/skills/qc/qa-designer/non-functional.md +3 -3
  32. package/core/skills/qc/qa-planner/risk-model.md +106 -0
  33. package/core/skills/qc/qa-planner/test-plan.md +35 -21
  34. package/core/skills/qc/qa-reviewer/script/e2e.md +1 -1
  35. package/core/skills/qc/qa-reviewer/script/exploratory.md +1 -1
  36. package/core/skills/qc/qa-reviewer/script/functional.md +1 -1
  37. package/core/skills/qc/qa-reviewer/script/integration.md +1 -1
  38. package/core/skills/qc/qa-reviewer/script/non-functional.md +1 -1
  39. package/core/skills/qc/qa-reviewer/test-case/e2e.md +1 -1
  40. package/core/skills/qc/qa-reviewer/test-case/exploratory.md +1 -1
  41. package/core/skills/qc/qa-reviewer/test-case/functional.md +1 -1
  42. package/core/skills/qc/qa-reviewer/test-case/integration.md +2 -2
  43. package/core/skills/qc/qa-reviewer/test-case/non-functional.md +1 -1
  44. package/core/skills/qc/qa-runner/e2e.md +1 -1
  45. package/core/skills/qc/qa-runner/exploratory/session.md +2 -2
  46. package/core/skills/qc/qa-runner/functional/api.md +1 -1
  47. package/core/skills/qc/qa-runner/functional/gui-feature.md +1 -1
  48. package/core/skills/qc/qa-runner/functional/gui-screen.md +1 -1
  49. package/core/skills/qc/qa-runner/integration.md +1 -1
  50. package/core/skills/qc/qa-runner/non-functional.md +1 -1
  51. package/core/skills/qc/qa-runner/report/report.md +1 -1
  52. package/core/steps/context-loader.md +1 -1
  53. package/core/steps/gap-verify.md +231 -0
  54. package/core/steps/qc-scope.md +119 -0
  55. package/core/steps/review-fanout.md +27 -1
  56. package/core/templates/project-context.yaml +5 -3
  57. package/docs/02-concepts/pipeline-steps/08-qc-automation.md +2 -2
  58. package/docs/04-reference/commands.md +1 -1
  59. package/docs/04-reference/configuration.md +146 -146
  60. package/docs/explain/03-refine-prd.md +8 -6
  61. package/docs/explain/15-qc-analyze.md +10 -7
  62. package/docs/explain/16-qc-plan.md +3 -3
  63. package/docs/explain/17-qc-design-test.md +1 -1
  64. package/docs/plans/qc-implementation-log.md +1587 -0
  65. package/docs/plans/qc-merge-plan.md +502 -0
  66. package/docs/plans/qc-sync-command.md +359 -0
  67. package/package.json +1 -1
  68. package/scripts/migrate-qc-docs.js +261 -0
  69. package/core/skills/qc/qa-analyst/DOC_GAPS.template.md +0 -63
@@ -0,0 +1,231 @@
1
+ # Gap Verify — cổng thẩm định độc lập, chống finding bịa
2
+
3
+ **Vì sao có cái này:** `steps/review-fanout.md` chỉ có một chiều lực — vòng
4
+ completeness-critic ở Phase 2 luôn hỏi *"còn thiếu gì nữa?"*, nên nó đẩy **recall** lên
5
+ và **không có gì kéo precision lại**. Fan-out càng rộng, critic càng lặp, thì finding bịa
6
+ càng nhiều: khẳng định hành vi spec không nêu, trích evidence sai, hoặc gắn nhãn "gap"
7
+ cho thứ thực ra là chuyện làm-kỹ-test.
8
+
9
+ Bước này là nửa còn thiếu đó. Nó **mở lại tài liệu nguồn** và bắt mỗi finding tự chứng minh
10
+ trước khi được giữ.
11
+
12
+ > **Nguyên tắc tối thượng:** một finding chỉ hợp lệ khi có **ĐỦ 2 vế** —
13
+ > **(1)** spec nguồn nêu hoặc ngụ ý hành vi X, **VÀ** **(2)** không tài liệu nào trong nguồn
14
+ > trả lời/phủ X. Thiếu một trong hai → **không phải finding**.
15
+
16
+ > ⚠️ **Cấm dùng chính trường evidence/quote của finding làm bằng chứng.** Phải mở file nguồn
17
+ > và đọc lại đoạn được trích — evidence có thể bị diễn giải sai hoặc bịa. Đây là toàn bộ lý do
18
+ > bước này tồn tại; bỏ qua nó thì bước này chỉ là một vòng critic nữa.
19
+
20
+ *Ported từ `ui-automation-testing` — `skills/qa-tc-analyst/gap-verifier.md`.*
21
+
22
+ ---
23
+
24
+ ## Tham số lệnh gọi truyền vào
25
+
26
+ | Tham số | Bắt buộc | Nghĩa |
27
+ |---|:---:|---|
28
+ | `FINDINGS` | ✅ | Tập finding cần thẩm định. Chỉ xét cái đang ở trạng thái mở (`Open` / `pending`); bỏ qua cái đã đóng trừ khi được yêu cầu soát lại. |
29
+ | `EVIDENCE_ROOT` | ✅ | Nơi chứa **sự thật gốc** — mặc định `{paths.specs_dir}` (spec submodule của PO). Verifier chỉ được lấy căn cứ từ đây. |
30
+ | `VERDICT_FIELD` | ✅ | Ghi kết quả vào đâu. `/qc-analyze` → cột `Trạng thái` + `Câu trả lời` của bảng gap; `/refine-prd` · `/review-context` → `status` + `suggestion` của findings YAML. |
31
+ | `RERATE` | | `on` (mặc định) chạy GIAI ĐOẠN 1B — hiệu chỉnh mức độ. `off` bỏ qua, chỉ giữ/bỏ. |
32
+
33
+ > **Bỏ qua ở chế độ sub-agent:** nếu Gate Bước 0 đã set `_agent_mode: true`, orchestrator
34
+ > chịu trách nhiệm gọi bước này một lần trên tập finding đã hợp nhất — sub-agent **không**
35
+ > tự verify phần của mình (verify từng mảnh rời không thấy được T6 trùng lặp).
36
+
37
+ ---
38
+
39
+ ## RÀNG BUỘC NGUỒN
40
+
41
+ - **Chỉ `EVIDENCE_ROOT`** làm căn cứ. **KHÔNG** dùng artifact nội bộ do chính pipeline sinh ra
42
+ (`{paths.qc_dir}/**`, `{paths.refinement_dir}/**`, test-case, report) — đó là vòng lặp:
43
+ lấy kết luận của mình làm bằng chứng cho mình.
44
+ - **Bỏ qua** — không đọc, không trích làm căn cứ — các section **Change Log**, **Appendix**,
45
+ và **Giả định AI / AI Assumptions** trong mọi tài liệu. Căn cứ chỉ lấy từ **thân bài**
46
+ (AC · BR · UC · Wireframe · Screen Spec · Scenario).
47
+ *Change log là "delta narrative", phải re-ground về thân bài; Appendix và Giả định AI là
48
+ ghi chú nháp, không phải nguồn chân lý.*
49
+ - Đọc **cả tài liệu gốc cấp trên** (`{paths.product_definitions_dir}/`) và **tài liệu liên quan**
50
+ (`{paths.business_dictionary}`, `{paths.core_entities}`) — một finding có thể đã được trả lời
51
+ ở tài liệu khác, không riêng spec đang xét.
52
+
53
+ ---
54
+
55
+ ## 5 anti-pattern — nhận diện trước khi kết luận
56
+
57
+ | # | Anti-pattern | Dấu hiệu |
58
+ |---|---|---|
59
+ | **AP1** | Phạm vi tích hợp lẫn vào spec nghiệp vụ | Finding nói về API contract, queue, service-to-service, retry backend, webhook — thứ PRD đã khai "ngoài phạm vi" |
60
+ | **AP2** | Rule cha bị tính là thiếu ở con | *"PRD con không mô tả X"* mà X đã có trong `{paths.product_definitions_dir}/` — PRD con **kế thừa** cha theo thiết kế |
61
+ | **AP3** | Finding UI tạo ra mà chưa đọc design-spec | *"thiếu behavior/navigation/state X"* mà X được mô tả rõ trong design-spec §Actions / §Screen States |
62
+ | **AP4** | Bias "nhiều finding = làm kỹ" | Cố sinh nhiều để thể hiện thoroughness. **5 finding thật tốt hơn 22 finding với 20 cái ảo.** Không cần điền đủ K nếu thực tế chỉ có M < K |
63
+ | **AP5** | Trích từ nguồn cấm | Evidence tham chiếu §Giả định AI / AI Assumptions / Change Log |
64
+ | **AP6** | Nâng note thứ cấp thành finding | Một ghi chú *"nghi X lệch"* trong BDD/design-spec là **claim cần verify, KHÔNG phải bằng chứng**. Chưa mở nguồn sơ cấp (PRD·BR·contract·Figma) thì chưa được raise. Không mở được asset → ghi *"chưa verify — cần Designer xác nhận"*, KHÔNG khẳng định *"asset đang sai"* |
65
+
66
+ ---
67
+
68
+ ## 3 câu hỏi lọc bắt buộc
69
+
70
+ Mỗi finding phải vượt **cả ba**. Rớt bất kỳ câu nào → loại.
71
+
72
+ | Câu | Giữ khi | Rớt thì |
73
+ |---|---|---|
74
+ | **Q1** — *"X đã được spec ở design-spec / product-definition / tech-docs chưa?"* | **Chưa** — tìm khắp `EVIDENCE_ROOT` không thấy | `❌ INVALID — spec đã trả lời` |
75
+ | **Q2** — *"X có thuộc phạm vi spec này không?"* | **Có** — spec này đặc tả hành vi X | `❌ INVALID — ngoài phạm vi` |
76
+ | **Q3** — *"Người thực thi tự quyết được không cần PO/BA confirm?"* | **Không** — bắt buộc cần PO/BA chốt | `⚠️ RECLASSIFY` (xem T5d/T5e) |
77
+
78
+ > **Q3 là câu bảo vệ thời gian của PO.** Mọi thứ QC/dev tự quyết được mà vẫn đẩy lên PO
79
+ > đều là chi phí thuần — và tệ hơn, nó làm loãng những câu thật.
80
+
81
+ ---
82
+
83
+ ## GIAI ĐOẠN 1 — T1…T6 cho từng finding
84
+
85
+ Chạy tuần tự. Rớt bất kỳ test nào → không hợp lệ, ghi verdict tương ứng.
86
+
87
+ ### T1 — Evidence có thật & đúng nội dung *(chống bịa trích dẫn)*
88
+ Mở đúng file/section mà finding trích. Tìm đoạn nguyên văn.
89
+ - **FAIL nếu:** trích dẫn không tồn tại · bị diễn giải sai lệch nghĩa · hoặc đoạn trích
90
+ **không thực sự nói điều finding khẳng định**.
91
+ - **FAIL nếu evidence trích từ Change Log / Appendix / Giả định AI** — nguồn cấm.
92
+ Phải re-ground về thân AC/BR/UC/Wireframe; thân bài không nói điều đó → finding sai.
93
+ - → `❌ INVALID — evidence bịa/sai/nguồn-cấm`
94
+
95
+ ### T2 — Hành vi "thiếu" đúng là yêu cầu của spec *(chống bịa yêu cầu)*
96
+ Với finding MISSING/AMBIGUOUS: spec nguồn **có thật sự nêu hoặc ngụ ý** hành vi X không?
97
+ - **FAIL nếu:** X **không được tài liệu nào yêu cầu** — finding tự nghĩ ra một yêu cầu
98
+ rồi than spec không mô tả nó.
99
+ - → `❌ INVALID — yêu cầu tự bịa`
100
+
101
+ ### T3 — Chưa được trả lời ở nơi khác *(chống finding đã cover)*
102
+ Tìm khắp `EVIDENCE_ROOT` (gồm tài liệu gốc + liên quan) xem câu hỏi đã có lời đáp chưa —
103
+ kể cả **trả lời ngầm định** bằng cách diễn đạt điều kiện.
104
+ - → `❌ INVALID — spec đã trả lời` *(kèm trích nguồn trả lời)*
105
+
106
+ ### T3b — Mâu thuẫn thật hay chỉ khác UC/pha *(chỉ áp cho finding CONTRADICTORY)*
107
+ Xác định **UC + pha** của TỪNG rule (chuẩn bị / thực hiện / nộp / công bố / quay lại).
108
+ - **FAIL nếu:** hai rule thuộc **UC/pha khác nhau** → thường là ngữ cảnh **tuần tự** hoặc
109
+ **không giao nhau**, không phải mâu thuẫn tại cùng một thời điểm quyết định.
110
+ - → `❌ INVALID — khác UC/pha, không mâu thuẫn`
111
+
112
+ ### T4 — Kế thừa tài liệu gốc *(chống "con không lặp lại cha")*
113
+ Rule đã định nghĩa trong `{paths.product_definitions_dir}/` thì việc spec con không lặp lại
114
+ **không phải finding**.
115
+ - → `❌ INVALID — đã có ở tài liệu gốc`
116
+
117
+ ### T5 — Đúng loại *(chống phân loại nhầm)*
118
+
119
+ > ⚠️ **BẮT BUỘC xác định HƯỚNG trước khi gán loại** (tài liệu dẫn xuất so với PRD):
120
+ > - **THIẾU (dẫn xuất < PRD):** PRD yêu cầu màn/rule mà design/BDD KHÔNG có → `MISSING`.
121
+ > Xử lý = bổ sung vào tài liệu dẫn xuất.
122
+ > - **THỪA (dẫn xuất > PRD):** design/BDD **tự thêm** hành vi PRD không sanction →
123
+ > `CONTRADICTORY`, **KHÔNG dùng `MISSING`**. Xử lý = PO chốt giữ (định nghĩa hệ quả vào PRD)
124
+ > hay gỡ.
125
+ >
126
+ > Sai hướng = framing sai — gọi *"design thiếu"* trong khi design **thừa**.
127
+
128
+ | Nhóm | Nghĩa | Verdict |
129
+ |---|---|---|
130
+ | **(a)** Finding nghiệp vụ thật | spec nêu hành vi, không tài liệu nào phủ | `✅ VALID` — giữ mở |
131
+ | **(b)** Lệch đồng bộ (SYNC) | PRD đã cập nhật nhưng design-spec / BDD chưa phản ánh nội dung mới | `✅ VALID — SYNC` — **giữ mở**, mức Low–Medium, giao đội spec. KHÔNG đóng: cần track để cập nhật |
132
+ | **(c)** Metadata lệch | chênh version header, sai tên trace, format — **nội dung nghiệp vụ vẫn đúng** | `⚠️ RECLASSIFY — metadata` |
133
+ | **(d)** Làm-kỹ-test | thêm giá trị biên, liệt kê đủ ô decision table, biến thể dữ liệu — mà **rule/behavior đã được phủ** | `⚠️ RECLASSIFY — làm-kỹ-test` |
134
+ | **(e)** Tech/UX tự quyết | số lần retry, timeout/delay, loading spinner, animation, exact-copy nút/label, xử lý crash, cơ chế lưu session — thuộc Dev/Design, không phải PO/BA | `⚠️ RECLASSIFY — tech/UX tự quyết` |
135
+
136
+ > **Ranh giới SYNC vs metadata:** SYNC = *nội dung* PRD mới chưa được phản ánh vào tài liệu
137
+ > dẫn xuất (section còn thiếu). Metadata = chỉ số version lệch, nội dung đã đúng.
138
+ >
139
+ > **Ranh giới (c)(d) vs (a):** nếu **bản thân hành vi/rule đã có scenario hoặc mô tả phủ**,
140
+ > mọi đề xuất *"thêm ca biên / thêm giá trị / đủ ô bảng"* đều là (d), KHÔNG phải finding.
141
+ >
142
+ > **Ngoại lệ GIỮ ở (e):** *ý chính / khung thông điệp* của popup do PO chốt intent;
143
+ > và mọi ranh giới pháp lý / privacy.
144
+
145
+ ### T6 — Không trùng lặp *(chống double-count)*
146
+ So với các finding còn lại: cùng root cause → merge, giữ một, ghi rõ *"merge từ …"*.
147
+ - → `🔁 MERGE → {id}`
148
+
149
+ **Qua sạch T1–T6 (+T3b nếu CONTRADICTORY) → `✅ VALID`.**
150
+
151
+ ---
152
+
153
+ ## GIAI ĐOẠN 1B — Hiệu chỉnh mức độ *(chạy khi `RERATE=on`)*
154
+
155
+ T1–T6 quyết định finding **còn hay bỏ**; giai đoạn này quyết định cái còn lại **nặng hay nhẹ**.
156
+ Nhiều finding hợp lệ về mặt tồn tại nhưng **bị gán mức quá cao** — và một danh sách toàn
157
+ 🔴 Critical thì không xếp được ưu tiên, tức mất luôn giá trị của cột mức độ.
158
+
159
+ Với **mỗi** finding còn mở, hạ mức hoặc chuyển sang "ghi chú phạm vi" nếu rơi vào một trong
160
+ năm nhóm sau — cả năm đều **không phải lỗ hổng của feature đang xét**:
161
+
162
+ | # | Nhóm | Dấu hiệu | Xử lý |
163
+ |---|---|---|---|
164
+ | **R1** | Lệch pha với tài liệu gốc | Mâu thuẫn thật giữa PRD con (đã duyệt, version mới hơn) và product-definition / dictionary về cùng một quan sát | → **Low**, nhãn *"master-sync"*. Con chi phối ⇒ không ảnh hưởng test. Không chặn |
165
+ | **R2** | Spec con tự rõ, chỉ nền domain lệch | PRD con phát biểu dứt khoát; chỉ dictionary/master mâu thuẫn | → **ghi chú phạm vi** (không phải finding của feature); đề nghị sync riêng nền domain |
166
+ | **R3** | Nguồn tự đánh dấu "giả định" | Evidence là mục trong design-spec có cảnh báo ⚠️ *"là giả định, cần Designer bổ sung"* | → **ghi chú phạm vi**, không lập finding *(đồng nhất luật AP5)* |
167
+ | **R4** | Nhánh phòng vệ bất-khả-đạt | Nhánh guard chỉ chạy trên dữ liệu **ngoài** enum hợp lệ; ca đạt tới được đã có phủ | → **Low**, nhãn *"test-design"* — vấn đề cách mô phỏng dữ liệu, không phải mơ hồ spec |
168
+ | **R5** | Greenfield thiếu tech-doc | Thiếu openapi/tech-doc cho hành động lõi ở feature xây mới | → nhãn *"feasibility"* — chặn **tự-động-hoá**, KHÔNG phải khuyết tật nghiệp vụ ở tầng PRD |
169
+
170
+ > **Mẹo chi phối:** một *pass-through rule* (hệ thống KHÔNG validate gì) làm tan phần lớn
171
+ > "mơ hồ" vì không có bề mặt test → hạ mạnh. Ngược lại, drift mà **chính PRD tự flag**, hoặc
172
+ > mơ hồ ở **luồng chính có giao diện**, là finding THẬT — giữ nguyên mức.
173
+
174
+ **Cách ghi:** GIỮ mô tả gốc (audit trail), thêm mục *"Phản biện & Re-rating"* liệt kê lý do
175
+ từng thay đổi mức, rồi cập nhật cột mức độ. Finding chuyển hẳn sang "ghi chú phạm vi" thì
176
+ đánh dấu rõ — **KHÔNG xoá**.
177
+
178
+ ---
179
+
180
+ ## GIAI ĐOẠN 2 — Bảng thẩm định
181
+
182
+ Xuất bảng verdict *(không chèn dòng trắng giữa các hàng — dòng trắng làm vỡ bảng Markdown)*:
183
+
184
+ | ID | Verdict | Test rớt | Bằng chứng thẩm định (mở file nguồn) |
185
+ |---|---|---|---|
186
+ | … | `✅ VALID` / `❌ INVALID` / `⚠️ RECLASSIFY` / `🔁 MERGE` | T1..T6 / — | trích đúng dòng trong `EVIDENCE_ROOT` chứng minh verdict |
187
+
188
+ **Số liệu tổng:** tổng verify = N · VALID = a · INVALID = b · RECLASSIFY = c · MERGE = d.
189
+
190
+ ---
191
+
192
+ ## GIAI ĐOẠN 3 — Áp verdict vào `VERDICT_FIELD`
193
+
194
+ **KHÔNG XOÁ finding nào** — giữ audit trail. Đóng kèm lý do thì kiểm chứng được; xoá thì không.
195
+
196
+ | Verdict | Áp thế nào |
197
+ |---|---|
198
+ | `✅ VALID` | giữ nguyên, trạng thái mở |
199
+ | `✅ VALID — SYNC` | giữ mở, loại `SYNC`, mức Low–Medium, giao đội spec; phần trả lời để trống |
200
+ | `❌ INVALID` | → **đóng**; ghi lý do ngắn + trích nguồn (vd *"Closed — spec đã trả lời tại §BR13: …"*) |
201
+ | `⚠️ RECLASSIFY` | → **đóng**; ghi rõ *"Không phải finding nghiệp vụ — [metadata / làm-kỹ-test / tech-UX tự quyết]"* + đề xuất chuyển sang mục việc tương ứng |
202
+ | `🔁 MERGE` | → **đóng**; ghi *"Trùng root cause với {id}"* |
203
+
204
+ Sau khi áp:
205
+ 1. Cập nhật **tổng số** ở header + bảng **ưu tiên xử lý** — chỉ đếm cái còn mở.
206
+ 2. Kiểm format bảng Markdown: **không có dòng trắng giữa các hàng**.
207
+ 3. Nếu artifact có section liệt kê **tài liệu đã đọc**: verifier vừa mở trực tiếp nguồn nên
208
+ đối chiếu lại — file đã dùng làm evidence mà **thiếu** trong bảng, hoặc file liệt kê nhưng
209
+ không tồn tại → sửa cho khớp.
210
+
211
+ ---
212
+
213
+ ## Đầu ra + cam kết
214
+
215
+ In tóm tắt:
216
+
217
+ ```
218
+ [GAP VERIFY] {artifact} — verify {N} finding đang mở:
219
+ ✅ VALID: {a} | ❌ INVALID: {b} | ⚠️ RECLASSIFY: {c} | 🔁 MERGE: {d}
220
+ INVALID chi tiết: {id} (evidence bịa), {id} (spec đã trả lời), …
221
+ Sau verify còn {a} finding nghiệp vụ đang mở.
222
+ ```
223
+
224
+ **Cam kết cuối — bắt buộc in nguyên văn:**
225
+
226
+ > *"Đã mở trực tiếp file nguồn trong `{EVIDENCE_ROOT}` để kiểm chứng từng finding — KHÔNG dựa
227
+ > vào trường evidence của artifact. Mỗi finding còn mở đều có đủ 2 vế: spec nêu hành vi +
228
+ > không tài liệu nào phủ. Không giữ lại finding bịa/sai sự thật."*
229
+
230
+ Cam kết này **không phải nghi thức**: nó là chỗ duy nhất bước này tự khai đã làm đúng việc
231
+ mà không ai kiểm được từ bên ngoài. Không in được cam kết ⇒ chưa chạy đúng bước.
@@ -0,0 +1,119 @@
1
+ # QC Scope — phân giải phạm vi cho mọi lệnh `qc-*`
2
+
3
+ **Chạy TRƯỚC phần logic riêng của lệnh, và SAU `steps/gate.md`.** Bước này chốt bốn thứ mà
4
+ cả 6 trạm QC đều cần, để chúng không tự suy mỗi trạm một kiểu:
5
+
6
+ | Biến | Là gì |
7
+ |---|---|
8
+ | `TICKET-ID` | mã PRD — **thư mục artifact QC mang tên này** |
9
+ | `active_platform` | `web` \| `app` \| `system` \| … — một QC pass khoá đúng MỘT nền |
10
+ | `qc_artifact_dir` | `{paths.qc_dir}/{TICKET-ID}/{active_platform}/` |
11
+ | `uc_list` | các UC của (PRD × nền) này, kèm trạng thái BDD từng UC |
12
+
13
+ > **Vì sao gom về một chỗ.** Luật phân giải nền từng được copy-paste ở 5 lệnh và câu chữ đã
14
+ > lệch nhau. Năm bản của một luật là nơi drift sống: sửa bốn, quên một, và trạm bị quên ghi
15
+ > artifact vào sai thư mục **trong im lặng**.
16
+
17
+ ---
18
+
19
+ ## 1 — `TICKET-ID`
20
+
21
+ Artifact QC gom theo **PRD**, không theo UC. Nên mọi trạm phải quy được về `TICKET-ID`:
22
+
23
+ | `$ARGUMENTS` là | Cách lấy |
24
+ |---|---|
25
+ | **UC-ID** (`{TICKET-ID}-UC{N}`) | phần **trước** `-UC` — đúng luật `steps/gate.md` Bước 1 dùng để tìm tech-doc gộp |
26
+ | **TICKET-ID** | dùng trực tiếp |
27
+ | một **path file** (`.feature` / PRD / design-spec) | phân giải `{domain}` + `{prd-slug}` theo luật `context-loader` Bước 1, rồi lấy `TICKET-ID` từ tên file PRD `{TICKET-ID}-{prd-slug}.md` — file `.md` duy nhất ở gốc feature folder |
28
+
29
+ Đối chiếu: `TICKET-ID` suy ra phải khớp tên file PRD thật. Lệch → **DỪNG**, in cả hai giá
30
+ trị. (Suy sai `TICKET-ID` là ghi cả một PRD vào sai thư mục — không có bước nào phía sau bắt được.)
31
+
32
+ ---
33
+
34
+ ## 2 — `active_platform`
35
+
36
+ > **PHẢI phân giải TRƯỚC mọi phép đọc `.feature`.** `{UC-ID}-SC{N}` chỉ độc nhất trong
37
+ > (UC × nền), nên một UC đa nền có **nhiều file `.feature`** — `bdd/web/`, `bdd/app/`,
38
+ > `bdd/system/` — và mỗi file mang `@trace.status` **riêng**: bản web có thể `approved`
39
+ > trong khi bản app còn `draft`. Đọc "file `.feature` của UC" khi chưa biết nền là đọc một
40
+ > file **bất kỳ trong ba**: báo `approved` trong khi bản đang dùng còn nháp, hoặc chặn oan
41
+ > một bản đã duyệt.
42
+
43
+ Theo thứ tự, dừng ở cái đầu tiên khớp:
44
+
45
+ 1. `$ARGUMENTS` nêu nền (`web`/`app`/`system`/…) → dùng.
46
+ 2. Target là một file `.feature` → đọc `# @trace.platform` của nó.
47
+ 3. Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/*/` — **đúng một** thư mục nền → dùng nó.
48
+ 4. Glob `{paths.qc_dir}/{TICKET-ID}/*/` — **đúng một** thư mục nền đã có artifact → dùng nó.
49
+ *(chỉ dùng cho trạm 2–6; trạm `/qc-analyze` là trạm tạo ra thư mục đó nên không có gì để soi.)*
50
+ 5. Nhiều nền mà không suy được → hỏi *"QC pass này cho nền nào? (web/app/system)"*.
51
+ **Có `--yes`:** không hỏi — DỪNG với lỗi rõ ràng, vì đoán bừa nền là ghi artifact vào sai
52
+ thư mục và ghi `qc_status` vào sai sổ trace:
53
+ ```
54
+ ❌ {TICKET-ID} có {n} nền ({list}) — không suy được nền nào cho QC pass này.
55
+ Chạy headless thì phải nêu tường minh: /{lệnh} {TICKET-ID} web --yes
56
+ ```
57
+
58
+ Lưu `active_platform`. Từ đây, **mọi** phép đọc `.feature` chỉ đọc thư mục
59
+ `bdd/{active_platform}/` — không trộn SC chéo nền.
60
+
61
+ ---
62
+
63
+ ## 3 — `qc_artifact_dir`
64
+
65
+ ```
66
+ qc_artifact_dir = {paths.qc_dir}/{TICKET-ID}/{active_platform}/
67
+ ```
68
+
69
+ Chứa: `REQUIREMENT_ANALYSIS.md` · `DOC_GAP.md` · `TEST_PLAN.md` · `test-cases/*.Test.md`
70
+ — **mỗi loại đúng MỘT file cho cả PRD**, các UC là mục/hàng bên trong.
71
+
72
+ `{paths.qc_dir}` là folder top-level **nhìn thấy** trong repo QC (mặc định `docs/`, **không**
73
+ phải `.agent/` ẩn) để đội QC mở và xử lý output dễ dàng. Spec chính thức ở lại spec submodule
74
+ của PO — đừng ghi artifact QC vào đó.
75
+
76
+ > **Sổ trace KHÔNG theo layout này.** Nó vẫn là `{paths.trace_dir}/{domain}/{prd-slug}/{UC-ID}-{active_platform}.tsv`
77
+ > — một sổ cho mỗi (UC × nền), vì mỗi hàng là một scenario. Liên kết giữa hai bên đi qua
78
+ > **cột `UC`** của bảng gap, không qua đường dẫn file.
79
+
80
+ ---
81
+
82
+ ## 4 — `uc_list`
83
+
84
+ Glob `{paths.specs_dir}/{domain}/{prd-slug}/bdd/{active_platform}/*.feature`. Mỗi file → một
85
+ UC: đọc `# @trace.id` (mã UC) và `# @trace.status` từ header.
86
+
87
+ Chia hai nhóm:
88
+
89
+ | Nhóm | Điều kiện | Xử lý |
90
+ |---|---|---|
91
+ | **Trong phạm vi** | `@trace.status: approved` | phân tích / thiết kế / chạy bình thường |
92
+ | **Chưa xét** | khác `approved` | **KHÔNG** phân tích; vẫn ghi một hàng vào bảng phạm vi kèm trạng thái thật |
93
+
94
+ In bảng phạm vi ra trước khi làm gì:
95
+ ```
96
+ Phạm vi QC — {TICKET-ID} / {active_platform}
97
+ ✅ {UC-ID} {tên UC} approved
98
+ ⏸ {UC-ID} {tên UC} draft → chưa xét
99
+ → {n} UC trong phạm vi · {m} chưa xét
100
+ ```
101
+
102
+ **Cờ `--include-draft`:** phân tích cả UC chưa duyệt, nhưng **vẫn in bảng trên** và đánh dấu
103
+ trong artifact là dựa trên BDD nháp.
104
+
105
+ **Không UC nào `approved` và không có `--include-draft` → DỪNG:**
106
+ ```
107
+ ❌ {TICKET-ID} ({active_platform}): 0/{n} UC có BDD approved — không có gì để chạy.
108
+ Cách đúng: người duyệt đặt `# @trace.status: approved` rồi chạy lại.
109
+ Muốn chạy sớm trên BDD nháp (prototype): thêm --include-draft
110
+ ```
111
+
112
+ > **Vì sao có `--include-draft` chứ không chặn cứng.** QC sớm trên BDD nháp là một cách dùng
113
+ > **cố ý được cho phép** từ trước (guard cũ là cảnh báo mềm, không phải chặn). Bỏ hẳn nó là
114
+ > lấy đi một năng lực đang có mà không ai khai. Còn để mặc định `approved`-only thì cái
115
+ > thường gặp là cái an toàn, và cái sớm phải nói ra.
116
+
117
+ > **Vì sao `--yes` không thay được `--include-draft`.** `--yes` nghĩa *"tôi không ngồi đây để
118
+ > trả lời"*; `--include-draft` nghĩa *"tôi biết BDD còn nháp và vẫn muốn chạy"*. Gộp hai cái
119
+ > là để một lần chạy headless âm thầm phân tích spec chưa chốt rồi bàn giao như thể đã chốt.
@@ -8,10 +8,11 @@ vòng không sinh thêm gì mới, *trước khi* ghi file findings.
8
8
 
9
9
  Lệnh gọi cung cấp hai thứ bắt buộc + hai tuỳ chọn:
10
10
  - **DIMENSIONS** — danh sách các chiều review để fan out
11
- (`/refine-prd` → 3 lăng kính; `/review-context` → các P-check hoặc B-check).
11
+ (`/refine-prd` → 4 lăng kính; `/review-context` → các P-check hoặc B-check; `/qc-analyze` → 3 lăng kính quét gap).
12
12
  - **FINDINGS SCHEMA** — dạng YAML mà mỗi finding phải theo (định nghĩa trong lệnh).
13
13
  - **GRANULARITY** *(tuỳ chọn, mặc định `auto`)* — `auto`: chọn độ mịn fan-out theo bảng ngưỡng kích thước ở Phase 1 (hành vi cũ). `per-uc`: **LUÔN** fan-out theo từng UC, **bỏ qua ngưỡng** — dùng cho review cần độ đầy đủ cao (`/refine-prd` truyền cái này để lần đầu đã quét sâu). Lệnh không truyền → `auto` → hành vi không đổi.
14
14
  - **CHANGED_SCOPE** *(tuỳ chọn)* — danh sách UC/section đã thay đổi (review **delta**). Nếu được truyền, Phase 1 chỉ fan-out trên các phạm vi này + PRD-global; Phase 2 critic vẫn quét **toàn doc** làm lưới an toàn. Không truyền → quét toàn bộ như thường.
15
+ - **VERIFY** *(tuỳ chọn, mặc định `off`)* — `on` chèn **Phase 2.5** (`steps/gap-verify.md`) giữa critic và dedup: mỗi finding phải mở lại tài liệu nguồn tự chứng minh trước khi được giữ. Không truyền → hành vi không đổi.
15
16
 
16
17
  > **Bỏ qua ở chế độ sub-agent:** Nếu Gate Bước 0 đã set `_agent_mode: true`, toàn bộ
17
18
  > quy trình này bị **bỏ qua** — orchestrator đã chạy sẵn một dimension/UC cho mỗi
@@ -130,6 +131,31 @@ Ghi lại `convergence_rounds` (số vòng critic đã chạy) cho report.
130
131
 
131
132
  ---
132
133
 
134
+ ## Phase 2.5 — Thẩm định *(chỉ chạy khi `VERIFY = on`)*
135
+
136
+ **Vì sao có bước này.** Phase 1 và Phase 2 chỉ có **một chiều lực**: fan-out mở rộng bề
137
+ ngang, critic lặp cho tới khi không còn gì mới — cả hai đều hỏi *"còn thiếu gì nữa?"*.
138
+ Không có gì hỏi ngược lại *"cái vừa tìm ra có thật không?"*. Nên quy trình này đẩy **recall**
139
+ lên mà **không có gì kéo precision lại**, và càng lặp critic thì tỉ lệ finding bịa càng cao —
140
+ đúng thứ nó tự sinh ra: khẳng định hành vi tài liệu không nêu, trích evidence sai, hoặc gắn
141
+ nhãn vấn đề cho thứ thực ra là chuyện làm-kỹ-hơn.
142
+
143
+ Chạy `steps/gap-verify.md` trên `ALL_FINDINGS` với:
144
+ - `FINDINGS` = `ALL_FINDINGS` (sau Phase 2)
145
+ - `EVIDENCE_ROOT` = `{paths.specs_dir}` — hoặc giá trị lệnh gọi chỉ định
146
+ - `VERDICT_FIELD` = trường trạng thái của FINDINGS SCHEMA mà lệnh định nghĩa
147
+ - `RERATE` = `on`
148
+
149
+ Finding bị `❌ INVALID` / `⚠️ RECLASSIFY` / `🔁 MERGE` **không đi tiếp sang Phase 3** — nhưng
150
+ **KHÔNG bị xoá**: chúng vào file findings với trạng thái đóng + lý do, để người đọc kiểm chứng
151
+ được vì sao chúng bị loại. Ghi lại số liệu verdict cho report.
152
+
153
+ > **Chạy TRƯỚC Phase 3, không phải sau.** Dedup và giải quyết xung đột là việc tốn suy luận;
154
+ > làm nó trên một tập còn lẫn finding bịa là vừa phí, vừa nguy hiểm — một finding ảo có thể
155
+ > "thắng" một finding thật ở bước giữ-cái-severity-cao-hơn.
156
+
157
+ ---
158
+
133
159
  ## Phase 3 — Dedup, giải quyết xung đột, merge
134
160
 
135
161
  Các sub-agent chạy **mù với nhau** (độc lập = độ phủ đa dạng). Chúng không bao giờ
@@ -63,14 +63,16 @@ paths:
63
63
  refinement_dir: ".agent/review"
64
64
 
65
65
  # QC's OWN analysis/design working docs (qc-analyze/plan/design-test outputs:
66
- # REQUIREMENT_ANALYSIS.md, DOC_GAPS.md, TEST_PLAN.md, test-cases/*.Test.md).
67
- # One subfolder per UC: {qc_dir}/{UC-ID}/. Default "docs" (the QC team's own
66
+ # REQUIREMENT_ANALYSIS.md, DOC_GAP.md, TEST_PLAN.md, test-cases/*.Test.md).
67
+ # Grouped by PRD: {qc_dir}/{TICKET-ID}/{platform}/ ONE DOC_GAP.md / TEST_PLAN.md /
68
+ # REQUIREMENT_ANALYSIS.md per (PRD x platform), with the UCs as rows/sections inside
69
+ # (see steps/qc-scope.md). Default "docs" (the QC team's own
68
70
  # convention), VISIBLE — not hidden under .agent/. NOTE: specs (PRD / .feature /
69
71
  # design-spec) are NOT here — they come from the PO spec submodule (spec_source).
70
72
  qc_dir: "docs"
71
73
 
72
74
  # WHERE the qc-* commands LOAD their skills from (qa-analyst / qa-designer / qa-planner
73
- # / qa-reviewer / qa-runner + DOC_GAPS.template.md). Default = the framework-bundled
75
+ # / qa-reviewer / qa-runner + DOC_GAP.template.md). Default = the framework-bundled
74
76
  # copy at .agent/skills/qc (works standalone). The QC team OWNS these skills in their
75
77
  # canonical repo (ai-automation-qc-base) — point this at that repo/submodule (e.g.
76
78
  # "qc-base/.claude/skills") so the skills evolve INDEPENDENTLY and are NOT overwritten
@@ -38,7 +38,7 @@
38
38
 
39
39
  | Artifact | Nội dung |
40
40
  |----------|----------|
41
- | `docs/{UC-ID}/…` | `REQUIREMENT_ANALYSIS.md`, `DOC_GAPS.md`, `TEST_PLAN.md`, `test-cases/*.Test.md` |
41
+ | `docs/{TICKET-ID}/{platform}/…` | `REQUIREMENT_ANALYSIS.md`, `DOC_GAP.md`, `TEST_PLAN.md`, `test-cases/*.Test.md` — **mỗi loại đúng một file cho cả (PRD × nền)**, các UC là hàng/mục bên trong (cột `UC`) |
42
42
  | Script Python pytest-playwright | Sinh từ `.Test.md` đã review |
43
43
  | Cột `qc_status` trong `.trace/…/{UC-ID}-{platform}.tsv` | Trạng thái QC **chính thức** |
44
44
  | Evidence + report | `/qc-report` — kèm product-gap đẩy về PO/Dev |
@@ -70,7 +70,7 @@ Dây chuyền **6 trạm**, output trạm trước là input trạm sau:
70
70
 
71
71
  | # | Trạm | Việc |
72
72
  |---|------|------|
73
- | 1 | `/qc-analyze` | Phân rã yêu cầu + phát hiện **gap tài liệu** (`DOC_GAPS.md`) |
73
+ | 1 | `/qc-analyze` | Phân rã yêu cầu + phát hiện **gap tài liệu** (`DOC_GAP.md`) |
74
74
  | 2 | `/qc-plan` | Đánh giá **rủi ro** + câu hỏi cho dev (`TEST_PLAN.md`) |
75
75
  | 3 | `/qc-design-test` | Thiết kế **test case** dạng Markdown (`*.Test.md`) |
76
76
  | 4 | `/qc-review` | 🛑 **Cổng review** hai chiều: test case & script trước khi chạy |
@@ -89,7 +89,7 @@ Mọi lệnh chạy chung một **Gate** (model check → target → context-loa
89
89
 
90
90
  | Lệnh | Input | Output | Owner |
91
91
  |------|-------|--------|-------|
92
- | `/qc-analyze` | UC + spec | `REQUIREMENT_ANALYSIS.md`, `DOC_GAPS.md` | QA |
92
+ | `/qc-analyze` | UC + spec | `REQUIREMENT_ANALYSIS.md`, `DOC_GAP.md` | QA |
93
93
  | `/qc-plan` | Analysis | `TEST_PLAN.md` (rủi ro) | QA |
94
94
  | `/qc-design-test` | Plan | `test-cases/*.Test.md` | QA |
95
95
  | `/qc-review` | Test case/script | 🛑 Cổng review | QA |